summaryrefslogtreecommitdiff
path: root/cmd/btrfs-rec
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2023-03-07 12:10:42 -0700
committerLuke Shumaker <lukeshu@lukeshu.com>2023-03-14 21:31:45 -0600
commit3949bd3ff240bc6d06dd08f6e3183e72571e0e1d (patch)
tree08a3de7f9b043e3f7aee37cf25e827a87c762111 /cmd/btrfs-rec
parentd8f9c4d091f6c2554251941c933e4549502d2e84 (diff)
Expose node-lists as a thing on the CLI
Diffstat (limited to 'cmd/btrfs-rec')
-rw-r--r--cmd/btrfs-rec/inspect_listnodes.go51
-rw-r--r--cmd/btrfs-rec/inspect_lstrees.go23
-rw-r--r--cmd/btrfs-rec/inspect_rebuildmappings.go44
-rw-r--r--cmd/btrfs-rec/inspect_rebuildtrees.go46
-rw-r--r--cmd/btrfs-rec/util.go25
5 files changed, 144 insertions, 45 deletions
diff --git a/cmd/btrfs-rec/inspect_listnodes.go b/cmd/btrfs-rec/inspect_listnodes.go
new file mode 100644
index 0000000..d9b24ed
--- /dev/null
+++ b/cmd/btrfs-rec/inspect_listnodes.go
@@ -0,0 +1,51 @@
+// Copyright (C) 2022-2023 Luke Shumaker <lukeshu@lukeshu.com>
+//
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package main
+
+import (
+ "os"
+
+ "git.lukeshu.com/go/lowmemjson"
+ "github.com/datawire/dlib/dlog"
+ "github.com/datawire/ocibuild/pkg/cliutil"
+ "github.com/spf13/cobra"
+
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfsutil"
+)
+
+func init() {
+ inspectors.AddCommand(&cobra.Command{
+ Use: "list-nodes",
+ Short: "Scan the filesystem for btree nodes",
+ Long: "" +
+ "This scans the filesystem sector-by-sector looking for nodes. " +
+ "If you are needing to rebuild the chunk/dev-extent/blockgroup " +
+ "trees with `btrfs-rec inspect rebuild-mappings` anyway, you may " +
+ "want to instead use `btrfs-rec inspect rebuild-mappings list-nodes` " +
+ "to take advantage of the sector-by-sector scan that's already " +
+ "performed by `btrfs-rec inspect rebuild-mappings scan`.",
+ Args: cliutil.WrapPositionalArgs(cobra.ExactArgs(1)),
+ RunE: runWithRawFS(func(fs *btrfs.FS, cmd *cobra.Command, args []string) error {
+ ctx := cmd.Context()
+
+ nodeList, err := btrfsutil.ListNodes(ctx, fs)
+ if err != nil {
+ return err
+ }
+
+ dlog.Infof(ctx, "Writing nodes to stdout...")
+ if err := writeJSONFile(os.Stdout, nodeList, lowmemjson.ReEncoderConfig{
+ Indent: "\t",
+ ForceTrailingNewlines: true,
+ }); err != nil {
+ return err
+ }
+ dlog.Info(ctx, "... done writing")
+
+ return nil
+ }),
+ })
+}
diff --git a/cmd/btrfs-rec/inspect_lstrees.go b/cmd/btrfs-rec/inspect_lstrees.go
index 1ff7671..05c3a57 100644
--- a/cmd/btrfs-rec/inspect_lstrees.go
+++ b/cmd/btrfs-rec/inspect_lstrees.go
@@ -26,14 +26,24 @@ import (
)
func init() {
- var scandevicesFilename string
+ var nodeListFilename string
cmd := &cobra.Command{
Use: "ls-trees",
Short: "A brief view what types of items are in each tree",
- Args: cliutil.WrapPositionalArgs(cobra.NoArgs),
+ Long: "" +
+ "If no --node-list is given, then a slow sector-by-sector scan " +
+ "will be used to find all lost+found nodes.",
+ Args: cliutil.WrapPositionalArgs(cobra.NoArgs),
RunE: runWithRawFS(func(fs *btrfs.FS, cmd *cobra.Command, _ []string) error {
ctx := cmd.Context()
- nodeList, err := readNodeList(ctx, scandevicesFilename)
+
+ var nodeList []btrfsvol.LogicalAddr
+ var err error
+ if nodeListFilename != "" {
+ nodeList, err = readJSONFile[[]btrfsvol.LogicalAddr](ctx, nodeListFilename)
+ } else {
+ nodeList, err = btrfsutil.ListNodes(ctx, fs)
+ }
if err != nil {
return err
}
@@ -86,7 +96,7 @@ func init() {
},
})
- if scandevicesFilename != "" {
+ {
treeErrCnt = 0
treeItemCnt = make(map[btrfsitem.Type]int)
textui.Fprintf(os.Stdout, "lost+found\n")
@@ -114,8 +124,9 @@ func init() {
return nil
}),
}
- cmd.Flags().StringVar(&scandevicesFilename, "scandevices", "", "Output of 'btrfs-recs inspect rebuild-mappings scan' to use for a lost+found tree")
- noError(cmd.MarkFlagFilename("scandevices"))
+ cmd.Flags().StringVar(&nodeListFilename, "node-list", "",
+ "Output of 'btrfs-recs inspect [rebuild-mappings] list-nodes' to use for a lost+found tree")
+ noError(cmd.MarkFlagFilename("node-list"))
inspectors.AddCommand(cmd)
}
diff --git a/cmd/btrfs-rec/inspect_rebuildmappings.go b/cmd/btrfs-rec/inspect_rebuildmappings.go
index 9c6b1cc..b215e7a 100644
--- a/cmd/btrfs-rec/inspect_rebuildmappings.go
+++ b/cmd/btrfs-rec/inspect_rebuildmappings.go
@@ -14,6 +14,9 @@ import (
"git.lukeshu.com/btrfs-progs-ng/cmd/btrfs-rec/inspect/rebuildmappings"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol"
+ "git.lukeshu.com/btrfs-progs-ng/lib/containers"
+ "git.lukeshu.com/btrfs-progs-ng/lib/maps"
)
func init() {
@@ -118,5 +121,46 @@ func init() {
}),
})
+ cmd.AddCommand(&cobra.Command{
+ Use: "list-nodes",
+ Short: "Produce a listing of btree nodes from previously read data",
+ Long: "" +
+ "This is a variant of `btrfs-rec inspect list-nodes` that takes " +
+ "advantage of using previously read data from " +
+ "`btrfs-rec inspect rebuild-nodes scan`.",
+ Args: cliutil.WrapPositionalArgs(cobra.ExactArgs(1)),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ ctx := cmd.Context()
+
+ scanResults, err := readJSONFile[rebuildmappings.ScanDevicesResult](ctx, args[0])
+ if err != nil {
+ return err
+ }
+
+ var cnt int
+ for _, devResults := range scanResults {
+ cnt += len(devResults.FoundNodes)
+ }
+ set := make(containers.Set[btrfsvol.LogicalAddr], cnt)
+ for _, devResults := range scanResults {
+ for laddr := range devResults.FoundNodes {
+ set.Insert(laddr)
+ }
+ }
+ nodeList := maps.SortedKeys(set)
+
+ dlog.Infof(ctx, "Writing nodes to stdout...")
+ if err := writeJSONFile(os.Stdout, nodeList, lowmemjson.ReEncoderConfig{
+ Indent: "\t",
+ ForceTrailingNewlines: true,
+ }); err != nil {
+ return err
+ }
+ dlog.Info(ctx, "... done writing")
+
+ return nil
+ },
+ })
+
inspectors.AddCommand(cmd)
}
diff --git a/cmd/btrfs-rec/inspect_rebuildtrees.go b/cmd/btrfs-rec/inspect_rebuildtrees.go
index f66f287..676533a 100644
--- a/cmd/btrfs-rec/inspect_rebuildtrees.go
+++ b/cmd/btrfs-rec/inspect_rebuildtrees.go
@@ -5,7 +5,6 @@
package main
import (
- "context"
"os"
"runtime"
"time"
@@ -17,25 +16,39 @@ import (
"git.lukeshu.com/btrfs-progs-ng/cmd/btrfs-rec/inspect/rebuildtrees"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfsutil"
"git.lukeshu.com/btrfs-progs-ng/lib/textui"
)
func init() {
- inspectors.AddCommand(&cobra.Command{
- Use: "rebuild-trees NODESCAN.json",
- Args: cliutil.WrapPositionalArgs(cobra.ExactArgs(1)),
+ var nodeListFilename string
+ cmd := &cobra.Command{
+ Use: "rebuild-trees",
+ Long: "" +
+ "Rebuild broken btrees based on missing items that are implied " +
+ "by present items. This requires functioning " +
+ "chunk/dev-extent/blockgroup trees, which can be rebuilt " +
+ "separately with `btrfs-rec inspect rebuild-mappings`.\n" +
+ "\n" +
+ "If no --node-list is given, then a slow sector-by-sector scan " +
+ "will be used to find all nodes.",
+ Args: cliutil.WrapPositionalArgs(cobra.NoArgs),
RunE: runWithRawFS(func(fs *btrfs.FS, cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
- // This is wrapped in a func in order to *ensure* that `nodeList` goes out of scope once
- // `rebuilder` has been created.
- rebuilder, err := func(ctx context.Context) (rebuildtrees.Rebuilder, error) {
- nodeList, err := readNodeList(ctx, args[0])
- if err != nil {
- return nil, err
- }
- return rebuildtrees.NewRebuilder(ctx, fs, nodeList)
- }(ctx)
+ var nodeList []btrfsvol.LogicalAddr
+ var err error
+ if nodeListFilename != "" {
+ nodeList, err = readJSONFile[[]btrfsvol.LogicalAddr](ctx, nodeListFilename)
+ } else {
+ nodeList, err = btrfsutil.ListNodes(ctx, fs)
+ }
+ if err != nil {
+ return err
+ }
+
+ rebuilder, err := rebuildtrees.NewRebuilder(ctx, fs, nodeList)
if err != nil {
return err
}
@@ -65,5 +78,10 @@ func init() {
return rebuildErr
}),
- })
+ }
+ cmd.Flags().StringVar(&nodeListFilename, "node-list", "",
+ "Output of 'btrfs-recs inspect [rebuild-mappings] list-nodes' to use for the node list")
+ noError(cmd.MarkFlagFilename("node-list"))
+
+ inspectors.AddCommand(cmd)
}
diff --git a/cmd/btrfs-rec/util.go b/cmd/btrfs-rec/util.go
index 2e4bb84..3d751a6 100644
--- a/cmd/btrfs-rec/util.go
+++ b/cmd/btrfs-rec/util.go
@@ -13,10 +13,6 @@ import (
"git.lukeshu.com/go/lowmemjson"
"github.com/datawire/dlib/dlog"
- "git.lukeshu.com/btrfs-progs-ng/cmd/btrfs-rec/inspect/rebuildmappings"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol"
- "git.lukeshu.com/btrfs-progs-ng/lib/containers"
- "git.lukeshu.com/btrfs-progs-ng/lib/maps"
"git.lukeshu.com/btrfs-progs-ng/lib/streamio"
)
@@ -51,24 +47,3 @@ func writeJSONFile(w io.Writer, obj any, cfg lowmemjson.ReEncoderConfig) (err er
}()
return lowmemjson.NewEncoder(lowmemjson.NewReEncoder(buffer, cfg)).Encode(obj)
}
-
-func readNodeList(ctx context.Context, filename string) ([]btrfsvol.LogicalAddr, error) {
- if filename == "" {
- return nil, nil
- }
- results, err := readJSONFile[rebuildmappings.ScanDevicesResult](ctx, filename)
- if err != nil {
- return nil, err
- }
- var cnt int
- for _, devResults := range results {
- cnt += len(devResults.FoundNodes)
- }
- set := make(containers.Set[btrfsvol.LogicalAddr], cnt)
- for _, devResults := range results {
- for laddr := range devResults.FoundNodes {
- set.Insert(laddr)
- }
- }
- return maps.SortedKeys(set), nil
-}