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