summaryrefslogtreecommitdiff
path: root/lib/btrfsprogs/btrfsinspect/scandevices.go
diff options
context:
space:
mode:
Diffstat (limited to 'lib/btrfsprogs/btrfsinspect/scandevices.go')
-rw-r--r--lib/btrfsprogs/btrfsinspect/scandevices.go260
1 files changed, 0 insertions, 260 deletions
diff --git a/lib/btrfsprogs/btrfsinspect/scandevices.go b/lib/btrfsprogs/btrfsinspect/scandevices.go
deleted file mode 100644
index d54be71..0000000
--- a/lib/btrfsprogs/btrfsinspect/scandevices.go
+++ /dev/null
@@ -1,260 +0,0 @@
-// Copyright (C) 2022-2023 Luke Shumaker <lukeshu@lukeshu.com>
-//
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-package btrfsinspect
-
-import (
- "context"
- "errors"
- "fmt"
- "strings"
- "sync"
- "time"
-
- "github.com/datawire/dlib/dgroup"
- "github.com/datawire/dlib/dlog"
-
- "git.lukeshu.com/btrfs-progs-ng/lib/binstruct"
- "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/btrfsprim"
- "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfssum"
- "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/containers"
- "git.lukeshu.com/btrfs-progs-ng/lib/textui"
-)
-
-type ScanDevicesResult map[btrfsvol.DeviceID]ScanOneDeviceResult
-
-func ScanDevices(ctx context.Context, fs *btrfs.FS) (ScanDevicesResult, error) {
- grp := dgroup.NewGroup(ctx, dgroup.GroupConfig{})
- var mu sync.Mutex
- result := make(map[btrfsvol.DeviceID]ScanOneDeviceResult)
- for id, dev := range fs.LV.PhysicalVolumes() {
- id := id
- dev := dev
- grp.Go(fmt.Sprintf("dev-%d", id), func(ctx context.Context) error {
- sb, err := dev.Superblock()
- if err != nil {
- return err
- }
- devResult, err := ScanOneDevice(ctx, dev, *sb)
- if err != nil {
- return err
- }
- mu.Lock()
- result[id] = devResult
- mu.Unlock()
- return nil
- })
- }
- if err := grp.Wait(); err != nil {
- return nil, err
- }
- return result, nil
-}
-
-type ScanOneDeviceResult struct {
- Checksums btrfssum.SumRun[btrfsvol.PhysicalAddr]
- FoundNodes map[btrfsvol.LogicalAddr][]btrfsvol.PhysicalAddr
- FoundChunks []btrfstree.SysChunk
- FoundBlockGroups []SysBlockGroup
- FoundDevExtents []SysDevExtent
- FoundExtentCSums []SysExtentCSum
-}
-
-type SysBlockGroup struct {
- Key btrfsprim.Key
- BG btrfsitem.BlockGroup
-}
-
-type SysDevExtent struct {
- Key btrfsprim.Key
- DevExt btrfsitem.DevExtent
-}
-
-type SysExtentCSum struct {
- Generation btrfsprim.Generation
- Sums btrfsitem.ExtentCSum
-}
-
-// Compare implements containers.Ordered.
-func (a SysExtentCSum) Compare(b SysExtentCSum) int {
- return containers.NativeCompare(a.Sums.Addr, b.Sums.Addr)
-}
-
-type scanStats struct {
- textui.Portion[btrfsvol.PhysicalAddr]
-
- NumFoundNodes int
- NumFoundChunks int
- NumFoundBlockGroups int
- NumFoundDevExtents int
- NumFoundExtentCSums int
-}
-
-func (s scanStats) String() string {
- return textui.Sprintf("scanned %v (found: %v nodes, %v chunks, %v block groups, %v dev extents, %v sum items)",
- s.Portion,
- s.NumFoundNodes,
- s.NumFoundChunks,
- s.NumFoundBlockGroups,
- s.NumFoundDevExtents,
- s.NumFoundExtentCSums)
-}
-
-var sbSize = btrfsvol.PhysicalAddr(binstruct.StaticSize(btrfstree.Superblock{}))
-
-// ScanOneDevice mostly mimics btrfs-progs
-// cmds/rescue-chunk-recover.c:scan_one_device().
-func ScanOneDevice(ctx context.Context, dev *btrfs.Device, sb btrfstree.Superblock) (ScanOneDeviceResult, error) {
- ctx = dlog.WithField(ctx, "btrfsinspect.scandevices.dev", dev.Name())
-
- result := ScanOneDeviceResult{
- FoundNodes: make(map[btrfsvol.LogicalAddr][]btrfsvol.PhysicalAddr),
- }
-
- devSize := dev.Size()
- if sb.NodeSize < sb.SectorSize {
- return result, fmt.Errorf("node_size(%v) < sector_size(%v)",
- sb.NodeSize, sb.SectorSize)
- }
- if sb.SectorSize != btrfssum.BlockSize {
- // TODO: probably handle this?
- return result, fmt.Errorf("sector_size(%v) != btrfssum.BlockSize",
- sb.SectorSize)
- }
- alg := sb.ChecksumType
- csumSize := alg.Size()
- numSums := int(devSize / btrfssum.BlockSize)
- var sums strings.Builder
- sums.Grow(numSums * csumSize)
-
- progressWriter := textui.NewProgress[scanStats](ctx, dlog.LogLevelInfo, textui.Tunable(1*time.Second))
- progress := func(pos btrfsvol.PhysicalAddr) {
- progressWriter.Set(scanStats{
- Portion: textui.Portion[btrfsvol.PhysicalAddr]{
- N: pos,
- D: devSize,
- },
- NumFoundNodes: len(result.FoundNodes),
- NumFoundChunks: len(result.FoundChunks),
- NumFoundBlockGroups: len(result.FoundBlockGroups),
- NumFoundDevExtents: len(result.FoundDevExtents),
- NumFoundExtentCSums: len(result.FoundExtentCSums),
- })
- }
-
- var minNextNode btrfsvol.PhysicalAddr
- for i := 0; i < numSums; i++ {
- if ctx.Err() != nil {
- return result, ctx.Err()
- }
- pos := btrfsvol.PhysicalAddr(i * btrfssum.BlockSize)
- progress(pos)
-
- sum, err := btrfs.ChecksumPhysical(dev, alg, pos)
- if err != nil {
- return result, err
- }
- sums.Write(sum[:csumSize])
-
- checkForNode := pos >= minNextNode && pos+btrfsvol.PhysicalAddr(sb.NodeSize) <= devSize
- if checkForNode {
- for _, sbAddr := range btrfs.SuperblockAddrs {
- if sbAddr <= pos && pos < sbAddr+sbSize {
- checkForNode = false
- break
- }
- }
- }
-
- if checkForNode {
- nodeRef, err := btrfstree.ReadNode[btrfsvol.PhysicalAddr](dev, sb, pos, btrfstree.NodeExpectations{})
- if err != nil {
- if !errors.Is(err, btrfstree.ErrNotANode) {
- dlog.Errorf(ctx, "error: %v", 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:
- switch itemBody := item.Body.(type) {
- case *btrfsitem.Chunk:
- dlog.Tracef(ctx, "node@%v: item %v: found chunk",
- nodeRef.Addr, i)
- result.FoundChunks = append(result.FoundChunks, btrfstree.SysChunk{
- Key: item.Key,
- Chunk: *itemBody,
- })
- case *btrfsitem.Error:
- dlog.Errorf(ctx, "node@%v: item %v: error: malformed CHUNK_ITEM: %v",
- nodeRef.Addr, i, itemBody.Err)
- default:
- panic(fmt.Errorf("should not happen: CHUNK_ITEM has unexpected item type: %T", itemBody))
- }
- case btrfsitem.BLOCK_GROUP_ITEM_KEY:
- switch itemBody := item.Body.(type) {
- case *btrfsitem.BlockGroup:
- dlog.Tracef(ctx, "node@%v: item %v: found block group",
- nodeRef.Addr, i)
- result.FoundBlockGroups = append(result.FoundBlockGroups, SysBlockGroup{
- Key: item.Key,
- BG: *itemBody,
- })
- case *btrfsitem.Error:
- dlog.Errorf(ctx, "node@%v: item %v: error: malformed BLOCK_GROUP_ITEM: %v",
- nodeRef.Addr, i, itemBody.Err)
- default:
- panic(fmt.Errorf("should not happen: BLOCK_GROUP_ITEM has unexpected item type: %T", itemBody))
- }
- case btrfsitem.DEV_EXTENT_KEY:
- switch itemBody := item.Body.(type) {
- case *btrfsitem.DevExtent:
- dlog.Tracef(ctx, "node@%v: item %v: found dev extent",
- nodeRef.Addr, i)
- result.FoundDevExtents = append(result.FoundDevExtents, SysDevExtent{
- Key: item.Key,
- DevExt: *itemBody,
- })
- case *btrfsitem.Error:
- dlog.Errorf(ctx, "node@%v: item %v: error: malformed DEV_EXTENT: %v",
- nodeRef.Addr, i, itemBody.Err)
- default:
- panic(fmt.Errorf("should not happen: DEV_EXTENT has unexpected item type: %T", itemBody))
- }
- case btrfsitem.EXTENT_CSUM_KEY:
- switch itemBody := item.Body.(type) {
- case *btrfsitem.ExtentCSum:
- dlog.Tracef(ctx, "node@%v: item %v: found csums",
- nodeRef.Addr, i)
- result.FoundExtentCSums = append(result.FoundExtentCSums, SysExtentCSum{
- Generation: nodeRef.Data.Head.Generation,
- Sums: *itemBody,
- })
- case *btrfsitem.Error:
- dlog.Errorf(ctx, "node@%v: item %v: error: malformed is EXTENT_CSUM: %v",
- nodeRef.Addr, i, itemBody.Err)
- default:
- panic(fmt.Errorf("should not happen: EXTENT_CSUM has unexpected item type: %T", itemBody))
- }
- }
- }
- minNextNode = pos + btrfsvol.PhysicalAddr(sb.NodeSize)
- }
- btrfstree.FreeNodeRef(nodeRef)
- }
- }
- progress(devSize)
- progressWriter.Done()
-
- result.Checksums = btrfssum.SumRun[btrfsvol.PhysicalAddr]{
- ChecksumSize: csumSize,
- Sums: btrfssum.ShortSum(sums.String()),
- }
-
- return result, nil
-}