fs: implement {mutFile,mutDir}.Access

On at least OS X, the stat(2) call will use an existing node without
issuing Lookup.  This introduces a filesystem inconsistency where a
delete removes an entry for further requests, but FUSE's cached access
of the node is still used for at least stat.

There's a call to Access directly against the node as retrieved from a
prior Lookup.  By invalidating the nodes when they're deleted and
verifying this at Access time, we keep things more consistent.

This isn't exactly camlistore.org/issue/324 as described, but it was
causing one of the tests to fail on OS X

Change-Id: Ib90a1de79d6d3960f96bac5b4fb448c952c4ba66
This commit is contained in:
Dustin Sallings 2014-01-06 23:16:37 -08:00
parent 8a5ce9c6a5
commit c2500c5444
1 changed files with 38 additions and 1 deletions

View File

@ -62,6 +62,7 @@ type mutDir struct {
lastPop time.Time
children map[string]mutFileOrDir
xattrs map[string][]byte
deleted bool
}
func (m *mutDir) String() string {
@ -85,6 +86,24 @@ func (n *mutDir) Attr() fuse.Attr {
}
}
func (n *mutDir) Access(req *fuse.AccessRequest, intr fuse.Intr) fuse.Error {
n.mu.Lock()
defer n.mu.Unlock()
if n.deleted {
return fuse.ENOENT
}
return nil
}
func (n *mutFile) Access(req *fuse.AccessRequest, intr fuse.Intr) fuse.Error {
n.mu.Lock()
defer n.mu.Unlock()
if n.deleted {
return fuse.ENOENT
}
return nil
}
// populate hits the blobstore to populate map of child nodes.
func (n *mutDir) populate() error {
n.mu.Lock()
@ -375,7 +394,11 @@ func (n *mutDir) Remove(req *fuse.RemoveRequest, intr fuse.Intr) fuse.Error {
// Remove child from map.
n.mu.Lock()
if n.children != nil {
delete(n.children, req.Name)
if removed, ok := n.children[req.Name]; ok {
removed.invalidate()
delete(n.children, req.Name)
log.Printf("Removed %v from %p", removed, n)
}
}
n.mu.Unlock()
return nil
@ -456,6 +479,7 @@ type mutFile struct {
size int64
mtime, atime time.Time // if zero, use serverStart
xattrs map[string][]byte
deleted bool
}
func (m *mutFile) String() string {
@ -789,6 +813,7 @@ func (h *mutFileHandle) Truncate(size uint64, intr fuse.Intr) fuse.Error {
// mutFileOrDir is a *mutFile or *mutDir
type mutFileOrDir interface {
fuse.Node
invalidate()
permanodeString() string
xattr() *xattr
}
@ -800,3 +825,15 @@ func (n *mutFile) permanodeString() string {
func (n *mutDir) permanodeString() string {
return n.permanode.String()
}
func (n *mutFile) invalidate() {
n.mu.Lock()
n.deleted = true
n.mu.Unlock()
}
func (n *mutDir) invalidate() {
n.mu.Lock()
n.deleted = true
n.mu.Unlock()
}