diff options
Diffstat (limited to 'lib/btrfsprogs/btrfsutil/broken_btree.go')
-rw-r--r-- | lib/btrfsprogs/btrfsutil/broken_btree.go | 106 |
1 files changed, 60 insertions, 46 deletions
diff --git a/lib/btrfsprogs/btrfsutil/broken_btree.go b/lib/btrfsprogs/btrfsutil/broken_btree.go index 3a8fb4b..6afaceb 100644 --- a/lib/btrfsprogs/btrfsutil/broken_btree.go +++ b/lib/btrfsprogs/btrfsutil/broken_btree.go @@ -15,6 +15,8 @@ import ( "github.com/datawire/dlib/dlog" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs" + "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/containers" "git.lukeshu.com/btrfs-progs-ng/lib/diskio" @@ -22,18 +24,18 @@ import ( ) type indexValue struct { - Key btrfs.Key + Key btrfsprim.Key ItemSize uint32 - Path btrfs.TreePath + Path btrfstree.TreePath } -var maxKey = btrfs.Key{ +var maxKey = btrfsprim.Key{ ObjectID: math.MaxUint64, ItemType: math.MaxUint8, Offset: math.MaxUint64, } -func keyMm(key btrfs.Key) btrfs.Key { +func keyMm(key btrfsprim.Key) btrfsprim.Key { switch { case key.Offset > 0: key.Offset-- @@ -45,10 +47,10 @@ func keyMm(key btrfs.Key) btrfs.Key { return key } -func span(fs *btrfs.FS, path btrfs.TreePath) (btrfs.Key, btrfs.Key) { +func span(fs *btrfs.FS, path btrfstree.TreePath) (btrfsprim.Key, btrfsprim.Key) { // tree root error if len(path) == 0 { - return btrfs.Key{}, maxKey + return btrfsprim.Key{}, maxKey } // item error @@ -63,11 +65,11 @@ func span(fs *btrfs.FS, path btrfs.TreePath) (btrfs.Key, btrfs.Key) { // // assume that path.Node(-1).NodeAddr is not readable, but that path.Node(-2).NodeAddr is. if len(path) == 1 { - return btrfs.Key{}, maxKey + return btrfsprim.Key{}, maxKey } parentNode, _ := fs.ReadNode(path.Parent()) low := parentNode.Data.BodyInternal[path.Node(-1).FromItemIdx].Key - var high btrfs.Key + var high btrfsprim.Key if path.Node(-1).FromItemIdx+1 < len(parentNode.Data.BodyInternal) { high = keyMm(parentNode.Data.BodyInternal[path.Node(-1).FromItemIdx+1].Key) } else { @@ -78,29 +80,29 @@ func span(fs *btrfs.FS, path btrfs.TreePath) (btrfs.Key, btrfs.Key) { } type spanError struct { - End btrfs.Key + End btrfsprim.Key Err error } type cachedIndex struct { TreeRootErr error - Items *containers.RBTree[btrfs.Key, indexValue] - Errors map[int]map[btrfs.Key][]spanError + Items *containers.RBTree[btrfsprim.Key, indexValue] + Errors map[int]map[btrfsprim.Key][]spanError } type brokenTrees struct { ctx context.Context inner *btrfs.FS - // btrfs.ROOT_TREE_OBJECTID + // btrfsprim.ROOT_TREE_OBJECTID rootTreeMu sync.Mutex rootTreeIndex *cachedIndex // for all other trees treeMu sync.Mutex - treeIndexes map[btrfs.ObjID]cachedIndex + treeIndexes map[btrfsprim.ObjID]cachedIndex } -var _ btrfs.Trees = (*brokenTrees)(nil) +var _ btrfstree.Trees = (*brokenTrees)(nil) // NewBrokenTrees wraps a *btrfs.FS to support looking up information // from broken trees. @@ -120,47 +122,59 @@ var _ btrfs.Trees = (*brokenTrees)(nil) // .TreeWalk to build an out-of-FS index of all of the items in the // tree, and re-implements TreeLookup, TreeSearch, and TreeSearchAll // using that index. -func NewBrokenTrees(ctx context.Context, inner *btrfs.FS) btrfs.Trees { +func NewBrokenTrees(ctx context.Context, inner *btrfs.FS) interface { + btrfstree.Trees + Superblock() (*btrfstree.Superblock, error) + ReadAt(p []byte, off btrfsvol.LogicalAddr) (int, error) +} { return &brokenTrees{ ctx: ctx, inner: inner, } } -func (bt *brokenTrees) treeIndex(treeID btrfs.ObjID) cachedIndex { - var treeRoot *btrfs.TreeRoot +func (bt *brokenTrees) treeIndex(treeID btrfsprim.ObjID) cachedIndex { + var treeRoot *btrfstree.TreeRoot var err error - if treeID == btrfs.ROOT_TREE_OBJECTID { + if treeID == btrfsprim.ROOT_TREE_OBJECTID { bt.rootTreeMu.Lock() defer bt.rootTreeMu.Unlock() if bt.rootTreeIndex != nil { return *bt.rootTreeIndex } - treeRoot, err = btrfs.LookupTreeRoot(bt.inner, treeID) + var sb *btrfstree.Superblock + sb, err = bt.inner.Superblock() + if err == nil { + treeRoot, err = btrfstree.LookupTreeRoot(bt.inner, *sb, treeID) + } } else { bt.treeMu.Lock() defer bt.treeMu.Unlock() if bt.treeIndexes == nil { - bt.treeIndexes = make(map[btrfs.ObjID]cachedIndex) + bt.treeIndexes = make(map[btrfsprim.ObjID]cachedIndex) } if cacheEntry, exists := bt.treeIndexes[treeID]; exists { return cacheEntry } - treeRoot, err = btrfs.LookupTreeRoot(bt, treeID) + var sb *btrfstree.Superblock + sb, err = bt.inner.Superblock() + if err == nil { + treeRoot, err = btrfstree.LookupTreeRoot(bt, *sb, treeID) + } } var cacheEntry cachedIndex - cacheEntry.Errors = make(map[int]map[btrfs.Key][]spanError) + cacheEntry.Errors = make(map[int]map[btrfsprim.Key][]spanError) if err != nil { cacheEntry.TreeRootErr = err } else { - cacheEntry.Items = &containers.RBTree[btrfs.Key, indexValue]{ - KeyFn: func(iv indexValue) btrfs.Key { return iv.Key }, + cacheEntry.Items = &containers.RBTree[btrfsprim.Key, indexValue]{ + KeyFn: func(iv indexValue) btrfsprim.Key { return iv.Key }, } dlog.Infof(bt.ctx, "indexing tree %v...", treeID) - bt.inner.RawTreeWalk( + btrfstree.TreesImpl{NodeSource: bt.inner}.RawTreeWalk( bt.ctx, *treeRoot, - func(err *btrfs.TreeError) { + func(err *btrfstree.TreeError) { if len(err.Path) > 0 && err.Path.Node(-1).ToNodeAddr == 0 { // This is a panic because on the filesystems I'm working with it more likely // indicates a bug in my item parser than a problem with the filesystem. @@ -169,7 +183,7 @@ func (bt *brokenTrees) treeIndex(treeID btrfs.ObjID) cachedIndex { invLvl := len(err.Path) lvlErrs, ok := cacheEntry.Errors[invLvl] if !ok { - lvlErrs = make(map[btrfs.Key][]spanError) + lvlErrs = make(map[btrfsprim.Key][]spanError) cacheEntry.Errors[invLvl] = lvlErrs } beg, end := span(bt.inner, err.Path) @@ -178,8 +192,8 @@ func (bt *brokenTrees) treeIndex(treeID btrfs.ObjID) cachedIndex { Err: err, }) }, - btrfs.TreeWalkHandler{ - Item: func(path btrfs.TreePath, item btrfs.Item) error { + btrfstree.TreeWalkHandler{ + Item: func(path btrfstree.TreePath, item btrfstree.Item) error { if cacheEntry.Items.Lookup(item.Key) != nil { // This is a panic because I'm not really sure what the best way to // handle this is, and so if this happens I want the program to crash @@ -197,7 +211,7 @@ func (bt *brokenTrees) treeIndex(treeID btrfs.ObjID) cachedIndex { ) dlog.Infof(bt.ctx, "... done indexing tree %v", treeID) } - if treeID == btrfs.ROOT_TREE_OBJECTID { + if treeID == btrfsprim.ROOT_TREE_OBJECTID { bt.rootTreeIndex = &cacheEntry } else { bt.treeIndexes[treeID] = cacheEntry @@ -205,29 +219,29 @@ func (bt *brokenTrees) treeIndex(treeID btrfs.ObjID) cachedIndex { return cacheEntry } -func (bt *brokenTrees) TreeLookup(treeID btrfs.ObjID, key btrfs.Key) (btrfs.Item, error) { - item, err := bt.TreeSearch(treeID, btrfs.KeySearch(key.Cmp)) +func (bt *brokenTrees) TreeLookup(treeID btrfsprim.ObjID, key btrfsprim.Key) (btrfstree.Item, error) { + item, err := bt.TreeSearch(treeID, btrfstree.KeySearch(key.Cmp)) if err != nil { err = fmt.Errorf("item with key=%v: %w", key, err) } return item, err } -func (bt *brokenTrees) TreeSearch(treeID btrfs.ObjID, fn func(btrfs.Key, uint32) int) (btrfs.Item, error) { +func (bt *brokenTrees) TreeSearch(treeID btrfsprim.ObjID, fn func(btrfsprim.Key, uint32) int) (btrfstree.Item, error) { index := bt.treeIndex(treeID) if index.TreeRootErr != nil { - return btrfs.Item{}, index.TreeRootErr + return btrfstree.Item{}, index.TreeRootErr } indexItem := index.Items.Search(func(indexItem indexValue) int { return fn(indexItem.Key, indexItem.ItemSize) }) if indexItem == nil { - return btrfs.Item{}, iofs.ErrNotExist + return btrfstree.Item{}, iofs.ErrNotExist } node, err := bt.inner.ReadNode(indexItem.Value.Path.Parent()) if err != nil { - return btrfs.Item{}, err + return btrfstree.Item{}, err } item := node.Data.BodyLeaf[indexItem.Value.Path.Node(-1).FromItemIdx] @@ -235,7 +249,7 @@ func (bt *brokenTrees) TreeSearch(treeID btrfs.ObjID, fn func(btrfs.Key, uint32) return item, nil } -func (bt *brokenTrees) TreeSearchAll(treeID btrfs.ObjID, fn func(btrfs.Key, uint32) int) ([]btrfs.Item, error) { +func (bt *brokenTrees) TreeSearchAll(treeID btrfsprim.ObjID, fn func(btrfsprim.Key, uint32) int) ([]btrfstree.Item, error) { index := bt.treeIndex(treeID) if index.TreeRootErr != nil { return nil, index.TreeRootErr @@ -247,8 +261,8 @@ func (bt *brokenTrees) TreeSearchAll(treeID btrfs.ObjID, fn func(btrfs.Key, uint return nil, iofs.ErrNotExist } - ret := make([]btrfs.Item, len(indexItems)) - var node *diskio.Ref[btrfsvol.LogicalAddr, btrfs.Node] + ret := make([]btrfstree.Item, len(indexItems)) + var node *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node] for i := range indexItems { if node == nil || node.Addr != indexItems[i].Path.Node(-2).ToNodeAddr { var err error @@ -283,18 +297,18 @@ func (bt *brokenTrees) TreeSearchAll(treeID btrfs.ObjID, fn func(btrfs.Key, uint return ret, nil } -func (bt *brokenTrees) TreeWalk(ctx context.Context, treeID btrfs.ObjID, errHandle func(*btrfs.TreeError), cbs btrfs.TreeWalkHandler) { +func (bt *brokenTrees) TreeWalk(ctx context.Context, treeID btrfsprim.ObjID, errHandle func(*btrfstree.TreeError), cbs btrfstree.TreeWalkHandler) { index := bt.treeIndex(treeID) if index.TreeRootErr != nil { - errHandle(&btrfs.TreeError{ - Path: btrfs.TreePath{{ + errHandle(&btrfstree.TreeError{ + Path: btrfstree.TreePath{{ FromTree: treeID, }}, Err: index.TreeRootErr, }) return } - var node *diskio.Ref[btrfsvol.LogicalAddr, btrfs.Node] + var node *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node] _ = index.Items.Walk(func(indexItem *containers.RBNode[indexValue]) error { if ctx.Err() != nil { return ctx.Err() @@ -307,20 +321,20 @@ func (bt *brokenTrees) TreeWalk(ctx context.Context, treeID btrfs.ObjID, errHand var err error node, err = bt.inner.ReadNode(indexItem.Value.Path.Parent()) if err != nil { - errHandle(&btrfs.TreeError{Path: indexItem.Value.Path, Err: err}) + errHandle(&btrfstree.TreeError{Path: indexItem.Value.Path, Err: err}) return nil } } item := node.Data.BodyLeaf[indexItem.Value.Path.Node(-1).FromItemIdx] if err := cbs.Item(indexItem.Value.Path, item); err != nil { - errHandle(&btrfs.TreeError{Path: indexItem.Value.Path, Err: err}) + errHandle(&btrfstree.TreeError{Path: indexItem.Value.Path, Err: err}) } } return nil }) } -func (bt *brokenTrees) Superblock() (*btrfs.Superblock, error) { +func (bt *brokenTrees) Superblock() (*btrfstree.Superblock, error) { return bt.inner.Superblock() } |