Commit 804ff7cc authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

nodefs: move Mode into FileID and rename to NodeAttr

parent de68ce05
...@@ -44,7 +44,7 @@ type rawBridge struct { ...@@ -44,7 +44,7 @@ type rawBridge struct {
} }
// newInode creates creates new inode pointing to ops. // newInode creates creates new inode pointing to ops.
func (b *rawBridge) newInode(ops Operations, mode uint32, id FileID, persistent bool) *Inode { func (b *rawBridge) newInode(ops Operations, id NodeAttr, persistent bool) *Inode {
b.mu.Lock() b.mu.Lock()
defer b.mu.Unlock() defer b.mu.Unlock()
...@@ -66,14 +66,14 @@ func (b *rawBridge) newInode(ops Operations, mode uint32, id FileID, persistent ...@@ -66,14 +66,14 @@ func (b *rawBridge) newInode(ops Operations, mode uint32, id FileID, persistent
// file // file
// //
// dir1.Lookup("file") and dir2.Lookup("file") are executed // dir1.Lookup("file") and dir2.Lookup("file") are executed
// simultaneously. The matching FileIDs ensure that we return the // simultaneously. The matching NodeAttrs ensure that we return the
// same node. // same node.
old := b.nodes[id.Ino] old := b.nodes[id.Ino]
if old != nil { if old != nil {
return old return old
} }
mode = mode &^ 07777 id.Mode = id.Mode &^ 07777
switch mode { switch id.Mode {
case fuse.S_IFDIR: case fuse.S_IFDIR:
_ = ops.(DirOperations) _ = ops.(DirOperations)
case fuse.S_IFLNK: case fuse.S_IFLNK:
...@@ -81,18 +81,17 @@ func (b *rawBridge) newInode(ops Operations, mode uint32, id FileID, persistent ...@@ -81,18 +81,17 @@ func (b *rawBridge) newInode(ops Operations, mode uint32, id FileID, persistent
case fuse.S_IFREG: case fuse.S_IFREG:
_ = ops.(FileOperations) _ = ops.(FileOperations)
default: default:
log.Panicf("filetype %o unimplemented", mode) log.Panicf("filetype %o unimplemented", id.Mode)
} }
inode := &Inode{ inode := &Inode{
mode: mode,
ops: ops, ops: ops,
nodeID: id, nodeID: id,
bridge: b, bridge: b,
persistent: persistent, persistent: persistent,
parents: make(map[parentData]struct{}), parents: make(map[parentData]struct{}),
} }
if mode == fuse.S_IFDIR { if id.Mode == fuse.S_IFDIR {
inode.children = make(map[string]*Inode) inode.children = make(map[string]*Inode)
} }
...@@ -168,13 +167,15 @@ func NewNodeFS(root DirOperations, opts *Options) fuse.RawFileSystem { ...@@ -168,13 +167,15 @@ func NewNodeFS(root DirOperations, opts *Options) fuse.RawFileSystem {
bridge.root = &Inode{ bridge.root = &Inode{
lookupCount: 1, lookupCount: 1,
mode: fuse.S_IFDIR,
children: make(map[string]*Inode), children: make(map[string]*Inode),
parents: nil, parents: nil,
ops: root, ops: root,
bridge: bridge, bridge: bridge,
nodeID: NodeAttr{
Ino: 1,
Mode: fuse.S_IFDIR,
},
} }
bridge.root.nodeID.Ino = 1
root.setInode(bridge.root) root.setInode(bridge.root)
bridge.nodes = map[uint64]*Inode{ bridge.nodes = map[uint64]*Inode{
1: bridge.root, 1: bridge.root,
...@@ -216,7 +217,7 @@ func (b *rawBridge) Lookup(cancel <-chan struct{}, header *fuse.InHeader, name s ...@@ -216,7 +217,7 @@ func (b *rawBridge) Lookup(cancel <-chan struct{}, header *fuse.InHeader, name s
b.addNewChild(parent, name, child, nil, 0, out) b.addNewChild(parent, name, child, nil, 0, out)
b.setEntryOutTimeout(out) b.setEntryOutTimeout(out)
out.Mode = child.mode | (out.Mode & 07777) out.Mode = child.nodeID.Mode | (out.Mode & 07777)
return fuse.OK return fuse.OK
} }
...@@ -321,7 +322,7 @@ func (b *rawBridge) Create(cancel <-chan struct{}, input *fuse.CreateIn, name st ...@@ -321,7 +322,7 @@ func (b *rawBridge) Create(cancel <-chan struct{}, input *fuse.CreateIn, name st
out.NodeId = child.nodeID.Ino out.NodeId = child.nodeID.Ino
b.setEntryOutTimeout(&out.EntryOut) b.setEntryOutTimeout(&out.EntryOut)
out.Mode = (out.Attr.Mode & 07777) | child.mode out.Mode = (out.Attr.Mode & 07777) | child.nodeID.Mode
return fuse.OK return fuse.OK
} }
...@@ -355,7 +356,7 @@ func (b *rawBridge) GetAttr(cancel <-chan struct{}, input *fuse.GetAttrIn, out * ...@@ -355,7 +356,7 @@ func (b *rawBridge) GetAttr(cancel <-chan struct{}, input *fuse.GetAttrIn, out *
status := fops.FGetAttr(ctx, f, out) status := fops.FGetAttr(ctx, f, out)
b.setAttrTimeout(out) b.setAttrTimeout(out)
out.Ino = input.NodeId out.Ino = input.NodeId
out.Mode = (out.Attr.Mode & 07777) | n.mode out.Mode = (out.Attr.Mode & 07777) | n.nodeID.Mode
return status return status
} }
return n.ops.GetAttr(ctx, out) return n.ops.GetAttr(ctx, out)
...@@ -707,12 +708,12 @@ func (b *rawBridge) ReadDirPlus(cancel <-chan struct{}, input *fuse.ReadIn, out ...@@ -707,12 +708,12 @@ func (b *rawBridge) ReadDirPlus(cancel <-chan struct{}, input *fuse.ReadIn, out
} else { } else {
b.addNewChild(n, e.Name, child, nil, 0, entryOut) b.addNewChild(n, e.Name, child, nil, 0, entryOut)
b.setEntryOutTimeout(entryOut) b.setEntryOutTimeout(entryOut)
if (e.Mode &^ 07777) != (child.mode &^ 07777) { if (e.Mode &^ 07777) != (child.nodeID.Mode &^ 07777) {
// should go back and change the // should go back and change the
// already serialized entry // already serialized entry
log.Panicf("mode mismatch between readdir %o and lookup %o", e.Mode, child.mode) log.Panicf("mode mismatch between readdir %o and lookup %o", e.Mode, child.nodeID.Mode)
} }
entryOut.Mode = child.mode | (entryOut.Mode & 07777) entryOut.Mode = child.nodeID.Mode | (entryOut.Mode & 07777)
} }
} }
......
...@@ -71,13 +71,13 @@ func (r *keepCacheRoot) OnAdd() { ...@@ -71,13 +71,13 @@ func (r *keepCacheRoot) OnAdd() {
keepCache: true, keepCache: true,
} }
f1.setContent(0) f1.setContent(0)
i.AddChild("keep", i.NewInode(f1, fuse.S_IFREG, FileID{}), true) i.AddChild("keep", i.NewInode(f1, NodeAttr{Mode: fuse.S_IFREG}), true)
f2 := &keepCacheFile{ f2 := &keepCacheFile{
keepCache: false, keepCache: false,
} }
f2.setContent(0) f2.setContent(0)
i.AddChild("nokeep", i.NewInode(f2, fuse.S_IFREG, FileID{}), true) i.AddChild("nokeep", i.NewInode(f2, NodeAttr{Mode: fuse.S_IFREG}), true)
} }
func TestKeepCache(t *testing.T) { func TestKeepCache(t *testing.T) {
...@@ -94,6 +94,7 @@ func TestKeepCache(t *testing.T) { ...@@ -94,6 +94,7 @@ func TestKeepCache(t *testing.T) {
&fuse.MountOptions{ &fuse.MountOptions{
Debug: testutil.VerboseTest(), Debug: testutil.VerboseTest(),
}) })
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
......
...@@ -38,7 +38,7 @@ var _ Operations = &DefaultOperations{} ...@@ -38,7 +38,7 @@ var _ Operations = &DefaultOperations{}
// //
// dir1.Lookup("file") and dir2.Lookup("file") are executed simultaneously. // dir1.Lookup("file") and dir2.Lookup("file") are executed simultaneously.
// //
// If not using FileID, the mapping in rawBridge does not help. So, // If not using NodeAttr, the mapping in rawBridge does not help. So,
// use atomics so that only one set can win. // use atomics so that only one set can win.
// //
// To read node.inode atomic.LoadPointer is used, however it is not expensive // To read node.inode atomic.LoadPointer is used, however it is not expensive
...@@ -135,7 +135,7 @@ func (n *DefaultOperations) ReadDir(ctx context.Context) (DirStream, fuse.Status ...@@ -135,7 +135,7 @@ func (n *DefaultOperations) ReadDir(ctx context.Context) (DirStream, fuse.Status
for k, ch := range InodeOf(n).Children() { for k, ch := range InodeOf(n).Children() {
r = append(r, fuse.DirEntry{Mode: ch.Mode(), r = append(r, fuse.DirEntry{Mode: ch.Mode(),
Name: k, Name: k,
Ino: ch.FileID().Ino}) Ino: ch.NodeAttr().Ino})
} }
return NewListDirStream(r), fuse.OK return NewListDirStream(r), fuse.OK
} }
......
...@@ -20,14 +20,17 @@ type parentData struct { ...@@ -20,14 +20,17 @@ type parentData struct {
parent *Inode parent *Inode
} }
// FileID provides a identifier for file objects defined by FUSE // NodeAttr holds immutable attributes of a object in the filesystem.
// filesystems. type NodeAttr struct {
type FileID struct { // Each Inode has a type, which does not change over the
// lifetime of the inode, for example fuse.S_IFDIR.
Mode uint32
// The inode number must be unique among the currently live // The inode number must be unique among the currently live
// objects in the file system. It is used to communicate to // objects in the file system. It is used to communicate to
// the kernel about this file object. The values uint64(-1), // the kernel about this file object. The values uint64(-1),
// and 1 are reserved. When using Ino==0, a unique, sequential // and 1 are reserved. When using Ino==0, a unique, sequential
// number is assigned (starting at 2^63) on Inode creation. // number is assigned (starting at 2^63 by default) on Inode creation.
Ino uint64 Ino uint64
// When reusing a previously used inode number for a new // When reusing a previously used inode number for a new
...@@ -37,8 +40,8 @@ type FileID struct { ...@@ -37,8 +40,8 @@ type FileID struct {
Gen uint64 Gen uint64
} }
// Reserved returns if the FileID is using reserved Inode numbers. // Reserved returns if the NodeAttr is using reserved Inode numbers.
func (i *FileID) Reserved() bool { func (i *NodeAttr) Reserved() bool {
return i.Ino == 1 || i.Ino == ^uint64(0) return i.Ino == 1 || i.Ino == ^uint64(0)
} }
...@@ -47,10 +50,7 @@ func (i *FileID) Reserved() bool { ...@@ -47,10 +50,7 @@ func (i *FileID) Reserved() bool {
// systems. One can create fully-formed trees of Inodes ahead of time // systems. One can create fully-formed trees of Inodes ahead of time
// by creating "persistent" Inodes. // by creating "persistent" Inodes.
type Inode struct { type Inode struct {
// The filetype bits from the mode. nodeID NodeAttr
mode uint32
nodeID FileID
ops Operations ops Operations
bridge *rawBridge bridge *rawBridge
...@@ -100,14 +100,14 @@ func (n *Inode) linkOps() SymlinkOperations { ...@@ -100,14 +100,14 @@ func (n *Inode) linkOps() SymlinkOperations {
return n.ops.(SymlinkOperations) return n.ops.(SymlinkOperations)
} }
// FileID returns the (Ino, Gen) tuple for this node. // NodeAttr returns the (Ino, Gen) tuple for this node.
func (n *Inode) FileID() FileID { func (n *Inode) NodeAttr() NodeAttr {
return n.nodeID return n.nodeID
} }
// Mode returns the filetype // Mode returns the filetype
func (n *Inode) Mode() uint32 { func (n *Inode) Mode() uint32 {
return n.mode return n.nodeID.Mode
} }
// IsRoot returns true if this is the root of the FUSE mount. // IsRoot returns true if this is the root of the FUSE mount.
...@@ -271,8 +271,8 @@ func (iparent *Inode) setEntry(name string, ichild *Inode) { ...@@ -271,8 +271,8 @@ func (iparent *Inode) setEntry(name string, ichild *Inode) {
// NewPersistentInode returns an Inode whose lifetime is not in // NewPersistentInode returns an Inode whose lifetime is not in
// control of the kernel. // control of the kernel.
func (n *Inode) NewPersistentInode(node Operations, mode uint32, opaque FileID) *Inode { func (n *Inode) NewPersistentInode(node Operations, id NodeAttr) *Inode {
return n.newInode(node, mode, opaque, true) return n.newInode(node, id, true)
} }
// ForgetPersistent manually marks the node as no longer important. If // ForgetPersistent manually marks the node as no longer important. If
...@@ -287,12 +287,12 @@ func (n *Inode) ForgetPersistent() { ...@@ -287,12 +287,12 @@ func (n *Inode) ForgetPersistent() {
// non-zero, is used to implement hard-links. If opaqueID is given, // non-zero, is used to implement hard-links. If opaqueID is given,
// and another node with the same ID is known, that will node will be // and another node with the same ID is known, that will node will be
// returned, and the passed-in `node` is ignored. // returned, and the passed-in `node` is ignored.
func (n *Inode) NewInode(node Operations, mode uint32, opaqueID FileID) *Inode { func (n *Inode) NewInode(node Operations, id NodeAttr) *Inode {
return n.newInode(node, mode, opaqueID, false) return n.newInode(node, id, false)
} }
func (n *Inode) newInode(node Operations, mode uint32, opaqueID FileID, persistent bool) *Inode { func (n *Inode) newInode(node Operations, id NodeAttr, persistent bool) *Inode {
return n.bridge.newInode(node, mode, opaqueID, persistent) return n.bridge.newInode(node, id, persistent)
} }
// removeRef decreases references. Returns if this operation caused // removeRef decreases references. Returns if this operation caused
......
...@@ -29,9 +29,10 @@ func (r *interruptRoot) Lookup(ctx context.Context, name string, out *fuse.Entry ...@@ -29,9 +29,10 @@ func (r *interruptRoot) Lookup(ctx context.Context, name string, out *fuse.Entry
if name != "file" { if name != "file" {
return nil, fuse.ENOENT return nil, fuse.ENOENT
} }
ch := InodeOf(r).NewInode(&r.child, fuse.S_IFREG, FileID{ ch := InodeOf(r).NewInode(&r.child, NodeAttr{
Ino: 2, Mode: fuse.S_IFREG,
Gen: 1}) Ino: 2,
Gen: 1})
return ch, fuse.OK return ch, fuse.OK
} }
......
...@@ -71,7 +71,7 @@ func (n *loopbackNode) Lookup(ctx context.Context, name string, out *fuse.EntryO ...@@ -71,7 +71,7 @@ func (n *loopbackNode) Lookup(ctx context.Context, name string, out *fuse.EntryO
out.Attr.FromStat(&st) out.Attr.FromStat(&st)
node := n.rootNode.newLoopbackNode() node := n.rootNode.newLoopbackNode()
ch := n.inode().NewInode(node, out.Attr.Mode, n.rootNode.idFromStat(&st)) ch := n.inode().NewInode(node, n.rootNode.idFromStat(&st))
return ch, fuse.OK return ch, fuse.OK
} }
...@@ -90,7 +90,7 @@ func (n *loopbackNode) Mknod(ctx context.Context, name string, mode, rdev uint32 ...@@ -90,7 +90,7 @@ func (n *loopbackNode) Mknod(ctx context.Context, name string, mode, rdev uint32
out.Attr.FromStat(&st) out.Attr.FromStat(&st)
node := n.rootNode.newLoopbackNode() node := n.rootNode.newLoopbackNode()
ch := n.inode().NewInode(node, out.Attr.Mode, n.rootNode.idFromStat(&st)) ch := n.inode().NewInode(node, n.rootNode.idFromStat(&st))
return ch, fuse.OK return ch, fuse.OK
} }
...@@ -110,7 +110,7 @@ func (n *loopbackNode) Mkdir(ctx context.Context, name string, mode uint32, out ...@@ -110,7 +110,7 @@ func (n *loopbackNode) Mkdir(ctx context.Context, name string, mode uint32, out
out.Attr.FromStat(&st) out.Attr.FromStat(&st)
node := n.rootNode.newLoopbackNode() node := n.rootNode.newLoopbackNode()
ch := n.inode().NewInode(node, out.Attr.Mode, n.rootNode.idFromStat(&st)) ch := n.inode().NewInode(node, n.rootNode.idFromStat(&st))
return ch, fuse.OK return ch, fuse.OK
} }
...@@ -147,7 +147,7 @@ func (n *loopbackNode) Rename(ctx context.Context, name string, newParent Operat ...@@ -147,7 +147,7 @@ func (n *loopbackNode) Rename(ctx context.Context, name string, newParent Operat
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
func (r *loopbackRoot) idFromStat(st *syscall.Stat_t) FileID { func (r *loopbackRoot) idFromStat(st *syscall.Stat_t) NodeAttr {
// We compose an inode number by the underlying inode, and // We compose an inode number by the underlying inode, and
// mixing in the device number. In traditional filesystems, // mixing in the device number. In traditional filesystems,
// the inode numbers are small. The device numbers are also // the inode numbers are small. The device numbers are also
...@@ -157,8 +157,9 @@ func (r *loopbackRoot) idFromStat(st *syscall.Stat_t) FileID { ...@@ -157,8 +157,9 @@ func (r *loopbackRoot) idFromStat(st *syscall.Stat_t) FileID {
// the underlying filesystem // the underlying filesystem
swapped := (st.Dev << 32) | (st.Dev >> 32) swapped := (st.Dev << 32) | (st.Dev >> 32)
swappedRootDev := (r.rootDev << 32) | (r.rootDev >> 32) swappedRootDev := (r.rootDev << 32) | (r.rootDev >> 32)
return FileID{ return NodeAttr{
Gen: 1, Mode: st.Mode,
Gen: 1,
// This should work well for traditional backing FSes, // This should work well for traditional backing FSes,
// not so much for other go-fuse FS-es // not so much for other go-fuse FS-es
Ino: (swapped ^ swappedRootDev) ^ st.Ino, Ino: (swapped ^ swappedRootDev) ^ st.Ino,
...@@ -180,7 +181,7 @@ func (n *loopbackNode) Create(ctx context.Context, name string, flags uint32, mo ...@@ -180,7 +181,7 @@ func (n *loopbackNode) Create(ctx context.Context, name string, flags uint32, mo
} }
node := n.rootNode.newLoopbackNode() node := n.rootNode.newLoopbackNode()
ch := n.inode().NewInode(node, uint32(st.Mode), n.rootNode.idFromStat(&st)) ch := n.inode().NewInode(node, n.rootNode.idFromStat(&st))
lf := NewLoopbackFile(fd) lf := NewLoopbackFile(fd)
return ch, lf, 0, fuse.OK return ch, lf, 0, fuse.OK
} }
...@@ -197,7 +198,7 @@ func (n *loopbackNode) Symlink(ctx context.Context, target, name string, out *fu ...@@ -197,7 +198,7 @@ func (n *loopbackNode) Symlink(ctx context.Context, target, name string, out *fu
return nil, fuse.ToStatus(err) return nil, fuse.ToStatus(err)
} }
node := n.rootNode.newLoopbackNode() node := n.rootNode.newLoopbackNode()
ch := n.inode().NewInode(node, uint32(st.Mode), n.rootNode.idFromStat(&st)) ch := n.inode().NewInode(node, n.rootNode.idFromStat(&st))
out.Attr.FromStat(&st) out.Attr.FromStat(&st)
return ch, fuse.OK return ch, fuse.OK
...@@ -217,7 +218,7 @@ func (n *loopbackNode) Link(ctx context.Context, target Operations, name string, ...@@ -217,7 +218,7 @@ func (n *loopbackNode) Link(ctx context.Context, target Operations, name string,
return nil, fuse.ToStatus(err) return nil, fuse.ToStatus(err)
} }
node := n.rootNode.newLoopbackNode() node := n.rootNode.newLoopbackNode()
ch := n.inode().NewInode(node, uint32(st.Mode), n.rootNode.idFromStat(&st)) ch := n.inode().NewInode(node, n.rootNode.idFromStat(&st))
out.Attr.FromStat(&st) out.Attr.FromStat(&st)
return ch, fuse.OK return ch, fuse.OK
......
...@@ -48,13 +48,13 @@ func (n *loopbackNode) renameExchange(name string, newparent *loopbackNode, newN ...@@ -48,13 +48,13 @@ func (n *loopbackNode) renameExchange(name string, newparent *loopbackNode, newN
if err := syscall.Fstat(fd1, &st); err != nil { if err := syscall.Fstat(fd1, &st); err != nil {
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
if !InodeOf(n).IsRoot() && InodeOf(n).FileID().Ino != n.rootNode.idFromStat(&st).Ino { if !InodeOf(n).IsRoot() && InodeOf(n).NodeAttr().Ino != n.rootNode.idFromStat(&st).Ino {
return fuse.EBUSY return fuse.EBUSY
} }
if err := syscall.Fstat(fd2, &st); err != nil { if err := syscall.Fstat(fd2, &st); err != nil {
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
if !InodeOf(newparent).IsRoot() && InodeOf(newparent).FileID().Ino != n.rootNode.idFromStat(&st).Ino { if !InodeOf(newparent).IsRoot() && InodeOf(newparent).NodeAttr().Ino != n.rootNode.idFromStat(&st).Ino {
return fuse.EBUSY return fuse.EBUSY
} }
......
...@@ -183,13 +183,13 @@ func (zr *zipRoot) OnAdd() { ...@@ -183,13 +183,13 @@ func (zr *zipRoot) OnAdd() {
ch := p.GetChild(component) ch := p.GetChild(component)
if ch == nil { if ch == nil {
ch = InodeOf(zr).NewPersistentInode(&DefaultOperations{}, ch = InodeOf(zr).NewPersistentInode(&DefaultOperations{},
fuse.S_IFDIR, FileID{}) NodeAttr{Mode: fuse.S_IFDIR})
p.AddChild(component, ch, true) p.AddChild(component, ch, true)
} }
p = ch p = ch
} }
ch := InodeOf(zr).NewPersistentInode(&zipFile{file: f}, fuse.S_IFREG, FileID{}) ch := InodeOf(zr).NewPersistentInode(&zipFile{file: f}, NodeAttr{Mode: fuse.S_IFREG})
p.AddChild(base, ch, true) p.AddChild(base, ch, true)
} }
} }
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