From 079c2a1316616b997e0050a1423c0a5e6bda4f16 Mon Sep 17 00:00:00 2001
From: Luke Shumaker <lukeshu@lukeshu.com>
Date: Mon, 29 Aug 2022 20:28:58 -0600
Subject: wip

---
 .../btrfsinspect/rebuildnodes/rebuildnodes.go      | 22 ++++++++++++----------
 .../btrfsinspect/rebuildnodes/uuidmap.go           |  9 +++------
 2 files changed, 15 insertions(+), 16 deletions(-)

(limited to 'lib/btrfsprogs/btrfsinspect')

diff --git a/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuildnodes.go b/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuildnodes.go
index 7ccccea..7950393 100644
--- a/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuildnodes.go
+++ b/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuildnodes.go
@@ -260,7 +260,8 @@ func reInitBrokenNodes(ctx context.Context, fs _FS, nodeScanResults btrfsinspect
 
 	lastPct := -1
 	total := countNodes(nodeScanResults)
-	progress := func(done int) {
+	done := 0
+	progress := func() {
 		pct := int(100 * float64(done) / float64(total))
 		if pct != lastPct || done == total {
 			dlog.Infof(ctx, "... %v%% (%v/%v)",
@@ -268,21 +269,20 @@ func reInitBrokenNodes(ctx context.Context, fs _FS, nodeScanResults btrfsinspect
 			lastPct = pct
 		}
 	}
-	var done int
 
 	rebuiltNodes := make(map[btrfsvol.LogicalAddr]*RebuiltNode)
-	dbg := make(map[btrfsvol.LogicalAddr]btrfstree.TreePath)
+	visitedNodes := make(map[btrfsvol.LogicalAddr]struct{})
 	walkHandler := btrfstree.TreeWalkHandler{
 		Node: func(path btrfstree.TreePath, _ *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node]) error {
-			if other, conflict := dbg[path.Node(-1).ToNodeAddr]; conflict {
-				panic(fmt.Errorf("same node visited twice: %v != %v", other, path))
+			addr := path.Node(-1).ToNodeAddr
+			if _, alreadyVisited := visitedNodes[addr]; alreadyVisited {
+				// Can happen because of COW subvolumes;
+				// this is really a DAG not a tree.
+				return iofs.SkipDir
 			}
-			dbg[path.Node(-1).ToNodeAddr] = path.DeepCopy()
+			visitedNodes[addr] = struct{}{}
 			done++
-			if done != len(dbg) {
-				panic(fmt.Errorf("done=%v != len(dbg)=%v", done, len(dbg)))
-			}
-			progress(done)
+			progress()
 			return nil
 		},
 		BadNode: func(path btrfstree.TreePath, node *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node], err error) error {
@@ -310,6 +310,7 @@ func reInitBrokenNodes(ctx context.Context, fs _FS, nodeScanResults btrfsinspect
 	// nodeScanResults so that we don't need to specifically check
 	// if any of the root nodes referenced directly by the
 	// superblock are dead.
+	progress()
 	btrfsutil.WalkAllTrees(ctx, fs, btrfsutil.WalkAllTreesHandler{
 		Err: func(err *btrfsutil.WalkError) {
 			// do nothing
@@ -323,6 +324,7 @@ func reInitBrokenNodes(ctx context.Context, fs _FS, nodeScanResults btrfsinspect
 			},
 			walkHandler)
 	}
+	progress()
 
 	return rebuiltNodes, nil
 }
diff --git a/lib/btrfsprogs/btrfsinspect/rebuildnodes/uuidmap.go b/lib/btrfsprogs/btrfsinspect/rebuildnodes/uuidmap.go
index 606f8f9..ba090fb 100644
--- a/lib/btrfsprogs/btrfsinspect/rebuildnodes/uuidmap.go
+++ b/lib/btrfsprogs/btrfsinspect/rebuildnodes/uuidmap.go
@@ -6,7 +6,6 @@ package rebuildnodes
 
 import (
 	"context"
-	"encoding/binary"
 	"fmt"
 
 	"github.com/datawire/dlib/dlog"
@@ -86,9 +85,7 @@ func buildUUIDMap(ctx context.Context, fs *btrfs.FS, scanResults btrfsinspect.Sc
 						return uuidMap{}, err
 					}
 				case btrfsitem.UUIDMap:
-					var uuid btrfsprim.UUID
-					binary.BigEndian.PutUint64(uuid[:8], uint64(item.Key.ObjectID))
-					binary.BigEndian.PutUint64(uuid[8:], uint64(item.Key.Offset))
+					uuid := btrfsitem.KeyToUUID(item.Key)
 					if err := maybeSet("ObjID2UUID", ret.ObjID2UUID, itemBody.ObjID, uuid); err != nil {
 						return uuidMap{}, err
 					}
@@ -106,7 +103,7 @@ func buildUUIDMap(ctx context.Context, fs *btrfs.FS, scanResults btrfsinspect.Sc
 
 	missing := make(map[btrfsprim.ObjID]struct{})
 	for treeID := range seenTreeIDs {
-		if _, ok := ret.ObjID2UUID[treeID]; !ok {
+		if _, ok := ret.ObjID2UUID[treeID]; !ok && treeID != btrfsprim.ROOT_TREE_OBJECTID {
 			missing[treeID] = struct{}{}
 			continue
 		}
@@ -115,7 +112,7 @@ func buildUUIDMap(ctx context.Context, fs *btrfs.FS, scanResults btrfsinspect.Sc
 		}
 	}
 	if len(missing) > 0 {
-		dlog.Errorf(ctx, "... could not find root items for trees %v", maps.SortedKeys(missing))
+		dlog.Errorf(ctx, "... could not find root items for %d trees: %v", len(missing), maps.SortedKeys(missing))
 	}
 
 	dlog.Info(ctx, "... done building table")
-- 
cgit v1.2.3-2-g168b