Commit bd746dd8 authored by Jakob Unterwurzacher's avatar Jakob Unterwurzacher

nodefs: lock early on FORGET

Taking the treeLock after inodeMap.Forget() exposed a
small window where the Inode that is about to be forgotten
could be handed out to the kernel under a new node ID.

Testing with fsstress for 1.000+ iterations showed that the
race can actually be hit, and causes "No such file or directory"
errors.

With the lock taken earlier, loopbackfs passes 10.000+ fsstress
iterations.

Change-Id: Ic02ae757d9a726ece01e8f0b3f0ff877f8e2dbc3
parent 0107672a
......@@ -125,18 +125,13 @@ func (c *FileSystemConnector) forgetUpdate(nodeID uint64, forgetCount int) {
return
}
if forgotten, handled := c.inodeMap.Forget(nodeID, forgetCount); forgotten {
node := (*Inode)(unsafe.Pointer(handled))
// Prevent concurrent modification of the tree while we are processing
// the FORGET
//
// TODO actually the lock should be taken BEFORE running inodeMap.Forget().
// However, treeLock is per-submount, and we don't know which one to lock
// in advance. Still passes fsstress testing just fine.
node.mount.treeLock.Lock()
defer node.mount.treeLock.Unlock()
// Prevent concurrent modification of the tree while we are processing
// the FORGET
node := (*Inode)(unsafe.Pointer(c.inodeMap.Decode(nodeID)))
node.mount.treeLock.Lock()
defer node.mount.treeLock.Unlock()
if forgotten, _ := c.inodeMap.Forget(nodeID, forgetCount); forgotten {
if len(node.children) > 0 || !node.Node().Deletable() ||
node == c.rootNode || node.mountPoint != nil {
// We cannot forget a directory that still has children as these
......
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