Commit 96be8078 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

nodefs: mask out root device number

This makes the inodes in loopback reflect the underlying inodes if
they don't span mounts
parent 18e0e322
...@@ -37,9 +37,9 @@ type FileID struct { ...@@ -37,9 +37,9 @@ type FileID struct {
Gen uint64 Gen uint64
} }
// Zero returns if the FileID is zeroed out // Reserved returns if the FileID is using reserved Inode numbers.
func (i *FileID) Reserved() bool { func (i *FileID) Reserved() bool {
return i.Ino == 0 || i.Ino == 1 || i.Ino == ^uint64(0) return i.Ino == 1 || i.Ino == ^uint64(0)
} }
// Inode is a node in VFS tree. Inodes are one-to-one mapped to // Inode is a node in VFS tree. Inodes are one-to-one mapped to
......
...@@ -18,7 +18,8 @@ import ( ...@@ -18,7 +18,8 @@ import (
type loopbackRoot struct { type loopbackRoot struct {
loopbackNode loopbackNode
root string root string
rootDev uint64
} }
func (n *loopbackRoot) newLoopbackNode() *loopbackNode { func (n *loopbackRoot) newLoopbackNode() *loopbackNode {
...@@ -70,7 +71,7 @@ func (n *loopbackNode) Lookup(ctx context.Context, name string, out *fuse.EntryO ...@@ -70,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, idFromStat(&st)) ch := n.inode().NewInode(node, out.Attr.Mode, n.rootNode.idFromStat(&st))
return ch, fuse.OK return ch, fuse.OK
} }
...@@ -89,7 +90,7 @@ func (n *loopbackNode) Mknod(ctx context.Context, name string, mode, rdev uint32 ...@@ -89,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, idFromStat(&st)) ch := n.inode().NewInode(node, out.Attr.Mode, n.rootNode.idFromStat(&st))
return ch, fuse.OK return ch, fuse.OK
} }
...@@ -109,7 +110,7 @@ func (n *loopbackNode) Mkdir(ctx context.Context, name string, mode uint32, out ...@@ -109,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, idFromStat(&st)) ch := n.inode().NewInode(node, out.Attr.Mode, n.rootNode.idFromStat(&st))
return ch, fuse.OK return ch, fuse.OK
} }
...@@ -146,12 +147,21 @@ func (n *loopbackNode) Rename(ctx context.Context, name string, newParent Operat ...@@ -146,12 +147,21 @@ func (n *loopbackNode) Rename(ctx context.Context, name string, newParent Operat
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
func idFromStat(st *syscall.Stat_t) FileID { func (r *loopbackRoot) idFromStat(st *syscall.Stat_t) FileID {
// 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
// small (typically 16 bit). Finally, we mask out the root
// device number of the root, so a loopback FS that does not
// encompass multiple mounts will reflect the inode numbers of
// the underlying filesystem
swapped := (st.Dev << 32) | (st.Dev >> 32)
swappedRootDev := (r.rootDev << 32) | (r.rootDev >> 32)
return FileID{ return FileID{
Gen: 1, 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: uint64(st.Dev)<<32 ^ st.Ino, Ino: (swapped ^ swappedRootDev) ^ st.Ino,
} }
} }
...@@ -170,7 +180,7 @@ func (n *loopbackNode) Create(ctx context.Context, name string, flags uint32, mo ...@@ -170,7 +180,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), idFromStat(&st)) ch := n.inode().NewInode(node, uint32(st.Mode), n.rootNode.idFromStat(&st))
lf := NewLoopbackFile(fd) lf := NewLoopbackFile(fd)
return ch, lf, 0, fuse.OK return ch, lf, 0, fuse.OK
} }
...@@ -187,7 +197,7 @@ func (n *loopbackNode) Symlink(ctx context.Context, target, name string, out *fu ...@@ -187,7 +197,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), idFromStat(&st)) ch := n.inode().NewInode(node, uint32(st.Mode), n.rootNode.idFromStat(&st))
out.Attr.FromStat(&st) out.Attr.FromStat(&st)
return ch, fuse.OK return ch, fuse.OK
...@@ -207,7 +217,7 @@ func (n *loopbackNode) Link(ctx context.Context, target Operations, name string, ...@@ -207,7 +217,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), idFromStat(&st)) ch := n.inode().NewInode(node, uint32(st.Mode), n.rootNode.idFromStat(&st))
out.Attr.FromStat(&st) out.Attr.FromStat(&st)
return ch, fuse.OK return ch, fuse.OK
...@@ -271,12 +281,19 @@ func (n *loopbackNode) FGetAttr(ctx context.Context, f FileHandle, out *fuse.Att ...@@ -271,12 +281,19 @@ func (n *loopbackNode) FGetAttr(ctx context.Context, f FileHandle, out *fuse.Att
// NewLoopback returns a root node for a loopback file system whose // NewLoopback returns a root node for a loopback file system whose
// root is at the given root. // root is at the given root.
func NewLoopback(root string) DirOperations { func NewLoopback(root string) (DirOperations, error) {
var st syscall.Stat_t
err := syscall.Stat(root, &st)
if err != nil {
return nil, err
}
n := &loopbackRoot{ n := &loopbackRoot{
root: root, root: root,
rootDev: st.Dev,
} }
n.rootNode = n n.rootNode = n
return n return n, nil
} }
func (n *loopbackNode) Access(ctx context.Context, mask uint32) fuse.Status { func (n *loopbackNode) Access(ctx context.Context, mask uint32) fuse.Status {
......
...@@ -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 != idFromStat(&st).Ino { if !InodeOf(n).IsRoot() && InodeOf(n).FileID().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 != idFromStat(&st).Ino { if !InodeOf(newparent).IsRoot() && InodeOf(newparent).FileID().Ino != n.rootNode.idFromStat(&st).Ino {
return fuse.EBUSY return fuse.EBUSY
} }
......
...@@ -68,8 +68,11 @@ func newTestCase(t *testing.T, entryCache bool, attrCache bool) *testCase { ...@@ -68,8 +68,11 @@ func newTestCase(t *testing.T, entryCache bool, attrCache bool) *testCase {
t.Fatal(err) t.Fatal(err)
} }
tc.loopback = NewLoopback(tc.origDir) var err error
_ = time.Second tc.loopback, err = NewLoopback(tc.origDir)
if err != nil {
t.Fatalf("NewLoopback: %v", err)
}
oneSec := time.Second oneSec := time.Second
...@@ -87,7 +90,6 @@ func newTestCase(t *testing.T, entryCache bool, attrCache bool) *testCase { ...@@ -87,7 +90,6 @@ func newTestCase(t *testing.T, entryCache bool, attrCache bool) *testCase {
AttrTimeout: attrDT, AttrTimeout: attrDT,
}) })
var err error
tc.server, err = fuse.NewServer(tc.rawFS, tc.mntDir, tc.server, err = fuse.NewServer(tc.rawFS, tc.mntDir,
&fuse.MountOptions{ &fuse.MountOptions{
Debug: testutil.VerboseTest(), Debug: testutil.VerboseTest(),
......
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