summaryrefslogtreecommitdiff
path: root/lib/btrfsprogs/btrfsinspect/rebuildmappings/rebuildmappings.go
diff options
context:
space:
mode:
Diffstat (limited to 'lib/btrfsprogs/btrfsinspect/rebuildmappings/rebuildmappings.go')
-rw-r--r--lib/btrfsprogs/btrfsinspect/rebuildmappings/rebuildmappings.go222
1 files changed, 0 insertions, 222 deletions
diff --git a/lib/btrfsprogs/btrfsinspect/rebuildmappings/rebuildmappings.go b/lib/btrfsprogs/btrfsinspect/rebuildmappings/rebuildmappings.go
deleted file mode 100644
index cdf5e5a..0000000
--- a/lib/btrfsprogs/btrfsinspect/rebuildmappings/rebuildmappings.go
+++ /dev/null
@@ -1,222 +0,0 @@
-// Copyright (C) 2022-2023 Luke Shumaker <lukeshu@lukeshu.com>
-//
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-package rebuildmappings
-
-import (
- "context"
- "fmt"
-
- "github.com/datawire/dlib/dlog"
-
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsinspect"
- "git.lukeshu.com/btrfs-progs-ng/lib/containers"
- "git.lukeshu.com/btrfs-progs-ng/lib/maps"
- "git.lukeshu.com/btrfs-progs-ng/lib/textui"
-)
-
-func getNodeSize(fs *btrfs.FS) (btrfsvol.AddrDelta, error) {
- sb, err := fs.Superblock()
- if err != nil {
- return 0, err
- }
- return btrfsvol.AddrDelta(sb.NodeSize), nil
-}
-
-func RebuildMappings(ctx context.Context, fs *btrfs.FS, scanResults btrfsinspect.ScanDevicesResult) error {
- nodeSize, err := getNodeSize(fs)
- if err != nil {
- return err
- }
-
- var numChunks, numDevExts, numBlockGroups, numNodes int
- devIDs := maps.SortedKeys(scanResults)
- devices := fs.LV.PhysicalVolumes()
- for _, devID := range devIDs {
- if _, ok := devices[devID]; !ok {
- return fmt.Errorf("device ID %v mentioned in scan results is not part of the filesystem", devID)
- }
- devResults := scanResults[devID]
- numChunks += len(devResults.FoundChunks)
- numDevExts += len(devResults.FoundDevExtents)
- numBlockGroups += len(devResults.FoundBlockGroups)
- for _, paddrs := range devResults.FoundNodes {
- numNodes += len(paddrs)
- }
- }
- dlog.Infof(ctx, "plan: 1/6 process %d chunks", numChunks)
- dlog.Infof(ctx, "plan: 2/6 process %d device extents", numDevExts)
- dlog.Infof(ctx, "plan: 3/6 process %d nodes", numNodes)
- dlog.Infof(ctx, "plan: 4/6 process %d block groups", numBlockGroups)
- dlog.Infof(ctx, "plan: 5/6 search for block groups in checksum map (exact)")
- dlog.Infof(ctx, "plan: 6/6 search for block groups in checksum map (fuzzy)")
-
- _ctx := ctx
- ctx = dlog.WithField(_ctx, "btrfsinspect.rebuild-mappings.step", "1/6")
- dlog.Infof(_ctx, "1/6: Processing %d chunks...", numChunks)
- for _, devID := range devIDs {
- devResults := scanResults[devID]
- for _, chunk := range devResults.FoundChunks {
- for _, mapping := range chunk.Chunk.Mappings(chunk.Key) {
- if err := fs.LV.AddMapping(mapping); err != nil {
- dlog.Errorf(ctx, "error: adding chunk: %v", err)
- }
- }
- }
- }
- dlog.Info(_ctx, "... done processing chunks")
-
- ctx = dlog.WithField(_ctx, "btrfsinspect.rebuild-mappings.step", "2/6")
- dlog.Infof(_ctx, "2/6: Processing %d device extents...", numDevExts)
- for _, devID := range devIDs {
- devResults := scanResults[devID]
- for _, ext := range devResults.FoundDevExtents {
- if err := fs.LV.AddMapping(ext.DevExt.Mapping(ext.Key)); err != nil {
- dlog.Errorf(ctx, "error: adding devext: %v", err)
- }
- }
- }
- dlog.Info(_ctx, "... done processing device extents")
-
- // Do the nodes "last" to avoid bloating the mappings table
- // too much. (Because nodes are numerous and small, while the
- // others are few and large; so it is likely that many of the
- // nodes will be subsumed by other things.)
- ctx = dlog.WithField(_ctx, "btrfsinspect.rebuild-mappings.step", "3/6")
- dlog.Infof(_ctx, "3/6: Processing %d nodes...", numNodes)
- for _, devID := range devIDs {
- devResults := scanResults[devID]
- // Sort them so that progress numbers are predictable.
- for _, laddr := range maps.SortedKeys(devResults.FoundNodes) {
- for _, paddr := range devResults.FoundNodes[laddr] {
- if err := fs.LV.AddMapping(btrfsvol.Mapping{
- LAddr: laddr,
- PAddr: btrfsvol.QualifiedPhysicalAddr{
- Dev: devID,
- Addr: paddr,
- },
- Size: nodeSize,
- SizeLocked: false,
- }); err != nil {
- dlog.Errorf(ctx, "error: adding node ident: %v", err)
- }
- }
- }
- }
- dlog.Info(_ctx, "... done processing nodes")
-
- // Use block groups to add missing flags (and as a hint to
- // combine node entries).
- ctx = dlog.WithField(_ctx, "btrfsinspect.rebuild-mappings.step", "4/6")
- dlog.Infof(_ctx, "4/6: Processing %d block groups...", numBlockGroups)
- // First dedup them, because they change for allocations and
- // CoW means that they'll bounce around a lot, so you likely
- // have oodles of duplicates?
- bgs, err := DedupBlockGroups(scanResults)
- if err != nil {
- return err
- }
- dlog.Infof(ctx, "... de-duplicated to %d block groups", len(bgs))
- for _, bgLAddr := range maps.SortedKeys(bgs) {
- bg := bgs[bgLAddr]
- otherLAddr, otherPAddr := fs.LV.ResolveAny(bg.LAddr, bg.Size)
- if otherLAddr < 0 || otherPAddr.Addr < 0 {
- dlog.Errorf(ctx, "error: could not pair blockgroup laddr=%v (size=%v flags=%v) with a mapping",
- bg.LAddr, bg.Size, bg.Flags)
- continue
- }
-
- offsetWithinChunk := otherLAddr.Sub(bg.LAddr)
- mapping := btrfsvol.Mapping{
- LAddr: bg.LAddr,
- PAddr: otherPAddr.Add(-offsetWithinChunk),
- Size: bg.Size,
- SizeLocked: true,
- Flags: containers.Optional[btrfsvol.BlockGroupFlags]{
- OK: true,
- Val: bg.Flags,
- },
- }
- if err := fs.LV.AddMapping(mapping); err != nil {
- dlog.Errorf(ctx, "error: adding flags from blockgroup: %v", err)
- continue
- }
- delete(bgs, bgLAddr)
- }
- dlog.Info(_ctx, "... done processing block groups")
-
- // More than once, I've been tempted to get rid of this exact-search step and just have the fuzzy-search step.
- // After all, looking at the timestamps in the log, it's faster per blockgroup! For some background, the big-O
- // for each (per blockgroup) looks like:
- //
- // - exact-search: O(bgSize+physicalBlocks)
- // - fuzzy-search: O(bgSize*physicalBlocks) worst-case; O(bgSize*log(physicalBlocks)) expected
- //
- // The fuzzy-search is only fast because the exact-search is so good at getting `physicalBlocks` down.
- // Empirically: if I remove the exact-search step, then the fuzzy-match step is more than an order of magnitude
- // slower.
- ctx = dlog.WithField(_ctx, "btrfsinspect.rebuild-mappings.step", "5/6")
- dlog.Infof(_ctx, "5/6: Searching for %d block groups in checksum map (exact)...", len(bgs))
- physicalSums := ExtractPhysicalSums(scanResults)
- logicalSums := ExtractLogicalSums(ctx, scanResults)
- if err := matchBlockGroupSums(ctx, fs, bgs, physicalSums, logicalSums); err != nil {
- return err
- }
- dlog.Info(ctx, "... done searching for exact block groups")
-
- ctx = dlog.WithField(_ctx, "btrfsinspect.rebuild-mappings.step", "6/6")
- dlog.Infof(_ctx, "6/6: Searching for %d block groups in checksum map (fuzzy)...", len(bgs))
- if err := fuzzyMatchBlockGroupSums(ctx, fs, bgs, physicalSums, logicalSums); err != nil {
- return err
- }
- dlog.Info(_ctx, "... done searching for fuzzy block groups")
-
- ctx = dlog.WithField(_ctx, "btrfsinspect.rebuild-mappings.step", "report")
- dlog.Info(_ctx, "report:")
-
- unmappedPhysicalRegions := ListUnmappedPhysicalRegions(fs)
- var unmappedPhysical btrfsvol.AddrDelta
- var numUnmappedPhysical int
- for _, devRegions := range unmappedPhysicalRegions {
- numUnmappedPhysical += len(devRegions)
- for _, region := range devRegions {
- unmappedPhysical += region.End.Sub(region.Beg)
- }
- }
- dlog.Infof(ctx, "... %d of unmapped physical space (across %d regions)", textui.IEC(unmappedPhysical, "B"), numUnmappedPhysical)
-
- unmappedLogicalRegions := ListUnmappedLogicalRegions(fs, logicalSums)
- var unmappedLogical btrfsvol.AddrDelta
- for _, region := range unmappedLogicalRegions {
- unmappedLogical += region.Size()
- }
- dlog.Infof(ctx, "... %d of unmapped summed logical space (across %d regions)", textui.IEC(unmappedLogical, "B"), len(unmappedLogicalRegions))
-
- var unmappedBlockGroups btrfsvol.AddrDelta
- for _, bg := range bgs {
- unmappedBlockGroups += bg.Size
- }
- dlog.Infof(ctx, "... %d of unmapped block groups (across %d groups)", textui.IEC(unmappedBlockGroups, "B"), len(bgs))
-
- dlog.Info(_ctx, "detailed report:")
- for _, devID := range maps.SortedKeys(unmappedPhysicalRegions) {
- for _, region := range unmappedPhysicalRegions[devID] {
- dlog.Infof(ctx, "... unmapped physical region: dev=%v beg=%v end=%v (size=%v)",
- devID, region.Beg, region.End, region.End.Sub(region.Beg))
- }
- }
- for _, region := range unmappedLogicalRegions {
- dlog.Infof(ctx, "... umapped summed logical region: beg=%v end=%v (size=%v)",
- region.Addr, region.Addr.Add(region.Size()), region.Size())
- }
- for _, laddr := range maps.SortedKeys(bgs) {
- bg := bgs[laddr]
- dlog.Infof(ctx, "... umapped block group: beg=%v end=%v (size=%v) flags=%v",
- bg.LAddr, bg.LAddr.Add(bg.Size), bg.Size, bg.Flags)
- }
-
- return nil
-}