summaryrefslogtreecommitdiff
path: root/lib/btrfsprogs
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2022-08-02 03:30:54 -0600
committerLuke Shumaker <lukeshu@lukeshu.com>2022-08-17 22:50:57 -0600
commit5afa6e03b8d6162b15e7edaa013e644f1931aaf9 (patch)
tree103c67d7e1a9ed277d3c5c8f711d8cfd275eff4e /lib/btrfsprogs
parent13b65d51ffc9768464e8330fdb73b6febd7410af (diff)
lib: feat: ScanOneDevice: Subsume ScanForNotes, checksum as we go, look for csum items
"ignore space change" is possibly useful for viewing this diff?
Diffstat (limited to 'lib/btrfsprogs')
-rw-r--r--lib/btrfsprogs/btrfsinspect/scan.go57
-rw-r--r--lib/btrfsprogs/btrfsinspect/scandevices.go171
2 files changed, 114 insertions, 114 deletions
diff --git a/lib/btrfsprogs/btrfsinspect/scan.go b/lib/btrfsprogs/btrfsinspect/scan.go
deleted file mode 100644
index ef1079f..0000000
--- a/lib/btrfsprogs/btrfsinspect/scan.go
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com>
-//
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-package btrfsinspect
-
-import (
- "context"
- "errors"
- "fmt"
-
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs"
- "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"
-)
-
-// ScanForNodes mimics btrfs-progs
-// cmds/rescue-chunk-recover.c:scan_one_device(), except rather than
-// doing something itself when it finds a node, it simply calls a
-// callback function.
-func ScanForNodes(ctx context.Context, dev *btrfs.Device, sb btrfs.Superblock, fn func(*diskio.Ref[btrfsvol.PhysicalAddr, btrfs.Node], error), prog func(btrfsvol.PhysicalAddr)) error {
- devSize := dev.Size()
-
- if sb.NodeSize < sb.SectorSize {
- return fmt.Errorf("node_size(%v) < sector_size(%v)",
- sb.NodeSize, sb.SectorSize)
- }
-
- for pos := btrfsvol.PhysicalAddr(0); pos+btrfsvol.PhysicalAddr(sb.NodeSize) < devSize; pos += btrfsvol.PhysicalAddr(sb.SectorSize) {
- if ctx.Err() != nil {
- return ctx.Err()
- }
- if slices.Contains(pos, btrfs.SuperblockAddrs) {
- //fmt.Printf("sector@%v is a superblock\n", pos)
- continue
- }
-
- if prog != nil {
- prog(pos)
- }
-
- nodeRef, err := btrfs.ReadNode[btrfsvol.PhysicalAddr](dev, sb, pos, nil)
- if err != nil && errors.Is(err, btrfs.ErrNotANode) {
- continue
- }
- fn(nodeRef, err)
-
- pos += btrfsvol.PhysicalAddr(sb.NodeSize) - btrfsvol.PhysicalAddr(sb.SectorSize)
- }
-
- if prog != nil {
- prog(devSize)
- }
-
- return nil
-}
diff --git a/lib/btrfsprogs/btrfsinspect/scandevices.go b/lib/btrfsprogs/btrfsinspect/scandevices.go
index 8094ab0..c590d81 100644
--- a/lib/btrfsprogs/btrfsinspect/scandevices.go
+++ b/lib/btrfsprogs/btrfsinspect/scandevices.go
@@ -6,20 +6,25 @@ package btrfsinspect
import (
"context"
+ "errors"
+ "fmt"
"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/diskio"
+ "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsutil"
+ "git.lukeshu.com/btrfs-progs-ng/lib/slices"
)
type ScanOneDeviceResult struct {
+ Checksums SumRun[btrfsvol.PhysicalAddr]
FoundNodes map[btrfsvol.LogicalAddr][]btrfsvol.PhysicalAddr
FoundChunks []btrfs.SysChunk
FoundBlockGroups []SysBlockGroup
FoundDevExtents []SysDevExtent
+ FoundExtentCSums []SysExtentCSum
}
type SysBlockGroup struct {
@@ -32,77 +37,129 @@ type SysDevExtent struct {
DevExt btrfsitem.DevExtent
}
+type SysExtentCSum struct {
+ Key btrfs.Key
+ Sums btrfsitem.ExtentCSum
+}
+
// 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) {
+func ScanOneDevice(ctx context.Context, dev *btrfs.Device, sb btrfs.Superblock) (ScanOneDeviceResult, error) {
result := ScanOneDeviceResult{
FoundNodes: make(map[btrfsvol.LogicalAddr][]btrfsvol.PhysicalAddr),
}
devSize := dev.Size()
- lastProgress := -1
+ if sb.NodeSize < sb.SectorSize {
+ return result, fmt.Errorf("node_size(%v) < sector_size(%v)",
+ sb.NodeSize, sb.SectorSize)
+ }
+ if sb.SectorSize != btrfsitem.CSumBlockSize {
+ // TODO: probably handle this?
+ return result, fmt.Errorf("sector_size(%v) != btrfsitem.CSumBlockSize",
+ sb.SectorSize)
+ }
+ alg := sb.ChecksumType
+ csumSize := alg.Size()
+ numSums := int(devSize / btrfsitem.CSumBlockSize)
+ sums := make([]byte, numSums*csumSize)
- err := ScanForNodes(ctx, dev, superblock, func(nodeRef *diskio.Ref[btrfsvol.PhysicalAddr, btrfs.Node], err error) {
- if err != nil {
- dlog.Infof(ctx, "... dev[%q] error: %v", dev.Name(), err)
- return
- }
- result.FoundNodes[nodeRef.Data.Head.Addr] = append(result.FoundNodes[nodeRef.Data.Head.Addr], nodeRef.Addr)
- for i, item := range nodeRef.Data.BodyLeaf {
- switch item.Key.ItemType {
- case btrfsitem.CHUNK_ITEM_KEY:
- chunk, ok := item.Body.(btrfsitem.Chunk)
- if !ok {
- dlog.Errorf(ctx, "... dev[%q] node@%v: item %v: error: type is CHUNK_ITEM_KEY, but struct is %T",
- dev.Name(), nodeRef.Addr, i, item.Body)
- continue
- }
- //dlog.Tracef(ctx, "... dev[%q] node@%v: item %v: found chunk",
- // dev.Name(), nodeRef.Addr, i)
- result.FoundChunks = append(result.FoundChunks, btrfs.SysChunk{
- Key: item.Key,
- Chunk: chunk,
- })
- case btrfsitem.BLOCK_GROUP_ITEM_KEY:
- bg, ok := item.Body.(btrfsitem.BlockGroup)
- if !ok {
- dlog.Errorf(ctx, "... dev[%q] node@%v: item %v: error: type is BLOCK_GROUP_ITEM_KEY, but struct is %T",
- dev.Name(), nodeRef.Addr, i, item.Body)
- continue
- }
- //dlog.Tracef(ctx, "... dev[%q] node@%v: item %v: found block group",
- // dev.Name(), nodeRef.Addr, i)
- result.FoundBlockGroups = append(result.FoundBlockGroups, SysBlockGroup{
- Key: item.Key,
- BG: bg,
- })
- case btrfsitem.DEV_EXTENT_KEY:
- devext, ok := item.Body.(btrfsitem.DevExtent)
- if !ok {
- dlog.Errorf(ctx, "... dev[%q] node@%v: item %v: error: type is DEV_EXTENT_KEY, but struct is %T",
- dev.Name(), nodeRef.Addr, i, item.Body)
- continue
- }
- //dlog.Tracef(ctx, "... dev[%q] node@%v: item %v: found dev extent",
- // dev.Name(), nodeRef.Addr, i)
- result.FoundDevExtents = append(result.FoundDevExtents, SysDevExtent{
- Key: item.Key,
- DevExt: devext,
- })
- }
- }
- }, func(pos btrfsvol.PhysicalAddr) {
+ lastProgress := -1
+ progress := func(pos btrfsvol.PhysicalAddr) {
pct := int(100 * float64(pos) / float64(devSize))
if pct != lastProgress || pos == devSize {
- dlog.Infof(ctx, "... dev[%q] scanned %v%% (found: %v nodes, %v chunks, %v block groups, %v dev extents)",
+ dlog.Infof(ctx, "... dev[%q] scanned %v%% (found: %v nodes, %v chunks, %v block groups, %v dev extents, %v sum items)",
dev.Name(), pct,
len(result.FoundNodes),
len(result.FoundChunks),
len(result.FoundBlockGroups),
- len(result.FoundDevExtents))
+ len(result.FoundDevExtents),
+ len(result.FoundExtentCSums))
lastProgress = pct
}
- })
+ }
+
+ for i := 0; i < numSums; i++ {
+ if ctx.Err() != nil {
+ return result, ctx.Err()
+ }
+ pos := btrfsvol.PhysicalAddr(i * btrfsitem.CSumBlockSize)
+ progress(pos)
+
+ sum, err := btrfsutil.ChecksumPhysical(dev, alg, pos)
+ if err != nil {
+ return result, err
+ }
+ copy(sums[i*csumSize:], sum[:csumSize])
+
+ if !slices.Contains(pos, btrfs.SuperblockAddrs) {
+ nodeRef, err := btrfs.ReadNode[btrfsvol.PhysicalAddr](dev, sb, pos, nil)
+ if err != nil {
+ if !errors.Is(err, btrfs.ErrNotANode) {
+ dlog.Infof(ctx, "... dev[%q] error: %v", dev.Name(), err)
+ }
+ } else {
+ result.FoundNodes[nodeRef.Data.Head.Addr] = append(result.FoundNodes[nodeRef.Data.Head.Addr], nodeRef.Addr)
+ for i, item := range nodeRef.Data.BodyLeaf {
+ switch item.Key.ItemType {
+ case btrfsitem.CHUNK_ITEM_KEY:
+ chunk, ok := item.Body.(btrfsitem.Chunk)
+ if !ok {
+ dlog.Errorf(ctx, "... dev[%q] node@%v: item %v: error: type is CHUNK_ITEM_KEY, but struct is %T",
+ dev.Name(), nodeRef.Addr, i, item.Body)
+ continue
+ }
+ //dlog.Tracef(ctx, "... dev[%q] node@%v: item %v: found chunk",
+ // dev.Name(), nodeRef.Addr, i)
+ result.FoundChunks = append(result.FoundChunks, btrfs.SysChunk{
+ Key: item.Key,
+ Chunk: chunk,
+ })
+ case btrfsitem.BLOCK_GROUP_ITEM_KEY:
+ bg, ok := item.Body.(btrfsitem.BlockGroup)
+ if !ok {
+ dlog.Errorf(ctx, "... dev[%q] node@%v: item %v: error: type is BLOCK_GROUP_ITEM_KEY, but struct is %T",
+ dev.Name(), nodeRef.Addr, i, item.Body)
+ continue
+ }
+ //dlog.Tracef(ctx, "... dev[%q] node@%v: item %v: found block group",
+ // dev.Name(), nodeRef.Addr, i)
+ result.FoundBlockGroups = append(result.FoundBlockGroups, SysBlockGroup{
+ Key: item.Key,
+ BG: bg,
+ })
+ case btrfsitem.DEV_EXTENT_KEY:
+ devext, ok := item.Body.(btrfsitem.DevExtent)
+ if !ok {
+ dlog.Errorf(ctx, "... dev[%q] node@%v: item %v: error: type is DEV_EXTENT_KEY, but struct is %T",
+ dev.Name(), nodeRef.Addr, i, item.Body)
+ continue
+ }
+ //dlog.Tracef(ctx, "... dev[%q] node@%v: item %v: found dev extent",
+ // dev.Name(), nodeRef.Addr, i)
+ result.FoundDevExtents = append(result.FoundDevExtents, SysDevExtent{
+ Key: item.Key,
+ DevExt: devext,
+ })
+ case btrfsitem.EXTENT_CSUM_KEY:
+ sums, ok := item.Body.(btrfsitem.ExtentCSum)
+ if !ok {
+ dlog.Errorf(ctx, "... dev[%q] node@%v: item %v: error: type is EXTENT_CSUM_OBJECTID, but struct is %T",
+ dev.Name(), nodeRef.Addr, i, item.Body)
+ continue
+ }
+ //dlog.Tracef(ctx, "... dev[%q] node@%v: item %v: found csums",
+ // dev.Name(), nodeRef.Addr, i)
+ result.FoundExtentCSums = append(result.FoundExtentCSums, SysExtentCSum{
+ Key: item.Key,
+ Sums: sums,
+ })
+ }
+ }
+ }
+ }
+ }
+ progress(devSize)
- return result, err
+ return result, nil
}