Browse Source

inomap: deterministically set root device

We used to have "first Translate() wins". This is not deterministic,
as the LOOKUP for the root directory does not seem to reach us, so
the first user LOOKUP would win, which may be on a mountpoint.
master
Jakob Unterwurzacher 10 months ago
parent
commit
c9b825c58a
  1. 12
      internal/fusefrontend/root_node.go
  2. 17
      internal/fusefrontend_reverse/root_node.go
  3. 13
      internal/inomap/inomap.go
  4. 17
      internal/inomap/inomap_test.go

12
internal/fusefrontend/root_node.go

@ -62,18 +62,28 @@ type RootNode struct {
}
func NewRootNode(args Args, c *contentenc.ContentEnc, n *nametransform.NameTransform) *RootNode {
var rootDev uint64
var st syscall.Stat_t
if err := syscall.Stat(args.Cipherdir, &st); err != nil {
tlog.Warn.Printf("Could not stat backing directory %q: %v", args.Cipherdir, err)
} else {
rootDev = uint64(st.Dev)
}
if len(args.Exclude) > 0 {
tlog.Warn.Printf("Forward mode does not support -exclude")
}
ivLen := nametransform.DirIVLen
if args.PlaintextNames {
ivLen = 0
}
rn := &RootNode{
args: args,
nameTransform: n,
contentEnc: c,
inoMap: inomap.New(),
inoMap: inomap.New(rootDev),
dirCache: dirCache{ivLen: ivLen},
quirks: syscallcompat.DetectQuirks(args.Cipherdir),
}

17
internal/fusefrontend_reverse/root_node.go

@ -2,10 +2,13 @@ package fusefrontend_reverse
import (
"log"
"os"
"path/filepath"
"strings"
"syscall"
"github.com/rfjakob/gocryptfs/v2/internal/exitcodes"
"github.com/rfjakob/gocryptfs/v2/internal/tlog"
"golang.org/x/sys/unix"
@ -46,12 +49,14 @@ type RootNode struct {
// ReverseFS provides an encrypted view.
func NewRootNode(args fusefrontend.Args, c *contentenc.ContentEnc, n *nametransform.NameTransform) *RootNode {
var rootDev uint64
if args.OneFileSystem {
var st syscall.Stat_t
err := syscall.Stat(args.Cipherdir, &st)
if err != nil {
log.Panicf("Could not stat backing directory %q: %v", args.Cipherdir, err)
var st syscall.Stat_t
if err := syscall.Stat(args.Cipherdir, &st); err != nil {
tlog.Warn.Printf("Could not stat backing directory %q: %v", args.Cipherdir, err)
if args.OneFileSystem {
tlog.Fatal.Printf("This is a fatal error in combination with -one-file-system")
os.Exit(exitcodes.CipherDir)
}
} else {
rootDev = uint64(st.Dev)
}
@ -59,7 +64,7 @@ func NewRootNode(args fusefrontend.Args, c *contentenc.ContentEnc, n *nametransf
args: args,
nameTransform: n,
contentEnc: c,
inoMap: inomap.New(),
inoMap: inomap.New(rootDev),
rootDev: rootDev,
}
if len(args.Exclude) > 0 || len(args.ExcludeWildcard) > 0 || len(args.ExcludeFrom) > 0 {

13
internal/inomap/inomap.go

@ -49,13 +49,22 @@ type InoMap struct {
}
// New returns a new InoMap.
func New() *InoMap {
return &InoMap{
// Inode numbers on device `rootDev` will be passed through as-is.
// If `rootDev` is zero, the first Translate() call decides the effective
// rootDev.
func New(rootDev uint64) *InoMap {
m := &InoMap{
namespaceMap: make(map[namespaceData]uint16),
namespaceNext: 0,
spillMap: make(map[QIno]uint64),
spillNext: 0,
}
if rootDev > 0 {
// Reserve namespace 0 for rootDev
m.namespaceMap[namespaceData{rootDev, 0}] = 0
m.namespaceNext = 1
}
return m
}
var spillWarn sync.Once

17
internal/inomap/inomap_test.go

@ -6,7 +6,7 @@ import (
)
func TestTranslate(t *testing.T) {
m := New()
m := New(0)
q := QIno{Ino: 1}
out := m.Translate(q)
if out != 1 {
@ -25,12 +25,7 @@ func TestTranslate(t *testing.T) {
func TestTranslateStress(t *testing.T) {
const baseDev = 12345
m := New()
// Make sure baseDev gets namespace id zero
var q QIno
q.Dev = baseDev
m.Translate(q)
m := New(baseDev)
var wg sync.WaitGroup
wg.Add(4)
@ -100,7 +95,7 @@ func TestTranslateStress(t *testing.T) {
}
func TestSpill(t *testing.T) {
m := New()
m := New(0)
var q QIno
q.Ino = maxPassthruIno + 1
out1 := m.Translate(q)
@ -119,7 +114,7 @@ func TestSpill(t *testing.T) {
// TestUniqueness checks that unique (Dev, Flags, Ino) tuples get unique inode
// numbers
func TestUniqueness(t *testing.T) {
m := New()
m := New(0)
var q QIno
outMap := make(map[uint64]struct{})
for q.Dev = 0; q.Dev < 10; q.Dev++ {
@ -141,7 +136,7 @@ func TestUniqueness(t *testing.T) {
}
func BenchmarkTranslateSingleDev(b *testing.B) {
m := New()
m := New(0)
var q QIno
for n := 0; n < b.N; n++ {
q.Ino = uint64(n % 1000)
@ -150,7 +145,7 @@ func BenchmarkTranslateSingleDev(b *testing.B) {
}
func BenchmarkTranslateManyDevs(b *testing.B) {
m := New()
m := New(0)
var q QIno
for n := 0; n < b.N; n++ {
q.Dev = uint64(n % 10)

Loading…
Cancel
Save