Commit a9ddcb8a authored by Jakob Unterwurzacher's avatar Jakob Unterwurzacher Committed by Han-Wen Nienhuys

handleMap: track per-handle generation number

We used to hand out a new generation number even
for already-known handles. This does not seem to
cause problems on Linux, but osxfuse throws errors
to userspace with

        osxfuse: vnode changed generation

showing up in the kernel log.

Introduce a per-handle generation number that stays
constant until the handle is forgotten.

Tested on Linux and MacOS via gocryptfs. Add test for handle map
behavior.

Fixes https://github.com/hanwen/go-fuse/issues/204
See also https://github.com/hanwen/go-fuse/pull/205
parent 73e231d6
...@@ -35,8 +35,9 @@ type handleMap interface { ...@@ -35,8 +35,9 @@ type handleMap interface {
} }
type handled struct { type handled struct {
handle uint64 handle uint64
count int generation uint64
count int
} }
func (h *handled) verify() { func (h *handled) verify() {
...@@ -75,25 +76,29 @@ func newPortableHandleMap() *portableHandleMap { ...@@ -75,25 +76,29 @@ func newPortableHandleMap() *portableHandleMap {
func (m *portableHandleMap) Register(obj *handled) (handle, generation uint64) { func (m *portableHandleMap) Register(obj *handled) (handle, generation uint64) {
m.Lock() m.Lock()
if obj.count == 0 { defer m.Unlock()
if len(m.freeIds) == 0 { // Reuse existing handle
handle = uint64(len(m.handles)) if obj.count != 0 {
m.handles = append(m.handles, obj) obj.count++
} else { return obj.handle, obj.generation
handle = m.freeIds[len(m.freeIds)-1] }
m.freeIds = m.freeIds[:len(m.freeIds)-1] // Create a new handle number or recycle one on from the free list
m.generation++ if len(m.freeIds) == 0 {
m.handles[handle] = obj obj.handle = uint64(len(m.handles))
} m.handles = append(m.handles, obj)
m.used++
obj.handle = handle
} else { } else {
handle = obj.handle obj.handle = m.freeIds[len(m.freeIds)-1]
m.freeIds = m.freeIds[:len(m.freeIds)-1]
m.handles[obj.handle] = obj
} }
// Increment generation number to guarantee the (handle, generation) tuple
// is unique
m.generation++
m.used++
obj.generation = m.generation
obj.count++ obj.count++
generation = m.generation
m.Unlock() return obj.handle, obj.generation
return
} }
func (m *portableHandleMap) Handle(obj *handled) (h uint64) { func (m *portableHandleMap) Handle(obj *handled) (h uint64) {
......
...@@ -126,3 +126,36 @@ func TestHandleMapGeneration(t *testing.T) { ...@@ -126,3 +126,36 @@ func TestHandleMapGeneration(t *testing.T) {
t.Fatalf("register should increase generation: got %d want greater than %d.", g2, g1) t.Fatalf("register should increase generation: got %d want greater than %d.", g2, g1)
} }
} }
func TestHandleMapGenerationKnown(t *testing.T) {
hm := newPortableHandleMap()
o1 := &handled{}
h1, g1 := hm.Register(o1)
o2 := &handled{}
h2, _ := hm.Register(o2)
h3, g3 := hm.Register(o1)
if h1 != h3 {
t.Fatalf("register known should reuse handle: got %d want %d.", h3, h1)
}
if g1 != g3 {
t.Fatalf("register known should reuse generation: got %d want %d.", g3, g1)
}
hm.Forget(h1, 2)
hm.Forget(h2, 1)
h1, g1 = hm.Register(o1)
h2, _ = hm.Register(o2)
h3, g3 = hm.Register(o1)
if h1 != h3 {
t.Fatalf("register known should reuse handle: got %d want %d.", h3, h1)
}
if g1 != g3 {
t.Fatalf("register known should reuse generation: got %d want %d.", g3, g1)
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment