diff --git a/fuse/fsconnector.go b/fuse/fsconnector.go index a92bc063ff551549d40b49ca85a045ca2f18e303..6b77fb74526c9459891c40718b80e0495802b929 100644 --- a/fuse/fsconnector.go +++ b/fuse/fsconnector.go @@ -121,9 +121,10 @@ func (c *FileSystemConnector) lookupUpdate(node *Inode) uint64 { node.nodeId = c.inodeMap.Register(&node.handled, node) } node.lookupCount += 1 + id := node.nodeId node.treeLock.Unlock() - return node.nodeId + return id } // Must run outside treeLock. @@ -294,6 +295,7 @@ func (c *FileSystemConnector) Mount(parent *Inode, name string, nodeFs NodeFileS // // EBUSY: there are open files, or submounts below this node. func (c *FileSystemConnector) Unmount(node *Inode) Status { + // TODO - racy. if node.mountPoint == nil { log.Println("not a mountpoint:", node.nodeId) return EINVAL @@ -324,13 +326,14 @@ func (c *FileSystemConnector) Unmount(node *Inode) Status { delete(parentNode.children, name) mount.fs.OnUnmount() - c.DeleteNotify(parentNode, mountInode, name) - + c.fsInit.DeleteNotify(parentNode.nodeId, mountInode.nodeId, name) return OK } func (c *FileSystemConnector) FileNotify(node *Inode, off int64, length int64) Status { + node.treeLock.RLock() n := node.nodeId + node.treeLock.RUnlock() if node == c.rootNode { n = raw.FUSE_ROOT_ID } @@ -346,7 +349,9 @@ func (c *FileSystemConnector) FileNotify(node *Inode, off int64, length int64) S } func (c *FileSystemConnector) EntryNotify(dir *Inode, name string) Status { + dir.treeLock.RLock() n := dir.nodeId + dir.treeLock.RUnlock() if dir == c.rootNode { n = raw.FUSE_ROOT_ID } @@ -357,12 +362,22 @@ func (c *FileSystemConnector) EntryNotify(dir *Inode, name string) Status { } func (c *FileSystemConnector) DeleteNotify(dir *Inode, child *Inode, name string) Status { + dir.treeLock.RLock() n := dir.nodeId + var chId uint64 + if child.treeLock != dir.treeLock { + child.treeLock.RLock() + chId = child.nodeId + child.treeLock.RUnlock() + } + + dir.treeLock.RUnlock() + if dir == c.rootNode { n = raw.FUSE_ROOT_ID } if n == 0 { return OK } - return c.fsInit.DeleteNotify(n, child.nodeId, name) + return c.fsInit.DeleteNotify(n, chId, name) } diff --git a/fuse/inode.go b/fuse/inode.go index 925ee42efb27a8806a861f526f4bedaee2fcbc36..b595c22b7e6af2822d8d082da7ddd5fe144fb728 100644 --- a/fuse/inode.go +++ b/fuse/inode.go @@ -41,8 +41,8 @@ type Inode struct { // The nodeId is only used to communicate to the kernel. If // it is zero, it means the kernel does not know about this - // Inode. You should probably never read nodeId, but always - // do lookupUpdate() on the node instead. + // Inode. Only forget/lookup/notify methods should nodeId + // directly. nodeId uint64 // lookupCount registers how often the kernel got this inode diff --git a/fuse/mount_test.go b/fuse/mount_test.go index 0f54e04eda3811f2a9f8f38e448807240b337c3b..c5df3a6334b38bd0c6337e69168ec366c41b0fa4 100644 --- a/fuse/mount_test.go +++ b/fuse/mount_test.go @@ -27,7 +27,10 @@ func TestMountOnExisting(t *testing.T) { t.Fatal("expect OK:", code) } - ts.pathFs.Unmount("mnt") + code = ts.pathFs.Unmount("mnt") + if !code.Ok() { + t.Errorf("Unmount failed: %v", code) + } } func TestMountRename(t *testing.T) { diff --git a/fuse/mountstate.go b/fuse/mountstate.go index 1a5b6ad93547f0819cf33c8641c515f3e22961c8..951e6d18b7e2dbaeb730c3d269e7ae974875e557 100644 --- a/fuse/mountstate.go +++ b/fuse/mountstate.go @@ -153,7 +153,8 @@ func (ms *MountState) Unmount() (err error) { if err == nil { break } - + + fmt.Fprintf(os.Stderr, "umount failed; retrying\n") // Sleep for a bit. This is not pretty, but there is // no way we can be certain that the kernel thinks all // open files have already been closed.