From 1bc243ca607c22e232017b0f1b4badcde288a9b3 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Thu, 16 Mar 2023 09:17:35 -0600 Subject: btrfstree: Have ReadNode return a *Node rather than a *diskio.Ref[Addr, Node] ... and take a ReaderAt instead of a diskio.File. --- cmd/btrfs-rec/inspect/dumptrees/print_tree.go | 9 +- cmd/btrfs-rec/inspect/rebuildmappings/scan.go | 25 ++-- cmd/btrfs-rec/inspect/rebuildtrees/scan.go | 10 +- cmd/btrfs-rec/inspect_lstrees.go | 7 +- lib/btrfs/btrfstree/btree.go | 10 +- lib/btrfs/btrfstree/btree_tree.go | 184 +++++++++++++------------- lib/btrfs/btrfstree/readnode.go | 4 +- lib/btrfs/btrfstree/types_node.go | 80 +++++------ lib/btrfs/io3_btree.go | 4 +- lib/btrfs/io4_fs.go | 3 +- lib/btrfsutil/graph.go | 32 ++--- lib/btrfsutil/listnodes.go | 5 +- lib/btrfsutil/old_rebuilt_forrest.go | 37 +++--- lib/btrfsutil/rebuilt_readitem.go | 28 ++-- lib/btrfsutil/scan.go | 9 +- lib/btrfsutil/skinny_paths.go | 24 ++-- lib/diskio/file_iface.go | 8 +- 17 files changed, 228 insertions(+), 251 deletions(-) diff --git a/cmd/btrfs-rec/inspect/dumptrees/print_tree.go b/cmd/btrfs-rec/inspect/dumptrees/print_tree.go index a8c2adf..9572f3a 100644 --- a/cmd/btrfs-rec/inspect/dumptrees/print_tree.go +++ b/cmd/btrfs-rec/inspect/dumptrees/print_tree.go @@ -19,7 +19,6 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfssum" "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/diskio" "git.lukeshu.com/btrfs-progs-ng/lib/slices" "git.lukeshu.com/btrfs-progs-ng/lib/textui" ) @@ -100,9 +99,9 @@ var nodeHeaderSize = binstruct.StaticSize(btrfstree.NodeHeader{}) func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfsprim.ObjID) { var itemOffset uint32 handlers := btrfstree.TreeWalkHandler{ - Node: func(path btrfstree.TreePath, nodeRef *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node]) error { - printHeaderInfo(out, nodeRef.Data) - itemOffset = nodeRef.Data.Size - uint32(nodeHeaderSize) + Node: func(path btrfstree.TreePath, node *btrfstree.Node) error { + printHeaderInfo(out, node) + itemOffset = node.Size - uint32(nodeHeaderSize) return nil }, PreKeyPointer: func(path btrfstree.TreePath, item btrfstree.KeyPointer) error { @@ -375,7 +374,7 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri } // printHeaderInfo mimics btrfs-progs kernel-shared/print-tree.c:print_header_info() -func printHeaderInfo(out io.Writer, node btrfstree.Node) { +func printHeaderInfo(out io.Writer, node *btrfstree.Node) { var typename string if node.Head.Level > 0 { // interior node typename = "node" diff --git a/cmd/btrfs-rec/inspect/rebuildmappings/scan.go b/cmd/btrfs-rec/inspect/rebuildmappings/scan.go index b88f01c..e23314e 100644 --- a/cmd/btrfs-rec/inspect/rebuildmappings/scan.go +++ b/cmd/btrfs-rec/inspect/rebuildmappings/scan.go @@ -19,7 +19,6 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" "git.lukeshu.com/btrfs-progs-ng/lib/btrfsutil" "git.lukeshu.com/btrfs-progs-ng/lib/containers" - "git.lukeshu.com/btrfs-progs-ng/lib/diskio" "git.lukeshu.com/btrfs-progs-ng/lib/textui" ) @@ -121,22 +120,22 @@ func (scanner *deviceScanner) ScanSector(_ context.Context, dev *btrfs.Device, p return nil } -func (scanner *deviceScanner) ScanNode(ctx context.Context, nodeRef *diskio.Ref[btrfsvol.PhysicalAddr, btrfstree.Node]) error { - scanner.result.FoundNodes[nodeRef.Data.Head.Addr] = append(scanner.result.FoundNodes[nodeRef.Data.Head.Addr], nodeRef.Addr) - for i, item := range nodeRef.Data.BodyLeaf { +func (scanner *deviceScanner) ScanNode(ctx context.Context, addr btrfsvol.PhysicalAddr, node *btrfstree.Node) error { + scanner.result.FoundNodes[node.Head.Addr] = append(scanner.result.FoundNodes[node.Head.Addr], addr) + for i, item := range node.BodyLeaf { switch item.Key.ItemType { case btrfsitem.CHUNK_ITEM_KEY: switch itemBody := item.Body.(type) { case *btrfsitem.Chunk: dlog.Tracef(ctx, "node@%v: item %v: found chunk", - nodeRef.Addr, i) + addr, i) scanner.result.FoundChunks = append(scanner.result.FoundChunks, btrfstree.SysChunk{ Key: item.Key, Chunk: *itemBody, }) case *btrfsitem.Error: dlog.Errorf(ctx, "node@%v: item %v: error: malformed CHUNK_ITEM: %v", - nodeRef.Addr, i, itemBody.Err) + addr, i, itemBody.Err) default: panic(fmt.Errorf("should not happen: CHUNK_ITEM has unexpected item type: %T", itemBody)) } @@ -144,14 +143,14 @@ func (scanner *deviceScanner) ScanNode(ctx context.Context, nodeRef *diskio.Ref[ switch itemBody := item.Body.(type) { case *btrfsitem.BlockGroup: dlog.Tracef(ctx, "node@%v: item %v: found block group", - nodeRef.Addr, i) + addr, i) scanner.result.FoundBlockGroups = append(scanner.result.FoundBlockGroups, SysBlockGroup{ Key: item.Key, BG: *itemBody, }) case *btrfsitem.Error: dlog.Errorf(ctx, "node@%v: item %v: error: malformed BLOCK_GROUP_ITEM: %v", - nodeRef.Addr, i, itemBody.Err) + addr, i, itemBody.Err) default: panic(fmt.Errorf("should not happen: BLOCK_GROUP_ITEM has unexpected item type: %T", itemBody)) } @@ -159,14 +158,14 @@ func (scanner *deviceScanner) ScanNode(ctx context.Context, nodeRef *diskio.Ref[ switch itemBody := item.Body.(type) { case *btrfsitem.DevExtent: dlog.Tracef(ctx, "node@%v: item %v: found dev extent", - nodeRef.Addr, i) + addr, i) scanner.result.FoundDevExtents = append(scanner.result.FoundDevExtents, SysDevExtent{ Key: item.Key, DevExt: *itemBody, }) case *btrfsitem.Error: dlog.Errorf(ctx, "node@%v: item %v: error: malformed DEV_EXTENT: %v", - nodeRef.Addr, i, itemBody.Err) + addr, i, itemBody.Err) default: panic(fmt.Errorf("should not happen: DEV_EXTENT has unexpected item type: %T", itemBody)) } @@ -174,14 +173,14 @@ func (scanner *deviceScanner) ScanNode(ctx context.Context, nodeRef *diskio.Ref[ switch itemBody := item.Body.(type) { case *btrfsitem.ExtentCSum: dlog.Tracef(ctx, "node@%v: item %v: found csums", - nodeRef.Addr, i) + addr, i) scanner.result.FoundExtentCSums = append(scanner.result.FoundExtentCSums, SysExtentCSum{ - Generation: nodeRef.Data.Head.Generation, + Generation: node.Head.Generation, Sums: *itemBody, }) case *btrfsitem.Error: dlog.Errorf(ctx, "node@%v: item %v: error: malformed is EXTENT_CSUM: %v", - nodeRef.Addr, i, itemBody.Err) + addr, i, itemBody.Err) default: panic(fmt.Errorf("should not happen: EXTENT_CSUM has unexpected item type: %T", itemBody)) } diff --git a/cmd/btrfs-rec/inspect/rebuildtrees/scan.go b/cmd/btrfs-rec/inspect/rebuildtrees/scan.go index ba56c5b..4bc09ad 100644 --- a/cmd/btrfs-rec/inspect/rebuildtrees/scan.go +++ b/cmd/btrfs-rec/inspect/rebuildtrees/scan.go @@ -41,18 +41,18 @@ func ScanDevices(ctx context.Context, fs *btrfs.FS, nodeList []btrfsvol.LogicalA if err := ctx.Err(); err != nil { return btrfstree.Superblock{}, btrfsutil.Graph{}, nil, err } - nodeRef, err := btrfstree.ReadNode[btrfsvol.LogicalAddr](fs, *sb, laddr, btrfstree.NodeExpectations{ + node, err := btrfstree.ReadNode[btrfsvol.LogicalAddr](fs, *sb, laddr, btrfstree.NodeExpectations{ LAddr: containers.Optional[btrfsvol.LogicalAddr]{OK: true, Val: laddr}, }) if err != nil { - btrfstree.FreeNodeRef(nodeRef) + node.Free() return btrfstree.Superblock{}, btrfsutil.Graph{}, nil, err } - nodeGraph.InsertNode(nodeRef) - keyIO.InsertNode(nodeRef) + nodeGraph.InsertNode(node) + keyIO.InsertNode(node) - btrfstree.FreeNodeRef(nodeRef) + node.Free() stats.N++ progressWriter.Set(stats) diff --git a/cmd/btrfs-rec/inspect_lstrees.go b/cmd/btrfs-rec/inspect_lstrees.go index 05c3a57..70f4f51 100644 --- a/cmd/btrfs-rec/inspect_lstrees.go +++ b/cmd/btrfs-rec/inspect_lstrees.go @@ -19,7 +19,6 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" "git.lukeshu.com/btrfs-progs-ng/lib/btrfsutil" "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" @@ -76,8 +75,8 @@ func init() { treeErrCnt++ }, TreeWalkHandler: btrfstree.TreeWalkHandler{ - Node: func(_ btrfstree.TreePath, ref *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node]) error { - visitedNodes.Insert(ref.Addr) + Node: func(path btrfstree.TreePath, node *btrfstree.Node) error { + visitedNodes.Insert(path.Node(-1).ToNodeAddr) return nil }, Item: func(_ btrfstree.TreePath, item btrfstree.Item) error { @@ -113,7 +112,7 @@ func init() { treeErrCnt++ continue } - for _, item := range node.Data.BodyLeaf { + for _, item := range node.BodyLeaf { typ := item.Key.ItemType treeItemCnt[typ]++ } diff --git a/lib/btrfs/btrfstree/btree.go b/lib/btrfs/btrfstree/btree.go index 89d4f9d..c71aad5 100644 --- a/lib/btrfs/btrfstree/btree.go +++ b/lib/btrfs/btrfstree/btree.go @@ -11,8 +11,6 @@ import ( "fmt" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsprim" - "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" - "git.lukeshu.com/btrfs-progs-ng/lib/diskio" ) type TreeSearcher interface { @@ -72,9 +70,9 @@ type TreeWalkHandler struct { // or BadNode return io/fs.SkipDir then key pointers and items // within the node are not processed. PreNode func(TreePath) error - Node func(TreePath, *diskio.Ref[btrfsvol.LogicalAddr, Node]) error - BadNode func(TreePath, *diskio.Ref[btrfsvol.LogicalAddr, Node], error) error - PostNode func(TreePath, *diskio.Ref[btrfsvol.LogicalAddr, Node]) error + Node func(TreePath, *Node) error + BadNode func(TreePath, *Node, error) error + PostNode func(TreePath, *Node) error // Callbacks for items on interior nodes PreKeyPointer func(TreePath, KeyPointer) error PostKeyPointer func(TreePath, KeyPointer) error @@ -96,5 +94,5 @@ func (e *TreeError) Error() string { type NodeSource interface { Superblock() (*Superblock, error) - ReadNode(TreePath) (*diskio.Ref[btrfsvol.LogicalAddr, Node], error) + ReadNode(TreePath) (*Node, error) } diff --git a/lib/btrfs/btrfstree/btree_tree.go b/lib/btrfs/btrfstree/btree_tree.go index 1e3c789..7561314 100644 --- a/lib/btrfs/btrfstree/btree_tree.go +++ b/lib/btrfs/btrfstree/btree_tree.go @@ -15,8 +15,6 @@ import ( "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/btrfsvol" - "git.lukeshu.com/btrfs-progs-ng/lib/diskio" "git.lukeshu.com/btrfs-progs-ng/lib/slices" ) @@ -72,7 +70,7 @@ func (fs TreeOperatorImpl) treeWalk(ctx context.Context, path TreePath, errHandl } } node, err := fs.ReadNode(path) - defer FreeNodeRef(node) + defer node.Free() if ctx.Err() != nil { return } @@ -97,17 +95,17 @@ func (fs TreeOperatorImpl) treeWalk(ctx context.Context, path TreePath, errHandl return } if node != nil { - for i, item := range node.Data.BodyInterior { + for i, item := range node.BodyInterior { toMaxKey := path.Node(-1).ToMaxKey - if i+1 < len(node.Data.BodyInterior) { - toMaxKey = node.Data.BodyInterior[i+1].Key.Mm() + if i+1 < len(node.BodyInterior) { + toMaxKey = node.BodyInterior[i+1].Key.Mm() } itemPath := append(path, TreePathElem{ - FromTree: node.Data.Head.Owner, + FromTree: node.Head.Owner, FromItemSlot: i, ToNodeAddr: item.BlockPtr, ToNodeGeneration: item.Generation, - ToNodeLevel: node.Data.Head.Level - 1, + ToNodeLevel: node.Head.Level - 1, ToKey: item.Key, ToMaxKey: toMaxKey, }) @@ -129,9 +127,9 @@ func (fs TreeOperatorImpl) treeWalk(ctx context.Context, path TreePath, errHandl } } } - for i, item := range node.Data.BodyLeaf { + for i, item := range node.BodyLeaf { itemPath := append(path, TreePathElem{ - FromTree: node.Data.Head.Owner, + FromTree: node.Head.Owner, FromItemSlot: i, ToKey: item.Key, ToMaxKey: item.Key, @@ -169,7 +167,7 @@ func (fs TreeOperatorImpl) treeWalk(ctx context.Context, path TreePath, errHandl } } -func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, uint32) int) (TreePath, *diskio.Ref[btrfsvol.LogicalAddr, Node], error) { +func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, uint32) int) (TreePath, *Node, error) { path := TreePath{{ FromTree: treeRoot.TreeID, FromItemSlot: -1, @@ -184,15 +182,15 @@ func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, } node, err := fs.ReadNode(path) if err != nil { - FreeNodeRef(node) + node.Free() return nil, nil, err } switch { - case node.Data.Head.Level > 0: + case node.Head.Level > 0: // interior node - // Search for the right-most node.Data.BodyInterior item for which + // Search for the right-most node.BodyInterior item for which // `fn(item.Key) >= 0`. // // + + + + 0 - - - - @@ -200,31 +198,31 @@ func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, // There may or may not be a value that returns '0'. // // i.e. find the highest value that isn't too high. - lastGood, ok := slices.SearchHighest(node.Data.BodyInterior, func(kp KeyPointer) int { + lastGood, ok := slices.SearchHighest(node.BodyInterior, func(kp KeyPointer) int { return slices.Min(fn(kp.Key, math.MaxUint32), 0) // don't return >0; a key can't be "too low" }) if !ok { - FreeNodeRef(node) + node.Free() return nil, nil, ErrNoItem } toMaxKey := path.Node(-1).ToMaxKey - if lastGood+1 < len(node.Data.BodyInterior) { - toMaxKey = node.Data.BodyInterior[lastGood+1].Key.Mm() + if lastGood+1 < len(node.BodyInterior) { + toMaxKey = node.BodyInterior[lastGood+1].Key.Mm() } path = append(path, TreePathElem{ - FromTree: node.Data.Head.Owner, + FromTree: node.Head.Owner, FromItemSlot: lastGood, - ToNodeAddr: node.Data.BodyInterior[lastGood].BlockPtr, - ToNodeGeneration: node.Data.BodyInterior[lastGood].Generation, - ToNodeLevel: node.Data.Head.Level - 1, - ToKey: node.Data.BodyInterior[lastGood].Key, + ToNodeAddr: node.BodyInterior[lastGood].BlockPtr, + ToNodeGeneration: node.BodyInterior[lastGood].Generation, + ToNodeLevel: node.Head.Level - 1, + ToKey: node.BodyInterior[lastGood].Key, ToMaxKey: toMaxKey, }) - FreeNodeRef(node) + node.Free() default: // leaf node - // Search for a member of node.Data.BodyLeaf for which + // Search for a member of node.BodyLeaf for which // `fn(item.Head.Key) == 0`. // // + + + + 0 - - - - @@ -234,25 +232,25 @@ func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, // is returned. // // Implement this search as a binary search. - slot, ok := slices.Search(node.Data.BodyLeaf, func(item Item) int { + slot, ok := slices.Search(node.BodyLeaf, func(item Item) int { return fn(item.Key, item.BodySize) }) if !ok { - FreeNodeRef(node) + node.Free() return nil, nil, ErrNoItem } path = append(path, TreePathElem{ - FromTree: node.Data.Head.Owner, + FromTree: node.Head.Owner, FromItemSlot: slot, - ToKey: node.Data.BodyLeaf[slot].Key, - ToMaxKey: node.Data.BodyLeaf[slot].Key, + ToKey: node.BodyLeaf[slot].Key, + ToMaxKey: node.BodyLeaf[slot].Key, }) return path, node, nil } } } -func (fs TreeOperatorImpl) prev(path TreePath, node *diskio.Ref[btrfsvol.LogicalAddr, Node]) (TreePath, *diskio.Ref[btrfsvol.LogicalAddr, Node], error) { +func (fs TreeOperatorImpl) prev(path TreePath, node *Node) (TreePath, *Node, error) { var err error path = path.DeepCopy() @@ -266,139 +264,139 @@ func (fs TreeOperatorImpl) prev(path TreePath, node *diskio.Ref[btrfsvol.Logical // go left path.Node(-1).FromItemSlot-- if path.Node(-1).ToNodeAddr != 0 { - if node.Addr != path.Node(-2).ToNodeAddr { - FreeNodeRef(node) + if node.Head.Addr != path.Node(-2).ToNodeAddr { + node.Free() node, err = fs.ReadNode(path.Parent()) if err != nil { - FreeNodeRef(node) + node.Free() return nil, nil, err } - path.Node(-1).ToNodeAddr = node.Data.BodyInterior[path.Node(-1).FromItemSlot].BlockPtr + path.Node(-1).ToNodeAddr = node.BodyInterior[path.Node(-1).FromItemSlot].BlockPtr } } // go down for path.Node(-1).ToNodeAddr != 0 { - if node.Addr != path.Node(-1).ToNodeAddr { - FreeNodeRef(node) + if node.Head.Addr != path.Node(-1).ToNodeAddr { + node.Free() node, err = fs.ReadNode(path) if err != nil { - FreeNodeRef(node) + node.Free() return nil, nil, err } } - if node.Data.Head.Level > 0 { + if node.Head.Level > 0 { path = append(path, TreePathElem{ - FromTree: node.Data.Head.Owner, - FromItemSlot: len(node.Data.BodyInterior) - 1, - ToNodeAddr: node.Data.BodyInterior[len(node.Data.BodyInterior)-1].BlockPtr, - ToNodeGeneration: node.Data.BodyInterior[len(node.Data.BodyInterior)-1].Generation, - ToNodeLevel: node.Data.Head.Level - 1, - ToKey: node.Data.BodyInterior[len(node.Data.BodyInterior)-1].Key, + FromTree: node.Head.Owner, + FromItemSlot: len(node.BodyInterior) - 1, + ToNodeAddr: node.BodyInterior[len(node.BodyInterior)-1].BlockPtr, + ToNodeGeneration: node.BodyInterior[len(node.BodyInterior)-1].Generation, + ToNodeLevel: node.Head.Level - 1, + ToKey: node.BodyInterior[len(node.BodyInterior)-1].Key, ToMaxKey: path.Node(-1).ToMaxKey, }) } else { path = append(path, TreePathElem{ - FromTree: node.Data.Head.Owner, - FromItemSlot: len(node.Data.BodyLeaf) - 1, - ToKey: node.Data.BodyLeaf[len(node.Data.BodyLeaf)-1].Key, - ToMaxKey: node.Data.BodyLeaf[len(node.Data.BodyLeaf)-1].Key, + FromTree: node.Head.Owner, + FromItemSlot: len(node.BodyLeaf) - 1, + ToKey: node.BodyLeaf[len(node.BodyLeaf)-1].Key, + ToMaxKey: node.BodyLeaf[len(node.BodyLeaf)-1].Key, }) } } // return - if node.Addr != path.Node(-2).ToNodeAddr { - FreeNodeRef(node) + if node.Head.Addr != path.Node(-2).ToNodeAddr { + node.Free() node, err = fs.ReadNode(path.Parent()) if err != nil { - FreeNodeRef(node) + node.Free() return nil, nil, err } } return path, node, nil } -func (fs TreeOperatorImpl) next(path TreePath, node *diskio.Ref[btrfsvol.LogicalAddr, Node]) (TreePath, *diskio.Ref[btrfsvol.LogicalAddr, Node], error) { +func (fs TreeOperatorImpl) next(path TreePath, node *Node) (TreePath, *Node, error) { var err error path = path.DeepCopy() // go up - if node.Addr != path.Node(-2).ToNodeAddr { - FreeNodeRef(node) + if node.Head.Addr != path.Node(-2).ToNodeAddr { + node.Free() node, err = fs.ReadNode(path.Parent()) if err != nil { - FreeNodeRef(node) + node.Free() return nil, nil, err } - path.Node(-2).ToNodeLevel = node.Data.Head.Level + path.Node(-2).ToNodeLevel = node.Head.Level } - for path.Node(-1).FromItemSlot+1 >= int(node.Data.Head.NumItems) { + for path.Node(-1).FromItemSlot+1 >= int(node.Head.NumItems) { path = path.Parent() if len(path) == 1 { return nil, nil, nil } - if node.Addr != path.Node(-2).ToNodeAddr { - FreeNodeRef(node) + if node.Head.Addr != path.Node(-2).ToNodeAddr { + node.Free() node, err = fs.ReadNode(path.Parent()) if err != nil { - FreeNodeRef(node) + node.Free() return nil, nil, err } - path.Node(-2).ToNodeLevel = node.Data.Head.Level + path.Node(-2).ToNodeLevel = node.Head.Level } } // go right path.Node(-1).FromItemSlot++ if path.Node(-1).ToNodeAddr != 0 { - if node.Addr != path.Node(-2).ToNodeAddr { - FreeNodeRef(node) + if node.Head.Addr != path.Node(-2).ToNodeAddr { + node.Free() node, err = fs.ReadNode(path.Parent()) if err != nil { - FreeNodeRef(node) + node.Free() return nil, nil, err } - path.Node(-1).ToNodeAddr = node.Data.BodyInterior[path.Node(-1).FromItemSlot].BlockPtr + path.Node(-1).ToNodeAddr = node.BodyInterior[path.Node(-1).FromItemSlot].BlockPtr } } // go down for path.Node(-1).ToNodeAddr != 0 { - if node.Addr != path.Node(-1).ToNodeAddr { - FreeNodeRef(node) + if node.Head.Addr != path.Node(-1).ToNodeAddr { + node.Free() node, err = fs.ReadNode(path) if err != nil { - FreeNodeRef(node) + node.Free() return nil, nil, err } - path.Node(-1).ToNodeLevel = node.Data.Head.Level + path.Node(-1).ToNodeLevel = node.Head.Level } - if node.Data.Head.Level > 0 { + if node.Head.Level > 0 { toMaxKey := path.Node(-1).ToMaxKey - if len(node.Data.BodyInterior) > 1 { - toMaxKey = node.Data.BodyInterior[1].Key.Mm() + if len(node.BodyInterior) > 1 { + toMaxKey = node.BodyInterior[1].Key.Mm() } path = append(path, TreePathElem{ - FromTree: node.Data.Head.Owner, + FromTree: node.Head.Owner, FromItemSlot: 0, - ToNodeAddr: node.Data.BodyInterior[0].BlockPtr, - ToNodeGeneration: node.Data.BodyInterior[0].Generation, - ToNodeLevel: node.Data.Head.Level - 1, - ToKey: node.Data.BodyInterior[0].Key, + ToNodeAddr: node.BodyInterior[0].BlockPtr, + ToNodeGeneration: node.BodyInterior[0].Generation, + ToNodeLevel: node.Head.Level - 1, + ToKey: node.BodyInterior[0].Key, ToMaxKey: toMaxKey, }) } else { path = append(path, TreePathElem{ - FromTree: node.Data.Head.Owner, + FromTree: node.Head.Owner, FromItemSlot: 0, - ToKey: node.Data.BodyInterior[0].Key, - ToMaxKey: node.Data.BodyInterior[0].Key, + ToKey: node.BodyInterior[0].Key, + ToMaxKey: node.BodyInterior[0].Key, }) } } // return - if node.Addr != path.Node(-2).ToNodeAddr { - FreeNodeRef(node) + if node.Head.Addr != path.Node(-2).ToNodeAddr { + node.Free() node, err = fs.ReadNode(path.Parent()) if err != nil { - FreeNodeRef(node) + node.Free() return nil, nil, err } } @@ -419,9 +417,9 @@ func (fs TreeOperatorImpl) TreeSearch(treeID btrfsprim.ObjID, searcher TreeSearc if err != nil { return Item{}, fmt.Errorf("item with %s: %w", searcher, err) } - item := node.Data.BodyLeaf[path.Node(-1).FromItemSlot] + item := node.BodyLeaf[path.Node(-1).FromItemSlot] item.Body = item.Body.CloneItem() - FreeNodeRef(node) + node.Free() return item, nil } @@ -444,7 +442,7 @@ func (fs TreeOperatorImpl) TreeSearchAll(treeID btrfsprim.ObjID, searcher TreeSe if err != nil { return nil, fmt.Errorf("items with %s: %w", searcher, err) } - middleItem := middleNode.Data.BodyLeaf[middlePath.Node(-1).FromItemSlot] + middleItem := middleNode.BodyLeaf[middlePath.Node(-1).FromItemSlot] ret := []Item{middleItem} var errs derror.MultiError @@ -458,7 +456,7 @@ func (fs TreeOperatorImpl) TreeSearchAll(treeID btrfsprim.ObjID, searcher TreeSe if len(prevPath) == 0 { break } - prevItem := prevNode.Data.BodyLeaf[prevPath.Node(-1).FromItemSlot] + prevItem := prevNode.BodyLeaf[prevPath.Node(-1).FromItemSlot] if searcher.Search(prevItem.Key, prevItem.BodySize) != 0 { break } @@ -467,11 +465,11 @@ func (fs TreeOperatorImpl) TreeSearchAll(treeID btrfsprim.ObjID, searcher TreeSe ret = append(ret, item) } slices.Reverse(ret) - if prevNode.Addr != middlePath.Node(-1).ToNodeAddr { - FreeNodeRef(prevNode) + if prevNode.Head.Addr != middlePath.Node(-1).ToNodeAddr { + prevNode.Free() middleNode, err = fs.ReadNode(middlePath) if err != nil { - FreeNodeRef(middleNode) + middleNode.Free() return nil, fmt.Errorf("items with %s: %w", searcher, err) } } @@ -485,7 +483,7 @@ func (fs TreeOperatorImpl) TreeSearchAll(treeID btrfsprim.ObjID, searcher TreeSe if len(nextPath) == 0 { break } - nextItem := nextNode.Data.BodyLeaf[nextPath.Node(-1).FromItemSlot] + nextItem := nextNode.BodyLeaf[nextPath.Node(-1).FromItemSlot] if searcher.Search(nextItem.Key, nextItem.BodySize) != 0 { break } @@ -493,7 +491,7 @@ func (fs TreeOperatorImpl) TreeSearchAll(treeID btrfsprim.ObjID, searcher TreeSe item.Body = item.Body.CloneItem() ret = append(ret, item) } - FreeNodeRef(nextNode) + nextNode.Free() if errs != nil { err = errs } diff --git a/lib/btrfs/btrfstree/readnode.go b/lib/btrfs/btrfstree/readnode.go index 4ccc17b..1c242ac 100644 --- a/lib/btrfs/btrfstree/readnode.go +++ b/lib/btrfs/btrfstree/readnode.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -34,7 +34,7 @@ type NodeFile interface { func FSReadNode( fs NodeFile, path TreePath, -) (*diskio.Ref[btrfsvol.LogicalAddr, Node], error) { +) (*Node, error) { sb, err := fs.Superblock() if err != nil { return nil, fmt.Errorf("btrfs.FS.ReadNode: %w", err) diff --git a/lib/btrfs/btrfstree/types_node.go b/lib/btrfs/btrfstree/types_node.go index 8295ccb..2147f5b 100644 --- a/lib/btrfs/btrfstree/types_node.go +++ b/lib/btrfs/btrfstree/types_node.go @@ -8,7 +8,6 @@ import ( "encoding/binary" "errors" "fmt" - "unsafe" "git.lukeshu.com/go/typedsync" "github.com/datawire/dlib/derror" @@ -308,12 +307,16 @@ type ItemHeader struct { var itemPool containers.SlicePool[Item] func (node *Node) Free() { + if node == nil { + return + } for i := range node.BodyLeaf { node.BodyLeaf[i].Body.Free() node.BodyLeaf[i] = Item{} } itemPool.Put(node.BodyLeaf) *node = Node{} + nodePool.Put(node) } func (node *Node) unmarshalLeaf(bodyBuf []byte) (int, error) { @@ -440,32 +443,19 @@ func (e *IOError) Unwrap() error { return e.Err } var bytePool containers.SlicePool[byte] -var nodePool = typedsync.Pool[*diskio.Ref[int64, Node]]{ - New: func() *diskio.Ref[int64, Node] { - return new(diskio.Ref[int64, Node]) +var nodePool = typedsync.Pool[*Node]{ + New: func() *Node { + return new(Node) }, } -func FreeNodeRef[Addr ~int64](ref *diskio.Ref[Addr, Node]) { - if ref == nil { - return - } - ref.Data.Free() - nodePool.Put((*diskio.Ref[int64, Node])(unsafe.Pointer(ref))) //nolint:gosec // I know it's unsafe. -} - -func newNodeRef[Addr ~int64]() *diskio.Ref[Addr, Node] { - ret, _ := nodePool.Get() - return (*diskio.Ref[Addr, Node])(unsafe.Pointer(ret)) //nolint:gosec // I know it's unsafe. -} - // ReadNode reads a node from the given file. // // It is possible that both a non-nil diskio.Ref and an error are // returned. The error returned (if non-nil) is always of type // *NodeError[Addr]. Notable errors that may be inside of the // NodeError are ErrNotANode and *IOError. -func ReadNode[Addr ~int64](fs diskio.File[Addr], sb Superblock, addr Addr, exp NodeExpectations) (*diskio.Ref[Addr, Node], error) { +func ReadNode[Addr ~int64](fs diskio.ReaderAt[Addr], sb Superblock, addr Addr, exp NodeExpectations) (*Node, error) { if int(sb.NodeSize) < nodeHeaderSize { return nil, &NodeError[Addr]{ Op: "btrfstree.ReadNode", NodeAddr: addr, @@ -481,16 +471,10 @@ func ReadNode[Addr ~int64](fs diskio.File[Addr], sb Superblock, addr Addr, exp N // parse (early) - nodeRef := newNodeRef[Addr]() - *nodeRef = diskio.Ref[Addr, Node]{ - File: fs, - Addr: addr, - Data: Node{ - Size: sb.NodeSize, - ChecksumType: sb.ChecksumType, - }, - } - if _, err := binstruct.Unmarshal(nodeBuf, &nodeRef.Data.Head); err != nil { + node, _ := nodePool.Get() + node.Size = sb.NodeSize + node.ChecksumType = sb.ChecksumType + if _, err := binstruct.Unmarshal(nodeBuf, &node.Head); err != nil { // If there are enough bytes there (and we checked // that above), then it shouldn't be possible for this // unmarshal to fail. @@ -499,20 +483,20 @@ func ReadNode[Addr ~int64](fs diskio.File[Addr], sb Superblock, addr Addr, exp N // sanity checking (that prevents the main parse) - if nodeRef.Data.Head.MetadataUUID != sb.EffectiveMetadataUUID() { + if node.Head.MetadataUUID != sb.EffectiveMetadataUUID() { bytePool.Put(nodeBuf) - return nodeRef, &NodeError[Addr]{Op: "btrfstree.ReadNode", NodeAddr: addr, Err: ErrNotANode} + return node, &NodeError[Addr]{Op: "btrfstree.ReadNode", NodeAddr: addr, Err: ErrNotANode} } - stored := nodeRef.Data.Head.Checksum - calced, err := nodeRef.Data.ChecksumType.Sum(nodeBuf[csumSize:]) + stored := node.Head.Checksum + calced, err := node.ChecksumType.Sum(nodeBuf[csumSize:]) if err != nil { bytePool.Put(nodeBuf) - return nodeRef, &NodeError[Addr]{Op: "btrfstree.ReadNode", NodeAddr: addr, Err: err} + return node, &NodeError[Addr]{Op: "btrfstree.ReadNode", NodeAddr: addr, Err: err} } if stored != calced { bytePool.Put(nodeBuf) - return nodeRef, &NodeError[Addr]{ + return node, &NodeError[Addr]{ Op: "btrfstree.ReadNode", NodeAddr: addr, Err: fmt.Errorf("looks like a node but is corrupt: checksum mismatch: stored=%v calculated=%v", stored, calced), @@ -530,9 +514,9 @@ func ReadNode[Addr ~int64](fs diskio.File[Addr], sb Superblock, addr Addr, exp N // garbage data that is was never a valid node, so parsing it // isn't useful. - if _, err := binstruct.Unmarshal(nodeBuf, &nodeRef.Data); err != nil { + if _, err := binstruct.Unmarshal(nodeBuf, node); err != nil { bytePool.Put(nodeBuf) - return nodeRef, &NodeError[Addr]{Op: "btrfstree.ReadNode", NodeAddr: addr, Err: err} + return node, &NodeError[Addr]{Op: "btrfstree.ReadNode", NodeAddr: addr, Err: err} } bytePool.Put(nodeBuf) @@ -540,40 +524,40 @@ func ReadNode[Addr ~int64](fs diskio.File[Addr], sb Superblock, addr Addr, exp N // sanity checking (that doesn't prevent parsing) var errs derror.MultiError - if exp.LAddr.OK && nodeRef.Data.Head.Addr != exp.LAddr.Val { + if exp.LAddr.OK && node.Head.Addr != exp.LAddr.Val { errs = append(errs, fmt.Errorf("read from laddr=%v but claims to be at laddr=%v", - exp.LAddr.Val, nodeRef.Data.Head.Addr)) + exp.LAddr.Val, node.Head.Addr)) } - if exp.Level.OK && nodeRef.Data.Head.Level != exp.Level.Val { + if exp.Level.OK && node.Head.Level != exp.Level.Val { errs = append(errs, fmt.Errorf("expected level=%v but claims to be level=%v", - exp.Level.Val, nodeRef.Data.Head.Level)) + exp.Level.Val, node.Head.Level)) } - if exp.Generation.OK && nodeRef.Data.Head.Generation != exp.Generation.Val { + if exp.Generation.OK && node.Head.Generation != exp.Generation.Val { errs = append(errs, fmt.Errorf("expected generation=%v but claims to be generation=%v", - exp.Generation.Val, nodeRef.Data.Head.Generation)) + exp.Generation.Val, node.Head.Generation)) } if exp.Owner != nil { - if err := exp.Owner(nodeRef.Data.Head.Owner); err != nil { + if err := exp.Owner(node.Head.Owner); err != nil { errs = append(errs, err) } } - if nodeRef.Data.Head.NumItems == 0 { + if node.Head.NumItems == 0 { errs = append(errs, fmt.Errorf("has no items")) } else { - if minItem, _ := nodeRef.Data.MinItem(); exp.MinItem.OK && exp.MinItem.Val.Compare(minItem) > 0 { + if minItem, _ := node.MinItem(); exp.MinItem.OK && exp.MinItem.Val.Compare(minItem) > 0 { errs = append(errs, fmt.Errorf("expected minItem>=%v but node has minItem=%v", exp.MinItem, minItem)) } - if maxItem, _ := nodeRef.Data.MaxItem(); exp.MaxItem.OK && exp.MaxItem.Val.Compare(maxItem) < 0 { + if maxItem, _ := node.MaxItem(); exp.MaxItem.OK && exp.MaxItem.Val.Compare(maxItem) < 0 { errs = append(errs, fmt.Errorf("expected maxItem<=%v but node has maxItem=%v", exp.MaxItem, maxItem)) } } if len(errs) > 0 { - return nodeRef, &NodeError[Addr]{Op: "btrfstree.ReadNode", NodeAddr: addr, Err: errs} + return node, &NodeError[Addr]{Op: "btrfstree.ReadNode", NodeAddr: addr, Err: errs} } // return - return nodeRef, nil + return node, nil } diff --git a/lib/btrfs/io3_btree.go b/lib/btrfs/io3_btree.go index 8d35269..467bbde 100644 --- a/lib/btrfs/io3_btree.go +++ b/lib/btrfs/io3_btree.go @@ -10,8 +10,6 @@ import ( "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" - "git.lukeshu.com/btrfs-progs-ng/lib/diskio" ) // This file is ordered from low-level to high-level. @@ -19,7 +17,7 @@ import ( // btrfstree.NodeSource //////////////////////////////////////////////////////// // ReadNode implements btrfstree.NodeSource. -func (fs *FS) ReadNode(path btrfstree.TreePath) (*diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node], error) { +func (fs *FS) ReadNode(path btrfstree.TreePath) (*btrfstree.Node, error) { return btrfstree.FSReadNode(fs, path) } diff --git a/lib/btrfs/io4_fs.go b/lib/btrfs/io4_fs.go index b1a1232..e4511a5 100644 --- a/lib/btrfs/io4_fs.go +++ b/lib/btrfs/io4_fs.go @@ -20,6 +20,7 @@ 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" @@ -65,7 +66,7 @@ type Subvolume struct { FS interface { btrfstree.TreeOperator Superblock() (*btrfstree.Superblock, error) - ReadAt(p []byte, off btrfsvol.LogicalAddr) (int, error) + diskio.ReaderAt[btrfsvol.LogicalAddr] } TreeID btrfsprim.ObjID NoChecksums bool diff --git a/lib/btrfsutil/graph.go b/lib/btrfsutil/graph.go index 09a17b4..a7c299a 100644 --- a/lib/btrfsutil/graph.go +++ b/lib/btrfsutil/graph.go @@ -149,29 +149,29 @@ func NewGraph(sb btrfstree.Superblock) *Graph { return g } -func (g Graph) InsertNode(nodeRef *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node]) { +func (g Graph) InsertNode(node *btrfstree.Node) { nodeData := GraphNode{ - Level: nodeRef.Data.Head.Level, - Generation: nodeRef.Data.Head.Generation, - Owner: nodeRef.Data.Head.Owner, + Level: node.Head.Level, + Generation: node.Head.Generation, + Owner: node.Head.Owner, } - if nodeRef.Data.Head.Level == 0 { + if node.Head.Level == 0 { cnt := 0 - for _, item := range nodeRef.Data.BodyLeaf { + for _, item := range node.BodyLeaf { if _, ok := item.Body.(*btrfsitem.Root); ok { cnt++ } } kps := make([]GraphEdge, 0, cnt) - keys := make([]btrfsprim.Key, len(nodeRef.Data.BodyLeaf)) + keys := make([]btrfsprim.Key, len(node.BodyLeaf)) nodeData.Items = keys - g.Nodes[nodeRef.Addr] = nodeData - for i, item := range nodeRef.Data.BodyLeaf { + g.Nodes[node.Head.Addr] = nodeData + for i, item := range node.BodyLeaf { keys[i] = item.Key if itemBody, ok := item.Body.(*btrfsitem.Root); ok { kps = append(kps, GraphEdge{ - FromRoot: nodeRef.Addr, + FromRoot: node.Head.Addr, FromItem: i, FromTree: item.Key.ObjectID, ToNode: itemBody.ByteNr, @@ -182,15 +182,15 @@ func (g Graph) InsertNode(nodeRef *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.No } } } else { - g.Nodes[nodeRef.Addr] = nodeData - kps := make([]GraphEdge, len(nodeRef.Data.BodyInterior)) - for i, kp := range nodeRef.Data.BodyInterior { + g.Nodes[node.Head.Addr] = nodeData + kps := make([]GraphEdge, len(node.BodyInterior)) + for i, kp := range node.BodyInterior { kps[i] = GraphEdge{ - FromNode: nodeRef.Addr, + FromNode: node.Head.Addr, FromItem: i, - FromTree: nodeRef.Data.Head.Owner, + FromTree: node.Head.Owner, ToNode: kp.BlockPtr, - ToLevel: nodeRef.Data.Head.Level - 1, + ToLevel: node.Head.Level - 1, ToKey: kp.Key, ToGeneration: kp.Generation, } diff --git a/lib/btrfsutil/listnodes.go b/lib/btrfsutil/listnodes.go index 5505d23..70b647c 100644 --- a/lib/btrfsutil/listnodes.go +++ b/lib/btrfsutil/listnodes.go @@ -11,7 +11,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/textui" ) @@ -44,8 +43,8 @@ func (*nodeScanner) ScanSector(context.Context, *btrfs.Device, btrfsvol.Physical return nil } -func (s *nodeScanner) ScanNode(_ context.Context, nodeRef *diskio.Ref[btrfsvol.PhysicalAddr, btrfstree.Node]) error { - s.nodes.Insert(nodeRef.Data.Head.Addr) +func (s *nodeScanner) ScanNode(_ context.Context, _ btrfsvol.PhysicalAddr, node *btrfstree.Node) error { + s.nodes.Insert(node.Head.Addr) return nil } diff --git a/lib/btrfsutil/old_rebuilt_forrest.go b/lib/btrfsutil/old_rebuilt_forrest.go index d49f34e..2ec1d83 100644 --- a/lib/btrfsutil/old_rebuilt_forrest.go +++ b/lib/btrfsutil/old_rebuilt_forrest.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" ) type oldRebuiltTree struct { @@ -226,12 +225,12 @@ func (bt *OldRebuiltForrest) TreeSearch(treeID btrfsprim.ObjID, searcher btrfstr itemPath := bt.arena.Inflate(indexItem.Value.Path) node, err := bt.inner.ReadNode(itemPath.Parent()) - defer btrfstree.FreeNodeRef(node) + defer node.Free() if err != nil { return btrfstree.Item{}, fmt.Errorf("item with %s: %w", searcher, bt.addErrs(tree, searcher.Search, err)) } - item := node.Data.BodyLeaf[itemPath.Node(-1).FromItemSlot] + item := node.BodyLeaf[itemPath.Node(-1).FromItemSlot] item.Body = item.Body.CloneItem() // Since we were only asked to return 1 item, it isn't @@ -259,22 +258,22 @@ func (bt *OldRebuiltForrest) TreeSearchAll(treeID btrfsprim.ObjID, searcher btrf } ret := make([]btrfstree.Item, len(indexItems)) - var node *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node] + var node *btrfstree.Node for i := range indexItems { itemPath := bt.arena.Inflate(indexItems[i].Path) - if node == nil || node.Addr != itemPath.Node(-2).ToNodeAddr { + if node == nil || node.Head.Addr != itemPath.Node(-2).ToNodeAddr { var err error - btrfstree.FreeNodeRef(node) + node.Free() node, err = bt.inner.ReadNode(itemPath.Parent()) if err != nil { - btrfstree.FreeNodeRef(node) + node.Free() return nil, fmt.Errorf("items with %s: %w", searcher, bt.addErrs(tree, searcher.Search, err)) } } - ret[i] = node.Data.BodyLeaf[itemPath.Node(-1).FromItemSlot] + ret[i] = node.BodyLeaf[itemPath.Node(-1).FromItemSlot] ret[i].Body = ret[i].Body.CloneItem() } - btrfstree.FreeNodeRef(node) + node.Free() err := bt.addErrs(tree, searcher.Search, nil) if err != nil { @@ -298,7 +297,7 @@ func (bt *OldRebuiltForrest) TreeWalk(ctx context.Context, treeID btrfsprim.ObjI if cbs.Item == nil { return } - var node *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node] + var node *btrfstree.Node tree.Items.Range(func(indexItem *containers.RBNode[oldRebuiltTreeValue]) bool { if ctx.Err() != nil { return false @@ -307,23 +306,23 @@ func (bt *OldRebuiltForrest) TreeWalk(ctx context.Context, treeID btrfsprim.ObjI return false } itemPath := bt.arena.Inflate(indexItem.Value.Path) - if node == nil || node.Addr != itemPath.Node(-2).ToNodeAddr { + if node == nil || node.Head.Addr != itemPath.Node(-2).ToNodeAddr { var err error - btrfstree.FreeNodeRef(node) + node.Free() node, err = bt.inner.ReadNode(itemPath.Parent()) if err != nil { - btrfstree.FreeNodeRef(node) + node.Free() errHandle(&btrfstree.TreeError{Path: itemPath, Err: err}) return true } } - item := node.Data.BodyLeaf[itemPath.Node(-1).FromItemSlot] + item := node.BodyLeaf[itemPath.Node(-1).FromItemSlot] if err := cbs.Item(itemPath, item); err != nil { errHandle(&btrfstree.TreeError{Path: itemPath, Err: err}) } return true }) - btrfstree.FreeNodeRef(node) + node.Free() } func (bt *OldRebuiltForrest) Superblock() (*btrfstree.Superblock, error) { @@ -343,8 +342,8 @@ func (bt *OldRebuiltForrest) Augment(treeID btrfsprim.ObjID, nodeAddr btrfsvol.L if tree.RootErr != nil { return nil, tree.RootErr } - nodeRef, err := btrfstree.ReadNode[btrfsvol.LogicalAddr](bt.inner, *sb, nodeAddr, btrfstree.NodeExpectations{}) - defer btrfstree.FreeNodeRef(nodeRef) + node, err := btrfstree.ReadNode[btrfsvol.LogicalAddr](bt.inner, *sb, nodeAddr, btrfstree.NodeExpectations{}) + defer node.Free() if err != nil { return nil, err } @@ -352,8 +351,8 @@ func (bt *OldRebuiltForrest) Augment(treeID btrfsprim.ObjID, nodeAddr btrfsvol.L bt.rawTreeWalk(btrfstree.TreeRoot{ TreeID: treeID, RootNode: nodeAddr, - Level: nodeRef.Data.Head.Level, - Generation: nodeRef.Data.Head.Generation, + Level: node.Head.Level, + Generation: node.Head.Generation, }, tree, &ret) return ret, nil } diff --git a/lib/btrfsutil/rebuilt_readitem.go b/lib/btrfsutil/rebuilt_readitem.go index 016299c..b1a0656 100644 --- a/lib/btrfsutil/rebuilt_readitem.go +++ b/lib/btrfsutil/rebuilt_readitem.go @@ -49,7 +49,7 @@ type KeyIO struct { Sizes map[ItemPtr]SizeAndErr // EXTENT_CSUM and EXTENT_DATA mu sync.Mutex - cache containers.ARCache[btrfsvol.LogicalAddr, *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node]] + cache containers.ARCache[btrfsvol.LogicalAddr, *btrfstree.Node] } func NewKeyIO(file diskio.File[btrfsvol.LogicalAddr], sb btrfstree.Superblock) *KeyIO { @@ -61,19 +61,19 @@ func NewKeyIO(file diskio.File[btrfsvol.LogicalAddr], sb btrfstree.Superblock) * Names: make(map[ItemPtr][]byte), Sizes: make(map[ItemPtr]SizeAndErr), - cache: containers.ARCache[btrfsvol.LogicalAddr, *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node]]{ + cache: containers.ARCache[btrfsvol.LogicalAddr, *btrfstree.Node]{ MaxLen: textui.Tunable(8), - OnRemove: func(_ btrfsvol.LogicalAddr, nodeRef *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node]) { - btrfstree.FreeNodeRef(nodeRef) + OnRemove: func(_ btrfsvol.LogicalAddr, node *btrfstree.Node) { + node.Free() }, }, } } -func (o *KeyIO) InsertNode(nodeRef *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node]) { - for i, item := range nodeRef.Data.BodyLeaf { +func (o *KeyIO) InsertNode(node *btrfstree.Node) { + for i, item := range node.BodyLeaf { ptr := ItemPtr{ - Node: nodeRef.Addr, + Node: node.Head.Addr, Slot: i, } switch itemBody := item.Body.(type) { @@ -102,12 +102,12 @@ func (o *KeyIO) InsertNode(nodeRef *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.N case btrfsprim.INODE_ITEM_KEY: o.Flags[ptr] = FlagsAndErr{ Err: fmt.Errorf("error decoding item: ptr=%v (tree=%v key=%v): %w", - ptr, nodeRef.Data.Head.Owner, item.Key, itemBody.Err), + ptr, node.Head.Owner, item.Key, itemBody.Err), } case btrfsprim.EXTENT_CSUM_KEY, btrfsprim.EXTENT_DATA_KEY: o.Sizes[ptr] = SizeAndErr{ Err: fmt.Errorf("error decoding item: ptr=%v (tree=%v key=%v): %w", - ptr, nodeRef.Data.Head.Owner, item.Key, itemBody.Err), + ptr, node.Head.Owner, item.Key, itemBody.Err), } } } @@ -118,7 +118,7 @@ func (o *KeyIO) SetGraph(graph Graph) { o.graph = graph } -func (o *KeyIO) readNode(ctx context.Context, laddr btrfsvol.LogicalAddr) *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node] { +func (o *KeyIO) readNode(ctx context.Context, laddr btrfsvol.LogicalAddr) *btrfstree.Node { if cached, ok := o.cache.Load(laddr); ok { dlog.Tracef(ctx, "cache-hit node@%v", laddr) return cached @@ -130,7 +130,7 @@ func (o *KeyIO) readNode(ctx context.Context, laddr btrfsvol.LogicalAddr) *diski } dlog.Debugf(ctx, "cache-miss node@%v, reading...", laddr) - ref, err := btrfstree.ReadNode(o.rawFile, o.sb, laddr, btrfstree.NodeExpectations{ + node, err := btrfstree.ReadNode[btrfsvol.LogicalAddr](o.rawFile, o.sb, laddr, btrfstree.NodeExpectations{ LAddr: containers.Optional[btrfsvol.LogicalAddr]{OK: true, Val: laddr}, Level: containers.Optional[uint8]{OK: true, Val: graphInfo.Level}, Generation: containers.Optional[btrfsprim.Generation]{OK: true, Val: graphInfo.Generation}, @@ -148,9 +148,9 @@ func (o *KeyIO) readNode(ctx context.Context, laddr btrfsvol.LogicalAddr) *diski panic(fmt.Errorf("should not happen: i/o error: %w", err)) } - o.cache.Store(laddr, ref) + o.cache.Store(laddr, node) - return ref + return node } func (o *KeyIO) ReadItem(ctx context.Context, ptr ItemPtr) btrfsitem.Item { @@ -162,7 +162,7 @@ func (o *KeyIO) ReadItem(ctx context.Context, ptr ItemPtr) btrfsitem.Item { if ptr.Slot < 0 { panic(fmt.Errorf("should not happen: btrfsutil.KeyIO.ReadItem called for negative item slot: %v", ptr.Slot)) } - items := o.readNode(ctx, ptr.Node).Data.BodyLeaf + items := o.readNode(ctx, ptr.Node).BodyLeaf if ptr.Slot >= len(items) { panic(fmt.Errorf("should not happen: btrfsutil.KeyIO.ReadItem called for out-of-bounds item slot: slot=%v len=%v", ptr.Slot, len(items))) diff --git a/lib/btrfsutil/scan.go b/lib/btrfsutil/scan.go index 97220aa..05b27d5 100644 --- a/lib/btrfsutil/scan.go +++ b/lib/btrfsutil/scan.go @@ -19,7 +19,6 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfssum" "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/diskio" "git.lukeshu.com/btrfs-progs-ng/lib/textui" ) @@ -30,7 +29,7 @@ type DeviceScannerFactory[Stats comparable, Result any] func(ctx context.Context type DeviceScanner[Stats comparable, Result any] interface { ScanStats() Stats ScanSector(ctx context.Context, dev *btrfs.Device, paddr btrfsvol.PhysicalAddr) error - ScanNode(ctx context.Context, nodeRef *diskio.Ref[btrfsvol.PhysicalAddr, btrfstree.Node]) error + ScanNode(ctx context.Context, addr btrfsvol.PhysicalAddr, node *btrfstree.Node) error ScanDone(ctx context.Context) (Result, error) } @@ -123,19 +122,19 @@ func ScanOneDevice[Stats comparable, Result any](ctx context.Context, dev *btrfs } if checkForNode { - nodeRef, err := btrfstree.ReadNode[btrfsvol.PhysicalAddr](dev, *sb, pos, btrfstree.NodeExpectations{}) + node, err := btrfstree.ReadNode[btrfsvol.PhysicalAddr](dev, *sb, pos, btrfstree.NodeExpectations{}) if err != nil { if !errors.Is(err, btrfstree.ErrNotANode) { dlog.Errorf(ctx, "error: %v", err) } } else { - if err := scanner.ScanNode(ctx, nodeRef); err != nil { + if err := scanner.ScanNode(ctx, pos, node); err != nil { var zero Result return zero, err } minNextNode = pos + btrfsvol.PhysicalAddr(sb.NodeSize) } - btrfstree.FreeNodeRef(nodeRef) + node.Free() } } diff --git a/lib/btrfsutil/skinny_paths.go b/lib/btrfsutil/skinny_paths.go index adf539b..1361fff 100644 --- a/lib/btrfsutil/skinny_paths.go +++ b/lib/btrfsutil/skinny_paths.go @@ -54,26 +54,26 @@ func (a *SkinnyPathArena) getItem(parent btrfstree.TreePath, itemSlot int) (btrf return ret, nil } - node, err := btrfstree.ReadNode(a.FS, a.SB, parent.Node(-1).ToNodeAddr, btrfstree.NodeExpectations{}) - defer btrfstree.FreeNodeRef(node) + node, err := btrfstree.ReadNode[btrfsvol.LogicalAddr](a.FS, a.SB, parent.Node(-1).ToNodeAddr, btrfstree.NodeExpectations{}) + defer node.Free() if err != nil { return btrfstree.TreePathElem{}, err } - if node.Data.Head.Level > 0 { - if itemSlot >= len(node.Data.BodyInterior) { + if node.Head.Level > 0 { + if itemSlot >= len(node.BodyInterior) { panic("should not happen") } - for i, item := range node.Data.BodyInterior { + for i, item := range node.BodyInterior { toMaxKey := parent.Node(-1).ToMaxKey - if i+1 < len(node.Data.BodyInterior) { - toMaxKey = node.Data.BodyInterior[i+1].Key.Mm() + if i+1 < len(node.BodyInterior) { + toMaxKey = node.BodyInterior[i+1].Key.Mm() } elem := btrfstree.TreePathElem{ - FromTree: node.Data.Head.Owner, + FromTree: node.Head.Owner, FromItemSlot: i, ToNodeAddr: item.BlockPtr, ToNodeGeneration: item.Generation, - ToNodeLevel: node.Data.Head.Level - 1, + ToNodeLevel: node.Head.Level - 1, ToKey: item.Key, ToMaxKey: toMaxKey, } @@ -83,12 +83,12 @@ func (a *SkinnyPathArena) getItem(parent btrfstree.TreePath, itemSlot int) (btrf } } } else { - if itemSlot >= len(node.Data.BodyLeaf) { + if itemSlot >= len(node.BodyLeaf) { panic("should not happen") } - for i, item := range node.Data.BodyLeaf { + for i, item := range node.BodyLeaf { elem := btrfstree.TreePathElem{ - FromTree: node.Data.Head.Owner, + FromTree: node.Head.Owner, FromItemSlot: i, ToKey: item.Key, ToMaxKey: item.Key, diff --git a/lib/diskio/file_iface.go b/lib/diskio/file_iface.go index d26ffcc..a30ddb0 100644 --- a/lib/diskio/file_iface.go +++ b/lib/diskio/file_iface.go @@ -9,11 +9,15 @@ import ( "io" ) +type ReaderAt[A ~int64] interface { + ReadAt(p []byte, off A) (n int, err error) +} + type File[A ~int64] interface { Name() string Size() A - Close() error - ReadAt(p []byte, off A) (n int, err error) + io.Closer + ReaderAt[A] WriteAt(p []byte, off A) (n int, err error) } -- cgit v1.2.3