summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2022-08-17 21:49:54 -0600
committerLuke Shumaker <lukeshu@lukeshu.com>2022-08-17 22:49:50 -0600
commit4047078908cc0732642f5807636f37b6580e7cd7 (patch)
treefa1736e7c089e6f836fb357aea7934246c5a63ea
parentff28ac9487ceb162bdef47f0639ce9a6c0cc7c28 (diff)
rename: Split some files up
-rw-r--r--lib/btrfsprogs/btrfsinspect/allsums.go214
-rw-r--r--lib/btrfsprogs/btrfsinspect/csums.go203
-rw-r--r--lib/btrfsprogs/btrfsinspect/rebuildmappings.go130
-rw-r--r--lib/btrfsprogs/btrfsinspect/scandevices.go116
4 files changed, 344 insertions, 319 deletions
diff --git a/lib/btrfsprogs/btrfsinspect/allsums.go b/lib/btrfsprogs/btrfsinspect/allsums.go
new file mode 100644
index 0000000..e18555f
--- /dev/null
+++ b/lib/btrfsprogs/btrfsinspect/allsums.go
@@ -0,0 +1,214 @@
+// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com>
+//
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package btrfsinspect
+
+import (
+ "context"
+ "encoding/gob"
+ "io"
+ "math"
+ "os"
+ "runtime"
+ "strings"
+ "sync"
+
+ "github.com/datawire/dlib/dgroup"
+ "github.com/datawire/dlib/dlog"
+
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsitem"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfssum"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsutil"
+)
+
+type AllSums struct {
+ Logical []SumRun[btrfsvol.LogicalAddr]
+ Physical map[btrfsvol.DeviceID]SumRun[btrfsvol.PhysicalAddr]
+}
+
+func (as AllSums) SumForPAddr(paddr btrfsvol.QualifiedPhysicalAddr) (ShortSum, bool) {
+ run, ok := as.Physical[paddr.Dev]
+ if !ok {
+ return "", false
+ }
+ return run.SumForAddr(paddr.Addr)
+}
+
+func (as AllSums) RunForLAddr(laddr btrfsvol.LogicalAddr) (SumRun[btrfsvol.LogicalAddr], btrfsvol.LogicalAddr, bool) {
+ for _, run := range as.Logical {
+ if run.Addr > laddr {
+ return SumRun[btrfsvol.LogicalAddr]{}, run.Addr, false
+ }
+ if run.Addr.Add(run.Size()) <= laddr {
+ continue
+ }
+ return run, 0, true
+ }
+ return SumRun[btrfsvol.LogicalAddr]{}, math.MaxInt64, false
+}
+
+func (as AllSums) SumForLAddr(laddr btrfsvol.LogicalAddr) (ShortSum, bool) {
+ run, _, ok := as.RunForLAddr(laddr)
+ if !ok {
+ return "", false
+ }
+ return run.SumForAddr(laddr)
+}
+
+func (as AllSums) WalkLogical(ctx context.Context, fn func(btrfsvol.LogicalAddr, ShortSum) error) error {
+ for _, run := range as.Logical {
+ if err := run.Walk(ctx, fn); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Read/Write AllSums ////////////////////////////////////////////////
+
+func ReadAllSums(filename string) (AllSums, error) {
+ fh, err := os.Open(filename)
+ if err != nil {
+ return AllSums{}, err
+ }
+ defer fh.Close()
+ var val AllSums
+ if err := gob.NewDecoder(fh).Decode(&val); err != nil {
+ return AllSums{}, err
+ }
+ return val, nil
+}
+
+func WriteAllSums(w io.Writer, sums AllSums) error {
+ return gob.NewEncoder(w).Encode(sums)
+}
+
+func SumEverything(ctx context.Context, fs *btrfs.FS) (AllSums, error) {
+ var ret AllSums
+
+ // ChecksumSize
+ var alg btrfssum.CSumType
+ var csumSize int
+ if err := func() error {
+ sb, err := fs.Superblock()
+ if err != nil {
+ return err
+ }
+ alg = sb.ChecksumType
+ csumSize = alg.Size()
+ return nil
+ }(); err != nil {
+ return ret, err
+ }
+
+ // Logical
+ dlog.Info(ctx, "Walking CSUM_TREE...")
+ func() {
+ var curAddr btrfsvol.LogicalAddr
+ var curSums strings.Builder
+ btrfsutil.NewBrokenTrees(ctx, fs).TreeWalk(ctx, btrfs.CSUM_TREE_OBJECTID,
+ func(err *btrfs.TreeError) {
+ dlog.Error(ctx, err)
+ },
+ btrfs.TreeWalkHandler{
+ Item: func(path btrfs.TreePath, item btrfs.Item) error {
+ if item.Key.ItemType != btrfsitem.EXTENT_CSUM_KEY {
+ return nil
+ }
+ body := item.Body.(btrfsitem.ExtentCSum)
+
+ for i, sum := range body.Sums {
+ laddr := btrfsvol.LogicalAddr(item.Key.Offset) + (btrfsvol.LogicalAddr(i) * btrfsitem.CSumBlockSize)
+ if laddr != curAddr+(btrfsvol.LogicalAddr(curSums.Len()/csumSize)*btrfsitem.CSumBlockSize) {
+ if curSums.Len() > 0 {
+ ret.Logical = append(ret.Logical, SumRun[btrfsvol.LogicalAddr]{
+ ChecksumSize: csumSize,
+ Addr: curAddr,
+ Sums: curSums.String(),
+ })
+ }
+ curAddr = laddr
+ curSums.Reset()
+ }
+ curSums.Write(sum[:csumSize])
+ }
+ return nil
+ },
+ },
+ )
+ if curSums.Len() > 0 {
+ ret.Logical = append(ret.Logical, SumRun[btrfsvol.LogicalAddr]{
+ ChecksumSize: csumSize,
+ Addr: curAddr,
+ Sums: curSums.String(),
+ })
+ }
+ }()
+ if err := ctx.Err(); err != nil {
+ return ret, err
+ }
+ dlog.Info(ctx, "... done walking")
+ runtime.GC()
+ dlog.Info(ctx, "... GC'd")
+
+ // Physical
+ dlog.Info(ctx, "Summing devices...")
+ if err := func() error {
+ devs := fs.LV.PhysicalVolumes()
+
+ var mu sync.Mutex
+ ret.Physical = make(map[btrfsvol.DeviceID]SumRun[btrfsvol.PhysicalAddr], len(devs))
+
+ grp := dgroup.NewGroup(ctx, dgroup.GroupConfig{})
+ for devID, dev := range devs {
+ devID, dev := devID, dev
+ grp.Go(dev.Name(), func(ctx context.Context) error {
+ devSize := dev.Size()
+ numSums := int(devSize / btrfsitem.CSumBlockSize)
+ sums := make([]byte, numSums*csumSize)
+ lastPct := -1
+ progress := func(curSum int) {
+ pct := int(100 * float64(curSum) / float64(numSums))
+ if pct != lastPct || curSum == numSums {
+ dlog.Infof(ctx, "... dev[%q] summed %v%%",
+ dev.Name(), pct)
+ lastPct = pct
+ }
+ }
+ for i := 0; i < numSums; i++ {
+ if err := ctx.Err(); err != nil {
+ return err
+ }
+ progress(i)
+ sum, err := btrfsutil.ChecksumPhysical(dev, alg, btrfsvol.PhysicalAddr(i*btrfsitem.CSumBlockSize))
+ if err != nil {
+ return err
+ }
+ copy(sums[i*csumSize:], sum[:csumSize])
+ }
+ progress(numSums)
+ sumsStr := string(sums)
+ mu.Lock()
+ ret.Physical[devID] = SumRun[btrfsvol.PhysicalAddr]{
+ ChecksumSize: csumSize,
+ Addr: 0,
+ Sums: sumsStr,
+ }
+ mu.Unlock()
+ return nil
+ })
+ }
+ return grp.Wait()
+ }(); err != nil {
+ return ret, err
+ }
+ dlog.Info(ctx, "... done summing devices")
+ runtime.GC()
+ dlog.Info(ctx, "... GC'd")
+
+ // Return
+ return ret, nil
+}
diff --git a/lib/btrfsprogs/btrfsinspect/csums.go b/lib/btrfsprogs/btrfsinspect/csums.go
index a062a77..78bf915 100644
--- a/lib/btrfsprogs/btrfsinspect/csums.go
+++ b/lib/btrfsprogs/btrfsinspect/csums.go
@@ -6,22 +6,10 @@ package btrfsinspect
import (
"context"
- "encoding/gob"
"io"
- "math"
- "os"
- "runtime"
- "strings"
- "sync"
- "github.com/datawire/dlib/dgroup"
- "github.com/datawire/dlib/dlog"
-
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsitem"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfssum"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsutil"
"git.lukeshu.com/btrfs-progs-ng/lib/diskio"
)
@@ -123,194 +111,3 @@ func (sg SumRunWithGaps[Addr]) Get(sumIdx int64) (ShortSum, error) {
addr := sg.Addr.Add(btrfsvol.AddrDelta(sumIdx) * btrfsitem.CSumBlockSize)
return sg.SumForAddr(addr)
}
-
-// AllSums ///////////////////////////////////////////////////////////
-
-type AllSums struct {
- Logical []SumRun[btrfsvol.LogicalAddr]
- Physical map[btrfsvol.DeviceID]SumRun[btrfsvol.PhysicalAddr]
-}
-
-func (as AllSums) SumForPAddr(paddr btrfsvol.QualifiedPhysicalAddr) (ShortSum, bool) {
- run, ok := as.Physical[paddr.Dev]
- if !ok {
- return "", false
- }
- return run.SumForAddr(paddr.Addr)
-}
-
-func (as AllSums) RunForLAddr(laddr btrfsvol.LogicalAddr) (SumRun[btrfsvol.LogicalAddr], btrfsvol.LogicalAddr, bool) {
- for _, run := range as.Logical {
- if run.Addr > laddr {
- return SumRun[btrfsvol.LogicalAddr]{}, run.Addr, false
- }
- if run.Addr.Add(run.Size()) <= laddr {
- continue
- }
- return run, 0, true
- }
- return SumRun[btrfsvol.LogicalAddr]{}, math.MaxInt64, false
-}
-
-func (as AllSums) SumForLAddr(laddr btrfsvol.LogicalAddr) (ShortSum, bool) {
- run, _, ok := as.RunForLAddr(laddr)
- if !ok {
- return "", false
- }
- return run.SumForAddr(laddr)
-}
-
-func (as AllSums) WalkLogical(ctx context.Context, fn func(btrfsvol.LogicalAddr, ShortSum) error) error {
- for _, run := range as.Logical {
- if err := run.Walk(ctx, fn); err != nil {
- return err
- }
- }
- return nil
-}
-
-// Read/Write AllSums ////////////////////////////////////////////////
-
-func ReadAllSums(filename string) (AllSums, error) {
- fh, err := os.Open(filename)
- if err != nil {
- return AllSums{}, err
- }
- defer fh.Close()
- var val AllSums
- if err := gob.NewDecoder(fh).Decode(&val); err != nil {
- return AllSums{}, err
- }
- return val, nil
-}
-
-func WriteAllSums(w io.Writer, sums AllSums) error {
- return gob.NewEncoder(w).Encode(sums)
-}
-
-func SumEverything(ctx context.Context, fs *btrfs.FS) (AllSums, error) {
- var ret AllSums
-
- // ChecksumSize
- var alg btrfssum.CSumType
- var csumSize int
- if err := func() error {
- sb, err := fs.Superblock()
- if err != nil {
- return err
- }
- alg = sb.ChecksumType
- csumSize = alg.Size()
- return nil
- }(); err != nil {
- return ret, err
- }
-
- // Logical
- dlog.Info(ctx, "Walking CSUM_TREE...")
- func() {
- var curAddr btrfsvol.LogicalAddr
- var curSums strings.Builder
- btrfsutil.NewBrokenTrees(ctx, fs).TreeWalk(ctx, btrfs.CSUM_TREE_OBJECTID,
- func(err *btrfs.TreeError) {
- dlog.Error(ctx, err)
- },
- btrfs.TreeWalkHandler{
- Item: func(path btrfs.TreePath, item btrfs.Item) error {
- if item.Key.ItemType != btrfsitem.EXTENT_CSUM_KEY {
- return nil
- }
- body := item.Body.(btrfsitem.ExtentCSum)
-
- for i, sum := range body.Sums {
- laddr := btrfsvol.LogicalAddr(item.Key.Offset) + (btrfsvol.LogicalAddr(i) * btrfsitem.CSumBlockSize)
- if laddr != curAddr+(btrfsvol.LogicalAddr(curSums.Len()/csumSize)*btrfsitem.CSumBlockSize) {
- if curSums.Len() > 0 {
- ret.Logical = append(ret.Logical, SumRun[btrfsvol.LogicalAddr]{
- ChecksumSize: csumSize,
- Addr: curAddr,
- Sums: curSums.String(),
- })
- }
- curAddr = laddr
- curSums.Reset()
- }
- curSums.Write(sum[:csumSize])
- }
- return nil
- },
- },
- )
- if curSums.Len() > 0 {
- ret.Logical = append(ret.Logical, SumRun[btrfsvol.LogicalAddr]{
- ChecksumSize: csumSize,
- Addr: curAddr,
- Sums: curSums.String(),
- })
- }
- }()
- if err := ctx.Err(); err != nil {
- return ret, err
- }
- dlog.Info(ctx, "... done walking")
- runtime.GC()
- dlog.Info(ctx, "... GC'd")
-
- // Physical
- dlog.Info(ctx, "Summing devices...")
- if err := func() error {
- devs := fs.LV.PhysicalVolumes()
-
- var mu sync.Mutex
- ret.Physical = make(map[btrfsvol.DeviceID]SumRun[btrfsvol.PhysicalAddr], len(devs))
-
- grp := dgroup.NewGroup(ctx, dgroup.GroupConfig{})
- for devID, dev := range devs {
- devID, dev := devID, dev
- grp.Go(dev.Name(), func(ctx context.Context) error {
- devSize := dev.Size()
- numSums := int(devSize / btrfsitem.CSumBlockSize)
- sums := make([]byte, numSums*csumSize)
- lastPct := -1
- progress := func(curSum int) {
- pct := int(100 * float64(curSum) / float64(numSums))
- if pct != lastPct || curSum == numSums {
- dlog.Infof(ctx, "... dev[%q] summed %v%%",
- dev.Name(), pct)
- lastPct = pct
- }
- }
- for i := 0; i < numSums; i++ {
- if err := ctx.Err(); err != nil {
- return err
- }
- progress(i)
- sum, err := btrfsutil.ChecksumPhysical(dev, alg, btrfsvol.PhysicalAddr(i*btrfsitem.CSumBlockSize))
- if err != nil {
- return err
- }
- copy(sums[i*csumSize:], sum[:csumSize])
- }
- progress(numSums)
- sumsStr := string(sums)
- mu.Lock()
- ret.Physical[devID] = SumRun[btrfsvol.PhysicalAddr]{
- ChecksumSize: csumSize,
- Addr: 0,
- Sums: sumsStr,
- }
- mu.Unlock()
- return nil
- })
- }
- return grp.Wait()
- }(); err != nil {
- return ret, err
- }
- dlog.Info(ctx, "... done summing devices")
- runtime.GC()
- dlog.Info(ctx, "... GC'd")
-
- // Return
- return ret, nil
-}
diff --git a/lib/btrfsprogs/btrfsinspect/rebuildmappings.go b/lib/btrfsprogs/btrfsinspect/rebuildmappings.go
new file mode 100644
index 0000000..bbfd6b7
--- /dev/null
+++ b/lib/btrfsprogs/btrfsinspect/rebuildmappings.go
@@ -0,0 +1,130 @@
+// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com>
+//
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package btrfsinspect
+
+import (
+ "context"
+ "sort"
+
+ "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/containers"
+ "git.lukeshu.com/btrfs-progs-ng/lib/maps"
+)
+
+func (found ScanOneDeviceResult) AddToLV(ctx context.Context, fs *btrfs.FS, dev *btrfs.Device) {
+ sb, _ := dev.Superblock()
+
+ total := len(found.FoundChunks) + len(found.FoundDevExtents)
+ for _, paddrs := range found.FoundNodes {
+ total += len(paddrs)
+ }
+ lastProgress := -1
+ done := 0
+ printProgress := func() {
+ pct := int(100 * float64(done) / float64(total))
+ if pct != lastProgress || done == total {
+ dlog.Infof(ctx, "... dev[%q] added %v%% of the mappings (%v/%v=>%v)",
+ dev.Name(), pct, done, total, len(fs.LV.Mappings()))
+ lastProgress = pct
+ }
+ }
+ printProgress()
+
+ for _, chunk := range found.FoundChunks {
+ for _, mapping := range chunk.Chunk.Mappings(chunk.Key) {
+ if err := fs.LV.AddMapping(mapping); err != nil {
+ dlog.Errorf(ctx, "... dev[%q] error: adding chunk: %v",
+ dev.Name(), err)
+ }
+ done++
+ printProgress()
+ }
+ }
+
+ for _, ext := range found.FoundDevExtents {
+ if err := fs.LV.AddMapping(ext.DevExt.Mapping(ext.Key)); err != nil {
+ dlog.Errorf(ctx, "... dev[%q] error: adding devext: %v",
+ dev.Name(), err)
+ }
+ done++
+ printProgress()
+ }
+
+ // 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.)
+ //
+ // Sort them so that progress numbers are predictable.
+ for _, laddr := range maps.SortedKeys(found.FoundNodes) {
+ for _, paddr := range found.FoundNodes[laddr] {
+ if err := fs.LV.AddMapping(btrfsvol.Mapping{
+ LAddr: laddr,
+ PAddr: btrfsvol.QualifiedPhysicalAddr{
+ Dev: sb.DevItem.DevID,
+ Addr: paddr,
+ },
+ Size: btrfsvol.AddrDelta(sb.NodeSize),
+ SizeLocked: false,
+ }); err != nil {
+ dlog.Errorf(ctx, "... dev[%q] error: adding node ident: %v",
+ dev.Name(), err)
+ }
+ done++
+ printProgress()
+ }
+ }
+
+ // Use block groups to add missing flags (and as a hint to
+ // combine node entries).
+ //
+ // 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?
+ type blockgroup struct {
+ LAddr btrfsvol.LogicalAddr
+ Size btrfsvol.AddrDelta
+ Flags btrfsvol.BlockGroupFlags
+ }
+ bgsSet := make(map[blockgroup]struct{})
+ for _, bg := range found.FoundBlockGroups {
+ bgsSet[blockgroup{
+ LAddr: btrfsvol.LogicalAddr(bg.Key.ObjectID),
+ Size: btrfsvol.AddrDelta(bg.Key.Offset),
+ Flags: bg.BG.Flags,
+ }] = struct{}{}
+ }
+ bgsOrdered := maps.Keys(bgsSet)
+ sort.Slice(bgsOrdered, func(i, j int) bool {
+ return bgsOrdered[i].LAddr < bgsOrdered[j].LAddr
+ })
+ for _, bg := range bgsOrdered {
+ otherLAddr, otherPAddr := fs.LV.ResolveAny(bg.LAddr, bg.Size)
+ if otherLAddr < 0 || otherPAddr.Addr < 0 {
+ dlog.Errorf(ctx, "... dev[%q] error: could not pair blockgroup laddr=%v (size=%v flags=%v) with a mapping",
+ dev.Name(), 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, "... dev[%q] error: adding flags from blockgroup: %v",
+ dev.Name(), err)
+ }
+ }
+}
diff --git a/lib/btrfsprogs/btrfsinspect/scandevices.go b/lib/btrfsprogs/btrfsinspect/scandevices.go
index 13c5d60..8094ab0 100644
--- a/lib/btrfsprogs/btrfsinspect/scandevices.go
+++ b/lib/btrfsprogs/btrfsinspect/scandevices.go
@@ -6,16 +6,13 @@ package btrfsinspect
import (
"context"
- "sort"
"github.com/datawire/dlib/dlog"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsitem"
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol"
- "git.lukeshu.com/btrfs-progs-ng/lib/containers"
"git.lukeshu.com/btrfs-progs-ng/lib/diskio"
- "git.lukeshu.com/btrfs-progs-ng/lib/maps"
)
type ScanOneDeviceResult struct {
@@ -35,119 +32,6 @@ type SysDevExtent struct {
DevExt btrfsitem.DevExtent
}
-func (found ScanOneDeviceResult) AddToLV(ctx context.Context, fs *btrfs.FS, dev *btrfs.Device) {
- sb, _ := dev.Superblock()
-
- total := len(found.FoundChunks) + len(found.FoundDevExtents)
- for _, paddrs := range found.FoundNodes {
- total += len(paddrs)
- }
- lastProgress := -1
- done := 0
- printProgress := func() {
- pct := int(100 * float64(done) / float64(total))
- if pct != lastProgress || done == total {
- dlog.Infof(ctx, "... dev[%q] added %v%% of the mappings (%v/%v=>%v)",
- dev.Name(), pct, done, total, len(fs.LV.Mappings()))
- lastProgress = pct
- }
- }
- printProgress()
-
- for _, chunk := range found.FoundChunks {
- for _, mapping := range chunk.Chunk.Mappings(chunk.Key) {
- if err := fs.LV.AddMapping(mapping); err != nil {
- dlog.Errorf(ctx, "... dev[%q] error: adding chunk: %v",
- dev.Name(), err)
- }
- done++
- printProgress()
- }
- }
-
- for _, ext := range found.FoundDevExtents {
- if err := fs.LV.AddMapping(ext.DevExt.Mapping(ext.Key)); err != nil {
- dlog.Errorf(ctx, "... dev[%q] error: adding devext: %v",
- dev.Name(), err)
- }
- done++
- printProgress()
- }
-
- // 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.)
- //
- // Sort them so that progress numbers are predictable.
- for _, laddr := range maps.SortedKeys(found.FoundNodes) {
- for _, paddr := range found.FoundNodes[laddr] {
- if err := fs.LV.AddMapping(btrfsvol.Mapping{
- LAddr: laddr,
- PAddr: btrfsvol.QualifiedPhysicalAddr{
- Dev: sb.DevItem.DevID,
- Addr: paddr,
- },
- Size: btrfsvol.AddrDelta(sb.NodeSize),
- SizeLocked: false,
- }); err != nil {
- dlog.Errorf(ctx, "... dev[%q] error: adding node ident: %v",
- dev.Name(), err)
- }
- done++
- printProgress()
- }
- }
-
- // Use block groups to add missing flags (and as a hint to
- // combine node entries).
- //
- // 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?
- type blockgroup struct {
- LAddr btrfsvol.LogicalAddr
- Size btrfsvol.AddrDelta
- Flags btrfsvol.BlockGroupFlags
- }
- bgsSet := make(map[blockgroup]struct{})
- for _, bg := range found.FoundBlockGroups {
- bgsSet[blockgroup{
- LAddr: btrfsvol.LogicalAddr(bg.Key.ObjectID),
- Size: btrfsvol.AddrDelta(bg.Key.Offset),
- Flags: bg.BG.Flags,
- }] = struct{}{}
- }
- bgsOrdered := maps.Keys(bgsSet)
- sort.Slice(bgsOrdered, func(i, j int) bool {
- return bgsOrdered[i].LAddr < bgsOrdered[j].LAddr
- })
- for _, bg := range bgsOrdered {
- otherLAddr, otherPAddr := fs.LV.ResolveAny(bg.LAddr, bg.Size)
- if otherLAddr < 0 || otherPAddr.Addr < 0 {
- dlog.Errorf(ctx, "... dev[%q] error: could not pair blockgroup laddr=%v (size=%v flags=%v) with a mapping",
- dev.Name(), 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, "... dev[%q] error: adding flags from blockgroup: %v",
- dev.Name(), err)
- }
- }
-}
-
// ScanOneDevice mostly mimics btrfs-progs
// cmds/rescue-chunk-recover.c:scan_one_device().
func ScanOneDevice(ctx context.Context, dev *btrfs.Device, superblock btrfs.Superblock) (ScanOneDeviceResult, error) {