summaryrefslogtreecommitdiff
path: root/cmd/btrfs-rec
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/btrfs-rec')
-rw-r--r--cmd/btrfs-rec/inspect/rebuildtrees/rebuild_treecb.go40
-rw-r--r--cmd/btrfs-rec/main.go33
2 files changed, 61 insertions, 12 deletions
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
+}
diff --git a/cmd/btrfs-rec/main.go b/cmd/btrfs-rec/main.go
index ad768de..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"
)
@@ -51,8 +53,8 @@ var globalFlags struct {
mappings string
nodeList string
- rebuildV1 bool
- rebuildV2 bool
+ rebuild bool
+ treeRoots string
stopProfiling profile.StopFunc
@@ -102,11 +104,12 @@ 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.rebuild, "rebuild", false,
+ "attempt to rebuild broken btrees when reading")
- argparser.PersistentFlags().BoolVar(&globalFlags.rebuildV2, "rebuild-v2", false,
- "attempt to rebuild broken btrees when reading (v2)")
+ 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.")
@@ -214,9 +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.rebuildV1 {
- rfs = btrfsutil.NewOldRebuiltForrest(fs)
- } else if globalFlags.rebuildV2 {
+ if globalFlags.rebuild || globalFlags.treeRoots != "" {
ctx := cmd.Context()
graph, err := btrfsutil.ReadGraph(ctx, fs, nodeList)
@@ -224,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.rebuildV2 {
+ if wantNodeList || globalFlags.rebuild || globalFlags.treeRoots != "" {
return runWithRawFSAndNodeList(inner)(cmd, args)
}
return runWithRawFS(func(fs *btrfs.FS, cmd *cobra.Command, args []string) error {