Commit e3ad7b09 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Turn Inode/FsNode relation inside out.

PathNodeFs.{addChild,rmChild} now calls Inode.{AddChild,RmChild}
rather than the reverse, and PathNodeFs manages its own locking.

Remove methods:

- FileSystemConnector.renameUpdate
- FileSystemConnector.unlinkUpdate
- FileSystemConnector.createChild
- Inode.CreateChild
- Inode.LockTree
parent 4e84bba2
......@@ -19,9 +19,9 @@ var paranoia = false
// FilesystemConnector is a raw FUSE filesystem that manages
// in-process mounts and inodes. Its job is twofold:
//
// * It translates between the raw kernel interface (padded structs
// of int32 and int64) and the more abstract NodeFileSystem interface.
// that is based on a hierarchy of Inodes
// * It translates between the raw kernel interface (padded structs of
// int32 and int64) and the more abstract Go-ish NodeFileSystem
// interface.
//
// * It manages mounting and unmounting of NodeFileSystems into the
// directory hierarchy
......@@ -61,7 +61,7 @@ func NewFileSystemConnector(nodeFs NodeFileSystem, opts *FileSystemOptions) (me
me.rootNode = newInode(true, nodeFs.Root())
// FUSE does not issue a LOOKUP for 1 (obviously), but it does
// issue a forget. This lookupCount is to make the counts match.
// issue a forget. This lookupUpdate is to make the counts match.
me.lookupUpdate(me.rootNode)
me.verify()
......@@ -77,21 +77,11 @@ func (me *FileSystemConnector) verify() {
root.verify(me.rootNode.mountPoint)
}
// createChild() creates a child for given as FsNode as child of 'parent'. The
// resulting inode will have its lookupCount incremented.
func (me *FileSystemConnector) createChild(parent *Inode, name string, fi *os.FileInfo, fsi FsNode) (out *EntryOut) {
parent.treeLock.Lock()
defer parent.treeLock.Unlock()
child := fsi.Inode()
if child == nil {
child = parent.createChild(name, fi.IsDirectory(), fsi)
} else {
parent.addChild(name, child)
}
out = parent.mount.fileInfoToEntry(fi)
out.Ino = me.lookupUpdate(child)
// Generate EntryOut and increase the lookup count for an inode.
func (me *FileSystemConnector) childLookup(fi *os.FileInfo, fsi FsNode) (out *EntryOut) {
n := fsi.Inode()
out = n.mount.fileInfoToEntry(fi)
out.Ino = me.lookupUpdate(n)
out.NodeId = out.Ino
return out
}
......@@ -181,32 +171,6 @@ func (me *FileSystemConnector) recursiveConsiderDropInode(n *Inode) (drop bool)
return len(n.openFiles) == 0
}
func (me *FileSystemConnector) renameUpdate(oldParent *Inode, oldName string, newParent *Inode, newName string) {
defer me.verify()
oldParent.treeLock.Lock()
defer oldParent.treeLock.Unlock()
if oldParent.mount != newParent.mount {
panic("Cross mount rename")
}
node := oldParent.rmChild(oldName)
if node == nil {
panic("Source of rename does not exist")
}
newParent.rmChild(newName)
newParent.addChild(newName, node)
}
func (me *FileSystemConnector) unlinkUpdate(parent *Inode, name string) {
defer me.verify()
parent.treeLock.Lock()
defer parent.treeLock.Unlock()
parent.rmChild(name)
}
// Walk the file system starting from the root. Will return nil if
// node not found.
func (me *FileSystemConnector) findLastKnownInode(fullPath string) (*Inode, []string) {
......
......@@ -15,12 +15,6 @@ func (me *FileSystemConnector) Init(fsInit *RawFsInit) {
me.fsInit = *fsInit
}
func (me *FileSystemConnector) Lookup(header *InHeader, name string) (out *EntryOut, status Status) {
parent := me.toInode(header.NodeId)
out, status = me.internalLookup(parent, name, &header.Context)
return out, status
}
func (me *FileSystemConnector) lookupMountUpdate(mount *fileSystemMount) (out *EntryOut, status Status) {
fi, err := mount.fs.Root().GetAttr(nil, nil)
if err == ENOENT && mount.options.NegativeTimeout > 0.0 {
......@@ -40,45 +34,26 @@ func (me *FileSystemConnector) lookupMountUpdate(mount *fileSystemMount) (out *E
return out, OK
}
func (me *FileSystemConnector) internalLookup(parent *Inode, name string, context *Context) (out *EntryOut, code Status) {
if mount := me.findMount(parent, name); mount != nil {
return me.lookupMountUpdate(mount)
func (me *FileSystemConnector) Lookup(header *InHeader, name string) (out *EntryOut, code Status) {
parent := me.toInode(header.NodeId)
context := &header.Context
if subMount := me.findMount(parent, name); subMount != nil {
return me.lookupMountUpdate(subMount)
}
lookupNode, getattrNode := me.preLookup(parent, name)
mount := parent.mount
child := parent.GetChild(name)
if child != nil {
parent = nil
}
var fi *os.FileInfo
var fsNode FsNode
if getattrNode != nil {
fi, code = getattrNode.fsInode.GetAttr(nil, nil)
} else if lookupNode != nil {
fi, fsNode, code = parent.fsInode.Lookup(name, context)
}
return me.postLookup(fi, fsNode, code, getattrNode, lookupNode, name)
}
// 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 {
return nil, child
}
return parent, nil
}
// Process the result of lookup/getattr.
func (me *FileSystemConnector) postLookup(fi *os.FileInfo, fsNode FsNode, code Status, attrNode *Inode, lookupNode *Inode, name string) (out *EntryOut, outCode Status) {
var mount *fileSystemMount
if attrNode != nil {
mount = attrNode.mount
fi, code = child.fsInode.GetAttr(nil, nil)
fsNode = child.FsNode()
} else {
mount = lookupNode.mount
fi, fsNode, code = parent.fsInode.Lookup(name, context)
}
if !code.Ok() {
......@@ -88,15 +63,13 @@ func (me *FileSystemConnector) postLookup(fi *os.FileInfo, fsNode FsNode, code S
return nil, code
}
if attrNode != nil {
me.lookupUpdate(attrNode)
out = attrNode.mount.fileInfoToEntry(fi)
out.Generation = 1
out.NodeId = attrNode.nodeId
out.Ino = attrNode.nodeId
} else if lookupNode != nil {
out = me.createChild(lookupNode, name, fi, fsNode)
out = mount.fileInfoToEntry(fi)
out.Generation = 1
if child == nil {
child = fsNode.Inode()
}
out.NodeId = me.lookupUpdate(child)
out.Ino = out.NodeId
return out, OK
}
......@@ -217,7 +190,7 @@ func (me *FileSystemConnector) Mknod(header *InHeader, input *MknodIn, name stri
parent := me.toInode(header.NodeId)
fi, fsNode, code := parent.fsInode.Mknod(name, input.Mode, uint32(input.Rdev), &header.Context)
if code.Ok() {
out = me.createChild(parent, name, fi, fsNode)
out = me.childLookup(fi, fsNode)
}
return out, code
}
......@@ -227,36 +200,26 @@ func (me *FileSystemConnector) Mkdir(header *InHeader, input *MkdirIn, name stri
fi, fsInode, code := parent.fsInode.Mkdir(name, input.Mode, &header.Context)
if code.Ok() {
out = me.createChild(parent, name, fi, fsInode)
out = me.childLookup(fi, fsInode)
}
return out, code
}
func (me *FileSystemConnector) Unlink(header *InHeader, name string) (code Status) {
parent := me.toInode(header.NodeId)
code = parent.fsInode.Unlink(name, &header.Context)
if code.Ok() {
// Like fuse.c, we update our internal tables.
me.unlinkUpdate(parent, name)
}
return code
return parent.fsInode.Unlink(name, &header.Context)
}
func (me *FileSystemConnector) Rmdir(header *InHeader, name string) (code Status) {
parent := me.toInode(header.NodeId)
code = parent.fsInode.Rmdir(name, &header.Context)
if code.Ok() {
// Like fuse.c, we update our internal tables.
me.unlinkUpdate(parent, name)
}
return code
return parent.fsInode.Rmdir(name, &header.Context)
}
func (me *FileSystemConnector) Symlink(header *InHeader, pointedTo string, linkName string) (out *EntryOut, code Status) {
parent := me.toInode(header.NodeId)
fi, fsNode, code := parent.fsInode.Symlink(linkName, pointedTo, &header.Context)
if code.Ok() {
out = me.createChild(parent, linkName, fi, fsNode)
out = me.childLookup(fi, fsNode)
}
return out, code
}
......@@ -273,11 +236,7 @@ func (me *FileSystemConnector) Rename(header *InHeader, input *RenameIn, oldName
return EXDEV
}
code = oldParent.fsInode.Rename(oldName, newParent.fsInode, newName, &header.Context)
if code.Ok() {
me.renameUpdate(oldParent, oldName, newParent, newName)
}
return code
return oldParent.fsInode.Rename(oldName, newParent.fsInode, newName, &header.Context)
}
func (me *FileSystemConnector) Link(header *InHeader, input *LinkIn, name string) (out *EntryOut, code Status) {
......@@ -289,11 +248,10 @@ func (me *FileSystemConnector) Link(header *InHeader, input *LinkIn, name string
}
fi, fsInode, code := parent.fsInode.Link(name, existing.fsInode, &header.Context)
if !code.Ok() {
return nil, code
if code.Ok() {
out = me.childLookup(fi, fsInode)
}
out = me.createChild(parent, name, fi, fsInode)
return out, code
}
......@@ -308,7 +266,7 @@ func (me *FileSystemConnector) Create(header *InHeader, input *CreateIn, name st
if !code.Ok() {
return 0, 0, nil, code
}
out = me.createChild(parent, name, fi, fsNode)
out = me.childLookup(fi, fsNode)
handle, opened := parent.mount.registerFileHandle(fsNode.Inode(), nil, f, input.Flags)
return opened.FuseFlags, handle, out, code
}
......
......@@ -70,20 +70,11 @@ func newInode(isDir bool, fsNode FsNode) *Inode {
}
me.fsInode = fsNode
me.fsInode.SetInode(me)
return me
}
// public methods.
// LockTree() Locks the mutex used for tree operations, and returns the
// unlock function.
func (me *Inode) LockTree() func() {
// TODO - this API is tricky.
me.treeLock.Lock()
return func() { me.treeLock.Unlock() }
}
// Returns any open file, preferably a r/w one.
func (me *Inode) AnyFile() (file File) {
me.openFilesMutex.Lock()
......@@ -98,8 +89,8 @@ func (me *Inode) AnyFile() (file File) {
}
func (me *Inode) Children() (out map[string]*Inode) {
me.treeLock.Lock()
defer me.treeLock.Unlock()
me.treeLock.RLock()
defer me.treeLock.RUnlock()
out = map[string]*Inode{}
for k, v := range me.children {
......@@ -130,37 +121,39 @@ func (me *Inode) IsDir() bool {
}
// CreateChild() creates node for synthetic use
func (me *Inode) CreateChild(name string, isDir bool, fsi FsNode) *Inode {
me.treeLock.Lock()
defer me.treeLock.Unlock()
ch := me.createChild(name, isDir, fsi)
func (me *Inode) NewSynthetic(isDir bool, fsi FsNode) *Inode {
ch := me.New(isDir, fsi)
ch.synthetic = true
return ch
}
// Creates an Inode as child.
func (me *Inode) createChild(name string, isDir bool, fsi FsNode) *Inode {
ch := me.children[name]
if ch != nil {
panic(fmt.Sprintf("already have a child at %v %q", me.nodeId, name))
}
ch = newInode(isDir, fsi)
func (me *Inode) New(isDir bool, fsi FsNode) *Inode {
ch := newInode(isDir, fsi)
ch.mount = me.mount
ch.treeLock = me.treeLock
me.addChild(name, ch)
return ch
}
func (me *Inode) GetChild(name string) (child *Inode) {
me.treeLock.RLock()
defer me.treeLock.RUnlock()
return me.children[name]
}
func (me *Inode) AddChild(name string, child *Inode) {
me.treeLock.Lock()
defer me.treeLock.Unlock()
me.addChild(name, child)
}
return me.children[name]
func (me *Inode) RmChild(name string) (ch *Inode) {
me.treeLock.Lock()
defer me.treeLock.Unlock()
return me.rmChild(name)
}
////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
// private
// Must be called with treeLock for the mount held.
......@@ -172,10 +165,6 @@ func (me *Inode) addChild(name string, child *Inode) {
}
}
me.children[name] = child
if child.mountPoint == nil {
me.fsInode.AddChild(name, child.fsInode)
}
}
// Must be called with treeLock for the mount held.
......@@ -183,7 +172,6 @@ func (me *Inode) rmChild(name string) (ch *Inode) {
ch = me.children[name]
if ch != nil {
me.children[name] = nil, false
me.fsInode.RmChild(name, ch.fsInode)
}
return ch
}
......
......@@ -31,7 +31,8 @@ type PathNodeFs struct {
root *pathInode
connector *FileSystemConnector
clientInodeMapMutex sync.Mutex
// protects clientInodeMap and pathInode.Parent pointers
pathLock sync.RWMutex
// This map lists all the parent links known for a given
// nodeId.
......@@ -173,6 +174,16 @@ type pathInode struct {
DefaultFsNode
}
func (me *pathInode) LockTree() (func()) {
me.pathFs.pathLock.Lock()
return func() { me.pathFs.pathLock.Unlock() }
}
func (me *pathInode) RLockTree() (func()) {
me.pathFs.pathLock.RLock()
return func() { me.pathFs.pathLock.RUnlock() }
}
func (me *pathInode) fillNewChildAttr(path string, child *pathInode, c *Context) (fi *os.FileInfo, code Status) {
fi, _ = me.fs.GetAttr(path, c)
if fi != nil && fi.Ino > 0 {
......@@ -188,10 +199,9 @@ func (me *pathInode) fillNewChildAttr(path string, child *pathInode, c *Context)
// GetPath returns the path relative to the mount governing this
// inode. It returns nil for mount if the file was deleted or the
// filesystem unmounted. This will take the treeLock for the mount,
// so it can not be used in internal methods.
// filesystem unmounted.
func (me *pathInode) GetPath() (path string) {
defer me.inode.LockTree()()
defer me.RLockTree()()
rev_components := make([]string, 0, 10)
n := me
......@@ -209,29 +219,31 @@ func (me *pathInode) GetPath() (path string) {
return p
}
func (me *pathInode) AddChild(name string, child FsNode) {
ch := child.(*pathInode)
ch.Parent = me
ch.Name = name
func (me *pathInode) addChild(name string, child *pathInode) {
me.Inode().AddChild(name, child.Inode())
child.Parent = me
child.Name = name
if ch.clientInode > 0 {
me.pathFs.clientInodeMapMutex.Lock()
defer me.pathFs.clientInodeMapMutex.Unlock()
m := me.pathFs.clientInodeMap[ch.clientInode]
if child.clientInode > 0 {
defer me.LockTree()()
m := me.pathFs.clientInodeMap[child.clientInode]
e := &clientInodePath{
me, name, child.(*pathInode),
me, name, child,
}
m = append(m, e)
me.pathFs.clientInodeMap[ch.clientInode] = m
me.pathFs.clientInodeMap[child.clientInode] = m
}
}
func (me *pathInode) RmChild(name string, child FsNode) {
ch := child.(*pathInode)
func (me *pathInode) rmChild(name string) *pathInode {
childInode := me.Inode().RmChild(name)
if childInode == nil {
return nil
}
ch := childInode.FsNode().(*pathInode)
if ch.clientInode > 0 {
me.pathFs.clientInodeMapMutex.Lock()
defer me.pathFs.clientInodeMapMutex.Unlock()
defer me.LockTree()()
m := me.pathFs.clientInodeMap[ch.clientInode]
idx := -1
......@@ -248,7 +260,7 @@ func (me *pathInode) RmChild(name string, child FsNode) {
if len(m) > 0 {
ch.Parent = m[0].parent
ch.Name = m[0].name
return
return ch
} else {
me.pathFs.clientInodeMap[ch.clientInode] = nil, false
}
......@@ -256,19 +268,21 @@ func (me *pathInode) RmChild(name string, child FsNode) {
ch.Name = ".deleted"
ch.Parent = nil
return ch
}
// Handle a change in clientInode number for an other wise unchanged
// pathInode.
func (me *pathInode) setClientInode(ino uint64) {
if ino == me.clientInode {
return
}
defer me.Inode().LockTree()()
me.pathFs.clientInodeMapMutex.Lock()
defer me.pathFs.clientInodeMapMutex.Unlock()
defer me.LockTree()()
if me.clientInode != 0 {
me.pathFs.clientInodeMap[me.clientInode] = nil, false
}
me.clientInode = ino
if me.Parent != nil {
e := &clientInodePath{
......@@ -282,8 +296,7 @@ func (me *pathInode) OnForget() {
if me.clientInode == 0 {
return
}
me.pathFs.clientInodeMapMutex.Lock()
defer me.pathFs.clientInodeMapMutex.Unlock()
defer me.LockTree()()
me.pathFs.clientInodeMap[me.clientInode] = nil, false
}
......@@ -332,9 +345,10 @@ func (me *pathInode) Mknod(name string, mode uint32, dev uint32, context *Contex
fullPath := filepath.Join(me.GetPath(), name)
code = me.fs.Mknod(fullPath, mode, dev, context)
if code.Ok() {
pNode := me.createChild(name)
pNode := me.createChild(false)
newNode = pNode
fi, code = me.fillNewChildAttr(fullPath, pNode, context)
me.addChild(name, pNode)
}
return
}
......@@ -343,28 +357,38 @@ func (me *pathInode) Mkdir(name string, mode uint32, context *Context) (fi *os.F
fullPath := filepath.Join(me.GetPath(), name)
code = me.fs.Mkdir(fullPath, mode, context)
if code.Ok() {
pNode := me.createChild(name)
pNode := me.createChild(true)
newNode = pNode
fi, code = me.fillNewChildAttr(fullPath, pNode, context)
me.addChild(name, pNode)
}
return
}
func (me *pathInode) Unlink(name string, context *Context) (code Status) {
return me.fs.Unlink(filepath.Join(me.GetPath(), name), context)
code = me.fs.Unlink(filepath.Join(me.GetPath(), name), context)
if code.Ok() {
me.rmChild(name)
}
return code
}
func (me *pathInode) Rmdir(name string, context *Context) (code Status) {
return me.fs.Rmdir(filepath.Join(me.GetPath(), name), context)
code = me.fs.Rmdir(filepath.Join(me.GetPath(), name), context)
if code.Ok() {
me.rmChild(name)
}
return code
}
func (me *pathInode) Symlink(name string, content string, context *Context) (fi *os.FileInfo, newNode FsNode, code Status) {
fullPath := filepath.Join(me.GetPath(), name)
code = me.fs.Symlink(content, fullPath, context)
if code.Ok() {
pNode := me.createChild(name)
pNode := me.createChild(false)
newNode = pNode
fi, code = me.fillNewChildAttr(fullPath, pNode, context)
me.addChild(name, pNode)
}
return
}
......@@ -373,21 +397,33 @@ func (me *pathInode) Rename(oldName string, newParent FsNode, newName string, co
p := newParent.(*pathInode)
oldPath := filepath.Join(me.GetPath(), oldName)
newPath := filepath.Join(p.GetPath(), newName)
return me.fs.Rename(oldPath, newPath, context)
code = me.fs.Rename(oldPath, newPath, context)
if code.Ok() {
ch := me.rmChild(oldName)
p.rmChild(newName)
p.addChild(newName, ch)
}
return code
}
func (me *pathInode) Link(name string, existing FsNode, context *Context) (fi *os.FileInfo, newNode FsNode, code Status) {
func (me *pathInode) Link(name string, existingFsnode FsNode, context *Context) (fi *os.FileInfo, newNode FsNode, code Status) {
newPath := filepath.Join(me.GetPath(), name)
e := existing.(*pathInode)
oldPath := e.GetPath()
existing := existingFsnode.(*pathInode)
oldPath := existing.GetPath()
code = me.fs.Link(oldPath, newPath, context)
if code.Ok() {
fi, _ = me.fs.GetAttr(newPath, context)
if fi != nil && e.clientInode != 0 && e.clientInode == fi.Ino {
fi, code = me.fs.GetAttr(newPath, context)
}
if code.Ok() {
if existing.clientInode != 0 && existing.clientInode == fi.Ino {
newNode = existing
me.addChild(name, existing)
} else {
newNode = me.createChild(name)
pNode := me.createChild(false)
newNode = pNode
pNode.clientInode = fi.Ino
me.addChild(name, pNode)
}
}
return
......@@ -397,19 +433,20 @@ func (me *pathInode) Create(name string, flags uint32, mode uint32, context *Con
fullPath := filepath.Join(me.GetPath(), name)
file, code = me.fs.Create(fullPath, flags, mode, context)
if code.Ok() {
pNode := me.createChild(name)
pNode := me.createChild(false)
newNode = pNode
fi, code = me.fillNewChildAttr(fullPath, pNode, context)
me.addChild(name, pNode)
}
return
}
func (me *pathInode) createChild(name string) *pathInode {
func (me *pathInode) createChild(isDir bool) *pathInode {
i := new(pathInode)
i.Parent = me
i.Name = name
i.fs = me.fs
i.pathFs = me.pathFs
me.Inode().New(isDir, i)
return i
}
......@@ -428,25 +465,26 @@ func (me *pathInode) Lookup(name string, context *Context) (fi *os.FileInfo, nod
fullPath := filepath.Join(me.GetPath(), name)
fi, code = me.fs.GetAttr(fullPath, context)
if code.Ok() {
node = me.findChild(fi.Ino, name)
node = me.findChild(fi.Ino, fi.IsDirectory(), name)
}
return
}
func (me *pathInode) findChild(ino uint64, name string) (out *pathInode) {
func (me *pathInode) findChild(ino uint64, isDir bool, name string) (out *pathInode) {
if ino > 0 {
me.pathFs.clientInodeMapMutex.Lock()
defer me.pathFs.clientInodeMapMutex.Unlock()
unlock := me.RLockTree()
v := me.pathFs.clientInodeMap[ino]
if len(v) > 0 {
out = v[0].node
}
unlock()
}
if out == nil {
out = me.createChild(name)
out = me.createChild(isDir)
out.clientInode = ino
me.addChild(name, out)
}
return out
......
......@@ -107,15 +107,16 @@ func (me *MemTreeFs) addFile(name string, f MemFile) {
node := me.root.Inode()
for i, c := range comps {
ch := node.GetChild(c)
if ch == nil {
child := node.GetChild(c)
if child == nil {
fsnode := &memNode{}
if i == len(comps)-1 {
fsnode.file = f
}
ch = node.CreateChild(c, fsnode.file == nil, fsnode)
child = node.NewSynthetic(fsnode.file == nil, fsnode)
node.AddChild(c, child)
}
node = ch
node = child
}
}
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