Commit 475f27fd authored by Jakob Unterwurzacher's avatar Jakob Unterwurzacher

nodefs: get rid of recursiveConsiderDropInode

Instead, drop the node from all parents in OnForget.

Fixes issue #106, stress-loopback (from
https://github.com/rfjakob/fsstress) now passes 40+ iterations.

Change-Id: I9a6bc08b88fc4f5a8bb63d449b29430e5b24ee7a
parent 6794332a
......@@ -127,9 +127,17 @@ func (c *FileSystemConnector) forgetUpdate(nodeID uint64, forgetCount int) {
if forgotten, handled := c.inodeMap.Forget(nodeID, forgetCount); forgotten {
node := (*Inode)(unsafe.Pointer(handled))
node.mount.treeLock.Lock()
c.recursiveConsiderDropInode(node)
if len(node.children) > 0 || !node.Node().Deletable() ||
node == c.rootNode || node.mountPoint != nil {
node.mount.treeLock.Unlock()
return
}
node.mount.treeLock.Unlock()
node.fsInode.OnForget()
}
// TODO - try to drop children even forget was not successful.
c.verify()
......@@ -140,39 +148,6 @@ func (c *FileSystemConnector) InodeHandleCount() int {
return c.inodeMap.Count()
}
// Must hold treeLock.
func (c *FileSystemConnector) recursiveConsiderDropInode(n *Inode) (drop bool) {
delChildren := []string{}
for k, v := range n.children {
// Only consider children from the same mount, or
// already unmounted mountpoints.
if v.mountPoint == nil && c.recursiveConsiderDropInode(v) {
delChildren = append(delChildren, k)
}
}
for _, k := range delChildren {
ch := n.rmChild(k)
if ch == nil {
log.Panicf("trying to del child %q, but not present", k)
}
ch.fsInode.OnForget()
}
if len(n.children) > 0 || !n.Node().Deletable() {
return false
}
if n == c.rootNode || n.mountPoint != nil {
return false
}
n.openFilesMutex.Lock()
ok := len(n.openFiles) == 0
n.openFilesMutex.Unlock()
return ok
}
// Finds a node within the currently known inodes, returns the last
// known node and the remaining unknown path components. If parent is
// nil, start from FUSE mountpoint.
......
......@@ -417,8 +417,21 @@ func (n *pathInode) OnForget() {
return
}
n.pathFs.pathLock.Lock()
delete(n.pathFs.clientInodeMap, n.clientInode)
parents := make(map[parentData]struct{}, len(n.parents))
for k, v := range n.parents {
parents[k] = v
}
n.pathFs.pathLock.Unlock()
// Remove ourself from all parents. This will also remove the entry from
// clientInodeMap when the last parent is removed.
for p := range parents {
if ch := p.parent.Inode().GetChild(p.name); ch != nil && ch.Node() != n {
// Another node has taken our place - leave it alone.
continue
}
p.parent.Inode().RmChild(p.name)
}
}
////////////////////////////////////////////////////////////////
......@@ -521,7 +534,10 @@ func (n *pathInode) Rename(oldName string, newParent nodefs.Node, newName string
code = n.fs.Rename(oldPath, newPath, context)
if code.Ok() {
ch := n.Inode().RmChild(oldName)
p.Inode().AddChild(newName, ch)
if ch != nil {
// oldName may have been forgotten in the meantime.
p.Inode().AddChild(newName, ch)
}
}
return code
}
......@@ -609,7 +625,7 @@ func (n *pathInode) findChild(fi *fuse.Attr, name string, fullPath string) (out
out = v[0].node
if fi.Nlink == 1 {
log.Println("Found linked inode, but Nlink == 1", fullPath)
log.Println("Found linked inode, but Nlink == 1, ino=%d", fullPath, fi.Ino)
}
}
n.pathFs.pathLock.RUnlock()
......@@ -619,7 +635,7 @@ func (n *pathInode) findChild(fi *fuse.Attr, name string, fullPath string) (out
out = n.createChild(name, fi.IsDir())
out.clientInode = fi.Ino
} else {
// should add 'out' as a child to n ?
n.Inode().AddChild(name, out.Inode())
}
return out
}
......
......@@ -1506,10 +1506,7 @@ func TestUnionFSBarf(t *testing.T) {
if err := os.Rename(wd+"/rw/dir/file", wd+"/rw/file"); err != nil {
t.Fatalf("os.Rename: %v", err)
}
err := os.Rename(wd+"/mnt/file", wd+"/mnt/dir2/file")
if fuse.ToStatus(err) != fuse.ENOENT {
// TODO - this should just succeed?
if err := os.Rename(wd+"/mnt/file", wd+"/mnt/dir2/file"); err != nil {
t.Fatalf("os.Rename: %v", err)
}
}
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