From 7f1391d48d63a5f8780dddc41817eaa9df3ce880 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 29 Mar 2023 17:11:27 -0600 Subject: tree-wide: Funnel all btrfstree.ReadNode[btrfsvol.LogicalAddr]() calls through btrfstree.NodeSource.ReadNode() --- cmd/btrfs-rec/inspect/rebuildtrees/scan.go | 4 ++-- cmd/btrfs-rec/inspect_lstrees.go | 3 +-- lib/btrfs/btrfstree/btree.go | 3 ++- lib/btrfs/btrfstree/btree_forrest.go | 5 ++++- lib/btrfs/btrfstree/btree_tree.go | 12 ++++++++---- lib/btrfs/btrfstree/readnode.go | 24 +++++++++++------------- lib/btrfs/io3_btree.go | 10 ++++++++-- lib/btrfsutil/graph.go | 5 ++--- lib/btrfsutil/old_rebuilt_forrest.go | 7 +------ lib/btrfsutil/rebuilt_forrest.go | 5 ++--- lib/btrfsutil/rebuilt_readitem.go | 2 +- 11 files changed, 42 insertions(+), 38 deletions(-) diff --git a/cmd/btrfs-rec/inspect/rebuildtrees/scan.go b/cmd/btrfs-rec/inspect/rebuildtrees/scan.go index 3339270..86d3741 100644 --- a/cmd/btrfs-rec/inspect/rebuildtrees/scan.go +++ b/cmd/btrfs-rec/inspect/rebuildtrees/scan.go @@ -71,7 +71,7 @@ func ScanDevices(ctx context.Context, fs *btrfs.FS, nodeList []btrfsvol.LogicalA if err := ctx.Err(); err != nil { return ScanDevicesResult{}, err } - node, err := btrfstree.ReadNode[btrfsvol.LogicalAddr](fs, *sb, laddr, btrfstree.NodeExpectations{ + node, err := fs.ReadNode(ctx, laddr, btrfstree.NodeExpectations{ LAddr: containers.OptionalValue(laddr), }) if err != nil { @@ -93,7 +93,7 @@ func ScanDevices(ctx context.Context, fs *btrfs.FS, nodeList []btrfsvol.LogicalA dlog.Info(ctx, "... done reading node data") ctx = dlog.WithField(ctx, "btrfs.inspect.rebuild-trees.read.substep", "check") - if err := ret.Graph.FinalCheck(ctx, fs, *sb); err != nil { + if err := ret.Graph.FinalCheck(ctx, fs); err != nil { return ScanDevicesResult{}, err } diff --git a/cmd/btrfs-rec/inspect_lstrees.go b/cmd/btrfs-rec/inspect_lstrees.go index 1449a21..9639a2e 100644 --- a/cmd/btrfs-rec/inspect_lstrees.go +++ b/cmd/btrfs-rec/inspect_lstrees.go @@ -101,13 +101,12 @@ func init() { treeErrCnt = 0 treeItemCnt = make(map[btrfsitem.Type]int) textui.Fprintf(os.Stdout, "lost+found\n") - sb, _ := fs.Superblock() for _, laddr := range nodeList { if visitedNodes.Has(laddr) { continue } visitedNodes.Insert(laddr) - node, err := btrfstree.ReadNode[btrfsvol.LogicalAddr](fs, *sb, laddr, btrfstree.NodeExpectations{ + node, err := fs.ReadNode(ctx, laddr, btrfstree.NodeExpectations{ LAddr: containers.OptionalValue(laddr), }) if err != nil { diff --git a/lib/btrfs/btrfstree/btree.go b/lib/btrfs/btrfstree/btree.go index bc1bac2..dde485a 100644 --- a/lib/btrfs/btrfstree/btree.go +++ b/lib/btrfs/btrfstree/btree.go @@ -11,6 +11,7 @@ import ( "fmt" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsprim" + "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" ) type TreeSearcher interface { @@ -96,5 +97,5 @@ func (e *TreeError) Error() string { type NodeSource interface { Superblock() (*Superblock, error) - ReadNode(Path) (*Node, error) + ReadNode(ctx context.Context, addr btrfsvol.LogicalAddr, exp NodeExpectations) (*Node, error) } diff --git a/lib/btrfs/btrfstree/btree_forrest.go b/lib/btrfs/btrfstree/btree_forrest.go index b017888..b04bfc0 100644 --- a/lib/btrfs/btrfstree/btree_forrest.go +++ b/lib/btrfs/btrfstree/btree_forrest.go @@ -83,7 +83,10 @@ func LookupTreeRoot(_ context.Context, fs TreeOperator, sb Superblock, treeID bt } type TreeOperatorImpl struct { - NodeSource NodeSource + NodeSource interface { + NodeSource + NodeFile + } } func (fs TreeOperatorImpl) RawTree(ctx context.Context, treeID btrfsprim.ObjID) (*RawTree, error) { diff --git a/lib/btrfs/btrfstree/btree_tree.go b/lib/btrfs/btrfstree/btree_tree.go index 89b4c52..a6311f9 100644 --- a/lib/btrfs/btrfstree/btree_tree.go +++ b/lib/btrfs/btrfstree/btree_tree.go @@ -22,6 +22,9 @@ type RawTree struct { } func (tree *RawTree) TreeWalk(ctx context.Context, cbs TreeWalkHandler) { + if tree.RootNode == 0 { + return + } path := Path{{ FromTree: tree.ID, FromItemSlot: -1, @@ -37,12 +40,13 @@ func (tree *RawTree) walk(ctx context.Context, path Path, cbs TreeWalkHandler) { if ctx.Err() != nil { return } - if path.Node(-1).ToNodeAddr == 0 { - return - } // 001 - node, err := tree.Forrest.NodeSource.ReadNode(path) + nodeAddr, nodeExp, ok := path.NodeExpectations(tree.Forrest.NodeSource) + if !ok { + return + } + node, err := tree.Forrest.NodeSource.ReadNode(ctx, nodeAddr, nodeExp) defer node.Free() if ctx.Err() != nil { return diff --git a/lib/btrfs/btrfstree/readnode.go b/lib/btrfs/btrfstree/readnode.go index ac82c62..a4ccf10 100644 --- a/lib/btrfs/btrfstree/readnode.go +++ b/lib/btrfs/btrfstree/readnode.go @@ -14,8 +14,7 @@ import ( ) type NodeFile interface { - diskio.File[btrfsvol.LogicalAddr] - Superblock() (*Superblock, error) + diskio.ReaderAt[btrfsvol.LogicalAddr] // ParentTree, given a tree ID, returns that tree's parent // tree, if it has one. @@ -29,15 +28,14 @@ type NodeFile interface { ParentTree(btrfsprim.ObjID) (btrfsprim.ObjID, btrfsprim.Generation, bool) } -// FSReadNode is a utility function to help with implementing the -// 'NodeSource' interface. -func FSReadNode( - fs NodeFile, - path Path, -) (*Node, error) { - sb, err := fs.Superblock() - if err != nil { - return nil, fmt.Errorf("btrfs.FS.ReadNode: %w", err) +// NodeExpectations returns the address to read and the expectations +// to have when reading the node pointed to by this Path. +// +// `ok` is false if the path is empty or if this Path points to an +// item rather than a node. +func (path Path) NodeExpectations(fs NodeFile) (_ btrfsvol.LogicalAddr, _ NodeExpectations, ok bool) { + if path.Node(-1).ToNodeAddr == 0 && path.Node(-1).ToNodeGeneration == 0 && path.Node(-1).ToNodeLevel == 0 { + return 0, NodeExpectations{}, false } checkOwner := func(owner btrfsprim.ObjID, gen btrfsprim.Generation) error { @@ -70,12 +68,12 @@ func FSReadNode( } } - return ReadNode[btrfsvol.LogicalAddr](fs, *sb, path.Node(-1).ToNodeAddr, NodeExpectations{ + return path.Node(-1).ToNodeAddr, NodeExpectations{ LAddr: containers.OptionalValue(path.Node(-1).ToNodeAddr), Level: containers.OptionalValue(path.Node(-1).ToNodeLevel), Generation: containers.OptionalValue(path.Node(-1).ToNodeGeneration), Owner: checkOwner, MinItem: containers.OptionalValue(path.Node(-1).ToKey), MaxItem: containers.OptionalValue(path.Node(-1).ToMaxKey), - }) + }, true } diff --git a/lib/btrfs/io3_btree.go b/lib/btrfs/io3_btree.go index f1436fb..bb68d7d 100644 --- a/lib/btrfs/io3_btree.go +++ b/lib/btrfs/io3_btree.go @@ -6,10 +6,12 @@ package btrfs import ( "context" + "fmt" "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/btrfs/btrfsvol" ) // This file is ordered from low-level to high-level. @@ -79,8 +81,12 @@ var _ btrfstree.NodeFile = (*FS)(nil) // btrfstree.NodeSource //////////////////////////////////////////////////////// // ReadNode implements btrfstree.NodeSource. -func (fs *FS) ReadNode(path btrfstree.Path) (*btrfstree.Node, error) { - return btrfstree.FSReadNode(fs, path) +func (fs *FS) ReadNode(_ context.Context, addr btrfsvol.LogicalAddr, exp btrfstree.NodeExpectations) (*btrfstree.Node, error) { + sb, err := fs.Superblock() + if err != nil { + return nil, fmt.Errorf("btrfs.FS.ReadNode: %w", err) + } + return btrfstree.ReadNode[btrfsvol.LogicalAddr](fs, *sb, addr, exp) } var _ btrfstree.NodeSource = (*FS)(nil) diff --git a/lib/btrfsutil/graph.go b/lib/btrfsutil/graph.go index 39e1cf2..4148f89 100644 --- a/lib/btrfsutil/graph.go +++ b/lib/btrfsutil/graph.go @@ -17,7 +17,6 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfstree" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" "git.lukeshu.com/btrfs-progs-ng/lib/containers" - "git.lukeshu.com/btrfs-progs-ng/lib/diskio" "git.lukeshu.com/btrfs-progs-ng/lib/maps" "git.lukeshu.com/btrfs-progs-ng/lib/slices" "git.lukeshu.com/btrfs-progs-ng/lib/textui" @@ -199,7 +198,7 @@ func (g Graph) InsertNode(node *btrfstree.Node) { } } -func (g Graph) FinalCheck(ctx context.Context, fs diskio.File[btrfsvol.LogicalAddr], sb btrfstree.Superblock) error { +func (g Graph) FinalCheck(ctx context.Context, fs btrfstree.NodeSource) error { var stats textui.Portion[int] dlog.Info(ctx, "Checking keypointers for dead-ends...") @@ -208,7 +207,7 @@ func (g Graph) FinalCheck(ctx context.Context, fs diskio.File[btrfsvol.LogicalAd progressWriter.Set(stats) for laddr := range g.EdgesTo { if _, ok := g.Nodes[laddr]; !ok { - _, err := btrfstree.ReadNode[btrfsvol.LogicalAddr](fs, sb, laddr, btrfstree.NodeExpectations{ + _, err := fs.ReadNode(ctx, laddr, btrfstree.NodeExpectations{ LAddr: containers.OptionalValue(laddr), }) if err == nil { diff --git a/lib/btrfsutil/old_rebuilt_forrest.go b/lib/btrfsutil/old_rebuilt_forrest.go index 5b99892..24faf79 100644 --- a/lib/btrfsutil/old_rebuilt_forrest.go +++ b/lib/btrfsutil/old_rebuilt_forrest.go @@ -231,12 +231,7 @@ func (tree oldRebuiltTree) addErrs(fn func(btrfsprim.Key, uint32) int, err error } func (bt *OldRebuiltForrest) readNode(nodeInfo nodeInfo) *btrfstree.Node { - sb, err := bt.inner.Superblock() - if err != nil { - panic(fmt.Errorf("should not happen: i/o error: %w", err)) - } - - node, err := btrfstree.ReadNode[btrfsvol.LogicalAddr](bt.inner, *sb, nodeInfo.LAddr, btrfstree.NodeExpectations{ + node, err := bt.inner.ReadNode(bt.ctx, nodeInfo.LAddr, btrfstree.NodeExpectations{ LAddr: containers.OptionalValue(nodeInfo.LAddr), Level: containers.OptionalValue(nodeInfo.Level), Generation: containers.OptionalValue(nodeInfo.Generation), diff --git a/lib/btrfsutil/rebuilt_forrest.go b/lib/btrfsutil/rebuilt_forrest.go index 811e1ac..4f7a24b 100644 --- a/lib/btrfsutil/rebuilt_forrest.go +++ b/lib/btrfsutil/rebuilt_forrest.go @@ -15,7 +15,6 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfstree" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" "git.lukeshu.com/btrfs-progs-ng/lib/containers" - "git.lukeshu.com/btrfs-progs-ng/lib/diskio" "git.lukeshu.com/btrfs-progs-ng/lib/slices" "git.lukeshu.com/btrfs-progs-ng/lib/textui" ) @@ -130,7 +129,7 @@ func (cb noopRebuiltForrestCallbacks) LookupUUID(ctx context.Context, uuid btrfs // NewRebuiltForrest(). type RebuiltForrest struct { // static - file diskio.File[btrfsvol.LogicalAddr] + file btrfstree.NodeSource sb btrfstree.Superblock graph Graph cb RebuiltForrestCallbacks @@ -148,7 +147,7 @@ type RebuiltForrest struct { // NewRebuiltForrest returns a new RebuiltForrest instance. The // RebuiltForrestCallbacks may be nil. -func NewRebuiltForrest(file diskio.File[btrfsvol.LogicalAddr], sb btrfstree.Superblock, graph Graph, cb RebuiltForrestCallbacks) *RebuiltForrest { +func NewRebuiltForrest(file btrfstree.NodeSource, sb btrfstree.Superblock, graph Graph, cb RebuiltForrestCallbacks) *RebuiltForrest { ret := &RebuiltForrest{ file: file, sb: sb, diff --git a/lib/btrfsutil/rebuilt_readitem.go b/lib/btrfsutil/rebuilt_readitem.go index d3a2253..2520593 100644 --- a/lib/btrfsutil/rebuilt_readitem.go +++ b/lib/btrfsutil/rebuilt_readitem.go @@ -34,7 +34,7 @@ func (ts *RebuiltForrest) readNode(ctx context.Context, laddr btrfsvol.LogicalAd panic(fmt.Errorf("should not happen: node@%v is not mentioned in the in-memory graph", laddr)) } - node, err := btrfstree.ReadNode[btrfsvol.LogicalAddr](ts.file, ts.sb, laddr, btrfstree.NodeExpectations{ + node, err := ts.file.ReadNode(ctx, laddr, btrfstree.NodeExpectations{ LAddr: containers.OptionalValue(laddr), Level: containers.OptionalValue(graphInfo.Level), Generation: containers.OptionalValue(graphInfo.Generation), -- cgit v1.2.3-2-g168b