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 \
direntry.go\
files.go \
fsmount.go \
fsinode.go \
fsconnector.go \
fuse.go \
handle.go \
......@@ -25,6 +24,7 @@ MANUAL_GOFILES=api.go \
mount.go \
mountstate.go \
opcode.go \
pathfs.go \
pathdebug.go \
fsops.go \
readonlyfs.go \
......
......@@ -8,7 +8,7 @@ import (
// Types for users to implement.
type InodeFs interface {
type NodeFileSystem interface {
Unmount()
Mount(conn *FileSystemConnector)
StatFs() *StatfsOut
......@@ -17,8 +17,9 @@ type InodeFs interface {
type FsNode interface {
// The following are called by the FileSystemConnector
Inode() *inode
SetInode(node *inode)
Inode() *Inode
SetInode(node *Inode)
RmChild(name string, child FsNode)
AddChild(name string, child FsNode)
......@@ -137,6 +138,7 @@ type File interface {
Fsync(*FsyncIn) (code Status)
}
// Wrap a File return in this to set FUSE flags.
type WithFlags struct {
File
......
......@@ -32,7 +32,7 @@ type FileSystemConnector struct {
fsInit RawFsInit
inodeMap HandleMap
rootNode *inode
rootNode *Inode
}
func NewFileSystemConnector(fs FileSystem, opts *FileSystemOptions) (me *FileSystemConnector) {
......@@ -56,17 +56,17 @@ func (me *FileSystemConnector) verify() {
root.verify(me.rootNode.mountPoint)
}
func (me *FileSystemConnector) newInode(isDir bool) *inode {
data := new(inode)
func (me *FileSystemConnector) newInode(isDir bool) *Inode {
data := new(Inode)
data.nodeId = me.inodeMap.Register(&data.handled)
if isDir {
data.children = make(map[string]*inode, initDirSize)
data.children = make(map[string]*Inode, initDirSize)
}
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()
parent.treeLock.Lock()
......@@ -83,7 +83,7 @@ func (me *FileSystemConnector) lookupUpdate(parent *inode, name string, isDir bo
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()
defer parent.treeLock.RUnlock()
if parent.mounts == nil {
......@@ -100,11 +100,11 @@ func (me *FileSystemConnector) lookupMount(parent *inode, name string, lookupCou
return nil
}
func (me *FileSystemConnector) getInodeData(nodeid uint64) *inode {
func (me *FileSystemConnector) getInodeData(nodeid uint64) *Inode {
if nodeid == FUSE_ROOT_ID {
return me.rootNode
}
return (*inode)(unsafe.Pointer(DecodeHandle(nodeid)))
return (*Inode)(unsafe.Pointer(DecodeHandle(nodeid)))
}
func (me *FileSystemConnector) forgetUpdate(nodeId uint64, forgetCount int) {
......@@ -119,7 +119,7 @@ func (me *FileSystemConnector) forgetUpdate(nodeId uint64, forgetCount int) {
me.considerDropInode(node)
}
func (me *FileSystemConnector) considerDropInode(n *inode) (drop bool) {
func (me *FileSystemConnector) considerDropInode(n *Inode) (drop bool) {
delChildren := []string{}
for k, v := range n.children {
if v.mountPoint == nil && me.considerDropInode(v) {
......@@ -146,7 +146,7 @@ func (me *FileSystemConnector) considerDropInode(n *inode) (drop bool) {
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()
oldParent.treeLock.Lock()
defer oldParent.treeLock.Unlock()
......@@ -163,7 +163,7 @@ func (me *FileSystemConnector) renameUpdate(oldParent *inode, oldName string, ne
newParent.addChild(newName, node)
}
func (me *FileSystemConnector) unlinkUpdate(parent *inode, name string) {
func (me *FileSystemConnector) unlinkUpdate(parent *Inode, name string) {
defer me.verify()
parent.treeLock.Lock()
......@@ -174,7 +174,7 @@ func (me *FileSystemConnector) unlinkUpdate(parent *inode, name string) {
// Walk the file system starting from the root. Will return nil if
// node not found.
func (me *FileSystemConnector) findLastKnownInode(fullPath string) (*inode, []string) {
func (me *FileSystemConnector) findLastKnownInode(fullPath string) (*Inode, []string) {
if fullPath == "" {
return me.rootNode, nil
}
......@@ -203,7 +203,7 @@ func (me *FileSystemConnector) findLastKnownInode(fullPath string) (*inode, []st
return node, nil
}
func (me *FileSystemConnector) findInode(fullPath string) *inode {
func (me *FileSystemConnector) findInode(fullPath string) *Inode {
n, rest := me.findLastKnownInode(fullPath)
if len(rest) > 0 {
return nil
......@@ -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 are inherited. The encompassing filesystem should pretend
// 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:
//
......@@ -257,8 +257,8 @@ func (me *FileSystemConnector) Mount(mountPoint string, fs FileSystem, opts *Fil
opts = me.rootNode.mountPoint.options
}
ifs := newInodeFs(fs)
node.mountFs(ifs, opts)
nodeFs := NewPathNodeFs(fs)
node.mountFs(nodeFs, opts)
parent.addChild(base, node)
if parent.mounts == nil {
......@@ -275,7 +275,7 @@ func (me *FileSystemConnector) Mount(mountPoint string, fs FileSystem, opts *Fil
}
func (me *FileSystemConnector) mountRoot(fs FileSystem, opts *FileSystemOptions) {
ifs := newInodeFs(fs)
ifs := NewPathNodeFs(fs)
me.rootNode.mountFs(ifs, opts)
ifs.Mount(me)
me.verify()
......
......@@ -24,10 +24,10 @@ type openedFile struct {
type fileSystemMount struct {
// The file system we mounted here.
fs InodeFs
fs NodeFileSystem
// Node that we were mounted on.
mountInode *inode
mountInode *Inode
// Options for the mount.
options *FileSystemOptions
......@@ -69,7 +69,7 @@ func (me *FileSystemConnector) getOpenedFile(h uint64) *openedFile {
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)
opened := (*openedFile)(unsafe.Pointer(obj))
node.openFilesMutex.Lock()
......@@ -90,7 +90,7 @@ func (me *fileSystemMount) unregisterFileHandle(handle uint64, node *inode) *ope
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()
defer node.openFilesMutex.Unlock()
b := &openedFile{
......
......@@ -22,7 +22,7 @@ func (me *FileSystemConnector) Lookup(header *InHeader, name string) (out *Entry
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)
if err == ENOENT && mount.options.NegativeTimeout > 0.0 {
return NegativeEntry(mount.options.NegativeTimeout), OK, nil
......@@ -41,7 +41,7 @@ func (me *FileSystemConnector) internalMountLookup(mount *fileSystemMount, looku
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 {
return me.internalMountLookup(mount, lookupCount)
}
......@@ -199,7 +199,7 @@ func (me *FileSystemConnector) Mknod(header *InHeader, input *MknodIn, name stri
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)
out = parent.mount.fileInfoToEntry(fi)
out.Ino = child.nodeId
......
......@@ -6,7 +6,7 @@ import (
)
// The inode reflects the kernel's idea of the inode.
type inode struct {
type Inode struct {
handled Handled
// Constant during lifetime.
......@@ -27,7 +27,7 @@ type inode struct {
// All data below is protected by treeLock.
fsInode FsNode
children map[string]*inode
children map[string]*Inode
// Contains directories that function as mounts. The entries
// are duplicated in children.
......@@ -43,7 +43,47 @@ type inode struct {
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()
defer me.treeLock.Unlock()
......@@ -62,7 +102,7 @@ func (me *inode) createChild(name string, isDir bool, fsi FsNode, conn *FileSyst
return ch
}
func (me *inode) getChild(name string) (child *inode) {
func (me *Inode) getChild(name string) (child *Inode) {
me.treeLock.Lock()
defer me.treeLock.Unlock()
......@@ -70,20 +110,22 @@ func (me *inode) getChild(name string) (child *inode) {
}
// 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 {
ch := me.children[name]
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.fsInode.AddChild(name, child.fsInode)
if child.mountPoint == nil {
me.fsInode.AddChild(name, child.fsInode)
}
}
// 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]
if ch != nil {
me.children[name] = nil, false
......@@ -93,7 +135,7 @@ func (me *inode) rmChild(name string) (ch *inode) {
}
// 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{
fs: fs,
openFiles: NewHandleMap(true),
......@@ -107,7 +149,7 @@ func (me *inode) mountFs(fs *inodeFs, opts *FileSystemOptions) {
}
// Must be called with treeLock held.
func (me *inode) canUnmount() bool {
func (me *Inode) canUnmount() bool {
for _, v := range me.children {
if v.mountPoint != nil {
// This access may be out of date, but it is no
......@@ -124,11 +166,7 @@ func (me *inode) canUnmount() bool {
return len(me.openFiles) == 0
}
func (me *inode) IsDir() bool {
return me.children != nil
}
func (me *inode) getMountDirEntries() (out []DirEntry) {
func (me *Inode) getMountDirEntries() (out []DirEntry) {
me.treeLock.RLock()
defer me.treeLock.RUnlock()
......@@ -141,35 +179,9 @@ func (me *inode) getMountDirEntries() (out []DirEntry) {
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
func (me *inode) verify(cur *fileSystemMount) {
func (me *Inode) verify(cur *fileSystemMount) {
if me.mountPoint != nil {
if me != me.mountPoint.mountInode {
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