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 {
}
// 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()
defer b.mu.Unlock()
......@@ -66,14 +66,14 @@ func (b *rawBridge) newInode(ops Operations, mode uint32, id FileID, persistent
// file
//
// 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.
old := b.nodes[id.Ino]
if old != nil {
return old
}
mode = mode &^ 07777
switch mode {
id.Mode = id.Mode &^ 07777
switch id.Mode {
case fuse.S_IFDIR:
_ = ops.(DirOperations)
case fuse.S_IFLNK:
......@@ -81,18 +81,17 @@ func (b *rawBridge) newInode(ops Operations, mode uint32, id FileID, persistent
case fuse.S_IFREG:
_ = ops.(FileOperations)
default:
log.Panicf("filetype %o unimplemented", mode)
log.Panicf("filetype %o unimplemented", id.Mode)
}
inode := &Inode{
mode: mode,
ops: ops,
nodeID: id,
bridge: b,
persistent: persistent,
parents: make(map[parentData]struct{}),
}
if mode == fuse.S_IFDIR {
if id.Mode == fuse.S_IFDIR {
inode.children = make(map[string]*Inode)
}
......@@ -168,13 +167,15 @@ func NewNodeFS(root DirOperations, opts *Options) fuse.RawFileSystem {
bridge.root = &Inode{
lookupCount: 1,
mode: fuse.S_IFDIR,
children: make(map[string]*Inode),
parents: nil,
ops: root,
bridge: bridge,
nodeID: NodeAttr{
Ino: 1,
Mode: fuse.S_IFDIR,
},
}
bridge.root.nodeID.Ino = 1
root.setInode(bridge.root)
bridge.nodes = map[uint64]*Inode{
1: bridge.root,
......@@ -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.setEntryOutTimeout(out)
out.Mode = child.mode | (out.Mode & 07777)
out.Mode = child.nodeID.Mode | (out.Mode & 07777)
return fuse.OK
}
......@@ -321,7 +322,7 @@ func (b *rawBridge) Create(cancel <-chan struct{}, input *fuse.CreateIn, name st
out.NodeId = child.nodeID.Ino
b.setEntryOutTimeout(&out.EntryOut)
out.Mode = (out.Attr.Mode & 07777) | child.mode
out.Mode = (out.Attr.Mode & 07777) | child.nodeID.Mode
return fuse.OK
}
......@@ -355,7 +356,7 @@ func (b *rawBridge) GetAttr(cancel <-chan struct{}, input *fuse.GetAttrIn, out *
status := fops.FGetAttr(ctx, f, out)
b.setAttrTimeout(out)
out.Ino = input.NodeId
out.Mode = (out.Attr.Mode & 07777) | n.mode
out.Mode = (out.Attr.Mode & 07777) | n.nodeID.Mode
return status
}
return n.ops.GetAttr(ctx, out)
......@@ -707,12 +708,12 @@ func (b *rawBridge) ReadDirPlus(cancel <-chan struct{}, input *fuse.ReadIn, out
} else {
b.addNewChild(n, e.Name, child, nil, 0, 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
// 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() {
keepCache: true,
}
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{
keepCache: false,
}
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) {
......@@ -94,6 +94,7 @@ func TestKeepCache(t *testing.T) {
&fuse.MountOptions{
Debug: testutil.VerboseTest(),
})
if err != nil {
t.Fatal(err)
}
......
......@@ -38,7 +38,7 @@ var _ Operations = &DefaultOperations{}
//
// 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.
//
// 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
for k, ch := range InodeOf(n).Children() {
r = append(r, fuse.DirEntry{Mode: ch.Mode(),
Name: k,
Ino: ch.FileID().Ino})
Ino: ch.NodeAttr().Ino})
}
return NewListDirStream(r), fuse.OK
}
......
......@@ -20,14 +20,17 @@ type parentData struct {
parent *Inode
}
// FileID provides a identifier for file objects defined by FUSE
// filesystems.
type FileID struct {
// NodeAttr holds immutable attributes of a object in the filesystem.
type NodeAttr 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
// objects in the file system. It is used to communicate to
// the kernel about this file object. The values uint64(-1),
// 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
// When reusing a previously used inode number for a new
......@@ -37,8 +40,8 @@ type FileID struct {
Gen uint64
}
// Reserved returns if the FileID is using reserved Inode numbers.
func (i *FileID) Reserved() bool {
// Reserved returns if the NodeAttr is using reserved Inode numbers.
func (i *NodeAttr) Reserved() bool {
return i.Ino == 1 || i.Ino == ^uint64(0)
}
......@@ -47,10 +50,7 @@ func (i *FileID) Reserved() bool {
// systems. One can create fully-formed trees of Inodes ahead of time
// by creating "persistent" Inodes.
type Inode struct {
// The filetype bits from the mode.
mode uint32
nodeID FileID
nodeID NodeAttr
ops Operations
bridge *rawBridge
......@@ -100,14 +100,14 @@ func (n *Inode) linkOps() SymlinkOperations {
return n.ops.(SymlinkOperations)
}
// FileID returns the (Ino, Gen) tuple for this node.
func (n *Inode) FileID() FileID {
// NodeAttr returns the (Ino, Gen) tuple for this node.
func (n *Inode) NodeAttr() NodeAttr {
return n.nodeID
}
// Mode returns the filetype
func (n *Inode) Mode() uint32 {
return n.mode
return n.nodeID.Mode
}
// IsRoot returns true if this is the root of the FUSE mount.
......@@ -271,8 +271,8 @@ func (iparent *Inode) setEntry(name string, ichild *Inode) {
// NewPersistentInode returns an Inode whose lifetime is not in
// control of the kernel.
func (n *Inode) NewPersistentInode(node Operations, mode uint32, opaque FileID) *Inode {
return n.newInode(node, mode, opaque, true)
func (n *Inode) NewPersistentInode(node Operations, id NodeAttr) *Inode {
return n.newInode(node, id, true)
}
// ForgetPersistent manually marks the node as no longer important. If
......@@ -287,12 +287,12 @@ func (n *Inode) ForgetPersistent() {
// 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
// returned, and the passed-in `node` is ignored.
func (n *Inode) NewInode(node Operations, mode uint32, opaqueID FileID) *Inode {
return n.newInode(node, mode, opaqueID, false)
func (n *Inode) NewInode(node Operations, id NodeAttr) *Inode {
return n.newInode(node, id, false)
}
func (n *Inode) newInode(node Operations, mode uint32, opaqueID FileID, persistent bool) *Inode {
return n.bridge.newInode(node, mode, opaqueID, persistent)
func (n *Inode) newInode(node Operations, id NodeAttr, persistent bool) *Inode {
return n.bridge.newInode(node, id, persistent)
}
// removeRef decreases references. Returns if this operation caused
......
......@@ -29,9 +29,10 @@ func (r *interruptRoot) Lookup(ctx context.Context, name string, out *fuse.Entry
if name != "file" {
return nil, fuse.ENOENT
}
ch := InodeOf(r).NewInode(&r.child, fuse.S_IFREG, FileID{
Ino: 2,
Gen: 1})
ch := InodeOf(r).NewInode(&r.child, NodeAttr{
Mode: fuse.S_IFREG,
Ino: 2,
Gen: 1})
return ch, fuse.OK
}
......
......@@ -71,7 +71,7 @@ func (n *loopbackNode) Lookup(ctx context.Context, name string, out *fuse.EntryO
out.Attr.FromStat(&st)
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
}
......@@ -90,7 +90,7 @@ func (n *loopbackNode) Mknod(ctx context.Context, name string, mode, rdev uint32
out.Attr.FromStat(&st)
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
}
......@@ -110,7 +110,7 @@ func (n *loopbackNode) Mkdir(ctx context.Context, name string, mode uint32, out
out.Attr.FromStat(&st)
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
}
......@@ -147,7 +147,7 @@ func (n *loopbackNode) Rename(ctx context.Context, name string, newParent Operat
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
// mixing in the device number. In traditional filesystems,
// the inode numbers are small. The device numbers are also
......@@ -157,8 +157,9 @@ func (r *loopbackRoot) idFromStat(st *syscall.Stat_t) FileID {
// the underlying filesystem
swapped := (st.Dev << 32) | (st.Dev >> 32)
swappedRootDev := (r.rootDev << 32) | (r.rootDev >> 32)
return FileID{
Gen: 1,
return NodeAttr{
Mode: st.Mode,
Gen: 1,
// This should work well for traditional backing FSes,
// not so much for other go-fuse FS-es
Ino: (swapped ^ swappedRootDev) ^ st.Ino,
......@@ -180,7 +181,7 @@ func (n *loopbackNode) Create(ctx context.Context, name string, flags uint32, mo
}
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)
return ch, lf, 0, fuse.OK
}
......@@ -197,7 +198,7 @@ func (n *loopbackNode) Symlink(ctx context.Context, target, name string, out *fu
return nil, fuse.ToStatus(err)
}
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)
return ch, fuse.OK
......@@ -217,7 +218,7 @@ func (n *loopbackNode) Link(ctx context.Context, target Operations, name string,
return nil, fuse.ToStatus(err)
}
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)
return ch, fuse.OK
......
......@@ -48,13 +48,13 @@ func (n *loopbackNode) renameExchange(name string, newparent *loopbackNode, newN
if err := syscall.Fstat(fd1, &st); err != nil {
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
}
if err := syscall.Fstat(fd2, &st); err != nil {
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
}
......
......@@ -183,13 +183,13 @@ func (zr *zipRoot) OnAdd() {
ch := p.GetChild(component)
if ch == nil {
ch = InodeOf(zr).NewPersistentInode(&DefaultOperations{},
fuse.S_IFDIR, FileID{})
NodeAttr{Mode: fuse.S_IFDIR})
p.AddChild(component, ch, true)
}
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)
}
}
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