summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/btrfs-clear-bad-nodes/main.go26
-rw-r--r--cmd/btrfs-dump-tree/main.go12
-rw-r--r--cmd/btrfs-fsck/pass1.go2
-rw-r--r--cmd/btrfs-fsck/pass2.go45
-rw-r--r--cmd/btrfs-ls-files/main.go15
-rw-r--r--cmd/btrfs-ls-trees/main.go9
-rw-r--r--pkg/btrfs/io2_lv.go2
-rw-r--r--pkg/btrfs/io3_btree.go115
-rw-r--r--pkg/btrfs/io4_fs.go27
-rw-r--r--pkg/btrfs/types_node.go3
-rw-r--r--pkg/btrfsmisc/print_tree.go4
-rw-r--r--pkg/btrfsmisc/walk.go117
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)
}
}
}