From ee2564cc3164e2c235b3d617a1a4fed2f9d9efc6 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Fri, 7 Apr 2023 15:30:46 -0600 Subject: btrfsutil.RebuiltForrest, rebuildtrees: Be more permissive of broken UUID_TREEs --- .../inspect/rebuildtrees/rebuild_treecb.go | 40 +++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'cmd') diff --git a/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_treecb.go b/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_treecb.go index b8205ae..466082c 100644 --- a/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_treecb.go +++ b/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_treecb.go @@ -75,7 +75,9 @@ func (o forrestCallbacks) LookupUUID(ctx context.Context, uuid btrfsprim.UUID) ( } ctx = withWant(ctx, logFieldTreeWant, "resolve parent UUID", wantKey) if !o._wantOff(ctx, wantKey) { - o.enqueueRetry(btrfsprim.UUID_TREE_OBJECTID) + if id, ok := o.slowLookupUUID(ctx, uuid); ok { + return id, nil + } return 0, btrfstree.ErrNoItem } item, _ := discardErr(o.rebuilt.RebuiltTree(ctx, wantKey.TreeID)).TreeLookup(ctx, wantKey.Key.Key()) @@ -85,6 +87,9 @@ func (o forrestCallbacks) LookupUUID(ctx context.Context, uuid btrfsprim.UUID) ( return itemBody.ObjID, nil case *btrfsitem.Error: graphCallbacks(o).FSErr(ctx, fmt.Errorf("error decoding item: %v: %w", wantKey, itemBody.Err)) + if id, ok := o.slowLookupUUID(ctx, uuid); ok { + return id, nil + } return 0, itemBody.Err default: // This is a panic because the item decoder should not emit UUID_SUBVOL items as anything but @@ -92,3 +97,36 @@ func (o forrestCallbacks) LookupUUID(ctx context.Context, uuid btrfsprim.UUID) ( panic(fmt.Errorf("should not happen: UUID_SUBVOL item has unexpected type: %T", itemBody)) } } + +func (o forrestCallbacks) slowLookupUUID(ctx context.Context, uuid btrfsprim.UUID) (id btrfsprim.ObjID, ok bool) { + rootTree, err := o.rebuilt.RebuiltTree(ctx, btrfsprim.ROOT_TREE_OBJECTID) + if err != nil { + o.enqueueRetry(btrfsprim.ROOT_TREE_OBJECTID) + return 0, false + } + var ret btrfsprim.ObjID + _ = rootTree.TreeRange(ctx, func(item btrfstree.Item) bool { + if item.Key.ItemType != btrfsprim.ROOT_ITEM_KEY { + return true + } + switch itemBody := item.Body.(type) { + case *btrfsitem.Root: + if itemBody.UUID == uuid { + ret = item.Key.ObjectID + return false + } + case *btrfsitem.Error: + graphCallbacks(o).FSErr(ctx, fmt.Errorf("error decoding item: %v: %w", item.Key, itemBody.Err)) + default: + // This is a panic because the item decoder should not emit ROOT_ITEM items as anything but + // btrfsitem.Root or btrfsitem.Error without this code also being updated. + panic(fmt.Errorf("should not happen: ROOT_ITEM item has unexpected type: %T", itemBody)) + } + return true + }) + if ret == 0 { + o.enqueueRetry(btrfsprim.ROOT_TREE_OBJECTID) + return 0, false + } + return ret, true +} -- cgit v1.2.3-2-g168b From dc1eddc75a17687ee4d3bc301dd8b2ff253095fe Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Fri, 10 Mar 2023 19:31:50 -0700 Subject: cmd/btrfs-rec, btrfsutil: Delete OldRebuiltForrest --- cmd/btrfs-rec/main.go | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'cmd') diff --git a/cmd/btrfs-rec/main.go b/cmd/btrfs-rec/main.go index ad768de..e167095 100644 --- a/cmd/btrfs-rec/main.go +++ b/cmd/btrfs-rec/main.go @@ -49,10 +49,9 @@ var globalFlags struct { logLevel textui.LogLevelFlag pvs []string - mappings string - nodeList string - rebuildV1 bool - rebuildV2 bool + mappings string + nodeList string + rebuild bool stopProfiling profile.StopFunc @@ -102,11 +101,8 @@ func main() { "load node list (output of 'btrfs-recs inspect [rebuild-mappings] list-nodes') from external JSON file `nodes.json`") noError(argparser.MarkPersistentFlagFilename("node-list")) - argparser.PersistentFlags().BoolVar(&globalFlags.rebuildV1, "rebuild", false, - "attempt to rebuild broken btrees when reading (v1)") - - argparser.PersistentFlags().BoolVar(&globalFlags.rebuildV2, "rebuild-v2", false, - "attempt to rebuild broken btrees when reading (v2)") + argparser.PersistentFlags().BoolVar(&globalFlags.rebuild, "rebuild", false, + "attempt to rebuild broken btrees when reading") globalFlags.stopProfiling = profile.AddProfileFlags(argparser.PersistentFlags(), "profile.") @@ -214,9 +210,7 @@ func runWithRawFSAndNodeList(runE func(*btrfs.FS, []btrfsvol.LogicalAddr, *cobra func _runWithReadableFS(wantNodeList bool, runE func(btrfs.ReadableFS, []btrfsvol.LogicalAddr, *cobra.Command, []string) error) func(*cobra.Command, []string) error { inner := func(fs *btrfs.FS, nodeList []btrfsvol.LogicalAddr, cmd *cobra.Command, args []string) error { var rfs btrfs.ReadableFS = fs - if globalFlags.rebuildV1 { - rfs = btrfsutil.NewOldRebuiltForrest(fs) - } else if globalFlags.rebuildV2 { + if globalFlags.rebuild { ctx := cmd.Context() graph, err := btrfsutil.ReadGraph(ctx, fs, nodeList) @@ -231,7 +225,7 @@ func _runWithReadableFS(wantNodeList bool, runE func(btrfs.ReadableFS, []btrfsvo } return func(cmd *cobra.Command, args []string) error { - if wantNodeList || globalFlags.rebuildV2 { + if wantNodeList || globalFlags.rebuild { return runWithRawFSAndNodeList(inner)(cmd, args) } return runWithRawFS(func(fs *btrfs.FS, cmd *cobra.Command, args []string) error { -- cgit v1.2.3-2-g168b From 6630e28213a6c5f506d6a6d6f3e764a42c967163 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Sun, 5 Mar 2023 11:40:32 -0700 Subject: btrfsutil: RebuiltForrest: Add a .RebuiltAddRoots() method, cmd/btrfs-rec: Add a --trees flag --- cmd/btrfs-rec/main.go | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) (limited to 'cmd') diff --git a/cmd/btrfs-rec/main.go b/cmd/btrfs-rec/main.go index e167095..39ba9ef 100644 --- a/cmd/btrfs-rec/main.go +++ b/cmd/btrfs-rec/main.go @@ -17,8 +17,10 @@ import ( "github.com/spf13/cobra" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs" + "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/btrfsutil" + "git.lukeshu.com/btrfs-progs-ng/lib/containers" "git.lukeshu.com/btrfs-progs-ng/lib/profile" "git.lukeshu.com/btrfs-progs-ng/lib/textui" ) @@ -49,9 +51,10 @@ var globalFlags struct { logLevel textui.LogLevelFlag pvs []string - mappings string - nodeList string - rebuild bool + mappings string + nodeList string + rebuild bool + treeRoots string stopProfiling profile.StopFunc @@ -104,6 +107,10 @@ func main() { argparser.PersistentFlags().BoolVar(&globalFlags.rebuild, "rebuild", false, "attempt to rebuild broken btrees when reading") + argparser.PersistentFlags().StringVar(&globalFlags.treeRoots, "trees", "", + "load list of tree roots (output of 'btrfs-recs inspect rebuild-trees') from external JSON file `trees.json`; implies --rebuild") + noError(argparser.MarkPersistentFlagFilename("trees")) + globalFlags.stopProfiling = profile.AddProfileFlags(argparser.PersistentFlags(), "profile.") globalFlags.openFlag = os.O_RDONLY @@ -210,7 +217,7 @@ func runWithRawFSAndNodeList(runE func(*btrfs.FS, []btrfsvol.LogicalAddr, *cobra func _runWithReadableFS(wantNodeList bool, runE func(btrfs.ReadableFS, []btrfsvol.LogicalAddr, *cobra.Command, []string) error) func(*cobra.Command, []string) error { inner := func(fs *btrfs.FS, nodeList []btrfsvol.LogicalAddr, cmd *cobra.Command, args []string) error { var rfs btrfs.ReadableFS = fs - if globalFlags.rebuild { + if globalFlags.rebuild || globalFlags.treeRoots != "" { ctx := cmd.Context() graph, err := btrfsutil.ReadGraph(ctx, fs, nodeList) @@ -218,14 +225,24 @@ func _runWithReadableFS(wantNodeList bool, runE func(btrfs.ReadableFS, []btrfsvo return err } - rfs = btrfsutil.NewRebuiltForrest(fs, graph, nil, true) + _rfs := btrfsutil.NewRebuiltForrest(fs, graph, nil, true) + + if globalFlags.treeRoots != "" { + roots, err := readJSONFile[map[btrfsprim.ObjID]containers.Set[btrfsvol.LogicalAddr]](ctx, globalFlags.treeRoots) + if err != nil { + return err + } + _rfs.RebuiltAddRoots(ctx, roots) + } + + rfs = _rfs } return runE(rfs, nodeList, cmd, args) } return func(cmd *cobra.Command, args []string) error { - if wantNodeList || globalFlags.rebuild { + if wantNodeList || globalFlags.rebuild || globalFlags.treeRoots != "" { return runWithRawFSAndNodeList(inner)(cmd, args) } return runWithRawFS(func(fs *btrfs.FS, cmd *cobra.Command, args []string) error { -- cgit v1.2.3-2-g168b