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

Make fsInode lookups return fsInodes directly.

Use inodeFs as layer between FileSystemConnector and FileSystem.
parent 76583006
......@@ -59,8 +59,6 @@ func (me *FileSystemConnector) verify() {
func (me *FileSystemConnector) newInode(isDir bool) *inode {
data := new(inode)
data.nodeId = me.inodeMap.Register(&data.handled)
data.fsInode = new(fsInode)
data.fsInode.inode = data
if isDir {
data.children = make(map[string]*inode, initDirSize)
}
......@@ -259,7 +257,8 @@ func (me *FileSystemConnector) Mount(mountPoint string, fs FileSystem, opts *Fil
opts = me.rootNode.mountPoint.options
}
node.mountFs(fs, opts)
ifs := newInodeFs(fs)
node.mountFs(ifs, opts)
parent.addChild(base, node)
if parent.mounts == nil {
......@@ -276,8 +275,9 @@ func (me *FileSystemConnector) Mount(mountPoint string, fs FileSystem, opts *Fil
}
func (me *FileSystemConnector) mountRoot(fs FileSystem, opts *FileSystemOptions) {
me.rootNode.mountFs(fs, opts)
fs.Mount(me)
ifs := newInodeFs(fs)
me.rootNode.mountFs(ifs, opts)
ifs.Mount(me)
me.verify()
}
......
......@@ -8,12 +8,46 @@ import (
var _ = log.Println
type inodeFs struct {
fs FileSystem
root *fsInode
}
func (me *inodeFs) Unmount() {
}
func (me *inodeFs) Mount(conn *FileSystemConnector) {
me.fs.Mount(conn)
}
func (me *inodeFs) StatFs() *StatfsOut {
return me.fs.StatFs()
}
func newInodeFs(fs FileSystem) *inodeFs {
root := new(fsInode)
root.fs = fs
me := &inodeFs{
fs: fs,
root: root,
}
root.ifs = me
return me
}
func (me *inodeFs) RootNode() *fsInode {
return me.root
}
// This is a combination of dentry (entry in the file/directory and
// the inode). This structure is used to implement glue for FSes where
// there is a one-to-one mapping of paths and inodes, ie. FSes that
// disallow hardlinks.
type fsInode struct {
*inode
ifs *inodeFs
fs FileSystem
Name string
// This is nil at the root of the mount.
......@@ -28,11 +62,6 @@ func (me *fsInode) GetPath() (path string) {
me.inode.treeLock.RLock()
defer me.inode.treeLock.RUnlock()
if me.inode.mount == nil {
// Node from unmounted file system.
return ".deleted"
}
rev_components := make([]string, 0, 10)
n := me
for ; n.Parent != nil; n = n.Parent {
......@@ -56,35 +85,42 @@ func (me *fsInode) rmChild(name string, ch *fsInode) {
ch.Parent = nil
}
func (me *fsInode) SetInode(node *inode) {
if me.inode != nil {
panic("already have inode")
}
me.inode = node
}
////////////////////////////////////////////////////////////////
func (me *fsInode) Readlink(c *Context) ([]byte, Status) {
path := me.GetPath()
val, err := me.inode.mount.fs.Readlink(path, c)
val, err := me.fs.Readlink(path, c)
return []byte(val), err
}
func (me *fsInode) Access(mode uint32, context *Context) (code Status) {
p := me.GetPath()
return me.inode.mount.fs.Access(p, mode, context)
return me.fs.Access(p, mode, context)
}
func (me *fsInode) GetXAttr(attribute string, context *Context) (data []byte, code Status) {
return me.inode.mount.fs.GetXAttr(me.GetPath(), attribute, context)
return me.fs.GetXAttr(me.GetPath(), attribute, context)
}
func (me *fsInode) RemoveXAttr(attr string, context *Context) Status {
p := me.GetPath()
return me.inode.mount.fs.RemoveXAttr(p, attr, context)
return me.fs.RemoveXAttr(p, attr, context)
}
func (me *fsInode) SetXAttr(attr string, data []byte, flags int, context *Context) Status {
return me.inode.mount.fs.SetXAttr(me.GetPath(), attr, data, flags, context)
return me.fs.SetXAttr(me.GetPath(), attr, data, flags, context)
}
func (me *fsInode) ListXAttr(context *Context) (attrs []string, code Status) {
return me.inode.mount.fs.ListXAttr(me.GetPath(), context)
return me.fs.ListXAttr(me.GetPath(), context)
}
func (me *fsInode) Flush(file File, openFlags uint32, context *Context) (code Status) {
......@@ -93,34 +129,55 @@ func (me *fsInode) Flush(file File, openFlags uint32, context *Context) (code St
// We only signal releases to the FS if the
// open could have changed things.
path := me.GetPath()
code = me.inode.mount.fs.Flush(path)
code = me.fs.Flush(path)
}
return code
}
func (me *fsInode) OpenDir(context *Context) (chan DirEntry, Status) {
return me.inode.mount.fs.OpenDir(me.GetPath(), context)
return me.fs.OpenDir(me.GetPath(), context)
}
func (me *fsInode) Mknod(name string, mode uint32, dev uint32, context *Context) Status {
func (me *fsInode) Mknod(name string, mode uint32, dev uint32, context *Context) (fi *os.FileInfo, newNode *fsInode, code Status) {
p := me.GetPath()
return me.inode.mount.fs.Mknod(filepath.Join(p, name), mode, dev, context)
code = me.fs.Mknod(filepath.Join(p, name), mode, dev, context)
if code.Ok() {
newNode = me.createChild(name)
fi = &os.FileInfo{
Mode: S_IFIFO | mode, // TODO
}
}
return
}
func (me *fsInode) Mkdir(name string, mode uint32, context *Context) (code Status) {
return me.inode.mount.fs.Mkdir(filepath.Join(me.GetPath(), name), mode, context)
func (me *fsInode) Mkdir(name string, mode uint32, context *Context) (fi *os.FileInfo, newNode *fsInode, code Status) {
code = me.fs.Mkdir(filepath.Join(me.GetPath(), name), mode, context)
if code.Ok() {
newNode = me.createChild(name)
fi = &os.FileInfo{
Mode: S_IFDIR | mode,
}
}
return
}
func (me *fsInode) Unlink(name string, context *Context) (code Status) {
return me.inode.mount.fs.Unlink(filepath.Join(me.GetPath(), name), context)
return me.fs.Unlink(filepath.Join(me.GetPath(), name), context)
}
func (me *fsInode) Rmdir(name string, context *Context) (code Status) {
return me.inode.mount.fs.Rmdir(filepath.Join(me.GetPath(), name), context)
return me.fs.Rmdir(filepath.Join(me.GetPath(), name), context)
}
func (me *fsInode) Symlink(name string, content string, context *Context) (code Status) {
return me.inode.mount.fs.Symlink(content, filepath.Join(me.GetPath(), name), context)
func (me *fsInode) Symlink(name string, content string, context *Context) (fi *os.FileInfo, newNode *fsInode, code Status) {
code = me.fs.Symlink(content, filepath.Join(me.GetPath(), name), context)
if code.Ok() {
newNode = me.createChild(name)
fi = &os.FileInfo{
Mode: S_IFLNK | 0666, // TODO
}
}
return
}
......@@ -128,26 +185,48 @@ func (me *fsInode) Rename(oldName string, newParent *fsInode, newName string, co
oldPath := filepath.Join(me.GetPath(), oldName)
newPath := filepath.Join(newParent.GetPath(), newName)
return me.inode.mount.fs.Rename(oldPath, newPath, context)
return me.fs.Rename(oldPath, newPath, context)
}
func (me *fsInode) Link(name string, existing *fsInode, context *Context) (code Status) {
return me.inode.mount.fs.Link(existing.GetPath(), filepath.Join(me.GetPath(), name), context)
return me.fs.Link(existing.GetPath(), filepath.Join(me.GetPath(), name), context)
}
func (me *fsInode) Create(name string, flags uint32, mode uint32, context *Context) (file File, code Status) {
func (me *fsInode) Create(name string, flags uint32, mode uint32, context *Context) (file File, fi *os.FileInfo, newNode *fsInode, code Status) {
fullPath := filepath.Join(me.GetPath(), name)
return me.inode.mount.fs.Create(fullPath, flags, mode, context)
file, code = me.fs.Create(fullPath, flags, mode, context)
if code.Ok() {
newNode = me.createChild(name)
fi = &os.FileInfo{
Mode: S_IFREG | mode,
// TODO - ctime, mtime, atime?
}
}
return
}
func (me *fsInode) createChild(name string) *fsInode {
i := new(fsInode)
i.Parent = me
i.Name = name
i.fs = me.fs
i.ifs = me.ifs
return i
}
func (me *fsInode) Open(flags uint32, context *Context) (file File, code Status) {
return me.inode.mount.fs.Open(me.GetPath(), flags, context)
return me.fs.Open(me.GetPath(), flags, context)
}
// TODO: should return fsInode.
func (me *fsInode) Lookup(name string) (fi *os.FileInfo, code Status) {
// TOOD - need context.
func (me *fsInode) Lookup(name string) (fi *os.FileInfo, node *fsInode, code Status) {
fullPath := filepath.Join(me.GetPath(), name)
return me.inode.mount.fs.GetAttr(fullPath, nil)
fi, code = me.fs.GetAttr(fullPath, nil)
if code.Ok() {
node = me.createChild(name)
}
return
}
func (me *fsInode) GetAttr(file File, context *Context) (fi *os.FileInfo, code Status) {
......@@ -161,7 +240,7 @@ func (me *fsInode) GetAttr(file File, context *Context) (fi *os.FileInfo, code S
}
if file == nil || code == ENOSYS {
fi, code = me.inode.mount.fs.GetAttr(me.GetPath(), context)
fi, code = me.fs.GetAttr(me.GetPath(), context)
}
if fi != nil && !fi.IsDirectory() {
......@@ -181,7 +260,7 @@ func (me *fsInode) Chmod(file File, perms uint32, context *Context) (code Status
}
if len(files) == 0 || code == ENOSYS {
code = me.inode.mount.fs.Chmod(me.GetPath(), perms, context)
code = me.fs.Chmod(me.GetPath(), perms, context)
}
return code
}
......@@ -198,7 +277,7 @@ func (me *fsInode) Chown(file File, uid uint32, gid uint32, context *Context) (c
}
if len(files) == 0 || code == ENOSYS {
// TODO - can we get just FATTR_GID but not FATTR_UID ?
code = me.inode.mount.fs.Chown(me.GetPath(), uid, gid, context)
code = me.fs.Chown(me.GetPath(), uid, gid, context)
}
return code
}
......@@ -214,7 +293,7 @@ func (me *fsInode) Truncate(file File, size uint64, context *Context) (code Stat
}
}
if len(files) == 0 || code == ENOSYS {
code = me.inode.mount.fs.Truncate(me.GetPath(), size, context)
code = me.fs.Truncate(me.GetPath(), size, context)
}
return code
}
......@@ -229,7 +308,7 @@ func (me *fsInode) Utimens(file File, atime uint64, mtime uint64, context *Conte
}
}
if len(files) == 0 || code == ENOSYS {
code = me.inode.mount.fs.Utimens(me.GetPath(), atime, mtime, context)
code = me.fs.Utimens(me.GetPath(), atime, mtime, context)
}
return code
}
package fuse
import (
"log"
"os"
"sync"
"unsafe"
)
var _ = log.Println
// openedFile stores either an open dir or an open file.
type openedFile struct {
......@@ -21,7 +24,7 @@ type openedFile struct {
type fileSystemMount struct {
// The file system we mounted here.
fs FileSystem
fs *inodeFs
// Node that we were mounted on.
mountInode *inode
......
......@@ -4,8 +4,8 @@ package fuse
import (
"bytes"
"fmt"
"log"
"os"
"time"
)
......@@ -23,7 +23,7 @@ func (me *FileSystemConnector) Lookup(header *InHeader, name string) (out *Entry
}
func (me *FileSystemConnector) internalMountLookup(mount *fileSystemMount, lookupCount int) (out *EntryOut, status Status, node *inode) {
fi, err := mount.fs.GetAttr("", nil)
fi, err := mount.fs.RootNode().GetAttr(nil, nil)
if err == ENOENT && mount.options.NegativeTimeout > 0.0 {
return NegativeEntry(mount.options.NegativeTimeout), OK, nil
}
......@@ -41,12 +41,16 @@ 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, status 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)
}
fi, code := parent.fsInode.Lookup(name)
var fi *os.FileInfo
child := parent.getChild(name)
if child != nil {
fi, code = child.fsInode.GetAttr(nil, nil)
}
mount := parent.mount
if code == ENOENT && mount.options.NegativeTimeout > 0.0 {
return NegativeEntry(mount.options.NegativeTimeout), OK, nil
......@@ -54,13 +58,25 @@ func (me *FileSystemConnector) internalLookup(parent *inode, name string, lookup
if !code.Ok() {
return nil, code, nil
}
node = me.lookupUpdate(parent, name, fi.IsDirectory(), lookupCount)
out = &EntryOut{
NodeId: node.nodeId,
Generation: 1, // where to get the generation?
if child != nil && code.Ok() {
out = &EntryOut{
NodeId: child.nodeId,
Generation: 1, // where to get the generation?
}
parent.mount.fileInfoToEntry(fi, out)
return out, OK, child
}
parent.mount.fileInfoToEntry(fi, out)
out.Attr.Ino = node.nodeId
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
}
out, _ = me.createChild(parent, name, fi, fsNode)
return out, OK, node
}
......@@ -122,7 +138,6 @@ func (me *FileSystemConnector) Open(header *InHeader, input *OpenIn) (flags uint
if !code.Ok() {
return 0, 0, code
}
h, opened := node.mount.registerFileHandle(node, nil, f, input.Flags)
return opened.FuseFlags, h, OK
}
......@@ -178,20 +193,30 @@ func (me *FileSystemConnector) Readlink(header *InHeader) (out []byte, code Stat
}
func (me *FileSystemConnector) Mknod(header *InHeader, input *MknodIn, name string) (out *EntryOut, code Status) {
n := me.getInodeData(header.NodeId)
code = n.fsInode.Mknod(name, input.Mode, uint32(input.Rdev), &header.Context)
parent := me.getInodeData(header.NodeId)
fi, fsNode, code := parent.fsInode.Mknod(name, input.Mode, uint32(input.Rdev), &header.Context)
if code.Ok() {
out, code, _ = me.internalLookup(n, name, 1, &header.Context)
out, _ = me.createChild(parent, name, fi, fsNode)
}
return out, code
}
func (me *FileSystemConnector) createChild(parent *inode, name string, fi *os.FileInfo, fsi *fsInode) (out *EntryOut, child *inode) {
child = parent.createChild(name, fi.IsDirectory(), fsi, me)
out = &EntryOut{}
parent.mount.fileInfoToEntry(fi, out)
out.Ino = child.nodeId
out.NodeId = child.nodeId
return out, child
}
func (me *FileSystemConnector) Mkdir(header *InHeader, input *MkdirIn, name string) (out *EntryOut, code Status) {
parent := me.getInodeData(header.NodeId)
code = parent.fsInode.Mkdir(name, input.Mode, &header.Context)
fi, fsInode, code := parent.fsInode.Mkdir(name, input.Mode, &header.Context)
if code.Ok() {
out, code, _ = me.internalLookup(parent, name, 1, &header.Context)
out, _ = me.createChild(parent, name, fi, fsInode)
}
return out, code
}
......@@ -218,9 +243,9 @@ func (me *FileSystemConnector) Rmdir(header *InHeader, name string) (code Status
func (me *FileSystemConnector) Symlink(header *InHeader, pointedTo string, linkName string) (out *EntryOut, code Status) {
parent := me.getInodeData(header.NodeId)
code = parent.fsInode.Symlink(linkName, pointedTo, &header.Context)
fi, fsNode, code := parent.fsInode.Symlink(linkName, pointedTo, &header.Context)
if code.Ok() {
out, code, _ = me.internalLookup(parent, linkName, 1, &header.Context)
out, _ = me.createChild(parent, linkName, fi, fsNode)
}
return out, code
}
......@@ -269,17 +294,12 @@ func (me *FileSystemConnector) Access(header *InHeader, input *AccessIn) (code S
func (me *FileSystemConnector) Create(header *InHeader, input *CreateIn, name string) (flags uint32, h uint64, out *EntryOut, code Status) {
parent := me.getInodeData(header.NodeId)
f, code := parent.fsInode.Create(name, uint32(input.Flags), input.Mode, &header.Context)
f, fi, fsNode, code := parent.fsInode.Create(name, uint32(input.Flags), input.Mode, &header.Context)
if !code.Ok() {
return 0, 0, nil, code
}
out, code, inode := me.internalLookup(parent, name, 1, &header.Context)
if inode == nil {
msg := fmt.Sprintf("Create succeded, but GetAttr returned no entry %v, %q. code %v", header.NodeId, name, code)
panic(msg)
}
handle, opened := parent.mount.registerFileHandle(inode, nil, f, input.Flags)
out, child := me.createChild(parent, name, fi, fsNode)
handle, opened := parent.mount.registerFileHandle(child, nil, f, input.Flags)
return opened.FuseFlags, handle, out, code
}
......
......@@ -43,6 +43,32 @@ type inode struct {
mount *fileSystemMount
}
func (me *inode) createChild(name string, isDir bool, fsi *fsInode, conn *FileSystemConnector) *inode {
me.treeLock.Lock()
defer me.treeLock.Unlock()
ch := me.children[name]
if ch != nil {
panic(fmt.Sprintf("already have a child at %v %q", me.nodeId, name))
}
ch = conn.newInode(isDir)
ch.fsInode = fsi
fsi.SetInode(ch)
ch.mount = me.mount
ch.treeLock = me.treeLock
ch.lookupCount = 1
me.addChild(name, ch)
return ch
}
func (me *inode) getChild(name string) (child *inode) {
me.treeLock.Lock()
defer me.treeLock.Unlock()
return me.children[name]
}
// Must be called with treeLock for the mount held.
func (me *inode) addChild(name string, child *inode) {
if paranoia {
......@@ -67,7 +93,7 @@ func (me *inode) rmChild(name string) (ch *inode) {
}
// Can only be called on untouched inodes.
func (me *inode) mountFs(fs FileSystem, opts *FileSystemOptions) {
func (me *inode) mountFs(fs *inodeFs, opts *FileSystemOptions) {
me.mountPoint = &fileSystemMount{
fs: fs,
openFiles: NewHandleMap(true),
......@@ -76,6 +102,8 @@ func (me *inode) mountFs(fs FileSystem, opts *FileSystemOptions) {
}
me.mount = me.mountPoint
me.treeLock = &me.mountPoint.treeLock
me.fsInode = fs.RootNode()
me.fsInode.SetInode(me)
}
// Must be called with treeLock held.
......
......@@ -50,7 +50,7 @@ func (me *FileSystemDebug) Open(path string, flags uint32, context *Context) (fu
return me.FileSystem.Open(path, flags, context)
}
var SeparatorString = string([]byte{filepath.Separator})
var SeparatorString = string(filepath.Separator)
func (me *FileSystemDebug) getContent(path string) []byte {
comps := strings.Split(path, SeparatorString)
......
......@@ -25,6 +25,7 @@ const (
S_IFDIR = syscall.S_IFDIR
S_IFREG = syscall.S_IFREG
S_IFLNK = syscall.S_IFLNK
S_IFIFO = syscall.S_IFIFO
// TODO - get this from a canonical place.
PAGESIZE = 4096
......
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