diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2023-07-22 21:18:40 -0600 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2023-07-23 00:53:05 -0600 |
commit | cbb2379d822bf391e4f9d1ed7dab8fca0aa85c6d (patch) | |
tree | ede006affa164dd50ff9c21c7632ec691abf6640 /cmd/btrfs-rec | |
parent | 17a9ea959d2f77b1ba55d45ac3feaf918f42f7dd (diff) |
wip: rebuildmappings process: Don't require --pvlukeshu/process-without-pv
Diffstat (limited to 'cmd/btrfs-rec')
-rw-r--r-- | cmd/btrfs-rec/inspect/rebuildmappings/file_phony.go | 49 | ||||
-rw-r--r-- | cmd/btrfs-rec/inspect_listnodes.go | 2 | ||||
-rw-r--r-- | cmd/btrfs-rec/inspect_rebuildmappings.go | 29 | ||||
-rw-r--r-- | cmd/btrfs-rec/main.go | 17 |
4 files changed, 90 insertions, 7 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..4c194c7 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", @@ -108,6 +110,29 @@ func init() { } 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 39ba9ef..30b7e3d 100644 --- a/cmd/btrfs-rec/main.go +++ b/cmd/btrfs-rec/main.go @@ -158,7 +158,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( + fallbackInit 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) { maybeSetErr := func(_err error) { if _err != nil && err == nil { @@ -166,7 +169,7 @@ func runWithRawFS(runE func(*btrfs.FS, *cobra.Command, []string) error) func(*co } } - if len(globalFlags.pvs) == 0 { + if len(globalFlags.pvs) == 0 && fallbackInit == 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")) @@ -179,6 +182,12 @@ func runWithRawFS(runE func(*btrfs.FS, *cobra.Command, []string) error) func(*co maybeSetErr(fs.Close()) }() + if fallbackInit != nil { + if err := fallbackInit(fs, cmd, args); err != nil { + return err + } + } + if globalFlags.mappings != "" { mappingsJSON, err := readJSONFile[[]btrfsvol.Mapping](cmd.Context(), globalFlags.mappings) if err != nil { @@ -196,7 +205,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 @@ -245,7 +254,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) } |