From 4047078908cc0732642f5807636f37b6580e7cd7 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 17 Aug 2022 21:49:54 -0600 Subject: rename: Split some files up --- lib/btrfsprogs/btrfsinspect/allsums.go | 214 +++++++++++++++++++++++++ lib/btrfsprogs/btrfsinspect/csums.go | 203 ----------------------- lib/btrfsprogs/btrfsinspect/rebuildmappings.go | 130 +++++++++++++++ lib/btrfsprogs/btrfsinspect/scandevices.go | 116 -------------- 4 files changed, 344 insertions(+), 319 deletions(-) create mode 100644 lib/btrfsprogs/btrfsinspect/allsums.go create mode 100644 lib/btrfsprogs/btrfsinspect/rebuildmappings.go 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 +// +// 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 +// +// 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) { -- cgit v1.2.3-2-g168b