From e1569565240cf6487ebeb5ec4c1386c8ba70f493 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Thu, 2 Mar 2023 22:35:00 -0700 Subject: btrfs: io4_fs.go: Subvolume: Don't have public members; use a constructor --- cmd/btrfs-rec/inspect/mount/mount.go | 35 +++++++++------- cmd/btrfs-rec/inspect_lsfiles.go | 14 +++---- lib/btrfs/io4_fs.go | 80 ++++++++++++++++++++---------------- 3 files changed, 71 insertions(+), 58 deletions(-) diff --git a/cmd/btrfs-rec/inspect/mount/mount.go b/cmd/btrfs-rec/inspect/mount/mount.go index 0e8faf1..4049393 100644 --- a/cmd/btrfs-rec/inspect/mount/mount.go +++ b/cmd/btrfs-rec/inspect/mount/mount.go @@ -28,6 +28,7 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsitem" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsprim" + "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfstree" "git.lukeshu.com/btrfs-progs-ng/lib/btrfsutil" "git.lukeshu.com/btrfs-progs-ng/lib/containers" "git.lukeshu.com/btrfs-progs-ng/lib/maps" @@ -45,14 +46,21 @@ func MountRO(ctx context.Context, fs *btrfs.FS, mountpoint string, noChecksums b deviceName = abs } + sb, err := fs.Superblock() + if err != nil { + return err + } + rootSubvol := &subvolume{ - Subvolume: btrfs.Subvolume{ - FS: btrfsutil.NewOldRebuiltForrest(ctx, fs), - TreeID: btrfsprim.FS_TREE_OBJECTID, - NoChecksums: noChecksums, - }, + Subvolume: btrfs.NewSubvolume( + btrfsutil.NewOldRebuiltForrest(ctx, fs), + btrfsprim.FS_TREE_OBJECTID, + noChecksums, + ), DeviceName: deviceName, Mountpoint: mountpoint, + + sb: sb, } return rootSubvol.Run(ctx) } @@ -107,10 +115,12 @@ type fileState struct { } type subvolume struct { - btrfs.Subvolume + *btrfs.Subvolume DeviceName string Mountpoint string + sb *btrfstree.Superblock + fuseutil.NotImplementedFileSystem lastHandle uint64 dirHandles typedsync.Map[fuseops.HandleID, *dirState] @@ -189,11 +199,8 @@ func (sv *subvolume) LoadDir(inode btrfsprim.ObjID) (val *btrfs.Dir, err error) workerName := fmt.Sprintf("%d-%s", val.Inode, filepath.Base(subMountpoint)) sv.grp.Go(workerName, func(ctx context.Context) error { subSv := &subvolume{ - Subvolume: btrfs.Subvolume{ - FS: sv.FS, - TreeID: entry.Location.ObjectID, - NoChecksums: sv.NoChecksums, - }, + sb: sv.sb, + Subvolume: sv.NewChildSubvolume(entry.Location.ObjectID), DeviceName: sv.DeviceName, Mountpoint: filepath.Join(sv.Mountpoint, subMountpoint[1:]), } @@ -208,11 +215,9 @@ func (sv *subvolume) LoadDir(inode btrfsprim.ObjID) (val *btrfs.Dir, err error) } func (sv *subvolume) StatFS(_ context.Context, op *fuseops.StatFSOp) error { + sb := sv.sb + // See linux.git/fs/btrfs/super.c:btrfs_statfs() - sb, err := sv.FS.Superblock() - if err != nil { - return err - } op.IoSize = sb.SectorSize op.BlockSize = sb.SectorSize diff --git a/cmd/btrfs-rec/inspect_lsfiles.go b/cmd/btrfs-rec/inspect_lsfiles.go index a2b46ab..e9fd057 100644 --- a/cmd/btrfs-rec/inspect_lsfiles.go +++ b/cmd/btrfs-rec/inspect_lsfiles.go @@ -45,10 +45,11 @@ func init() { }() ctx := cmd.Context() - printSubvol(out, "", true, "/", &btrfs.Subvolume{ - FS: btrfsutil.NewOldRebuiltForrest(ctx, fs), - TreeID: btrfsprim.FS_TREE_OBJECTID, - }) + printSubvol(out, "", true, "/", btrfs.NewSubvolume( + btrfsutil.NewOldRebuiltForrest(ctx, fs), + btrfsprim.FS_TREE_OBJECTID, + false, + )) return nil }), @@ -160,10 +161,7 @@ func printDirEntry(out io.Writer, prefix string, isLast bool, subvol *btrfs.Subv } printDir(out, prefix, isLast, name, dir) case btrfsitem.ROOT_ITEM_KEY: - printSubvol(out, prefix, isLast, name, &btrfs.Subvolume{ - FS: subvol.FS, - TreeID: entry.Location.ObjectID, - }) + printSubvol(out, prefix, isLast, name, subvol.NewChildSubvolume(entry.Location.ObjectID)) default: panic(fmt.Errorf("TODO: I don't know how to handle an FT_DIR with location.ItemType=%v: %q", entry.Location.ItemType, name)) diff --git a/lib/btrfs/io4_fs.go b/lib/btrfs/io4_fs.go index e4511a5..0445441 100644 --- a/lib/btrfs/io4_fs.go +++ b/lib/btrfs/io4_fs.go @@ -10,7 +10,6 @@ import ( "path/filepath" "reflect" "sort" - "sync" "github.com/datawire/dlib/derror" @@ -63,15 +62,13 @@ type File struct { } type Subvolume struct { - FS interface { + fs interface { btrfstree.TreeOperator Superblock() (*btrfstree.Superblock, error) diskio.ReaderAt[btrfsvol.LogicalAddr] } TreeID btrfsprim.ObjID - NoChecksums bool - - initOnce sync.Once + noChecksums bool rootVal btrfsitem.Root rootErr error @@ -82,41 +79,57 @@ type Subvolume struct { fileCache containers.ARCache[btrfsprim.ObjID, *File] } -func (sv *Subvolume) init() { - sv.initOnce.Do(func() { - root, err := sv.FS.TreeSearch(btrfsprim.ROOT_TREE_OBJECTID, btrfstree.SearchRootItem(sv.TreeID)) - if err != nil { - sv.rootErr = err - } else { - switch rootBody := root.Body.(type) { - case *btrfsitem.Root: - sv.rootVal = rootBody.Clone() - case *btrfsitem.Error: - sv.rootErr = fmt.Errorf("FS_TREE ROOT_ITEM has malformed body: %w", rootBody.Err) - default: - panic(fmt.Errorf("should not happen: ROOT_ITEM has unexpected item type: %T", rootBody)) - } +func NewSubvolume( + fs interface { + btrfstree.TreeOperator + Superblock() (*btrfstree.Superblock, error) + diskio.ReaderAt[btrfsvol.LogicalAddr] + }, + treeID btrfsprim.ObjID, + noChecksums bool, +) *Subvolume { + sv := &Subvolume{ + fs: fs, + TreeID: treeID, + noChecksums: noChecksums, + } + + root, err := sv.fs.TreeSearch(btrfsprim.ROOT_TREE_OBJECTID, btrfstree.SearchRootItem(sv.TreeID)) + if err != nil { + sv.rootErr = err + } else { + switch rootBody := root.Body.(type) { + case *btrfsitem.Root: + sv.rootVal = rootBody.Clone() + case *btrfsitem.Error: + sv.rootErr = fmt.Errorf("FS_TREE ROOT_ITEM has malformed body: %w", rootBody.Err) + default: + panic(fmt.Errorf("should not happen: ROOT_ITEM has unexpected item type: %T", rootBody)) } + } - sv.bareInodeCache.MaxLen = textui.Tunable(128) - sv.fullInodeCache.MaxLen = textui.Tunable(128) - sv.dirCache.MaxLen = textui.Tunable(128) - sv.fileCache.MaxLen = textui.Tunable(128) - }) + sv.bareInodeCache.MaxLen = textui.Tunable(128) + sv.fullInodeCache.MaxLen = textui.Tunable(128) + sv.dirCache.MaxLen = textui.Tunable(128) + sv.fileCache.MaxLen = textui.Tunable(128) + + return sv +} + +func (sv *Subvolume) NewChildSubvolume(childID btrfsprim.ObjID) *Subvolume { + return NewSubvolume(sv.fs, childID, sv.noChecksums) } func (sv *Subvolume) GetRootInode() (btrfsprim.ObjID, error) { - sv.init() return sv.rootVal.RootDirID, sv.rootErr } func (sv *Subvolume) LoadBareInode(inode btrfsprim.ObjID) (*BareInode, error) { - sv.init() val := containers.LoadOrElse[btrfsprim.ObjID, *BareInode](&sv.bareInodeCache, inode, func(inode btrfsprim.ObjID) (val *BareInode) { val = &BareInode{ Inode: inode, } - item, err := sv.FS.TreeLookup(sv.TreeID, btrfsprim.Key{ + item, err := sv.fs.TreeLookup(sv.TreeID, btrfsprim.Key{ ObjectID: inode, ItemType: btrfsitem.INODE_ITEM_KEY, Offset: 0, @@ -145,7 +158,6 @@ func (sv *Subvolume) LoadBareInode(inode btrfsprim.ObjID) (*BareInode, error) { } func (sv *Subvolume) LoadFullInode(inode btrfsprim.ObjID) (*FullInode, error) { - sv.init() val := containers.LoadOrElse[btrfsprim.ObjID, *FullInode](&sv.fullInodeCache, inode, func(indoe btrfsprim.ObjID) (val *FullInode) { val = &FullInode{ BareInode: BareInode{ @@ -153,7 +165,7 @@ func (sv *Subvolume) LoadFullInode(inode btrfsprim.ObjID) (*FullInode, error) { }, XAttrs: make(map[string]string), } - items, err := sv.FS.TreeSearchAll(sv.TreeID, btrfstree.SearchObject(inode)) + items, err := sv.fs.TreeSearchAll(sv.TreeID, btrfstree.SearchObject(inode)) if err != nil { val.Errs = append(val.Errs, err) if len(items) == 0 { @@ -200,7 +212,6 @@ func (sv *Subvolume) LoadFullInode(inode btrfsprim.ObjID) (*FullInode, error) { } func (sv *Subvolume) LoadDir(inode btrfsprim.ObjID) (*Dir, error) { - sv.init() val := containers.LoadOrElse[btrfsprim.ObjID, *Dir](&sv.dirCache, inode, func(inode btrfsprim.ObjID) (val *Dir) { val = new(Dir) fullInode, err := sv.LoadFullInode(inode) @@ -337,7 +348,6 @@ func (dir *Dir) AbsPath() (string, error) { } func (sv *Subvolume) LoadFile(inode btrfsprim.ObjID) (*File, error) { - sv.init() val := containers.LoadOrElse[btrfsprim.ObjID, *File](&sv.fileCache, inode, func(inode btrfsprim.ObjID) (val *File) { val = new(File) fullInode, err := sv.LoadFullInode(inode) @@ -449,7 +459,7 @@ func (file *File) maybeShortReadAt(dat []byte, off int64) (int, error) { case btrfsitem.FILE_EXTENT_INLINE: return copy(dat, extent.BodyInline[offsetWithinExt:offsetWithinExt+readSize]), nil case btrfsitem.FILE_EXTENT_REG, btrfsitem.FILE_EXTENT_PREALLOC: - sb, err := file.SV.FS.Superblock() + sb, err := file.SV.fs.Superblock() if err != nil { return 0, err } @@ -458,7 +468,7 @@ func (file *File) maybeShortReadAt(dat []byte, off int64) (int, error) { Add(btrfsvol.AddrDelta(offsetWithinExt)) var block [btrfssum.BlockSize]byte blockBeg := (beg / btrfssum.BlockSize) * btrfssum.BlockSize - n, err := file.SV.FS.ReadAt(block[:], blockBeg) + n, err := file.SV.fs.ReadAt(block[:], blockBeg) if n > int(beg-blockBeg) { n = copy(dat[:readSize], block[beg-blockBeg:]) } else { @@ -467,8 +477,8 @@ func (file *File) maybeShortReadAt(dat []byte, off int64) (int, error) { if err != nil { return 0, err } - if !file.SV.NoChecksums { - sumRun, err := LookupCSum(file.SV.FS, sb.ChecksumType, blockBeg) + if !file.SV.noChecksums { + sumRun, err := LookupCSum(file.SV.fs, sb.ChecksumType, blockBeg) if err != nil { return 0, fmt.Errorf("checksum@%v: %w", blockBeg, err) } -- cgit v1.1-4-g5e80