Commit 0ea25f6d authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Revise Lookup implementation.

* Always take R/W lock

* If the child exists, do addLookupCount() before GetAttr, so the
  child can't be cleaned up during the unprotected GetAttr() call.
parent 675bdda5
...@@ -17,69 +17,96 @@ func (me *FileSystemConnector) Init(fsInit *RawFsInit) { ...@@ -17,69 +17,96 @@ func (me *FileSystemConnector) Init(fsInit *RawFsInit) {
func (me *FileSystemConnector) Lookup(header *InHeader, name string) (out *EntryOut, status Status) { func (me *FileSystemConnector) Lookup(header *InHeader, name string) (out *EntryOut, status Status) {
parent := me.getInodeData(header.NodeId) parent := me.getInodeData(header.NodeId)
out, status, _ = me.internalLookup(parent, name, 1, &header.Context) out, status = me.internalLookup(parent, name, &header.Context)
return out, status return out, status
} }
func (me *FileSystemConnector) lookupMountUpdate(mount *fileSystemMount, lookupCount int) (out *EntryOut, status Status, node *Inode) { func (me *FileSystemConnector) lookupMountUpdate(mount *fileSystemMount) (out *EntryOut, status Status) {
fi, err := mount.fs.Root().GetAttr(nil, nil) fi, err := mount.fs.Root().GetAttr(nil, nil)
if err == ENOENT && mount.options.NegativeTimeout > 0.0 { if err == ENOENT && mount.options.NegativeTimeout > 0.0 {
return NegativeEntry(mount.options.NegativeTimeout), OK, nil return NegativeEntry(mount.options.NegativeTimeout), OK
} }
if !err.Ok() { if !err.Ok() {
return nil, err, mount.mountInode return nil, err
} }
mount.treeLock.Lock() mount.treeLock.Lock()
defer mount.treeLock.Unlock() defer mount.treeLock.Unlock()
mount.mountInode.addLookupCount(lookupCount) mount.mountInode.addLookupCount(1)
out = mount.fileInfoToEntry(fi) out = mount.fileInfoToEntry(fi)
out.NodeId = mount.mountInode.nodeId out.NodeId = mount.mountInode.nodeId
// We don't do NFS. // We don't do NFS.
out.Generation = 1 out.Generation = 1
return out, OK, mount.mountInode return out, OK
} }
func (me *FileSystemConnector) internalLookup(parent *Inode, name string, lookupCount int, context *Context) (out *EntryOut, code Status, node *Inode) { func (me *FileSystemConnector) internalLookup(parent *Inode, name string, context *Context) (out *EntryOut, code Status) {
if mount := me.findMount(parent, name); mount != nil { if mount := me.findMount(parent, name); mount != nil {
return me.lookupMountUpdate(mount, lookupCount) return me.lookupMountUpdate(mount)
} }
lookupNode, getattrNode := me.preLookup(parent, name)
var fi *os.FileInfo var fi *os.FileInfo
child := parent.GetChild(name) var fsNode FsNode
if child != nil { if getattrNode != nil {
fi, code = child.fsInode.GetAttr(nil, nil) fi, code = getattrNode.fsInode.GetAttr(nil, nil)
} } else if lookupNode != nil {
mount := parent.mount fi, fsNode, code = parent.fsInode.Lookup(name)
if code == ENOENT && mount.options.NegativeTimeout > 0.0 {
return NegativeEntry(mount.options.NegativeTimeout), OK, nil
}
if !code.Ok() {
return nil, code, nil
} }
if child != nil && code.Ok() { return me.postLookup(fi, fsNode, code, getattrNode, lookupNode, name)
mount.treeLock.Lock() }
defer mount.treeLock.Unlock()
// Prepare for lookup: we are either looking for getattr of an
// existing node, or lookup a new one. Here we decide which of those
func (me *FileSystemConnector) preLookup(parent *Inode, name string) (lookupNode *Inode, attrNode *Inode) {
parent.treeLock.Lock()
defer parent.treeLock.Unlock()
child := parent.children[name]
if child != nil {
// Make sure the child doesn't die inbetween.
child.addLookupCount(1) child.addLookupCount(1)
out = parent.mount.fileInfoToEntry(fi) return nil, child
out.NodeId = child.nodeId
out.Generation = 1
return out, OK, child
} }
return parent, nil
}
fi, fsNode, code := parent.fsInode.Lookup(name) // Process the result of lookup/getattr.
if code == ENOENT && mount.options.NegativeTimeout > 0.0 { func (me *FileSystemConnector) postLookup(fi *os.FileInfo, fsNode FsNode, code Status, attrNode *Inode, lookupNode *Inode, name string) (out *EntryOut, outCode Status) {
return NegativeEntry(mount.options.NegativeTimeout), OK, nil var mount *fileSystemMount
if attrNode != nil {
mount = attrNode.mount
} else {
mount = lookupNode.mount
} }
if !code.Ok() { if !code.Ok() {
return nil, code, nil if attrNode != nil {
mount.treeLock.Lock()
defer mount.treeLock.Unlock()
attrNode.addLookupCount(-1)
}
if code == ENOENT && mount.options.NegativeTimeout > 0.0 {
return NegativeEntry(mount.options.NegativeTimeout), OK
}
return nil, code
} }
out, _ = me.createChild(parent, name, fi, fsNode) if attrNode != nil {
return out, OK, node out = attrNode.mount.fileInfoToEntry(fi)
out.Generation = 1
out.NodeId = attrNode.nodeId
} else if lookupNode != nil {
out, _ = me.createChild(lookupNode, name, fi, fsNode)
return out, OK
}
return out, OK
} }
func (me *FileSystemConnector) Forget(h *InHeader, input *ForgetIn) { func (me *FileSystemConnector) Forget(h *InHeader, input *ForgetIn) {
......
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