diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2022-07-08 00:05:52 -0600 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2022-07-08 01:29:21 -0600 |
commit | 8e27c43c1b882c8f2f759eec556f90229c067cc9 (patch) | |
tree | 7a94a92d19f6639c07263537f49226406dd5b4e5 | |
parent | 7e09476e6cf9922baa3c3a49b559b5b9af970561 (diff) |
get initial expected levels from the superblock
-rw-r--r-- | cmd/btrfs-clear-bad-nodes/main.go | 26 | ||||
-rw-r--r-- | cmd/btrfs-dump-tree/main.go | 12 | ||||
-rw-r--r-- | cmd/btrfs-fsck/pass1.go | 2 | ||||
-rw-r--r-- | cmd/btrfs-fsck/pass2.go | 45 | ||||
-rw-r--r-- | cmd/btrfs-ls-files/main.go | 15 | ||||
-rw-r--r-- | cmd/btrfs-ls-trees/main.go | 9 | ||||
-rw-r--r-- | pkg/btrfs/io2_lv.go | 2 | ||||
-rw-r--r-- | pkg/btrfs/io3_btree.go | 115 | ||||
-rw-r--r-- | pkg/btrfs/io4_fs.go | 27 | ||||
-rw-r--r-- | pkg/btrfs/types_node.go | 3 | ||||
-rw-r--r-- | pkg/btrfsmisc/print_tree.go | 4 | ||||
-rw-r--r-- | pkg/btrfsmisc/walk.go | 117 |
12 files changed, 194 insertions, 183 deletions
diff --git a/cmd/btrfs-clear-bad-nodes/main.go b/cmd/btrfs-clear-bad-nodes/main.go index 44f6697..0bad792 100644 --- a/cmd/btrfs-clear-bad-nodes/main.go +++ b/cmd/btrfs-clear-bad-nodes/main.go @@ -1,8 +1,8 @@ package main import ( + "errors" "fmt" - "math" "os" "lukeshu.com/btrfs-tools/pkg/btrfs" @@ -38,8 +38,8 @@ func Main(imgfilenames ...string) (err error) { var treeName string var treeID btrfs.ObjID - btrfsmisc.WalkFS(fs, btrfsmisc.WalkFSHandler{ - PreTree: func(name string, id btrfs.ObjID, _ btrfsvol.LogicalAddr) { + btrfsmisc.WalkAllTrees(fs, btrfsmisc.WalkAllTreesHandler{ + PreTree: func(name string, id btrfs.ObjID) { treeName = name treeID = id }, @@ -49,7 +49,7 @@ func Main(imgfilenames ...string) (err error) { UnsafeNodes: true, TreeWalkHandler: btrfs.TreeWalkHandler{ Node: func(path btrfs.TreePath, node *util.Ref[btrfsvol.LogicalAddr, btrfs.Node], err error) error { - if node == nil || err == nil { + if err == nil { if !uuidsInited { metadataUUID = node.Data.Head.MetadataUUID chunkTreeUUID = node.Data.Head.ChunkTreeUUID @@ -57,17 +57,21 @@ func Main(imgfilenames ...string) (err error) { } return nil } + if !errors.Is(err, btrfs.ErrNotANode) { + err = btrfsmisc.WalkErr{ + TreeName: treeName, + Path: path, + Err: err, + } + fmt.Printf("error: %v\n", err) + return nil + } origErr := err if !uuidsInited { // TODO(lukeshu): Is there a better way to get the chunk - // tree UUID. + // tree UUID? return fmt.Errorf("cannot repair node@%v: not (yet?) sure what the chunk tree UUID is", node.Addr) } - nodeLevel := path[len(path)-1].NodeLevel - if nodeLevel == math.MaxUint8 { - // TODO(lukeshu): Use level from the superblock or whatever. - nodeLevel = 0 - } node.Data = btrfs.Node{ Size: node.Data.Size, ChecksumType: node.Data.ChecksumType, @@ -81,7 +85,7 @@ func Main(imgfilenames ...string) (err error) { Generation: 0, Owner: treeID, NumItems: 0, - Level: nodeLevel, + Level: path[len(path)-1].NodeLevel, }, } node.Data.Head.Checksum, err = node.Data.CalculateChecksum() diff --git a/cmd/btrfs-dump-tree/main.go b/cmd/btrfs-dump-tree/main.go index 7f1aba4..56727d4 100644 --- a/cmd/btrfs-dump-tree/main.go +++ b/cmd/btrfs-dump-tree/main.go @@ -41,29 +41,29 @@ func Main(imgfilename string) (err error) { fmt.Printf("btrfs-progs v%v\n", version) if superblock.Data.RootTree != 0 { fmt.Printf("root tree\n") - if err := btrfsmisc.PrintTree(fs, superblock.Data.RootTree); err != nil { + if err := btrfsmisc.PrintTree(fs, btrfs.ROOT_TREE_OBJECTID); err != nil { return err } } if superblock.Data.ChunkTree != 0 { fmt.Printf("chunk tree\n") - if err := btrfsmisc.PrintTree(fs, superblock.Data.ChunkTree); err != nil { + if err := btrfsmisc.PrintTree(fs, btrfs.CHUNK_TREE_OBJECTID); err != nil { return err } } if superblock.Data.LogTree != 0 { fmt.Printf("log root tree\n") - if err := btrfsmisc.PrintTree(fs, superblock.Data.LogTree); err != nil { + if err := btrfsmisc.PrintTree(fs, btrfs.TREE_LOG_OBJECTID); err != nil { return err } } if superblock.Data.BlockGroupRoot != 0 { fmt.Printf("block group tree\n") - if err := btrfsmisc.PrintTree(fs, superblock.Data.BlockGroupRoot); err != nil { + if err := btrfsmisc.PrintTree(fs, btrfs.BLOCK_GROUP_TREE_OBJECTID); err != nil { return err } } - if err := fs.TreeWalk(superblock.Data.RootTree, btrfs.TreeWalkHandler{ + if err := fs.TreeWalk(btrfs.ROOT_TREE_OBJECTID, btrfs.TreeWalkHandler{ Item: func(_ btrfs.TreePath, item btrfs.Item) error { if item.Head.Key.ItemType != btrfsitem.ROOT_ITEM_KEY { return nil @@ -92,7 +92,7 @@ func Main(imgfilename string) (err error) { treeName = "file" } fmt.Printf("%v tree %v \n", treeName, btrfsmisc.FmtKey(item.Head.Key)) - return btrfsmisc.PrintTree(fs, item.Body.(btrfsitem.Root).ByteNr) + return btrfsmisc.PrintTree(fs, item.Head.Key.ObjectID) }, }); err != nil { return err diff --git a/cmd/btrfs-fsck/pass1.go b/cmd/btrfs-fsck/pass1.go index f8626af..a674b30 100644 --- a/cmd/btrfs-fsck/pass1.go +++ b/cmd/btrfs-fsck/pass1.go @@ -22,7 +22,7 @@ func pass1(fs *btrfs.FS, superblock *util.Ref[btrfsvol.PhysicalAddr, btrfs.Super fmt.Printf("Pass 1: ... walking fs\n") visitedNodes := make(map[btrfsvol.LogicalAddr]struct{}) - btrfsmisc.WalkFS(fs, btrfsmisc.WalkFSHandler{ + btrfsmisc.WalkAllTrees(fs, btrfsmisc.WalkAllTreesHandler{ TreeWalkHandler: btrfs.TreeWalkHandler{ Node: func(path btrfs.TreePath, node *util.Ref[btrfsvol.LogicalAddr, btrfs.Node], err error) error { if err != nil { diff --git a/cmd/btrfs-fsck/pass2.go b/cmd/btrfs-fsck/pass2.go index 95a307c..a8c0c9b 100644 --- a/cmd/btrfs-fsck/pass2.go +++ b/cmd/btrfs-fsck/pass2.go @@ -2,7 +2,6 @@ package main import ( "fmt" - iofs "io/fs" "lukeshu.com/btrfs-tools/pkg/btrfs" "lukeshu.com/btrfs-tools/pkg/btrfs/btrfsvol" @@ -14,7 +13,7 @@ func pass2(fs *btrfs.FS, foundNodes map[btrfsvol.LogicalAddr]struct{}) { fmt.Printf("\nPass 2: orphaned nodes\n") visitedNodes := make(map[btrfsvol.LogicalAddr]struct{}) - btrfsmisc.WalkFS(fs, btrfsmisc.WalkFSHandler{ + btrfsmisc.WalkAllTrees(fs, btrfsmisc.WalkAllTreesHandler{ TreeWalkHandler: btrfs.TreeWalkHandler{ Node: func(path btrfs.TreePath, node *util.Ref[btrfsvol.LogicalAddr, btrfs.Node], err error) error { visitedNodes[node.Addr] = struct{}{} @@ -37,26 +36,28 @@ func pass2(fs *btrfs.FS, foundNodes map[btrfsvol.LogicalAddr]struct{}) { for node := range orphanedNodes { orphanedRoots[node] = struct{}{} } - for potentialRoot := range orphanedRoots { - if err := fs.TreeWalk(potentialRoot, btrfs.TreeWalkHandler{ - Node: func(path btrfs.TreePath, _ *util.Ref[btrfsvol.LogicalAddr, btrfs.Node], _ error) error { - nodeAddr := path[len(path)-1].NodeAddr - if nodeAddr != potentialRoot { - delete(orphanedRoots, nodeAddr) - } - orphanedNodes[nodeAddr] = orphanedNodes[nodeAddr] + 1 - visitCnt := orphanedNodes[nodeAddr] - if visitCnt > 1 { - return iofs.SkipDir - } - return nil - }, - }); err != nil { - fmt.Printf("Pass 2: walk orphans: error: %v\n", err) + /* + for potentialRoot := range orphanedRoots { + if err := fs.TreeWalk(potentialRoot, btrfs.TreeWalkHandler{ + Node: func(path btrfs.TreePath, _ *util.Ref[btrfsvol.LogicalAddr, btrfs.Node], _ error) error { + nodeAddr := path[len(path)-1].NodeAddr + if nodeAddr != potentialRoot { + delete(orphanedRoots, nodeAddr) + } + orphanedNodes[nodeAddr] = orphanedNodes[nodeAddr] + 1 + visitCnt := orphanedNodes[nodeAddr] + if visitCnt > 1 { + return iofs.SkipDir + } + return nil + }, + }); err != nil { + fmt.Printf("Pass 2: walk orphans: error: %v\n", err) + } } - } - for _, node := range util.SortedMapKeys(orphanedRoots) { - fmt.Printf("Pass 2: orphaned root: %v\n", node) - } + for _, node := range util.SortedMapKeys(orphanedRoots) { + fmt.Printf("Pass 2: orphaned root: %v\n", node) + } + */ } diff --git a/cmd/btrfs-ls-files/main.go b/cmd/btrfs-ls-files/main.go index 22eefcb..c2e9e06 100644 --- a/cmd/btrfs-ls-files/main.go +++ b/cmd/btrfs-ls-files/main.go @@ -10,7 +10,6 @@ import ( "lukeshu.com/btrfs-tools/pkg/btrfs" "lukeshu.com/btrfs-tools/pkg/btrfs/btrfsitem" - "lukeshu.com/btrfs-tools/pkg/btrfs/btrfsvol" "lukeshu.com/btrfs-tools/pkg/btrfsmisc" "lukeshu.com/btrfs-tools/pkg/util" ) @@ -54,23 +53,17 @@ const ( ) func printSubvol(fs *btrfs.FS, prefix0, prefix1, name string, key btrfs.Key) { - sb, err := fs.Superblock() - if err != nil { - fmt.Printf("%s%q error: could not read superblock: %v\n", prefix0, name, err) - return - } - - root, err := fs.TreeLookup(sb.Data.RootTree, key) + root, err := fs.TreeLookup(btrfs.ROOT_TREE_OBJECTID, key) if err != nil { fmt.Printf("%s%q error: could not look up root %v: %v\n", prefix0, name, key, err) return } rootBody := root.Body.(btrfsitem.Root) - printDir(fs, rootBody.ByteNr, prefix0, prefix1, name, rootBody.RootDirID) + printDir(fs, root.Head.Key.ObjectID, prefix0, prefix1, name, rootBody.RootDirID) } -func printDir(fs *btrfs.FS, fsTree btrfsvol.LogicalAddr, prefix0, prefix1, dirName string, dirInode btrfs.ObjID) { +func printDir(fs *btrfs.FS, fsTree btrfs.ObjID, prefix0, prefix1, dirName string, dirInode btrfs.ObjID) { var errs derror.MultiError items, err := fs.TreeSearchAll(fsTree, func(key btrfs.Key) int { return util.CmpUint(dirInode, key.ObjectID) @@ -190,7 +183,7 @@ func printDir(fs *btrfs.FS, fsTree btrfsvol.LogicalAddr, prefix0, prefix1, dirNa } } -func printDirEntry(fs *btrfs.FS, fsTree btrfsvol.LogicalAddr, prefix0, prefix1 string, entry btrfsitem.DirEntry) { +func printDirEntry(fs *btrfs.FS, fsTree btrfs.ObjID, prefix0, prefix1 string, entry btrfsitem.DirEntry) { if len(entry.Data) != 0 { fmt.Printf("%s%q: error: TODO: I don't know how to handle dirent.data\n", prefix0, entry.Name) diff --git a/cmd/btrfs-ls-trees/main.go b/cmd/btrfs-ls-trees/main.go index a444e34..534b095 100644 --- a/cmd/btrfs-ls-trees/main.go +++ b/cmd/btrfs-ls-trees/main.go @@ -8,7 +8,6 @@ import ( "lukeshu.com/btrfs-tools/pkg/btrfs" "lukeshu.com/btrfs-tools/pkg/btrfs/btrfsitem" - "lukeshu.com/btrfs-tools/pkg/btrfs/btrfsvol" "lukeshu.com/btrfs-tools/pkg/btrfsmisc" "lukeshu.com/btrfs-tools/pkg/util" ) @@ -37,11 +36,11 @@ func Main(imgfilenames ...string) (err error) { var treeErrCnt int var treeItemCnt map[btrfsitem.Type]int - btrfsmisc.WalkFS(fs, btrfsmisc.WalkFSHandler{ - PreTree: func(name string, _ btrfs.ObjID, laddr btrfsvol.LogicalAddr) { + btrfsmisc.WalkAllTrees(fs, btrfsmisc.WalkAllTreesHandler{ + PreTree: func(name string, treeID btrfs.ObjID) { treeErrCnt = 0 treeItemCnt = make(map[btrfsitem.Type]int) - fmt.Printf("tree laddr=%v name=%q\n", laddr, name) + fmt.Printf("tree id=%v name=%q\n", treeID, name) }, Err: func(_ error) { treeErrCnt++ @@ -53,7 +52,7 @@ func Main(imgfilenames ...string) (err error) { return nil }, }, - PostTree: func(name string, _ btrfs.ObjID, laddr btrfsvol.LogicalAddr) { + PostTree: func(_ string, _ btrfs.ObjID) { totalItems := 0 for _, cnt := range treeItemCnt { totalItems += cnt diff --git a/pkg/btrfs/io2_lv.go b/pkg/btrfs/io2_lv.go index 0564066..486a4ae 100644 --- a/pkg/btrfs/io2_lv.go +++ b/pkg/btrfs/io2_lv.go @@ -153,7 +153,7 @@ func (fs *FS) initDev(sb *util.Ref[btrfsvol.PhysicalAddr, Superblock]) error { } } } - if err := fs.TreeWalk(sb.Data.ChunkTree, TreeWalkHandler{ + if err := fs.TreeWalk(CHUNK_TREE_OBJECTID, TreeWalkHandler{ Item: func(_ TreePath, item Item) error { if item.Head.Key.ItemType != btrfsitem.CHUNK_ITEM_KEY { return nil diff --git a/pkg/btrfs/io3_btree.go b/pkg/btrfs/io3_btree.go index 1bcb193..be46d21 100644 --- a/pkg/btrfs/io3_btree.go +++ b/pkg/btrfs/io3_btree.go @@ -5,11 +5,11 @@ import ( "fmt" "io" iofs "io/fs" - "math" "strings" "github.com/datawire/dlib/derror" + "lukeshu.com/btrfs-tools/pkg/btrfs/btrfsitem" "lukeshu.com/btrfs-tools/pkg/btrfs/btrfsvol" "lukeshu.com/btrfs-tools/pkg/util" ) @@ -74,16 +74,12 @@ type TreePathElem struct { // being pointed at. NodeAddr btrfsvol.LogicalAddr // NodeLevel is the expected or actual level of the node at - // NodeAddr, or 255 if there is no knowledge of the level. + // NodeAddr. NodeLevel uint8 } func (elem TreePathElem) writeNodeTo(w io.Writer) { - if elem.NodeLevel != math.MaxUint8 { - fmt.Fprintf(w, "node:%d@%v", elem.NodeLevel, elem.NodeAddr) - } else { - fmt.Fprintf(w, "node@%v", elem.NodeAddr) - } + fmt.Fprintf(w, "node:%d@%v", elem.NodeLevel, elem.NodeAddr) } func (path TreePath) String() string { @@ -102,6 +98,75 @@ func (path TreePath) String() string { return ret.String() } +// A treeRoot is more-or-less a btrfsitem.Root, but simpler and generalized for +type treeRoot struct { + TreeID ObjID + RootNode btrfsvol.LogicalAddr + Level uint8 + Generation Generation +} + +func (fs *FS) lookupTree(treeID ObjID) (*treeRoot, error) { + sb, err := fs.Superblock() + if err != nil { + return nil, err + } + switch treeID { + case ROOT_TREE_OBJECTID: + return &treeRoot{ + TreeID: treeID, + RootNode: sb.Data.RootTree, + Level: sb.Data.RootLevel, + Generation: sb.Data.Generation, // XXX: same generation as LOG_TREE? + }, nil + case CHUNK_TREE_OBJECTID: + return &treeRoot{ + TreeID: treeID, + RootNode: sb.Data.ChunkTree, + Level: sb.Data.ChunkLevel, + Generation: sb.Data.ChunkRootGeneration, + }, nil + case TREE_LOG_OBJECTID: + return &treeRoot{ + TreeID: treeID, + RootNode: sb.Data.LogTree, + Level: sb.Data.LogLevel, + Generation: sb.Data.Generation, // XXX: same generation as ROOT_TREE? + }, nil + case BLOCK_GROUP_TREE_OBJECTID: + return &treeRoot{ + TreeID: treeID, + RootNode: sb.Data.BlockGroupRoot, + Level: sb.Data.BlockGroupRootLevel, + Generation: sb.Data.BlockGroupRootGeneration, + }, nil + default: + rootItem, err := fs.TreeSearch(ROOT_TREE_OBJECTID, func(key Key) int { + if key.ObjectID == treeID && key.ItemType == btrfsitem.ROOT_ITEM_KEY { + return 0 + } + return Key{ + ObjectID: treeID, + ItemType: btrfsitem.ROOT_ITEM_KEY, + Offset: 0, + }.Cmp(key) + }) + if err != nil { + return nil, err + } + rootItemBody, ok := rootItem.Body.(btrfsitem.Root) + if !ok { + return nil, fmt.Errorf("malformed ROOT_ITEM for tree %v", treeID) + } + return &treeRoot{ + TreeID: treeID, + RootNode: rootItemBody.ByteNr, + Level: rootItemBody.Level, + Generation: rootItemBody.Generation, + }, nil + } +} + type TreeWalkHandler struct { // Callbacks for entire nodes PreNode func(TreePath) error @@ -127,12 +192,16 @@ type TreeWalkHandler struct { // else: // 004 .Item() // 007 .PostNode() -func (fs *FS) TreeWalk(treeRoot btrfsvol.LogicalAddr, cbs TreeWalkHandler) error { +func (fs *FS) TreeWalk(treeID ObjID, cbs TreeWalkHandler) error { + rootInfo, err := fs.lookupTree(treeID) + if err != nil { + return err + } path := TreePath{ TreePathElem{ ItemIdx: -1, - NodeAddr: treeRoot, - NodeLevel: math.MaxUint8, + NodeAddr: rootInfo.RootNode, + NodeLevel: rootInfo.Level, }, } return fs.treeWalk(path, cbs) @@ -216,12 +285,12 @@ func (fs *FS) treeWalk(path TreePath, cbs TreeWalkHandler) error { return nil } -func (fs *FS) treeSearch(treeRoot btrfsvol.LogicalAddr, fn func(Key) int) (TreePath, *util.Ref[btrfsvol.LogicalAddr, Node], error) { +func (fs *FS) treeSearch(treeRoot treeRoot, fn func(Key) int) (TreePath, *util.Ref[btrfsvol.LogicalAddr, Node], error) { path := TreePath{ TreePathElem{ ItemIdx: -1, - NodeAddr: treeRoot, - NodeLevel: math.MaxUint8, + NodeAddr: treeRoot.RootNode, + NodeLevel: treeRoot.Level, }, } for { @@ -418,16 +487,20 @@ func (fs *FS) next(path TreePath, node *util.Ref[btrfsvol.LogicalAddr, Node]) (T return path, node, nil } -func (fs *FS) TreeSearch(treeRoot btrfsvol.LogicalAddr, fn func(Key) int) (Item, error) { - path, node, err := fs.treeSearch(treeRoot, fn) +func (fs *FS) TreeSearch(treeID ObjID, fn func(Key) int) (Item, error) { + rootInfo, err := fs.lookupTree(treeID) + if err != nil { + return Item{}, err + } + path, node, err := fs.treeSearch(*rootInfo, fn) if err != nil { return Item{}, err } return node.Data.BodyLeaf[path[len(path)-1].ItemIdx], nil } -func (fs *FS) TreeLookup(treeRoot btrfsvol.LogicalAddr, key Key) (Item, error) { - item, err := fs.TreeSearch(treeRoot, key.Cmp) +func (fs *FS) TreeLookup(treeID ObjID, key Key) (Item, error) { + item, err := fs.TreeSearch(treeID, key.Cmp) if err != nil { err = fmt.Errorf("item with key=%v: %w", key, err) } @@ -438,8 +511,12 @@ func (fs *FS) TreeLookup(treeRoot btrfsvol.LogicalAddr, key Key) (Item, error) { // return *both* a list of items and an error. // // If no such item is found, an error that is io/fs.ErrNotExist is returned. -func (fs *FS) TreeSearchAll(treeRoot btrfsvol.LogicalAddr, fn func(Key) int) ([]Item, error) { - middlePath, middleNode, err := fs.treeSearch(treeRoot, fn) +func (fs *FS) TreeSearchAll(treeID ObjID, fn func(Key) int) ([]Item, error) { + rootInfo, err := fs.lookupTree(treeID) + if err != nil { + return nil, err + } + middlePath, middleNode, err := fs.treeSearch(*rootInfo, fn) if err != nil { return nil, err } diff --git a/pkg/btrfs/io4_fs.go b/pkg/btrfs/io4_fs.go index 37d949e..cd8e281 100644 --- a/pkg/btrfs/io4_fs.go +++ b/pkg/btrfs/io4_fs.go @@ -66,13 +66,7 @@ type Subvolume struct { func (sv *Subvolume) init() { sv.rootOnce.Do(func() { - sb, err := sv.FS.Superblock() - if err != nil { - sv.rootErr = err - return - } - - root, err := sv.FS.TreeLookup(sb.Data.RootTree, Key{ + root, err := sv.FS.TreeLookup(ROOT_TREE_OBJECTID, Key{ ObjectID: sv.TreeID, ItemType: btrfsitem.ROOT_ITEM_KEY, Offset: 0, @@ -97,22 +91,12 @@ func (sv *Subvolume) GetRootInode() (ObjID, error) { return sv.rootVal.RootDirID, sv.rootErr } -func (sv *Subvolume) GetFSTree() (btrfsvol.LogicalAddr, error) { - sv.init() - return sv.rootVal.ByteNr, sv.rootErr -} - func (sv *Subvolume) LoadBareInode(inode ObjID) (*BareInode, error) { val := sv.bareInodeCache.GetOrElse(inode, func() (val *BareInode) { val = &BareInode{ Inode: inode, } - tree, err := sv.GetFSTree() - if err != nil { - val.Errs = append(val.Errs, err) - return - } - item, err := sv.FS.TreeLookup(tree, Key{ + item, err := sv.FS.TreeLookup(sv.TreeID, Key{ ObjectID: inode, ItemType: btrfsitem.INODE_ITEM_KEY, Offset: 0, @@ -144,12 +128,7 @@ func (sv *Subvolume) LoadFullInode(inode ObjID) (*FullInode, error) { Inode: inode, }, } - tree, err := sv.GetFSTree() - if err != nil { - val.Errs = append(val.Errs, err) - return - } - items, err := sv.FS.TreeSearchAll(tree, func(key Key) int { + items, err := sv.FS.TreeSearchAll(sv.TreeID, func(key Key) int { return util.CmpUint(inode, key.ObjectID) }) if err != nil { diff --git a/pkg/btrfs/types_node.go b/pkg/btrfs/types_node.go index 92f7513..4382a91 100644 --- a/pkg/btrfs/types_node.go +++ b/pkg/btrfs/types_node.go @@ -4,7 +4,6 @@ import ( "encoding/binary" "errors" "fmt" - "math" "lukeshu.com/btrfs-tools/pkg/binstruct" "lukeshu.com/btrfs-tools/pkg/btrfs/btrfsitem" @@ -404,7 +403,7 @@ func (fs *FS) readNodeAtLevel(addr btrfsvol.LogicalAddr, expLevel uint8) (*util. if err != nil { return node, err } - if expLevel != math.MaxUint8 && node.Data.Head.Level != expLevel { + if node.Data.Head.Level != expLevel { return node, fmt.Errorf("btrfs.FS.ReadNode: node@%v: expected level %v but has level %v", node.Addr, expLevel, node.Data.Head.Level) } diff --git a/pkg/btrfsmisc/print_tree.go b/pkg/btrfsmisc/print_tree.go index 8bfcbe5..cc3055d 100644 --- a/pkg/btrfsmisc/print_tree.go +++ b/pkg/btrfsmisc/print_tree.go @@ -15,8 +15,8 @@ import ( // PrintTree mimics btrfs-progs // kernel-shared/print-tree.c:btrfs_print_tree() and // kernel-shared/print-tree.c:btrfs_print_leaf() -func PrintTree(fs *btrfs.FS, root btrfsvol.LogicalAddr) error { - return fs.TreeWalk(root, btrfs.TreeWalkHandler{ +func PrintTree(fs *btrfs.FS, treeID btrfs.ObjID) error { + return fs.TreeWalk(treeID, btrfs.TreeWalkHandler{ Node: func(path btrfs.TreePath, nodeRef *util.Ref[btrfsvol.LogicalAddr, btrfs.Node], err error) error { if err != nil { fmt.Fprintf(os.Stderr, "error: %v: %v\n", path, err) diff --git a/pkg/btrfsmisc/walk.go b/pkg/btrfsmisc/walk.go index 231f46b..55adf1d 100644 --- a/pkg/btrfsmisc/walk.go +++ b/pkg/btrfsmisc/walk.go @@ -24,20 +24,20 @@ func (e WalkErr) Error() string { return fmt.Sprintf("%v: %v: %v", e.TreeName, e.Path, e.Err) } -type WalkFSHandler struct { +type WalkAllTreesHandler struct { Err func(error) // Callbacks for entire trees - PreTree func(name string, id btrfs.ObjID, laddr btrfsvol.LogicalAddr) - PostTree func(name string, id btrfs.ObjID, laddr btrfsvol.LogicalAddr) + PreTree func(name string, id btrfs.ObjID) + PostTree func(name string, id btrfs.ObjID) // Callbacks for nodes or smaller UnsafeNodes bool btrfs.TreeWalkHandler } -// WalkFS walks all trees in a *btrfs.FS. Rather than returning an -// error, it calls errCb each time an error is encountered. The error -// will always be of type WalkErr. -func WalkFS(fs *btrfs.FS, cbs WalkFSHandler) { +// WalkAllTrees walks all trees in a *btrfs.FS. Rather than returning +// an error, it calls errCb each time an error is encountered. The +// error will always be of type WalkErr. +func WalkAllTrees(fs *btrfs.FS, cbs WalkAllTreesHandler) { var treeName string handleErr := func(path btrfs.TreePath, err error) { cbs.Err(WalkErr{ @@ -47,29 +47,38 @@ func WalkFS(fs *btrfs.FS, cbs WalkFSHandler) { }) } - var foundTrees []struct { + trees := []struct { Name string ID btrfs.ObjID - Root btrfsvol.LogicalAddr + }{ + { + Name: "root tree", + ID: btrfs.ROOT_TREE_OBJECTID, + }, + { + Name: "chunk tree", + ID: btrfs.CHUNK_TREE_OBJECTID, + }, + { + Name: "log tree", + ID: btrfs.TREE_LOG_OBJECTID, + }, + { + Name: "block group tree", + ID: btrfs.BLOCK_GROUP_TREE_OBJECTID, + }, } origItem := cbs.Item cbs.Item = func(path btrfs.TreePath, item btrfs.Item) error { if item.Head.Key.ItemType == btrfsitem.ROOT_ITEM_KEY { - root, ok := item.Body.(btrfsitem.Root) - if !ok { - handleErr(path, fmt.Errorf("ROOT_ITEM_KEY is a %T, not a btrfsitem.Root", item.Body)) - } else { - foundTrees = append(foundTrees, struct { - Name string - ID btrfs.ObjID - Root btrfsvol.LogicalAddr - }{ - Name: fmt.Sprintf("tree %v (via %v %v)", - item.Head.Key.ObjectID.Format(0), treeName, path), - ID: item.Head.Key.ObjectID, - Root: root.ByteNr, - }) - } + trees = append(trees, struct { + Name string + ID btrfs.ObjID + }{ + Name: fmt.Sprintf("tree %v (via %v %v)", + item.Head.Key.ObjectID.Format(0), treeName, path), + ID: item.Head.Key.ObjectID, + }) } if origItem != nil { return origItem(path, item) @@ -90,67 +99,17 @@ func WalkFS(fs *btrfs.FS, cbs WalkFSHandler) { } } - treeName = "superblock" - superblock, err := fs.Superblock() - if err != nil { - handleErr(nil, err) - return - } - - treeName = "root tree" - if cbs.PreTree != nil { - cbs.PreTree(treeName, btrfs.ROOT_TREE_OBJECTID, superblock.Data.RootTree) - } - if err := fs.TreeWalk(superblock.Data.RootTree, cbs.TreeWalkHandler); err != nil { - handleErr(nil, err) - } - if cbs.PostTree != nil { - cbs.PostTree(treeName, btrfs.ROOT_TREE_OBJECTID, superblock.Data.RootTree) - } - - treeName = "chunk tree" - if cbs.PreTree != nil { - cbs.PreTree(treeName, btrfs.CHUNK_TREE_OBJECTID, superblock.Data.ChunkTree) - } - if err := fs.TreeWalk(superblock.Data.ChunkTree, cbs.TreeWalkHandler); err != nil { - handleErr(nil, err) - } - if cbs.PostTree != nil { - cbs.PostTree(treeName, btrfs.CHUNK_TREE_OBJECTID, superblock.Data.ChunkTree) - } - - treeName = "log tree" - if cbs.PreTree != nil { - cbs.PreTree(treeName, btrfs.TREE_LOG_OBJECTID, superblock.Data.LogTree) - } - if err := fs.TreeWalk(superblock.Data.LogTree, cbs.TreeWalkHandler); err != nil { - handleErr(nil, err) - } - if cbs.PostTree != nil { - cbs.PostTree(treeName, btrfs.TREE_LOG_OBJECTID, superblock.Data.LogTree) - } - - treeName = "block group tree" - if cbs.PreTree != nil { - cbs.PreTree(treeName, btrfs.BLOCK_GROUP_TREE_OBJECTID, superblock.Data.BlockGroupRoot) - } - if err := fs.TreeWalk(superblock.Data.BlockGroupRoot, cbs.TreeWalkHandler); err != nil { - handleErr(nil, err) - } - if cbs.PostTree != nil { - cbs.PostTree(treeName, btrfs.BLOCK_GROUP_TREE_OBJECTID, superblock.Data.BlockGroupRoot) - } - - for _, tree := range foundTrees { + for i := 0; i < len(trees); i++ { + tree := trees[i] treeName = tree.Name if cbs.PreTree != nil { - cbs.PreTree(treeName, tree.ID, tree.Root) + cbs.PreTree(treeName, tree.ID) } - if err := fs.TreeWalk(tree.Root, cbs.TreeWalkHandler); err != nil { + if err := fs.TreeWalk(tree.ID, cbs.TreeWalkHandler); err != nil { handleErr(nil, err) } if cbs.PostTree != nil { - cbs.PostTree(treeName, tree.ID, tree.Root) + cbs.PostTree(treeName, tree.ID) } } } |