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