diff options
Diffstat (limited to 'internal/inomap')
-rw-r--r-- | internal/inomap/inomap.go | 41 | ||||
-rw-r--r-- | internal/inomap/inomap_test.go | 13 |
2 files changed, 38 insertions, 16 deletions
diff --git a/internal/inomap/inomap.go b/internal/inomap/inomap.go index 0f7ade3..b4dbf27 100644 --- a/internal/inomap/inomap.go +++ b/internal/inomap/inomap.go @@ -3,8 +3,8 @@ // // Format of the returned inode numbers: // -// [spill bit = 0][15 bit namespace id][48 bit passthru inode number] -// [spill bit = 1][63 bit spill inode number ] +// [spill bit = 0][15 bit namespace id][48 bit passthru inode number] = 64 bit translated inode number +// [spill bit = 1][63 bit counter ] = 64 bit spill inode number // // Each (Dev, Tag) tuple gets a namespace id assigned. The original inode // number is then passed through in the lower 48 bits. @@ -16,7 +16,9 @@ package inomap import ( "log" + "math" "sync" + "sync/atomic" "syscall" "github.com/rfjakob/gocryptfs/v2/internal/tlog" @@ -27,10 +29,8 @@ const ( maxNamespaceId = 1<<15 - 1 // max value of 48 bit passthru inode number maxPassthruIno = 1<<48 - 1 - // max value of 63 bit spill inode number - maxSpillIno = 1<<63 - 1 - // bit 63 is used as the spill bit - spillBit = 1 << 63 + // the spill inode number space starts at 0b10000...0. + spillSpaceStart = 1 << 63 ) // InoMap stores the maps using for inode number translation. @@ -57,7 +57,7 @@ func New(rootDev uint64) *InoMap { namespaceMap: make(map[namespaceData]uint16), namespaceNext: 0, spillMap: make(map[QIno]uint64), - spillNext: 0, + spillNext: spillSpaceStart, } if rootDev > 0 { // Reserve namespace 0 for rootDev @@ -69,23 +69,32 @@ func New(rootDev uint64) *InoMap { var spillWarn sync.Once +// NextSpillIno returns a fresh inode number from the spill pool without adding it to +// spillMap. +// Reverse mode NextSpillIno() for gocryptfs.longname.*.name files where a stable +// mapping is not needed. +func (m *InoMap) NextSpillIno() (out uint64) { + if m.spillNext == math.MaxUint64 { + log.Panicf("spillMap overflow: spillNext = 0x%x", m.spillNext) + } + return atomic.AddUint64(&m.spillNext, 1) - 1 +} + func (m *InoMap) spill(in QIno) (out uint64) { - spillWarn.Do(func() { tlog.Warn.Printf("InoMap: opening spillMap for %v", in) }) + spillWarn.Do(func() { tlog.Warn.Printf("InoMap: opening spillMap for %#v", in) }) out, found := m.spillMap[in] if found { - return out | spillBit - } - if m.spillNext >= maxSpillIno { - log.Panicf("spillMap overflow: spillNext = 0x%x", m.spillNext) + return out } - out = m.spillNext - m.spillNext++ + + out = m.NextSpillIno() m.spillMap[in] = out - return out | spillBit + + return out } -// Translate maps the passed-in (device, inode) pair to a unique inode number. +// Translate maps the passed-in (device, tag, inode) tuple to a unique inode number. func (m *InoMap) Translate(in QIno) (out uint64) { m.Lock() defer m.Unlock() diff --git a/internal/inomap/inomap_test.go b/internal/inomap/inomap_test.go index 9ec2932..ce5b880 100644 --- a/internal/inomap/inomap_test.go +++ b/internal/inomap/inomap_test.go @@ -5,6 +5,11 @@ import ( "testing" ) +const ( + // bit 63 is used as the spill bit + spillBit = 1 << 63 +) + func TestTranslate(t *testing.T) { m := New(0) q := QIno{Ino: 1} @@ -102,6 +107,9 @@ func TestSpill(t *testing.T) { if out1&spillBit == 0 { t.Error("spill bit not set") } + if out1 != spillSpaceStart { + t.Errorf("unexpected first spill inode number %d", out1) + } out2 := m.Translate(q) if out2&spillBit == 0 { t.Error("spill bit not set") @@ -109,6 +117,11 @@ func TestSpill(t *testing.T) { if out1 != out2 { t.Errorf("unstable mapping: %d vs %d", out1, out2) } + q.Ino = maxPassthruIno + 2 + out3 := m.Translate(q) + if out3 != out1+1 { + t.Errorf("unexpected 2nd spill inode number %d", out1) + } } // TestUniqueness checks that unique (Dev, Flags, Ino) tuples get unique inode |