summaryrefslogtreecommitdiff
path: root/cmd/btrfs-rec/inspect/rebuildtrees
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/btrfs-rec/inspect/rebuildtrees')
-rw-r--r--cmd/btrfs-rec/inspect/rebuildtrees/rebuild.go62
-rw-r--r--cmd/btrfs-rec/inspect/rebuildtrees/rebuild_treecb.go26
-rw-r--r--cmd/btrfs-rec/inspect/rebuildtrees/rebuild_wantcb.go86
-rw-r--r--cmd/btrfs-rec/inspect/rebuildtrees/rebuild_wanttyp.go22
-rw-r--r--cmd/btrfs-rec/inspect/rebuildtrees/scan.go105
5 files changed, 189 insertions, 112 deletions
diff --git a/cmd/btrfs-rec/inspect/rebuildtrees/rebuild.go b/cmd/btrfs-rec/inspect/rebuildtrees/rebuild.go
index ca1ce8c..0d25ac3 100644
--- a/cmd/btrfs-rec/inspect/rebuildtrees/rebuild.go
+++ b/cmd/btrfs-rec/inspect/rebuildtrees/rebuild.go
@@ -47,9 +47,7 @@ func (o keyAndTree) String() string {
}
type rebuilder struct {
- sb btrfstree.Superblock
- graph btrfsutil.Graph
- keyIO *btrfsutil.KeyIO
+ scan ScanDevicesResult
rebuilt *btrfsutil.RebuiltForrest
@@ -67,9 +65,9 @@ type rebuilder struct {
}
type treeAugmentQueue struct {
- zero map[Want]struct{}
- single map[Want]btrfsvol.LogicalAddr
- multi map[Want]containers.Set[btrfsvol.LogicalAddr]
+ zero map[want]struct{}
+ single map[want]btrfsvol.LogicalAddr
+ multi map[want]containers.Set[btrfsvol.LogicalAddr]
}
type Rebuilder interface {
@@ -79,22 +77,20 @@ type Rebuilder interface {
func NewRebuilder(ctx context.Context, fs *btrfs.FS, nodeList []btrfsvol.LogicalAddr) (Rebuilder, error) {
ctx = dlog.WithField(ctx, "btrfs.inspect.rebuild-trees.step", "read-fs-data")
- sb, nodeGraph, keyIO, err := ScanDevices(ctx, fs, nodeList) // ScanDevices does its own logging
+ scanData, err := ScanDevices(ctx, fs, nodeList) // ScanDevices does its own logging
if err != nil {
return nil, err
}
o := &rebuilder{
- sb: sb,
- graph: nodeGraph,
- keyIO: keyIO,
+ scan: scanData,
}
- o.rebuilt = btrfsutil.NewRebuiltForrest(sb, nodeGraph, keyIO, o)
+ o.rebuilt = btrfsutil.NewRebuiltForrest(fs, scanData.Superblock, scanData.Graph, forrestCallbacks{o})
return o, nil
}
func (o *rebuilder) ListRoots(ctx context.Context) map[btrfsprim.ObjID]containers.Set[btrfsvol.LogicalAddr] {
- return o.rebuilt.ListRoots(ctx)
+ return o.rebuilt.RebuiltListRoots(ctx)
}
func (o *rebuilder) Rebuild(ctx context.Context) error {
@@ -163,7 +159,7 @@ func (o *rebuilder) processTreeQueue(ctx context.Context) error {
}
// This will call o.AddedItem as nescessary, which
// inserts to o.addedItemQueue.
- _ = o.rebuilt.Tree(ctx, o.curKey.TreeID)
+ _ = o.rebuilt.RebuiltTree(ctx, o.curKey.TreeID)
}
return nil
@@ -201,18 +197,18 @@ func (o *rebuilder) processAddedItemQueue(ctx context.Context) error {
progressWriter.Set(progress)
ctx := dlog.WithField(ctx, "btrfs.inspect.rebuild-trees.rebuild.settle.item", key)
- tree := o.rebuilt.Tree(ctx, key.TreeID)
- incPtr, ok := tree.Items(ctx).Load(key.Key)
+ tree := o.rebuilt.RebuiltTree(ctx, key.TreeID)
+ incPtr, ok := tree.RebuiltItems(ctx).Load(key.Key)
if !ok {
panic(fmt.Errorf("should not happen: failed to load already-added item: %v", key))
}
- excPtr, ok := tree.PotentialItems(ctx).Load(key.Key)
- if ok && tree.ShouldReplace(incPtr.Node, excPtr.Node) {
- wantKey := WantWithTree{
+ excPtr, ok := tree.RebuiltPotentialItems(ctx).Load(key.Key)
+ if ok && tree.RebuiltShouldReplace(incPtr.Node, excPtr.Node) {
+ wantKey := wantWithTree{
TreeID: key.TreeID,
Key: wantFromKey(key.Key),
}
- o.wantAugment(ctx, wantKey, tree.LeafToRoots(ctx, excPtr.Node))
+ o.wantAugment(ctx, wantKey, tree.RebuiltLeafToRoots(ctx, excPtr.Node))
progress.NumAugments = o.numAugments
progress.NumAugmentTrees = len(o.augmentQueue)
progressWriter.Set(progress)
@@ -270,7 +266,7 @@ func (o *rebuilder) processSettledItemQueue(ctx context.Context) error {
ctx := dlog.WithField(ctx, "btrfs.inspect.rebuild-trees.rebuild.process.item", key)
item := keyAndBody{
keyAndTree: key,
- Body: o.rebuilt.Tree(ctx, key.TreeID).ReadItem(ctx, key.Key),
+ Body: o.rebuilt.RebuiltTree(ctx, key.TreeID).ReadItem(ctx, key.Key),
}
select {
case itemChan <- item:
@@ -286,7 +282,7 @@ func (o *rebuilder) processSettledItemQueue(ctx context.Context) error {
ctx := dlog.WithField(ctx, "btrfs.inspect.rebuild-trees.rebuild.process.item", item.keyAndTree)
o.curKey.TreeID = item.TreeID
o.curKey.Key.Val = item.Key
- btrfscheck.HandleItem(ctx, o, item.TreeID, btrfstree.Item{
+ btrfscheck.HandleItem(ctx, graphCallbacks{o}, item.TreeID, btrfstree.Item{
Key: item.Key,
Body: item.Body,
})
@@ -337,7 +333,7 @@ func (o *rebuilder) processAugmentQueue(ctx context.Context) error {
progressWriter.Set(progress)
// This will call o.AddedItem as nescessary, which
// inserts to o.addedItemQueue.
- o.rebuilt.Tree(ctx, treeID).AddRoot(ctx, nodeAddr)
+ o.rebuilt.RebuiltTree(ctx, treeID).RebuiltAddRoot(ctx, nodeAddr)
progress.N++
}
}
@@ -385,8 +381,8 @@ func (o *rebuilder) resolveTreeAugments(ctx context.Context, treeID btrfsprim.Ob
} else {
choices[choice] = ChoiceInfo{
Count: 1,
- Distance: discardOK(o.rebuilt.Tree(ctx, treeID).COWDistance(o.graph.Nodes[choice].Owner)),
- Generation: o.graph.Nodes[choice].Generation,
+ Distance: discardOK(o.rebuilt.RebuiltTree(ctx, treeID).RebuiltCOWDistance(o.scan.Graph.Nodes[choice].Owner)),
+ Generation: o.scan.Graph.Nodes[choice].Generation,
}
}
}
@@ -399,8 +395,8 @@ func (o *rebuilder) resolveTreeAugments(ctx context.Context, treeID btrfsprim.Ob
} else {
choices[choice] = ChoiceInfo{
Count: 1,
- Distance: discardOK(o.rebuilt.Tree(ctx, treeID).COWDistance(o.graph.Nodes[choice].Owner)),
- Generation: o.graph.Nodes[choice].Generation,
+ Distance: discardOK(o.rebuilt.RebuiltTree(ctx, treeID).RebuiltCOWDistance(o.scan.Graph.Nodes[choice].Owner)),
+ Generation: o.scan.Graph.Nodes[choice].Generation,
}
}
}
@@ -520,7 +516,7 @@ func (o *rebuilder) resolveTreeAugments(ctx context.Context, treeID btrfsprim.Ob
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-func (queue *treeAugmentQueue) has(wantKey Want) bool {
+func (queue *treeAugmentQueue) has(wantKey want) bool {
if queue != nil {
if queue.zero != nil {
if _, ok := queue.zero[wantKey]; ok {
@@ -541,7 +537,7 @@ func (queue *treeAugmentQueue) has(wantKey Want) bool {
return false
}
-func (queue *treeAugmentQueue) store(wantKey Want, choices containers.Set[btrfsvol.LogicalAddr]) {
+func (queue *treeAugmentQueue) store(wantKey want, choices containers.Set[btrfsvol.LogicalAddr]) {
if len(choices) == 0 && wantKey.OffsetType > offsetExact {
// This wantKey is unlikely to come up again, so it's
// not worth the RAM of storing a negative result.
@@ -550,27 +546,27 @@ func (queue *treeAugmentQueue) store(wantKey Want, choices containers.Set[btrfsv
switch len(choices) {
case 0:
if queue.zero == nil {
- queue.zero = make(map[Want]struct{})
+ queue.zero = make(map[want]struct{})
}
queue.zero[wantKey] = struct{}{}
case 1:
if queue.single == nil {
- queue.single = make(map[Want]btrfsvol.LogicalAddr)
+ queue.single = make(map[want]btrfsvol.LogicalAddr)
}
queue.single[wantKey] = choices.TakeOne()
default:
if queue.multi == nil {
- queue.multi = make(map[Want]containers.Set[btrfsvol.LogicalAddr])
+ queue.multi = make(map[want]containers.Set[btrfsvol.LogicalAddr])
}
queue.multi[wantKey] = choices
}
}
-func (o *rebuilder) hasAugment(wantKey WantWithTree) bool {
+func (o *rebuilder) hasAugment(wantKey wantWithTree) bool {
return o.augmentQueue[wantKey.TreeID].has(wantKey.Key)
}
-func (o *rebuilder) wantAugment(ctx context.Context, wantKey WantWithTree, choices containers.Set[btrfsvol.LogicalAddr]) {
+func (o *rebuilder) wantAugment(ctx context.Context, wantKey wantWithTree, choices containers.Set[btrfsvol.LogicalAddr]) {
if o.augmentQueue[wantKey.TreeID] == nil {
o.augmentQueue[wantKey.TreeID] = new(treeAugmentQueue)
}
diff --git a/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_treecb.go b/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_treecb.go
index a422a47..92b5ee5 100644
--- a/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_treecb.go
+++ b/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_treecb.go
@@ -13,8 +13,12 @@ import (
"git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol"
)
+type forrestCallbacks struct {
+ *rebuilder
+}
+
// AddedItem implements btrfsutil.RebuiltForrestCallbacks.
-func (o *rebuilder) AddedItem(_ context.Context, tree btrfsprim.ObjID, key btrfsprim.Key) {
+func (o forrestCallbacks) AddedItem(_ context.Context, tree btrfsprim.ObjID, key btrfsprim.Key) {
o.addedItemQueue.Insert(keyAndTree{
TreeID: tree,
Key: key,
@@ -22,17 +26,17 @@ func (o *rebuilder) AddedItem(_ context.Context, tree btrfsprim.ObjID, key btrfs
}
// AddedRoot implements btrfsutil.RebuiltForrestCallbacks.
-func (o *rebuilder) AddedRoot(_ context.Context, tree btrfsprim.ObjID, _ btrfsvol.LogicalAddr) {
+func (o forrestCallbacks) AddedRoot(_ context.Context, tree btrfsprim.ObjID, _ btrfsvol.LogicalAddr) {
if retries := o.retryItemQueue[tree]; retries != nil {
o.addedItemQueue.InsertFrom(retries)
}
}
// LookupRoot implements btrfsutil.RebuiltForrestCallbacks.
-func (o *rebuilder) LookupRoot(ctx context.Context, tree btrfsprim.ObjID) (offset btrfsprim.Generation, item btrfsitem.Root, ok bool) {
- wantKey := WantWithTree{
+func (o forrestCallbacks) LookupRoot(ctx context.Context, tree btrfsprim.ObjID) (offset btrfsprim.Generation, item btrfsitem.Root, ok bool) {
+ wantKey := wantWithTree{
TreeID: btrfsprim.ROOT_TREE_OBJECTID,
- Key: Want{
+ Key: want{
ObjectID: tree,
ItemType: btrfsitem.ROOT_ITEM_KEY,
OffsetType: offsetAny,
@@ -44,13 +48,13 @@ func (o *rebuilder) LookupRoot(ctx context.Context, tree btrfsprim.ObjID) (offse
o.enqueueRetry(btrfsprim.ROOT_TREE_OBJECTID)
return 0, btrfsitem.Root{}, false
}
- itemBody := o.rebuilt.Tree(ctx, wantKey.TreeID).ReadItem(ctx, foundKey)
+ itemBody := o.rebuilt.RebuiltTree(ctx, wantKey.TreeID).ReadItem(ctx, foundKey)
defer itemBody.Free()
switch itemBody := itemBody.(type) {
case *btrfsitem.Root:
return btrfsprim.Generation(foundKey.Offset), *itemBody, true
case *btrfsitem.Error:
- o.FSErr(ctx, fmt.Errorf("error decoding item: %v: %w", foundKey, itemBody.Err))
+ graphCallbacks(o).FSErr(ctx, fmt.Errorf("error decoding item: %v: %w", foundKey, itemBody.Err))
return 0, btrfsitem.Root{}, false
default:
// This is a panic because the item decoder should not emit ROOT_ITEM items as anything but
@@ -60,8 +64,8 @@ func (o *rebuilder) LookupRoot(ctx context.Context, tree btrfsprim.ObjID) (offse
}
// LookupUUID implements btrfsutil.RebuiltForrestCallbacks.
-func (o *rebuilder) LookupUUID(ctx context.Context, uuid btrfsprim.UUID) (id btrfsprim.ObjID, ok bool) {
- wantKey := WantWithTree{
+func (o forrestCallbacks) LookupUUID(ctx context.Context, uuid btrfsprim.UUID) (id btrfsprim.ObjID, ok bool) {
+ wantKey := wantWithTree{
TreeID: btrfsprim.UUID_TREE_OBJECTID,
Key: wantFromKey(btrfsitem.UUIDToKey(uuid)),
}
@@ -70,13 +74,13 @@ func (o *rebuilder) LookupUUID(ctx context.Context, uuid btrfsprim.UUID) (id btr
o.enqueueRetry(btrfsprim.UUID_TREE_OBJECTID)
return 0, false
}
- itemBody := o.rebuilt.Tree(ctx, wantKey.TreeID).ReadItem(ctx, wantKey.Key.Key())
+ itemBody := o.rebuilt.RebuiltTree(ctx, wantKey.TreeID).ReadItem(ctx, wantKey.Key.Key())
defer itemBody.Free()
switch itemBody := itemBody.(type) {
case *btrfsitem.UUIDMap:
return itemBody.ObjID, true
case *btrfsitem.Error:
- o.FSErr(ctx, fmt.Errorf("error decoding item: %v: %w", wantKey, itemBody.Err))
+ graphCallbacks(o).FSErr(ctx, fmt.Errorf("error decoding item: %v: %w", wantKey, itemBody.Err))
return 0, false
default:
// This is a panic because the item decoder should not emit UUID_SUBVOL items as anything but
diff --git a/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_wantcb.go b/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_wantcb.go
index 704f4ee..eff2a83 100644
--- a/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_wantcb.go
+++ b/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_wantcb.go
@@ -19,16 +19,20 @@ import (
"git.lukeshu.com/btrfs-progs-ng/lib/containers"
)
+type graphCallbacks struct {
+ *rebuilder
+}
+
// FSErr implements btrfscheck.GraphCallbacks.
-func (*rebuilder) FSErr(ctx context.Context, e error) {
+func (graphCallbacks) FSErr(ctx context.Context, e error) {
dlog.Errorf(ctx, "filesystem error: %v", e)
}
// Want implements btrfscheck.GraphCallbacks.
-func (o *rebuilder) Want(ctx context.Context, reason string, treeID btrfsprim.ObjID, objID btrfsprim.ObjID, typ btrfsprim.ItemType) {
- wantKey := WantWithTree{
+func (o graphCallbacks) Want(ctx context.Context, reason string, treeID btrfsprim.ObjID, objID btrfsprim.ObjID, typ btrfsprim.ItemType) {
+ wantKey := wantWithTree{
TreeID: treeID,
- Key: Want{
+ Key: want{
ObjectID: objID,
ItemType: typ,
OffsetType: offsetAny,
@@ -38,8 +42,8 @@ func (o *rebuilder) Want(ctx context.Context, reason string, treeID btrfsprim.Ob
o._want(ctx, wantKey)
}
-func (o *rebuilder) _want(ctx context.Context, wantKey WantWithTree) (key btrfsprim.Key, ok bool) {
- if o.rebuilt.Tree(ctx, wantKey.TreeID) == nil {
+func (o *rebuilder) _want(ctx context.Context, wantKey wantWithTree) (key btrfsprim.Key, ok bool) {
+ if o.rebuilt.RebuiltTree(ctx, wantKey.TreeID) == nil {
o.enqueueRetry(wantKey.TreeID)
return btrfsprim.Key{}, false
}
@@ -47,7 +51,7 @@ func (o *rebuilder) _want(ctx context.Context, wantKey WantWithTree) (key btrfsp
// check if we already have it
tgt := wantKey.Key.Key()
- if key, _, ok := o.rebuilt.Tree(ctx, wantKey.TreeID).Items(ctx).Search(func(key btrfsprim.Key, _ btrfsutil.ItemPtr) int {
+ if key, _, ok := o.rebuilt.RebuiltTree(ctx, wantKey.TreeID).RebuiltItems(ctx).Search(func(key btrfsprim.Key, _ btrfsutil.ItemPtr) int {
key.Offset = 0
return tgt.Compare(key)
}); ok {
@@ -60,13 +64,13 @@ func (o *rebuilder) _want(ctx context.Context, wantKey WantWithTree) (key btrfsp
return btrfsprim.Key{}, false
}
wants := make(containers.Set[btrfsvol.LogicalAddr])
- o.rebuilt.Tree(ctx, wantKey.TreeID).PotentialItems(ctx).Subrange(
+ o.rebuilt.RebuiltTree(ctx, wantKey.TreeID).RebuiltPotentialItems(ctx).Subrange(
func(k btrfsprim.Key, _ btrfsutil.ItemPtr) int {
k.Offset = 0
return tgt.Compare(k)
},
func(_ btrfsprim.Key, v btrfsutil.ItemPtr) bool {
- wants.InsertFrom(o.rebuilt.Tree(ctx, wantKey.TreeID).LeafToRoots(ctx, v.Node))
+ wants.InsertFrom(o.rebuilt.RebuiltTree(ctx, wantKey.TreeID).RebuiltLeafToRoots(ctx, v.Node))
return true
})
o.wantAugment(ctx, wantKey, wants)
@@ -74,10 +78,10 @@ func (o *rebuilder) _want(ctx context.Context, wantKey WantWithTree) (key btrfsp
}
// WantOff implements btrfscheck.GraphCallbacks.
-func (o *rebuilder) WantOff(ctx context.Context, reason string, treeID btrfsprim.ObjID, objID btrfsprim.ObjID, typ btrfsprim.ItemType, off uint64) {
- wantKey := WantWithTree{
+func (o graphCallbacks) WantOff(ctx context.Context, reason string, treeID btrfsprim.ObjID, objID btrfsprim.ObjID, typ btrfsprim.ItemType, off uint64) {
+ wantKey := wantWithTree{
TreeID: treeID,
- Key: Want{
+ Key: want{
ObjectID: objID,
ItemType: typ,
OffsetType: offsetExact,
@@ -88,8 +92,8 @@ func (o *rebuilder) WantOff(ctx context.Context, reason string, treeID btrfsprim
o._wantOff(ctx, wantKey)
}
-func (o *rebuilder) _wantOff(ctx context.Context, wantKey WantWithTree) (ok bool) {
- if o.rebuilt.Tree(ctx, wantKey.TreeID) == nil {
+func (o *rebuilder) _wantOff(ctx context.Context, wantKey wantWithTree) (ok bool) {
+ if o.rebuilt.RebuiltTree(ctx, wantKey.TreeID) == nil {
o.enqueueRetry(wantKey.TreeID)
return false
}
@@ -97,7 +101,7 @@ func (o *rebuilder) _wantOff(ctx context.Context, wantKey WantWithTree) (ok bool
// check if we already have it
tgt := wantKey.Key.Key()
- if _, ok := o.rebuilt.Tree(ctx, wantKey.TreeID).Items(ctx).Load(tgt); ok {
+ if _, ok := o.rebuilt.RebuiltTree(ctx, wantKey.TreeID).RebuiltItems(ctx).Load(tgt); ok {
return true
}
@@ -107,10 +111,10 @@ func (o *rebuilder) _wantOff(ctx context.Context, wantKey WantWithTree) (ok bool
return false
}
wants := make(containers.Set[btrfsvol.LogicalAddr])
- o.rebuilt.Tree(ctx, wantKey.TreeID).PotentialItems(ctx).Subrange(
+ o.rebuilt.RebuiltTree(ctx, wantKey.TreeID).RebuiltPotentialItems(ctx).Subrange(
func(k btrfsprim.Key, _ btrfsutil.ItemPtr) int { return tgt.Compare(k) },
func(_ btrfsprim.Key, v btrfsutil.ItemPtr) bool {
- wants.InsertFrom(o.rebuilt.Tree(ctx, wantKey.TreeID).LeafToRoots(ctx, v.Node))
+ wants.InsertFrom(o.rebuilt.RebuiltTree(ctx, wantKey.TreeID).RebuiltLeafToRoots(ctx, v.Node))
return true
})
o.wantAugment(ctx, wantKey, wants)
@@ -118,10 +122,10 @@ func (o *rebuilder) _wantOff(ctx context.Context, wantKey WantWithTree) (ok bool
}
// WantDirIndex implements btrfscheck.GraphCallbacks.
-func (o *rebuilder) WantDirIndex(ctx context.Context, reason string, treeID btrfsprim.ObjID, objID btrfsprim.ObjID, name []byte) {
- wantKey := WantWithTree{
+func (o graphCallbacks) WantDirIndex(ctx context.Context, reason string, treeID btrfsprim.ObjID, objID btrfsprim.ObjID, name []byte) {
+ wantKey := wantWithTree{
TreeID: treeID,
- Key: Want{
+ Key: want{
ObjectID: objID,
ItemType: btrfsitem.DIR_INDEX_KEY,
OffsetType: offsetName,
@@ -130,7 +134,7 @@ func (o *rebuilder) WantDirIndex(ctx context.Context, reason string, treeID btrf
}
ctx = withWant(ctx, logFieldItemWant, reason, wantKey)
- if o.rebuilt.Tree(ctx, treeID) == nil {
+ if o.rebuilt.RebuiltTree(ctx, treeID) == nil {
o.enqueueRetry(treeID)
return
}
@@ -139,13 +143,13 @@ func (o *rebuilder) WantDirIndex(ctx context.Context, reason string, treeID btrf
tgt := wantKey.Key.Key()
found := false
- o.rebuilt.Tree(ctx, treeID).Items(ctx).Subrange(
+ o.rebuilt.RebuiltTree(ctx, treeID).RebuiltItems(ctx).Subrange(
func(key btrfsprim.Key, _ btrfsutil.ItemPtr) int {
key.Offset = 0
return tgt.Compare(key)
},
func(_ btrfsprim.Key, ptr btrfsutil.ItemPtr) bool {
- if itemName, ok := o.keyIO.Names[ptr]; ok && bytes.Equal(itemName, name) {
+ if itemName, ok := o.scan.Names[ptr]; ok && bytes.Equal(itemName, name) {
found = true
}
return !found
@@ -160,21 +164,21 @@ func (o *rebuilder) WantDirIndex(ctx context.Context, reason string, treeID btrf
return
}
wants := make(containers.Set[btrfsvol.LogicalAddr])
- o.rebuilt.Tree(ctx, treeID).PotentialItems(ctx).Subrange(
+ o.rebuilt.RebuiltTree(ctx, treeID).RebuiltPotentialItems(ctx).Subrange(
func(key btrfsprim.Key, _ btrfsutil.ItemPtr) int {
key.Offset = 0
return tgt.Compare(key)
},
func(_ btrfsprim.Key, ptr btrfsutil.ItemPtr) bool {
- if itemName, ok := o.keyIO.Names[ptr]; ok && bytes.Equal(itemName, name) {
- wants.InsertFrom(o.rebuilt.Tree(ctx, treeID).LeafToRoots(ctx, ptr.Node))
+ if itemName, ok := o.scan.Names[ptr]; ok && bytes.Equal(itemName, name) {
+ wants.InsertFrom(o.rebuilt.RebuiltTree(ctx, treeID).RebuiltLeafToRoots(ctx, ptr.Node))
}
return true
})
o.wantAugment(ctx, wantKey, wants)
}
-func (o *rebuilder) _walkRange(
+func (o graphCallbacks) _walkRange(
ctx context.Context,
items *containers.SortedMap[btrfsprim.Key, btrfsutil.ItemPtr],
treeID, objID btrfsprim.ObjID, typ btrfsprim.ItemType,
@@ -203,7 +207,7 @@ func (o *rebuilder) _walkRange(
}
},
func(runKey btrfsprim.Key, runPtr btrfsutil.ItemPtr) bool {
- runSizeAndErr, ok := o.keyIO.Sizes[runPtr]
+ runSizeAndErr, ok := o.scan.Sizes[runPtr]
if !ok {
panic(fmt.Errorf("should not happen: %v (%v) did not have a size recorded",
runPtr, keyAndTree{TreeID: treeID, Key: runKey}))
@@ -239,14 +243,14 @@ func (a gap) Compare(b gap) int {
return containers.NativeCompare(a.Beg, b.Beg)
}
-func (o *rebuilder) _wantRange(
+func (o graphCallbacks) _wantRange(
ctx context.Context, reason string,
treeID btrfsprim.ObjID, objID btrfsprim.ObjID, typ btrfsprim.ItemType,
beg, end uint64,
) {
- wantKey := WantWithTree{
+ wantKey := wantWithTree{
TreeID: treeID,
- Key: Want{
+ Key: want{
ObjectID: objID,
ItemType: typ,
OffsetType: offsetAny,
@@ -255,7 +259,7 @@ func (o *rebuilder) _wantRange(
ctx = withWant(ctx, logFieldItemWant, reason, wantKey)
wantKey.Key.OffsetType = offsetRange
- if o.rebuilt.Tree(ctx, treeID) == nil {
+ if o.rebuilt.RebuiltTree(ctx, treeID) == nil {
o.enqueueRetry(treeID)
return
}
@@ -271,7 +275,7 @@ func (o *rebuilder) _wantRange(
})
o._walkRange(
ctx,
- o.rebuilt.Tree(ctx, treeID).Items(ctx),
+ o.rebuilt.RebuiltTree(ctx, treeID).RebuiltItems(ctx),
treeID, objID, typ, beg, end,
func(runKey btrfsprim.Key, _ btrfsutil.ItemPtr, runBeg, runEnd uint64) {
var overlappingGaps []*containers.RBNode[gap]
@@ -316,7 +320,7 @@ func (o *rebuilder) _wantRange(
if gaps.Len() == 0 {
return
}
- potentialItems := o.rebuilt.Tree(ctx, treeID).PotentialItems(ctx)
+ potentialItems := o.rebuilt.RebuiltTree(ctx, treeID).RebuiltPotentialItems(ctx)
gaps.Range(func(rbNode *containers.RBNode[gap]) bool {
gap := rbNode.Value
last := gap.Beg
@@ -336,7 +340,7 @@ func (o *rebuilder) _wantRange(
wantKey.Key.OffsetLow = gap.Beg
wantKey.Key.OffsetHigh = gap.End
wantCtx := withWant(ctx, logFieldItemWant, reason, wantKey)
- o.wantAugment(wantCtx, wantKey, o.rebuilt.Tree(wantCtx, treeID).LeafToRoots(wantCtx, v.Node))
+ o.wantAugment(wantCtx, wantKey, o.rebuilt.RebuiltTree(wantCtx, treeID).RebuiltLeafToRoots(wantCtx, v.Node))
last = runEnd
})
if last < gap.End {
@@ -353,10 +357,10 @@ func (o *rebuilder) _wantRange(
// WantCSum implements btrfscheck.GraphCallbacks.
//
// interval is [beg, end)
-func (o *rebuilder) WantCSum(ctx context.Context, reason string, inodeTree, inode btrfsprim.ObjID, beg, end btrfsvol.LogicalAddr) {
- inodeWant := WantWithTree{
+func (o graphCallbacks) WantCSum(ctx context.Context, reason string, inodeTree, inode btrfsprim.ObjID, beg, end btrfsvol.LogicalAddr) {
+ inodeWant := wantWithTree{
TreeID: inodeTree,
- Key: Want{
+ Key: want{
ObjectID: inode,
ItemType: btrfsitem.INODE_ITEM_KEY,
OffsetType: offsetExact,
@@ -368,11 +372,11 @@ func (o *rebuilder) WantCSum(ctx context.Context, reason string, inodeTree, inod
o.enqueueRetry(inodeTree)
return
}
- inodePtr, ok := o.rebuilt.Tree(inodeCtx, inodeTree).Items(inodeCtx).Load(inodeWant.Key.Key())
+ inodePtr, ok := o.rebuilt.RebuiltTree(inodeCtx, inodeTree).RebuiltItems(inodeCtx).Load(inodeWant.Key.Key())
if !ok {
panic(fmt.Errorf("should not happen: could not load key: %v", inodeWant))
}
- inodeFlags, ok := o.keyIO.Flags[inodePtr]
+ inodeFlags, ok := o.scan.Flags[inodePtr]
if !ok {
panic(fmt.Errorf("should not happen: INODE_ITEM did not have flags recorded"))
}
@@ -392,7 +396,7 @@ func (o *rebuilder) WantCSum(ctx context.Context, reason string, inodeTree, inod
}
// WantFileExt implements btrfscheck.GraphCallbacks.
-func (o *rebuilder) WantFileExt(ctx context.Context, reason string, treeID btrfsprim.ObjID, ino btrfsprim.ObjID, size int64) {
+func (o graphCallbacks) WantFileExt(ctx context.Context, reason string, treeID btrfsprim.ObjID, ino btrfsprim.ObjID, size int64) {
o._wantRange(
ctx, reason,
treeID, ino, btrfsprim.EXTENT_DATA_KEY,
diff --git a/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_wanttyp.go b/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_wanttyp.go
index 8fe8a49..6c9d72b 100644
--- a/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_wanttyp.go
+++ b/cmd/btrfs-rec/inspect/rebuildtrees/rebuild_wanttyp.go
@@ -23,8 +23,8 @@ const (
offsetName
)
-type Want struct {
- // TODO(lukeshu): Delete the 'Want' type in favor of
+type want struct {
+ // TODO(lukeshu): Delete the 'want' type in favor of
// btrfstree.Search.
ObjectID btrfsprim.ObjID
ItemType btrfsprim.ItemType
@@ -34,7 +34,7 @@ type Want struct {
OffsetName string
}
-func (a Want) Compare(b Want) int {
+func (a want) Compare(b want) int {
if d := containers.NativeCompare(a.ObjectID, b.ObjectID); d != 0 {
return d
}
@@ -56,7 +56,7 @@ func (a Want) Compare(b Want) int {
return 0
}
-func (o Want) Key() btrfsprim.Key {
+func (o want) Key() btrfsprim.Key {
return btrfsprim.Key{
ObjectID: o.ObjectID,
ItemType: o.ItemType,
@@ -64,8 +64,8 @@ func (o Want) Key() btrfsprim.Key {
}
}
-func wantFromKey(k btrfsprim.Key) Want {
- return Want{
+func wantFromKey(k btrfsprim.Key) want {
+ return want{
ObjectID: k.ObjectID,
ItemType: k.ItemType,
OffsetType: offsetExact,
@@ -73,7 +73,7 @@ func wantFromKey(k btrfsprim.Key) Want {
}
}
-func (o Want) String() string {
+func (o want) String() string {
switch o.OffsetType {
case offsetAny:
return fmt.Sprintf("{%v %v ?}", o.ObjectID, o.ItemType)
@@ -88,12 +88,12 @@ func (o Want) String() string {
}
}
-type WantWithTree struct {
+type wantWithTree struct {
TreeID btrfsprim.ObjID
- Key Want
+ Key want
}
-func (o WantWithTree) String() string {
+func (o wantWithTree) String() string {
return fmt.Sprintf("tree=%v key=%v", o.TreeID, o.Key)
}
@@ -102,7 +102,7 @@ const (
logFieldTreeWant = "btrfs.util.rebuilt-forrest.add-tree.want"
)
-func withWant(ctx context.Context, logField, reason string, wantKey WantWithTree) context.Context {
+func withWant(ctx context.Context, logField, reason string, wantKey wantWithTree) context.Context {
ctx = dlog.WithField(ctx, logField+".reason", reason)
ctx = dlog.WithField(ctx, logField+".key", wantKey)
return ctx
diff --git a/cmd/btrfs-rec/inspect/rebuildtrees/scan.go b/cmd/btrfs-rec/inspect/rebuildtrees/scan.go
index ba56c5b..ada9f6f 100644
--- a/cmd/btrfs-rec/inspect/rebuildtrees/scan.go
+++ b/cmd/btrfs-rec/inspect/rebuildtrees/scan.go
@@ -6,11 +6,14 @@ package rebuildtrees
import (
"context"
+ "fmt"
"time"
"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/btrfsprim"
"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/btrfsutil"
@@ -18,11 +21,31 @@ import (
"git.lukeshu.com/btrfs-progs-ng/lib/textui"
)
-func ScanDevices(ctx context.Context, fs *btrfs.FS, nodeList []btrfsvol.LogicalAddr) (btrfstree.Superblock, btrfsutil.Graph, *btrfsutil.KeyIO, error) {
+type SizeAndErr struct {
+ Size uint64
+ Err error
+}
+
+type FlagsAndErr struct {
+ NoDataSum bool
+ Err error
+}
+
+type ScanDevicesResult struct {
+ Superblock btrfstree.Superblock
+
+ Graph btrfsutil.Graph
+
+ Flags map[btrfsutil.ItemPtr]FlagsAndErr // INODE_ITEM
+ Names map[btrfsutil.ItemPtr][]byte // DIR_INDEX
+ Sizes map[btrfsutil.ItemPtr]SizeAndErr // EXTENT_CSUM and EXTENT_DATA
+}
+
+func ScanDevices(ctx context.Context, fs *btrfs.FS, nodeList []btrfsvol.LogicalAddr) (ScanDevicesResult, error) {
dlog.Info(ctx, "Reading superblock...")
sb, err := fs.Superblock()
if err != nil {
- return btrfstree.Superblock{}, btrfsutil.Graph{}, nil, err
+ return ScanDevicesResult{}, err
}
dlog.Infof(ctx, "Reading node data from FS...")
@@ -33,26 +56,32 @@ func ScanDevices(ctx context.Context, fs *btrfs.FS, nodeList []btrfsvol.LogicalA
dlog.WithField(ctx, "btrfs.inspect.rebuild-trees.read.substep", "read-nodes"),
dlog.LogLevelInfo, textui.Tunable(1*time.Second))
- nodeGraph := btrfsutil.NewGraph(*sb)
- keyIO := btrfsutil.NewKeyIO(fs, *sb)
+ ret := ScanDevicesResult{
+ Superblock: *sb,
+
+ Graph: btrfsutil.NewGraph(*sb),
+
+ Flags: make(map[btrfsutil.ItemPtr]FlagsAndErr),
+ Names: make(map[btrfsutil.ItemPtr][]byte),
+ Sizes: make(map[btrfsutil.ItemPtr]SizeAndErr),
+ }
progressWriter.Set(stats)
for _, laddr := range nodeList {
if err := ctx.Err(); err != nil {
- return btrfstree.Superblock{}, btrfsutil.Graph{}, nil, err
+ return ScanDevicesResult{}, err
}
- nodeRef, err := btrfstree.ReadNode[btrfsvol.LogicalAddr](fs, *sb, laddr, btrfstree.NodeExpectations{
- LAddr: containers.Optional[btrfsvol.LogicalAddr]{OK: true, Val: laddr},
+ node, err := btrfstree.ReadNode[btrfsvol.LogicalAddr](fs, *sb, laddr, btrfstree.NodeExpectations{
+ LAddr: containers.OptionalValue(laddr),
})
if err != nil {
- btrfstree.FreeNodeRef(nodeRef)
- return btrfstree.Superblock{}, btrfsutil.Graph{}, nil, err
+ node.Free()
+ return ScanDevicesResult{}, err
}
- nodeGraph.InsertNode(nodeRef)
- keyIO.InsertNode(nodeRef)
+ ret.insertNode(node)
- btrfstree.FreeNodeRef(nodeRef)
+ node.Free()
stats.N++
progressWriter.Set(stats)
@@ -64,10 +93,54 @@ func ScanDevices(ctx context.Context, fs *btrfs.FS, nodeList []btrfsvol.LogicalA
dlog.Info(ctx, "... done reading node data")
ctx = dlog.WithField(ctx, "btrfs.inspect.rebuild-trees.read.substep", "check")
- if err := nodeGraph.FinalCheck(ctx, fs, *sb); err != nil {
- return btrfstree.Superblock{}, btrfsutil.Graph{}, nil, err
+ if err := ret.Graph.FinalCheck(ctx, fs, *sb); err != nil {
+ return ScanDevicesResult{}, err
}
- keyIO.SetGraph(*nodeGraph)
- return *sb, *nodeGraph, keyIO, nil
+ return ret, nil
+}
+
+func (o *ScanDevicesResult) insertNode(node *btrfstree.Node) {
+ o.Graph.InsertNode(node)
+ for i, item := range node.BodyLeaf {
+ ptr := btrfsutil.ItemPtr{
+ Node: node.Head.Addr,
+ Slot: i,
+ }
+ switch itemBody := item.Body.(type) {
+ case *btrfsitem.Inode:
+ o.Flags[ptr] = FlagsAndErr{
+ NoDataSum: itemBody.Flags.Has(btrfsitem.INODE_NODATASUM),
+ Err: nil,
+ }
+ case *btrfsitem.DirEntry:
+ if item.Key.ItemType == btrfsprim.DIR_INDEX_KEY {
+ o.Names[ptr] = append([]byte(nil), itemBody.Name...)
+ }
+ case *btrfsitem.ExtentCSum:
+ o.Sizes[ptr] = SizeAndErr{
+ Size: uint64(itemBody.Size()),
+ Err: nil,
+ }
+ case *btrfsitem.FileExtent:
+ size, err := itemBody.Size()
+ o.Sizes[ptr] = SizeAndErr{
+ Size: uint64(size),
+ Err: err,
+ }
+ case *btrfsitem.Error:
+ switch item.Key.ItemType {
+ case btrfsprim.INODE_ITEM_KEY:
+ o.Flags[ptr] = FlagsAndErr{
+ Err: fmt.Errorf("error decoding item: ptr=%v (tree=%v key=%v): %w",
+ ptr, node.Head.Owner, item.Key, itemBody.Err),
+ }
+ case btrfsprim.EXTENT_CSUM_KEY, btrfsprim.EXTENT_DATA_KEY:
+ o.Sizes[ptr] = SizeAndErr{
+ Err: fmt.Errorf("error decoding item: ptr=%v (tree=%v key=%v): %w",
+ ptr, node.Head.Owner, item.Key, itemBody.Err),
+ }
+ }
+ }
+ }
}