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

nodefs: fsconnector: add lookupLock: prevent concurrent LOOKUP and FORGET

Add a lock that prevents LOOKUP and FORGET from running concurrently.

Locking at this level is a big hammer, but makes sure we don't return
forgotten nodes to the kernel. Problems solved by this lock:

https://github.com/hanwen/go-fuse/issues/168
https://github.com/rfjakob/gocryptfs/issues/322
parent 19e761f1
...@@ -12,6 +12,7 @@ import ( ...@@ -12,6 +12,7 @@ import (
"log" "log"
"path/filepath" "path/filepath"
"strings" "strings"
"sync"
"time" "time"
"unsafe" "unsafe"
...@@ -35,6 +36,13 @@ type FileSystemConnector struct { ...@@ -35,6 +36,13 @@ type FileSystemConnector struct {
// The root of the FUSE file system. // The root of the FUSE file system.
rootNode *Inode rootNode *Inode
// This lock prevents Lookup() and Forget() from running concurrently.
// Locking at this level is a big hammer, but makes sure we don't return
// forgotten nodes to the kernel. Problems solved by this lock:
// https://github.com/hanwen/go-fuse/issues/168
// https://github.com/rfjakob/gocryptfs/issues/322
lookupLock sync.Mutex
} }
// NewOptions generates FUSE options that correspond to libfuse's // NewOptions generates FUSE options that correspond to libfuse's
......
...@@ -95,11 +95,16 @@ func (c *FileSystemConnector) internalLookup(out *fuse.Attr, parent *Inode, name ...@@ -95,11 +95,16 @@ func (c *FileSystemConnector) internalLookup(out *fuse.Attr, parent *Inode, name
} }
func (c *rawBridge) Lookup(header *fuse.InHeader, name string, out *fuse.EntryOut) (code fuse.Status) { func (c *rawBridge) Lookup(header *fuse.InHeader, name string, out *fuse.EntryOut) (code fuse.Status) {
// Prevent Lookup() and Forget() from running concurrently.
c.lookupLock.Lock()
defer c.lookupLock.Unlock()
parent := c.toInode(header.NodeId) parent := c.toInode(header.NodeId)
if !parent.IsDir() { if !parent.IsDir() {
log.Printf("Lookup %q called on non-Directory node %d", name, header.NodeId) log.Printf("Lookup %q called on non-Directory node %d", name, header.NodeId)
return fuse.ENOTDIR return fuse.ENOTDIR
} }
child, code := c.fsConn().internalLookup(&out.Attr, parent, name, header) child, code := c.fsConn().internalLookup(&out.Attr, parent, name, header)
if code == fuse.ENOENT && parent.mount.negativeEntry(out) { if code == fuse.ENOENT && parent.mount.negativeEntry(out) {
return fuse.OK return fuse.OK
...@@ -121,6 +126,10 @@ func (c *rawBridge) Lookup(header *fuse.InHeader, name string, out *fuse.EntryOu ...@@ -121,6 +126,10 @@ func (c *rawBridge) Lookup(header *fuse.InHeader, name string, out *fuse.EntryOu
} }
func (c *rawBridge) Forget(nodeID, nlookup uint64) { func (c *rawBridge) Forget(nodeID, nlookup uint64) {
// Prevent Lookup() and Forget() from running concurrently.
c.lookupLock.Lock()
defer c.lookupLock.Unlock()
c.fsConn().forgetUpdate(nodeID, int(nlookup)) c.fsConn().forgetUpdate(nodeID, int(nlookup))
} }
......
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