diff options
-rw-r--r-- | cmd/btrfs-mount/main.go | 6 | ||||
-rw-r--r-- | cmd/btrfs-mount/subvol_fuse.go | 51 | ||||
-rw-r--r-- | pkg/btrfs/io3_fs.go (renamed from cmd/btrfs-mount/subvol.go) | 128 | ||||
-rw-r--r-- | pkg/util/lru.go (renamed from cmd/btrfs-mount/lru.go) | 2 |
4 files changed, 93 insertions, 94 deletions
diff --git a/cmd/btrfs-mount/main.go b/cmd/btrfs-mount/main.go index e059351..64cae30 100644 --- a/cmd/btrfs-mount/main.go +++ b/cmd/btrfs-mount/main.go @@ -71,10 +71,12 @@ func Main(ctx context.Context, mountpoint string, imgfilenames ...string) (err e grp.Go("main", func(ctx context.Context) error { defer atomic.StoreUint32(&mounted, 0) rootSubvol := &Subvolume{ - FS: fs, + Subvolume: btrfs.Subvolume{ + FS: fs, + TreeID: btrfs.FS_TREE_OBJECTID, + }, DeviceName: tryAbs(imgfilenames[0]), Mountpoint: mountpoint, - TreeID: btrfs.FS_TREE_OBJECTID, } return rootSubvol.Run(ctx) }) diff --git a/cmd/btrfs-mount/subvol_fuse.go b/cmd/btrfs-mount/subvol_fuse.go index 6f3f267..1163e9f 100644 --- a/cmd/btrfs-mount/subvol_fuse.go +++ b/cmd/btrfs-mount/subvol_fuse.go @@ -6,6 +6,9 @@ import ( "sync/atomic" "syscall" + "github.com/datawire/dlib/dcontext" + "github.com/datawire/dlib/dlog" + "github.com/jacobsa/fuse" "github.com/jacobsa/fuse/fuseops" "github.com/jacobsa/fuse/fuseutil" @@ -15,21 +18,45 @@ import ( ) type dirState struct { - Dir *dir + Dir *btrfs.Dir } type fileState struct { - File *file + File *btrfs.File } -type subvolumeFUSE struct { +type Subvolume struct { + btrfs.Subvolume + DeviceName string + Mountpoint string + fuseutil.NotImplementedFileSystem lastHandle uint64 dirHandles util.SyncMap[fuseops.HandleID, *dirState] fileHandles util.SyncMap[fuseops.HandleID, *fileState] } -func (sv *subvolumeFUSE) newHandle() fuseops.HandleID { +func (sv *Subvolume) Run(ctx context.Context) error { + mount, err := fuse.Mount( + sv.Mountpoint, + fuseutil.NewFileSystemServer(sv), + &fuse.MountConfig{ + OpContext: ctx, + ErrorLogger: dlog.StdLogger(ctx, dlog.LogLevelError), + DebugLogger: dlog.StdLogger(ctx, dlog.LogLevelDebug), + + FSName: sv.DeviceName, + Subtype: "btrfs", + + ReadOnly: true, + }) + if err != nil { + return err + } + return mount.Join(dcontext.HardContext(ctx)) +} + +func (sv *Subvolume) newHandle() fuseops.HandleID { return fuseops.HandleID(atomic.AddUint64(&sv.lastHandle, 1)) } @@ -73,14 +100,14 @@ func (sv *Subvolume) StatFS(_ context.Context, op *fuseops.StatFSOp) error { func (sv *Subvolume) LookUpInode(_ context.Context, op *fuseops.LookUpInodeOp) error { if op.Parent == fuseops.RootInodeID { - parent, err := sv.getRootInode() + parent, err := sv.GetRootInode() if err != nil { return err } op.Parent = fuseops.InodeID(parent) } - dir, err := sv.loadDir(btrfs.ObjID(op.Parent)) + dir, err := sv.LoadDir(btrfs.ObjID(op.Parent)) if err != nil { return err } @@ -91,7 +118,7 @@ func (sv *Subvolume) LookUpInode(_ context.Context, op *fuseops.LookUpInodeOp) e if entry.Location.ItemType != btrfsitem.INODE_ITEM_KEY { return fmt.Errorf("child %q is not an inode: %w", op.Name, syscall.ENOSYS) } - bareInode, err := sv.loadBareInode(entry.Location.ObjectID) + bareInode, err := sv.LoadBareInode(entry.Location.ObjectID) if err != nil { return err } @@ -105,14 +132,14 @@ func (sv *Subvolume) LookUpInode(_ context.Context, op *fuseops.LookUpInodeOp) e func (sv *Subvolume) GetInodeAttributes(_ context.Context, op *fuseops.GetInodeAttributesOp) error { if op.Inode == fuseops.RootInodeID { - inode, err := sv.getRootInode() + inode, err := sv.GetRootInode() if err != nil { return err } op.Inode = fuseops.InodeID(inode) } - bareInode, err := sv.loadBareInode(btrfs.ObjID(op.Inode)) + bareInode, err := sv.LoadBareInode(btrfs.ObjID(op.Inode)) if err != nil { return err } @@ -123,14 +150,14 @@ func (sv *Subvolume) GetInodeAttributes(_ context.Context, op *fuseops.GetInodeA func (sv *Subvolume) OpenDir(_ context.Context, op *fuseops.OpenDirOp) error { if op.Inode == fuseops.RootInodeID { - inode, err := sv.getRootInode() + inode, err := sv.GetRootInode() if err != nil { return err } op.Inode = fuseops.InodeID(inode) } - dir, err := sv.loadDir(btrfs.ObjID(op.Inode)) + dir, err := sv.LoadDir(btrfs.ObjID(op.Inode)) if err != nil { return err } @@ -184,7 +211,7 @@ func (sv *Subvolume) ReleaseDirHandle(_ context.Context, op *fuseops.ReleaseDirH } func (sv *Subvolume) OpenFile(_ context.Context, op *fuseops.OpenFileOp) error { - file, err := sv.loadFile(btrfs.ObjID(op.Inode)) + file, err := sv.LoadFile(btrfs.ObjID(op.Inode)) if err != nil { return err } diff --git a/cmd/btrfs-mount/subvol.go b/pkg/btrfs/io3_fs.go index 1d5e9db..a418b05 100644 --- a/cmd/btrfs-mount/subvol.go +++ b/pkg/btrfs/io3_fs.go @@ -1,89 +1,59 @@ -package main +package btrfs import ( - "context" "fmt" "io" "reflect" "sort" "sync" - "github.com/datawire/dlib/dcontext" "github.com/datawire/dlib/derror" - "github.com/datawire/dlib/dlog" - "github.com/jacobsa/fuse" - "github.com/jacobsa/fuse/fuseutil" - "lukeshu.com/btrfs-tools/pkg/btrfs" "lukeshu.com/btrfs-tools/pkg/btrfs/btrfsitem" "lukeshu.com/btrfs-tools/pkg/btrfs/btrfsvol" "lukeshu.com/btrfs-tools/pkg/util" ) -type bareInode struct { - Inode btrfs.ObjID +type BareInode struct { + Inode ObjID InodeItem *btrfsitem.Inode Errs derror.MultiError } -type fullInode struct { - bareInode - OtherItems []btrfs.Item +type FullInode struct { + BareInode + OtherItems []Item } -type dir struct { - fullInode +type Dir struct { + FullInode ChildrenByName map[string]btrfsitem.DirEntry ChildrenByIndex map[uint64]btrfsitem.DirEntry } -type fileExtent struct { +type FileExtent struct { OffsetWithinFile int64 btrfsitem.FileExtent } -type file struct { - fullInode - Extents []fileExtent - FS *btrfs.FS +type File struct { + FullInode + Extents []FileExtent + FS *FS } type Subvolume struct { - FS *btrfs.FS - DeviceName string - Mountpoint string - TreeID btrfs.ObjID + FS *FS + TreeID ObjID rootOnce sync.Once rootVal btrfsitem.Root rootErr error - bareInodeCache LRUCache[btrfs.ObjID, *bareInode] - fullInodeCache LRUCache[btrfs.ObjID, *fullInode] - dirCache LRUCache[btrfs.ObjID, *dir] - fileCache LRUCache[btrfs.ObjID, *file] - - subvolumeFUSE -} - -func (sv *Subvolume) Run(ctx context.Context) error { - mount, err := fuse.Mount( - sv.Mountpoint, - fuseutil.NewFileSystemServer(sv), - &fuse.MountConfig{ - OpContext: ctx, - ErrorLogger: dlog.StdLogger(ctx, dlog.LogLevelError), - DebugLogger: dlog.StdLogger(ctx, dlog.LogLevelDebug), - - FSName: sv.DeviceName, - Subtype: "btrfs", - - ReadOnly: true, - }) - if err != nil { - return err - } - return mount.Join(dcontext.HardContext(ctx)) + bareInodeCache util.LRUCache[ObjID, *BareInode] + fullInodeCache util.LRUCache[ObjID, *FullInode] + dirCache util.LRUCache[ObjID, *Dir] + fileCache util.LRUCache[ObjID, *File] } func (sv *Subvolume) init() { @@ -94,7 +64,7 @@ func (sv *Subvolume) init() { return } - root, err := sv.FS.TreeLookup(sb.Data.RootTree, btrfs.Key{ + root, err := sv.FS.TreeLookup(sb.Data.RootTree, Key{ ObjectID: sv.TreeID, ItemType: btrfsitem.ROOT_ITEM_KEY, Offset: 0, @@ -114,27 +84,27 @@ func (sv *Subvolume) init() { }) } -func (sv *Subvolume) getRootInode() (btrfs.ObjID, error) { +func (sv *Subvolume) GetRootInode() (ObjID, error) { sv.init() return sv.rootVal.RootDirID, sv.rootErr } -func (sv *Subvolume) getFSTree() (btrfsvol.LogicalAddr, error) { +func (sv *Subvolume) GetFSTree() (btrfsvol.LogicalAddr, error) { sv.init() return sv.rootVal.ByteNr, sv.rootErr } -func (sv *Subvolume) loadBareInode(inode btrfs.ObjID) (*bareInode, error) { - val := sv.bareInodeCache.GetOrElse(inode, func() (val *bareInode) { - val = &bareInode{ +func (sv *Subvolume) LoadBareInode(inode ObjID) (*BareInode, error) { + val := sv.bareInodeCache.GetOrElse(inode, func() (val *BareInode) { + val = &BareInode{ Inode: inode, } - tree, err := sv.getFSTree() + tree, err := sv.GetFSTree() if err != nil { val.Errs = append(val.Errs, err) return } - item, err := sv.FS.TreeLookup(tree, btrfs.Key{ + item, err := sv.FS.TreeLookup(tree, Key{ ObjectID: inode, ItemType: btrfsitem.INODE_ITEM_KEY, Offset: 0, @@ -159,19 +129,19 @@ func (sv *Subvolume) loadBareInode(inode btrfs.ObjID) (*bareInode, error) { return val, nil } -func (sv *Subvolume) loadFullInode(inode btrfs.ObjID) (*fullInode, error) { - val := sv.fullInodeCache.GetOrElse(inode, func() (val *fullInode) { - val = &fullInode{ - bareInode: bareInode{ +func (sv *Subvolume) LoadFullInode(inode ObjID) (*FullInode, error) { + val := sv.fullInodeCache.GetOrElse(inode, func() (val *FullInode) { + val = &FullInode{ + BareInode: BareInode{ Inode: inode, }, } - tree, err := sv.getFSTree() + tree, err := sv.GetFSTree() if err != nil { val.Errs = append(val.Errs, err) return } - items, err := sv.FS.TreeSearchAll(tree, func(key btrfs.Key) int { + items, err := sv.FS.TreeSearchAll(tree, func(key Key) int { return util.CmpUint(inode, key.ObjectID) }) if err != nil { @@ -203,15 +173,15 @@ func (sv *Subvolume) loadFullInode(inode btrfs.ObjID) (*fullInode, error) { return val, nil } -func (sv *Subvolume) loadDir(inode btrfs.ObjID) (*dir, error) { - val := sv.dirCache.GetOrElse(inode, func() (val *dir) { - val = new(dir) - fullInode, err := sv.loadFullInode(inode) +func (sv *Subvolume) LoadDir(inode ObjID) (*Dir, error) { + val := sv.dirCache.GetOrElse(inode, func() (val *Dir) { + val = new(Dir) + fullInode, err := sv.LoadFullInode(inode) if err != nil { val.Errs = append(val.Errs, err) return } - val.fullInode = *fullInode + val.FullInode = *fullInode val.populate() return }) @@ -221,7 +191,7 @@ func (sv *Subvolume) loadDir(inode btrfs.ObjID) (*dir, error) { return val, nil } -func (ret *dir) populate() { +func (ret *Dir) populate() { ret.ChildrenByName = make(map[string]btrfsitem.DirEntry) ret.ChildrenByIndex = make(map[uint64]btrfsitem.DirEntry) for _, item := range ret.OtherItems { @@ -295,15 +265,15 @@ func (ret *dir) populate() { return } -func (sv *Subvolume) loadFile(inode btrfs.ObjID) (*file, error) { - val := sv.fileCache.GetOrElse(inode, func() (val *file) { - val = new(file) - fullInode, err := sv.loadFullInode(inode) +func (sv *Subvolume) LoadFile(inode ObjID) (*File, error) { + val := sv.fileCache.GetOrElse(inode, func() (val *File) { + val = new(File) + fullInode, err := sv.LoadFullInode(inode) if err != nil { val.Errs = append(val.Errs, err) return } - val.fullInode = *fullInode + val.FullInode = *fullInode val.FS = sv.FS val.populate() return @@ -314,13 +284,13 @@ func (sv *Subvolume) loadFile(inode btrfs.ObjID) (*file, error) { return val, nil } -func (ret *file) populate() { +func (ret *File) populate() { for _, item := range ret.OtherItems { switch item.Head.Key.ItemType { case btrfsitem.INODE_REF_KEY: // TODO case btrfsitem.EXTENT_DATA_KEY: - ret.Extents = append(ret.Extents, fileExtent{ + ret.Extents = append(ret.Extents, FileExtent{ OffsetWithinFile: int64(item.Head.Key.Offset), FileExtent: item.Body.(btrfsitem.FileExtent), }) @@ -364,7 +334,7 @@ func (ret *file) populate() { } } -func (file *file) ReadAt(dat []byte, off int64) (int, error) { +func (file *File) ReadAt(dat []byte, off int64) (int, error) { // These stateles maybe-short-reads each do an O(n) extent // lookup, so reading a file is O(n^2), but we expect n to be // small, so whatev. Turn file.Extents it in to an rbtree if @@ -380,7 +350,7 @@ func (file *file) ReadAt(dat []byte, off int64) (int, error) { return done, nil } -func (file *file) maybeShortReadAt(dat []byte, off int64) (int, error) { +func (file *File) maybeShortReadAt(dat []byte, off int64) (int, error) { for _, extent := range file.Extents { extBeg := extent.OffsetWithinFile if extBeg > off { @@ -409,4 +379,4 @@ func (file *file) maybeShortReadAt(dat []byte, off int64) (int, error) { return 0, fmt.Errorf("read: could not map position %v", off) } -var _ io.ReaderAt = (*file)(nil) +var _ io.ReaderAt = (*File)(nil) diff --git a/cmd/btrfs-mount/lru.go b/pkg/util/lru.go index bf91c5e..2b62e69 100644 --- a/cmd/btrfs-mount/lru.go +++ b/pkg/util/lru.go @@ -1,4 +1,4 @@ -package main +package util import ( "sync" |