mirror of https://github.com/perkeep/perkeep.git
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:
parent
8a5ce9c6a5
commit
c2500c5444
|
@ -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()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue