summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2023-07-22 21:18:40 -0600
committerLuke Shumaker <lukeshu@lukeshu.com>2023-07-25 12:55:22 -0600
commitb581d0ceb3cd0fee2e78c677bb0805cc68115661 (patch)
tree7345d8fb1b1d6b0221b6fac81e8c5c96cb6ed4d4
parent4afd0a5b438f0eda8af3be8018bc024daeb738c3 (diff)
rebuildmappings process: Don't require --pv
-rw-r--r--cmd/btrfs-rec/inspect/rebuildmappings/file_phony.go49
-rw-r--r--cmd/btrfs-rec/inspect_listnodes.go2
-rw-r--r--cmd/btrfs-rec/inspect_rebuildmappings.go32
-rw-r--r--cmd/btrfs-rec/main.go21
4 files changed, 94 insertions, 10 deletions
diff --git a/cmd/btrfs-rec/inspect/rebuildmappings/file_phony.go b/cmd/btrfs-rec/inspect/rebuildmappings/file_phony.go
new file mode 100644
index 0000000..a41a16b
--- /dev/null
+++ b/cmd/btrfs-rec/inspect/rebuildmappings/file_phony.go
@@ -0,0 +1,49 @@
+// Copyright (C) 2023 Luke Shumaker <lukeshu@lukeshu.com>
+//
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package rebuildmappings
+
+import (
+ "fmt"
+
+ "git.lukeshu.com/btrfs-progs-ng/lib/binstruct"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
+ "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"
+)
+
+type phonyFile struct {
+ size btrfsvol.PhysicalAddr
+ sb btrfstree.Superblock
+}
+
+var _ diskio.File[btrfsvol.PhysicalAddr] = (*phonyFile)(nil)
+
+func NewPhonyFile(size btrfsvol.PhysicalAddr, sb btrfstree.Superblock) *phonyFile {
+ return &phonyFile{
+ size: size,
+ sb: sb,
+ }
+}
+
+func (f *phonyFile) Name() string { return fmt.Sprintf("phony_file:device_id=%v", f.sb.DevItem.DevID) }
+func (f *phonyFile) Size() btrfsvol.PhysicalAddr { return f.size }
+func (*phonyFile) Close() error { return nil }
+
+func (f *phonyFile) ReadAt(p []byte, off btrfsvol.PhysicalAddr) (int, error) {
+ if len(p) == int(btrfs.SuperblockSize) && slices.Contains(off, btrfs.SuperblockAddrs) {
+ bs, err := binstruct.Marshal(f.sb)
+ if err != nil {
+ return 0, err
+ }
+ return copy(p, bs), nil
+ }
+ panic(fmt.Errorf("%T: should not happen: ReadAt should not be called for a phony file", f))
+}
+
+func (f *phonyFile) WriteAt([]byte, btrfsvol.PhysicalAddr) (int, error) {
+ panic(fmt.Errorf("%T: should not happen: WriteAt should not be called for a phony file", f))
+}
diff --git a/cmd/btrfs-rec/inspect_listnodes.go b/cmd/btrfs-rec/inspect_listnodes.go
index d9b24ed..eb088e8 100644
--- a/cmd/btrfs-rec/inspect_listnodes.go
+++ b/cmd/btrfs-rec/inspect_listnodes.go
@@ -28,7 +28,7 @@ func init() {
"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 {
+ RunE: runWithRawFS(nil, func(fs *btrfs.FS, cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
nodeList, err := btrfsutil.ListNodes(ctx, fs)
diff --git a/cmd/btrfs-rec/inspect_rebuildmappings.go b/cmd/btrfs-rec/inspect_rebuildmappings.go
index e883b93..dcd4b0a 100644
--- a/cmd/btrfs-rec/inspect_rebuildmappings.go
+++ b/cmd/btrfs-rec/inspect_rebuildmappings.go
@@ -5,6 +5,7 @@
package main
import (
+ "fmt"
"os"
"git.lukeshu.com/go/lowmemjson"
@@ -37,7 +38,7 @@ func init() {
"\tbtrfs-rec inspect rebuild-mappings scan > SCAN.json # read\n" +
"\tbtrfs-rec inspect rebuild-mappings process SCAN.json # CPU\n",
Args: cliutil.WrapPositionalArgs(cobra.NoArgs),
- RunE: runWithRawFS(func(fs *btrfs.FS, cmd *cobra.Command, args []string) error {
+ RunE: runWithRawFS(nil, func(fs *btrfs.FS, cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
scanResults, err := rebuildmappings.ScanDevices(ctx, fs)
@@ -67,7 +68,7 @@ func init() {
Use: "scan",
Short: "Read from the filesystem all data nescessary to rebuild the mappings",
Args: cliutil.WrapPositionalArgs(cobra.NoArgs),
- RunE: runWithRawFS(func(fs *btrfs.FS, cmd *cobra.Command, _ []string) (err error) {
+ RunE: runWithRawFS(nil, func(fs *btrfs.FS, cmd *cobra.Command, _ []string) (err error) {
ctx := cmd.Context()
devResults, err := rebuildmappings.ScanDevices(ctx, fs)
@@ -94,6 +95,7 @@ func init() {
}),
})
+ var scanResults rebuildmappings.ScanResult
cmd.AddCommand(&cobra.Command{
Use: "process",
Short: "Rebuild the mappings based on previously read data",
@@ -102,12 +104,36 @@ func init() {
ctx := cmd.Context()
dlog.Infof(ctx, "Reading %q...", args[0])
- scanResults, err := readJSONFile[rebuildmappings.ScanResult](ctx, args[0])
+ var err error
+ scanResults, err = readJSONFile[rebuildmappings.ScanResult](ctx, args[0])
if err != nil {
return err
}
dlog.Infof(ctx, "... done reading %q", args[0])
+ pvDevices := fs.LV.PhysicalVolumes()
+ for _, devID := range maps.SortedKeys(scanResults.Devices) {
+ if maps.HasKey(pvDevices, devID) {
+ continue
+ }
+ devFile := &btrfs.Device{
+ File: rebuildmappings.NewPhonyFile(
+ scanResults.Devices[devID].Size,
+ scanResults.Devices[devID].Superblock.Val),
+ }
+ if err := fs.AddDevice(ctx, devFile); err != nil {
+ return fmt.Errorf("device file: %q: %w", devFile.Name(), err)
+ }
+ }
+ for _, mapping := range scanResults.Mappings {
+ if err := fs.LV.AddMapping(mapping); err != nil {
+ return err
+ }
+ }
+ return nil
+ }, func(fs *btrfs.FS, cmd *cobra.Command, _ []string) error {
+ ctx := cmd.Context()
+
if err := rebuildmappings.RebuildMappings(ctx, fs, scanResults.Devices); err != nil {
return err
}
diff --git a/cmd/btrfs-rec/main.go b/cmd/btrfs-rec/main.go
index 258e35f..7f89369 100644
--- a/cmd/btrfs-rec/main.go
+++ b/cmd/btrfs-rec/main.go
@@ -159,7 +159,10 @@ func run(runE func(*cobra.Command, []string) error) func(*cobra.Command, []strin
}
}
-func runWithRawFS(runE func(*btrfs.FS, *cobra.Command, []string) error) func(*cobra.Command, []string) error {
+func runWithRawFS(
+ overrideInitChunks func(*btrfs.FS, *cobra.Command, []string) error,
+ runE func(*btrfs.FS, *cobra.Command, []string) error,
+) func(*cobra.Command, []string) error {
return run(func(cmd *cobra.Command, args []string) (err error) {
ctx := cmd.Context()
@@ -169,7 +172,7 @@ func runWithRawFS(runE func(*btrfs.FS, *cobra.Command, []string) error) func(*co
}
}
- if len(globalFlags.pvs) == 0 {
+ if len(globalFlags.pvs) == 0 && overrideInitChunks == nil {
// We do this here instead of calling argparser.MarkPersistentFlagRequired("pv") so that
// it doesn't interfere with the `help` sub-command.
return cliutil.FlagErrorFunc(cmd, fmt.Errorf("must specify 1 or more physical volumes with --pv"))
@@ -201,8 +204,14 @@ func runWithRawFS(runE func(*btrfs.FS, *cobra.Command, []string) error) func(*co
return fmt.Errorf("device file %q: %w", filename, err)
}
}
- if err := fs.InitChunks(ctx); err != nil {
- dlog.Errorf(ctx, "error: InitChunks: %v", err)
+ if overrideInitChunks != nil {
+ if err := overrideInitChunks(fs, cmd, args); err != nil {
+ return err
+ }
+ } else {
+ if err := fs.InitChunks(ctx); err != nil {
+ dlog.Errorf(ctx, "error: InitChunks: %v", err)
+ }
}
if globalFlags.mappings != "" {
@@ -222,7 +231,7 @@ func runWithRawFS(runE func(*btrfs.FS, *cobra.Command, []string) error) func(*co
}
func runWithRawFSAndNodeList(runE func(*btrfs.FS, []btrfsvol.LogicalAddr, *cobra.Command, []string) error) func(*cobra.Command, []string) error {
- return runWithRawFS(func(fs *btrfs.FS, cmd *cobra.Command, args []string) error {
+ return runWithRawFS(nil, func(fs *btrfs.FS, cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
var nodeList []btrfsvol.LogicalAddr
@@ -271,7 +280,7 @@ func _runWithReadableFS(wantNodeList bool, runE func(btrfs.ReadableFS, []btrfsvo
if wantNodeList || globalFlags.rebuild || globalFlags.treeRoots != "" {
return runWithRawFSAndNodeList(inner)(cmd, args)
}
- return runWithRawFS(func(fs *btrfs.FS, cmd *cobra.Command, args []string) error {
+ return runWithRawFS(nil, func(fs *btrfs.FS, cmd *cobra.Command, args []string) error {
return inner(fs, nil, cmd, args)
})(cmd, args)
}