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

Introduce new interfaces:

* NodeFileSystem: interface for defining filesystems in terms of inodes.

* FsNode: interface for inodes to be used by NodeFileSystem

* PathNodeFs: NodeFileSystem that assumes bijective mapping between
  inodes and paths

* Change inode to Inode, a public (but mostly opaque) type.
parent 61fa4895
...@@ -12,7 +12,6 @@ MANUAL_GOFILES=api.go \ ...@@ -12,7 +12,6 @@ MANUAL_GOFILES=api.go \
direntry.go\ direntry.go\
files.go \ files.go \
fsmount.go \ fsmount.go \
fsinode.go \
fsconnector.go \ fsconnector.go \
fuse.go \ fuse.go \
handle.go \ handle.go \
...@@ -25,6 +24,7 @@ MANUAL_GOFILES=api.go \ ...@@ -25,6 +24,7 @@ MANUAL_GOFILES=api.go \
mount.go \ mount.go \
mountstate.go \ mountstate.go \
opcode.go \ opcode.go \
pathfs.go \
pathdebug.go \ pathdebug.go \
fsops.go \ fsops.go \
readonlyfs.go \ readonlyfs.go \
......
...@@ -8,7 +8,7 @@ import ( ...@@ -8,7 +8,7 @@ import (
// Types for users to implement. // Types for users to implement.
type InodeFs interface { type NodeFileSystem interface {
Unmount() Unmount()
Mount(conn *FileSystemConnector) Mount(conn *FileSystemConnector)
StatFs() *StatfsOut StatFs() *StatfsOut
...@@ -17,8 +17,9 @@ type InodeFs interface { ...@@ -17,8 +17,9 @@ type InodeFs interface {
type FsNode interface { type FsNode interface {
// The following are called by the FileSystemConnector // The following are called by the FileSystemConnector
Inode() *inode Inode() *Inode
SetInode(node *inode) SetInode(node *Inode)
RmChild(name string, child FsNode) RmChild(name string, child FsNode)
AddChild(name string, child FsNode) AddChild(name string, child FsNode)
...@@ -137,6 +138,7 @@ type File interface { ...@@ -137,6 +138,7 @@ type File interface {
Fsync(*FsyncIn) (code Status) Fsync(*FsyncIn) (code Status)
} }
// Wrap a File return in this to set FUSE flags.
type WithFlags struct { type WithFlags struct {
File File
......
...@@ -32,7 +32,7 @@ type FileSystemConnector struct { ...@@ -32,7 +32,7 @@ type FileSystemConnector struct {
fsInit RawFsInit fsInit RawFsInit
inodeMap HandleMap inodeMap HandleMap
rootNode *inode rootNode *Inode
} }
func NewFileSystemConnector(fs FileSystem, opts *FileSystemOptions) (me *FileSystemConnector) { func NewFileSystemConnector(fs FileSystem, opts *FileSystemOptions) (me *FileSystemConnector) {
...@@ -56,17 +56,17 @@ func (me *FileSystemConnector) verify() { ...@@ -56,17 +56,17 @@ func (me *FileSystemConnector) verify() {
root.verify(me.rootNode.mountPoint) root.verify(me.rootNode.mountPoint)
} }
func (me *FileSystemConnector) newInode(isDir bool) *inode { func (me *FileSystemConnector) newInode(isDir bool) *Inode {
data := new(inode) data := new(Inode)
data.nodeId = me.inodeMap.Register(&data.handled) data.nodeId = me.inodeMap.Register(&data.handled)
if isDir { if isDir {
data.children = make(map[string]*inode, initDirSize) data.children = make(map[string]*Inode, initDirSize)
} }
return data return data
} }
func (me *FileSystemConnector) lookupUpdate(parent *inode, name string, isDir bool, lookupCount int) *inode { func (me *FileSystemConnector) lookupUpdate(parent *Inode, name string, isDir bool, lookupCount int) *Inode {
defer me.verify() defer me.verify()
parent.treeLock.Lock() parent.treeLock.Lock()
...@@ -83,7 +83,7 @@ func (me *FileSystemConnector) lookupUpdate(parent *inode, name string, isDir bo ...@@ -83,7 +83,7 @@ func (me *FileSystemConnector) lookupUpdate(parent *inode, name string, isDir bo
return data return data
} }
func (me *FileSystemConnector) lookupMount(parent *inode, name string, lookupCount int) (mount *fileSystemMount) { func (me *FileSystemConnector) lookupMount(parent *Inode, name string, lookupCount int) (mount *fileSystemMount) {
parent.treeLock.RLock() parent.treeLock.RLock()
defer parent.treeLock.RUnlock() defer parent.treeLock.RUnlock()
if parent.mounts == nil { if parent.mounts == nil {
...@@ -100,11 +100,11 @@ func (me *FileSystemConnector) lookupMount(parent *inode, name string, lookupCou ...@@ -100,11 +100,11 @@ func (me *FileSystemConnector) lookupMount(parent *inode, name string, lookupCou
return nil return nil
} }
func (me *FileSystemConnector) getInodeData(nodeid uint64) *inode { func (me *FileSystemConnector) getInodeData(nodeid uint64) *Inode {
if nodeid == FUSE_ROOT_ID { if nodeid == FUSE_ROOT_ID {
return me.rootNode return me.rootNode
} }
return (*inode)(unsafe.Pointer(DecodeHandle(nodeid))) return (*Inode)(unsafe.Pointer(DecodeHandle(nodeid)))
} }
func (me *FileSystemConnector) forgetUpdate(nodeId uint64, forgetCount int) { func (me *FileSystemConnector) forgetUpdate(nodeId uint64, forgetCount int) {
...@@ -119,7 +119,7 @@ func (me *FileSystemConnector) forgetUpdate(nodeId uint64, forgetCount int) { ...@@ -119,7 +119,7 @@ func (me *FileSystemConnector) forgetUpdate(nodeId uint64, forgetCount int) {
me.considerDropInode(node) me.considerDropInode(node)
} }
func (me *FileSystemConnector) considerDropInode(n *inode) (drop bool) { func (me *FileSystemConnector) considerDropInode(n *Inode) (drop bool) {
delChildren := []string{} delChildren := []string{}
for k, v := range n.children { for k, v := range n.children {
if v.mountPoint == nil && me.considerDropInode(v) { if v.mountPoint == nil && me.considerDropInode(v) {
...@@ -146,7 +146,7 @@ func (me *FileSystemConnector) considerDropInode(n *inode) (drop bool) { ...@@ -146,7 +146,7 @@ func (me *FileSystemConnector) considerDropInode(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) { func (me *FileSystemConnector) renameUpdate(oldParent *Inode, oldName string, newParent *Inode, newName string) {
defer me.verify() defer me.verify()
oldParent.treeLock.Lock() oldParent.treeLock.Lock()
defer oldParent.treeLock.Unlock() defer oldParent.treeLock.Unlock()
...@@ -163,7 +163,7 @@ func (me *FileSystemConnector) renameUpdate(oldParent *inode, oldName string, ne ...@@ -163,7 +163,7 @@ func (me *FileSystemConnector) renameUpdate(oldParent *inode, oldName string, ne
newParent.addChild(newName, node) newParent.addChild(newName, node)
} }
func (me *FileSystemConnector) unlinkUpdate(parent *inode, name string) { func (me *FileSystemConnector) unlinkUpdate(parent *Inode, name string) {
defer me.verify() defer me.verify()
parent.treeLock.Lock() parent.treeLock.Lock()
...@@ -174,7 +174,7 @@ func (me *FileSystemConnector) unlinkUpdate(parent *inode, name string) { ...@@ -174,7 +174,7 @@ func (me *FileSystemConnector) unlinkUpdate(parent *inode, name string) {
// 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) {
if fullPath == "" { if fullPath == "" {
return me.rootNode, nil return me.rootNode, nil
} }
...@@ -203,7 +203,7 @@ func (me *FileSystemConnector) findLastKnownInode(fullPath string) (*inode, []st ...@@ -203,7 +203,7 @@ func (me *FileSystemConnector) findLastKnownInode(fullPath string) (*inode, []st
return node, nil return node, nil
} }
func (me *FileSystemConnector) findInode(fullPath string) *inode { func (me *FileSystemConnector) findInode(fullPath string) *Inode {
n, rest := me.findLastKnownInode(fullPath) n, rest := me.findLastKnownInode(fullPath)
if len(rest) > 0 { if len(rest) > 0 {
return nil return nil
...@@ -217,7 +217,7 @@ func (me *FileSystemConnector) findInode(fullPath string) *inode { ...@@ -217,7 +217,7 @@ func (me *FileSystemConnector) findInode(fullPath string) *inode {
// system there. If opts is nil, the mount options of the root file // system there. If opts is nil, the mount options of the root file
// system are inherited. The encompassing filesystem should pretend // system are inherited. The encompassing filesystem should pretend
// the mount point does not exist. If it does, it will generate an // the mount point does not exist. If it does, it will generate an
// inode with the same, which will cause Mount() to return EBUSY. // Inode with the same, which will cause Mount() to return EBUSY.
// //
// Return values: // Return values:
// //
...@@ -257,8 +257,8 @@ func (me *FileSystemConnector) Mount(mountPoint string, fs FileSystem, opts *Fil ...@@ -257,8 +257,8 @@ func (me *FileSystemConnector) Mount(mountPoint string, fs FileSystem, opts *Fil
opts = me.rootNode.mountPoint.options opts = me.rootNode.mountPoint.options
} }
ifs := newInodeFs(fs) nodeFs := NewPathNodeFs(fs)
node.mountFs(ifs, opts) node.mountFs(nodeFs, opts)
parent.addChild(base, node) parent.addChild(base, node)
if parent.mounts == nil { if parent.mounts == nil {
...@@ -275,7 +275,7 @@ func (me *FileSystemConnector) Mount(mountPoint string, fs FileSystem, opts *Fil ...@@ -275,7 +275,7 @@ func (me *FileSystemConnector) Mount(mountPoint string, fs FileSystem, opts *Fil
} }
func (me *FileSystemConnector) mountRoot(fs FileSystem, opts *FileSystemOptions) { func (me *FileSystemConnector) mountRoot(fs FileSystem, opts *FileSystemOptions) {
ifs := newInodeFs(fs) ifs := NewPathNodeFs(fs)
me.rootNode.mountFs(ifs, opts) me.rootNode.mountFs(ifs, opts)
ifs.Mount(me) ifs.Mount(me)
me.verify() me.verify()
......
...@@ -24,10 +24,10 @@ type openedFile struct { ...@@ -24,10 +24,10 @@ type openedFile struct {
type fileSystemMount struct { type fileSystemMount struct {
// The file system we mounted here. // The file system we mounted here.
fs InodeFs fs NodeFileSystem
// Node that we were mounted on. // Node that we were mounted on.
mountInode *inode mountInode *Inode
// Options for the mount. // Options for the mount.
options *FileSystemOptions options *FileSystemOptions
...@@ -69,7 +69,7 @@ func (me *FileSystemConnector) getOpenedFile(h uint64) *openedFile { ...@@ -69,7 +69,7 @@ func (me *FileSystemConnector) getOpenedFile(h uint64) *openedFile {
return b return b
} }
func (me *fileSystemMount) unregisterFileHandle(handle uint64, node *inode) *openedFile { func (me *fileSystemMount) unregisterFileHandle(handle uint64, node *Inode) *openedFile {
obj := me.openFiles.Forget(handle) obj := me.openFiles.Forget(handle)
opened := (*openedFile)(unsafe.Pointer(obj)) opened := (*openedFile)(unsafe.Pointer(obj))
node.openFilesMutex.Lock() node.openFilesMutex.Lock()
...@@ -90,7 +90,7 @@ func (me *fileSystemMount) unregisterFileHandle(handle uint64, node *inode) *ope ...@@ -90,7 +90,7 @@ func (me *fileSystemMount) unregisterFileHandle(handle uint64, node *inode) *ope
return opened return opened
} }
func (me *fileSystemMount) registerFileHandle(node *inode, dir rawDir, f File, flags uint32) (uint64, *openedFile) { func (me *fileSystemMount) registerFileHandle(node *Inode, dir rawDir, f File, flags uint32) (uint64, *openedFile) {
node.openFilesMutex.Lock() node.openFilesMutex.Lock()
defer node.openFilesMutex.Unlock() defer node.openFilesMutex.Unlock()
b := &openedFile{ b := &openedFile{
......
...@@ -22,7 +22,7 @@ func (me *FileSystemConnector) Lookup(header *InHeader, name string) (out *Entry ...@@ -22,7 +22,7 @@ func (me *FileSystemConnector) Lookup(header *InHeader, name string) (out *Entry
return out, status return out, status
} }
func (me *FileSystemConnector) internalMountLookup(mount *fileSystemMount, lookupCount int) (out *EntryOut, status Status, node *inode) { func (me *FileSystemConnector) internalMountLookup(mount *fileSystemMount, lookupCount int) (out *EntryOut, status Status, node *Inode) {
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, nil
...@@ -41,7 +41,7 @@ func (me *FileSystemConnector) internalMountLookup(mount *fileSystemMount, looku ...@@ -41,7 +41,7 @@ func (me *FileSystemConnector) internalMountLookup(mount *fileSystemMount, looku
return out, OK, mount.mountInode return out, OK, mount.mountInode
} }
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, lookupCount int, context *Context) (out *EntryOut, code Status, node *Inode) {
if mount := me.lookupMount(parent, name, lookupCount); mount != nil { if mount := me.lookupMount(parent, name, lookupCount); mount != nil {
return me.internalMountLookup(mount, lookupCount) return me.internalMountLookup(mount, lookupCount)
} }
...@@ -199,7 +199,7 @@ func (me *FileSystemConnector) Mknod(header *InHeader, input *MknodIn, name stri ...@@ -199,7 +199,7 @@ func (me *FileSystemConnector) Mknod(header *InHeader, input *MknodIn, name stri
return out, code return out, code
} }
func (me *FileSystemConnector) createChild(parent *inode, name string, fi *os.FileInfo, fsi FsNode) (out *EntryOut, child *inode) { func (me *FileSystemConnector) createChild(parent *Inode, name string, fi *os.FileInfo, fsi FsNode) (out *EntryOut, child *Inode) {
child = parent.createChild(name, fi.IsDirectory(), fsi, me) child = parent.createChild(name, fi.IsDirectory(), fsi, me)
out = parent.mount.fileInfoToEntry(fi) out = parent.mount.fileInfoToEntry(fi)
out.Ino = child.nodeId out.Ino = child.nodeId
......
...@@ -6,7 +6,7 @@ import ( ...@@ -6,7 +6,7 @@ import (
) )
// The inode reflects the kernel's idea of the inode. // The inode reflects the kernel's idea of the inode.
type inode struct { type Inode struct {
handled Handled handled Handled
// Constant during lifetime. // Constant during lifetime.
...@@ -27,7 +27,7 @@ type inode struct { ...@@ -27,7 +27,7 @@ type inode struct {
// All data below is protected by treeLock. // All data below is protected by treeLock.
fsInode FsNode fsInode FsNode
children map[string]*inode children map[string]*Inode
// Contains directories that function as mounts. The entries // Contains directories that function as mounts. The entries
// are duplicated in children. // are duplicated in children.
...@@ -43,7 +43,47 @@ type inode struct { ...@@ -43,7 +43,47 @@ type inode struct {
mount *fileSystemMount mount *fileSystemMount
} }
func (me *inode) createChild(name string, isDir bool, fsi FsNode, conn *FileSystemConnector) *inode { // 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()
defer me.openFilesMutex.Unlock()
for _, f := range me.openFiles {
if file == nil || f.OpenFlags & O_ANYWRITE != 0 {
file = f.file
}
}
return file
}
// Returns an open writable file for the given Inode.
func (me *Inode) WritableFiles() (files []File) {
me.openFilesMutex.Lock()
defer me.openFilesMutex.Unlock()
for _, f := range me.openFiles {
if f.OpenFlags & O_ANYWRITE != 0 {
files = append(files, f.file)
}
}
return files
}
func (me *Inode) IsDir() bool {
return me.children != nil
}
func (me *Inode) createChild(name string, isDir bool, fsi FsNode, conn *FileSystemConnector) *Inode {
me.treeLock.Lock() me.treeLock.Lock()
defer me.treeLock.Unlock() defer me.treeLock.Unlock()
...@@ -62,7 +102,7 @@ func (me *inode) createChild(name string, isDir bool, fsi FsNode, conn *FileSyst ...@@ -62,7 +102,7 @@ func (me *inode) createChild(name string, isDir bool, fsi FsNode, conn *FileSyst
return ch return ch
} }
func (me *inode) getChild(name string) (child *inode) { func (me *Inode) getChild(name string) (child *Inode) {
me.treeLock.Lock() me.treeLock.Lock()
defer me.treeLock.Unlock() defer me.treeLock.Unlock()
...@@ -70,20 +110,22 @@ func (me *inode) getChild(name string) (child *inode) { ...@@ -70,20 +110,22 @@ func (me *inode) getChild(name string) (child *inode) {
} }
// Must be called with treeLock for the mount held. // Must be called with treeLock for the mount held.
func (me *inode) addChild(name string, child *inode) { func (me *Inode) addChild(name string, child *Inode) {
if paranoia { if paranoia {
ch := me.children[name] ch := me.children[name]
if ch != nil { if ch != nil {
panic(fmt.Sprintf("Already have an inode with same name: %v: %v", name, ch)) panic(fmt.Sprintf("Already have an Inode with same name: %v: %v", name, ch))
} }
} }
me.children[name] = child me.children[name] = child
if child.mountPoint == nil {
me.fsInode.AddChild(name, child.fsInode) me.fsInode.AddChild(name, child.fsInode)
}
} }
// Must be called with treeLock for the mount held. // Must be called with treeLock for the mount held.
func (me *inode) rmChild(name string) (ch *inode) { 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
...@@ -93,7 +135,7 @@ func (me *inode) rmChild(name string) (ch *inode) { ...@@ -93,7 +135,7 @@ func (me *inode) rmChild(name string) (ch *inode) {
} }
// Can only be called on untouched inodes. // Can only be called on untouched inodes.
func (me *inode) mountFs(fs *inodeFs, opts *FileSystemOptions) { func (me *Inode) mountFs(fs NodeFileSystem, opts *FileSystemOptions) {
me.mountPoint = &fileSystemMount{ me.mountPoint = &fileSystemMount{
fs: fs, fs: fs,
openFiles: NewHandleMap(true), openFiles: NewHandleMap(true),
...@@ -107,7 +149,7 @@ func (me *inode) mountFs(fs *inodeFs, opts *FileSystemOptions) { ...@@ -107,7 +149,7 @@ func (me *inode) mountFs(fs *inodeFs, opts *FileSystemOptions) {
} }
// Must be called with treeLock held. // Must be called with treeLock held.
func (me *inode) canUnmount() bool { func (me *Inode) canUnmount() bool {
for _, v := range me.children { for _, v := range me.children {
if v.mountPoint != nil { if v.mountPoint != nil {
// This access may be out of date, but it is no // This access may be out of date, but it is no
...@@ -124,11 +166,7 @@ func (me *inode) canUnmount() bool { ...@@ -124,11 +166,7 @@ func (me *inode) canUnmount() bool {
return len(me.openFiles) == 0 return len(me.openFiles) == 0
} }
func (me *inode) IsDir() bool { func (me *Inode) getMountDirEntries() (out []DirEntry) {
return me.children != nil
}
func (me *inode) getMountDirEntries() (out []DirEntry) {
me.treeLock.RLock() me.treeLock.RLock()
defer me.treeLock.RUnlock() defer me.treeLock.RUnlock()
...@@ -141,35 +179,9 @@ func (me *inode) getMountDirEntries() (out []DirEntry) { ...@@ -141,35 +179,9 @@ func (me *inode) getMountDirEntries() (out []DirEntry) {
return out return out
} }
// Returns any open file, preferably a r/w one.
func (me *inode) getAnyFile() (file File) {
me.openFilesMutex.Lock()
defer me.openFilesMutex.Unlock()
for _, f := range me.openFiles {
if file == nil || f.OpenFlags & O_ANYWRITE != 0 {
file = f.file
}
}
return file
}
// Returns an open writable file for the given inode.
func (me *inode) getWritableFiles() (files []File) {
me.openFilesMutex.Lock()
defer me.openFilesMutex.Unlock()
for _, f := range me.openFiles {
if f.OpenFlags & O_ANYWRITE != 0 {
files = append(files, f.file)
}
}
return files
}
const initDirSize = 20 const initDirSize = 20
func (me *inode) verify(cur *fileSystemMount) { func (me *Inode) verify(cur *fileSystemMount) {
if me.mountPoint != nil { if me.mountPoint != nil {
if me != me.mountPoint.mountInode { if me != me.mountPoint.mountInode {
panic("mountpoint mismatch") panic("mountpoint mismatch")
......
This diff is collapsed.
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