summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/btrfs-clear-bad-nodes/main.go81
-rw-r--r--cmd/btrfs-ls-trees/main.go4
-rw-r--r--pkg/btrfs/btrfsitem/item_uuid.go34
-rw-r--r--pkg/btrfs/io4_fs.go2
-rw-r--r--pkg/btrfsmisc/print_tree.go5
-rw-r--r--pkg/btrfsmisc/walk.go27
6 files changed, 81 insertions, 72 deletions
diff --git a/cmd/btrfs-clear-bad-nodes/main.go b/cmd/btrfs-clear-bad-nodes/main.go
index 754e08b..098d862 100644
--- a/cmd/btrfs-clear-bad-nodes/main.go
+++ b/cmd/btrfs-clear-bad-nodes/main.go
@@ -5,6 +5,7 @@ import (
"os"
"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"
@@ -33,9 +34,11 @@ func Main(imgfilenames ...string) (err error) {
}()
var treeName string
+ var treeID btrfs.ObjID
btrfsmisc.WalkFS(fs, btrfsmisc.WalkFSHandler{
- PreTree: func(name string, _ btrfsvol.LogicalAddr) {
+ PreTree: func(name string, id btrfs.ObjID, _ btrfsvol.LogicalAddr) {
treeName = name
+ treeID = id
},
Err: func(err error) {
fmt.Printf("error: %v\n", err)
@@ -48,29 +51,59 @@ func Main(imgfilenames ...string) (err error) {
}
origErr := err
if len(path) < 2 {
- // TODO(lukeshu): Get info from the superblock and such
- // instead of the parent node, so that we can repair broken
- // root nodes.
- return fmt.Errorf("root node: %w", err)
- }
- parentNode, err := fs.ReadNode(path[len(path)-2].NodeAddr)
- if err != nil {
- return err
- }
- node.Data = btrfs.Node{
- Size: node.Data.Size,
- ChecksumType: node.Data.ChecksumType,
- Head: btrfs.NodeHeader{
- //Checksum: filled below,
- MetadataUUID: parentNode.Data.Head.MetadataUUID,
- Addr: node.Addr,
- Flags: btrfs.NodeWritten,
- BackrefRev: parentNode.Data.Head.BackrefRev,
- Generation: 0,
- Owner: parentNode.Data.Head.Owner,
- NumItems: 0,
- Level: parentNode.Data.Head.Level - 1,
- },
+ sb, err := fs.Superblock()
+ if err != nil {
+ return err
+ }
+ chunkRoot, err := fs.TreeLookup(sb.Data.RootTree, btrfs.Key{
+ ObjectID: btrfs.CHUNK_TREE_OBJECTID,
+ ItemType: btrfsitem.ROOT_ITEM_KEY,
+ Offset: 0,
+ })
+ if err != nil {
+ return err
+ }
+ chunkRootBody, ok := chunkRoot.Body.(btrfsitem.Root)
+ if !ok {
+ return fmt.Errorf("CHUNK_TREE_OBJECTID ROOT_ITEM has malformed body")
+ }
+ node.Data = btrfs.Node{
+ Size: node.Data.Size,
+ ChecksumType: node.Data.ChecksumType,
+ Head: btrfs.NodeHeader{
+ //Checksum: filled below,
+ MetadataUUID: sb.Data.EffectiveMetadataUUID(),
+ Addr: node.Addr,
+ Flags: btrfs.NodeWritten,
+ BackrefRev: btrfs.MixedBackrefRev,
+ ChunkTreeUUID: chunkRootBody.UUID,
+ Generation: 0,
+ Owner: treeID,
+ NumItems: 0,
+ Level: 0,
+ },
+ }
+ } else {
+ parentNode, err := fs.ReadNode(path[len(path)-2].NodeAddr)
+ if err != nil {
+ return err
+ }
+ node.Data = btrfs.Node{
+ Size: node.Data.Size,
+ ChecksumType: node.Data.ChecksumType,
+ Head: btrfs.NodeHeader{
+ //Checksum: filled below,
+ MetadataUUID: parentNode.Data.Head.MetadataUUID,
+ Addr: node.Addr,
+ Flags: btrfs.NodeWritten,
+ BackrefRev: parentNode.Data.Head.BackrefRev,
+ ChunkTreeUUID: parentNode.Data.Head.ChunkTreeUUID,
+ Generation: 0,
+ Owner: parentNode.Data.Head.Owner,
+ NumItems: 0,
+ Level: parentNode.Data.Head.Level - 1,
+ },
+ }
}
node.Data.Head.Checksum, err = node.Data.CalculateChecksum()
if err != nil {
diff --git a/cmd/btrfs-ls-trees/main.go b/cmd/btrfs-ls-trees/main.go
index eb4fef5..a444e34 100644
--- a/cmd/btrfs-ls-trees/main.go
+++ b/cmd/btrfs-ls-trees/main.go
@@ -38,7 +38,7 @@ func Main(imgfilenames ...string) (err error) {
var treeErrCnt int
var treeItemCnt map[btrfsitem.Type]int
btrfsmisc.WalkFS(fs, btrfsmisc.WalkFSHandler{
- PreTree: func(name string, laddr btrfsvol.LogicalAddr) {
+ PreTree: func(name string, _ btrfs.ObjID, laddr btrfsvol.LogicalAddr) {
treeErrCnt = 0
treeItemCnt = make(map[btrfsitem.Type]int)
fmt.Printf("tree laddr=%v name=%q\n", laddr, name)
@@ -53,7 +53,7 @@ func Main(imgfilenames ...string) (err error) {
return nil
},
},
- PostTree: func(name string, laddr btrfsvol.LogicalAddr) {
+ PostTree: func(name string, _ btrfs.ObjID, laddr btrfsvol.LogicalAddr) {
totalItems := 0
for _, cnt := range treeItemCnt {
totalItems += cnt
diff --git a/pkg/btrfs/btrfsitem/item_uuid.go b/pkg/btrfs/btrfsitem/item_uuid.go
index 6b47547..45543b3 100644
--- a/pkg/btrfs/btrfsitem/item_uuid.go
+++ b/pkg/btrfs/btrfsitem/item_uuid.go
@@ -5,36 +5,12 @@ import (
"lukeshu.com/btrfs-tools/pkg/btrfs/internal"
)
-// The Key for this item is a UUID, and the item is a list of
-// subvolume IDs (ObjectIDs) that that UUID maps to.
+// The Key for this item is a UUID, and the item is a subvolume IDs
+// that that UUID maps to.
//
// key.objectid = first half of UUID
// key.offset = second half of UUID
-type UUIDMap []internal.ObjID // UUID_SUBVOL=251 UUID_RECEIVED_SUBVOL=252
-
-func (o *UUIDMap) UnmarshalBinary(dat []byte) (int, error) {
- *o = nil
- var n int
- for len(dat) > n {
- var subvolID internal.ObjID
- _n, err := binstruct.Unmarshal(dat[n:], &subvolID)
- n += _n
- if err != nil {
- return n, err
- }
- *o = append(*o, subvolID)
- }
- return n, nil
-}
-
-func (o UUIDMap) MarshalBinary() ([]byte, error) {
- var ret []byte
- for _, subvolID := range o {
- bs, err := binstruct.Marshal(subvolID)
- ret = append(ret, bs...)
- if err != nil {
- return ret, err
- }
- }
- return ret, nil
+type UUIDMap struct { // UUID_SUBVOL=251 UUID_RECEIVED_SUBVOL=252
+ ObjID internal.ObjID `bin:"off=0, siz=8"`
+ binstruct.End `bin:"off=8"`
}
diff --git a/pkg/btrfs/io4_fs.go b/pkg/btrfs/io4_fs.go
index 75b973b..37d949e 100644
--- a/pkg/btrfs/io4_fs.go
+++ b/pkg/btrfs/io4_fs.go
@@ -84,7 +84,7 @@ func (sv *Subvolume) init() {
rootBody, ok := root.Body.(btrfsitem.Root)
if !ok {
- sv.rootErr = fmt.Errorf("FS_TREE_ ROOT_ITEM has malformed body")
+ sv.rootErr = fmt.Errorf("FS_TREE ROOT_ITEM has malformed body")
return
}
diff --git a/pkg/btrfsmisc/print_tree.go b/pkg/btrfsmisc/print_tree.go
index c03cb4a..8bfcbe5 100644
--- a/pkg/btrfsmisc/print_tree.go
+++ b/pkg/btrfsmisc/print_tree.go
@@ -221,10 +221,7 @@ func PrintTree(fs *btrfs.FS, root btrfsvol.LogicalAddr) error {
//case btrfsitem.QGROUP_LIMIT_KEY:
// // TODO
case btrfsitem.UUIDMap:
- for _, subvolID := range body {
- fmt.Printf("\t\tsubvol_id %d\n",
- subvolID)
- }
+ fmt.Printf("\t\tsubvol_id %d\n", body.ObjID)
//case btrfsitem.STRING_ITEM_KEY:
// // TODO
case btrfsitem.DevStats:
diff --git a/pkg/btrfsmisc/walk.go b/pkg/btrfsmisc/walk.go
index 0f3f811..231f46b 100644
--- a/pkg/btrfsmisc/walk.go
+++ b/pkg/btrfsmisc/walk.go
@@ -27,8 +27,8 @@ func (e WalkErr) Error() string {
type WalkFSHandler struct {
Err func(error)
// Callbacks for entire trees
- PreTree func(name string, laddr btrfsvol.LogicalAddr)
- PostTree func(name string, laddr btrfsvol.LogicalAddr)
+ PreTree func(name string, id btrfs.ObjID, laddr btrfsvol.LogicalAddr)
+ PostTree func(name string, id btrfs.ObjID, laddr btrfsvol.LogicalAddr)
// Callbacks for nodes or smaller
UnsafeNodes bool
btrfs.TreeWalkHandler
@@ -49,6 +49,7 @@ func WalkFS(fs *btrfs.FS, cbs WalkFSHandler) {
var foundTrees []struct {
Name string
+ ID btrfs.ObjID
Root btrfsvol.LogicalAddr
}
origItem := cbs.Item
@@ -60,10 +61,12 @@ func WalkFS(fs *btrfs.FS, cbs WalkFSHandler) {
} 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,
})
}
@@ -96,58 +99,58 @@ func WalkFS(fs *btrfs.FS, cbs WalkFSHandler) {
treeName = "root tree"
if cbs.PreTree != nil {
- cbs.PreTree(treeName, superblock.Data.RootTree)
+ 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, superblock.Data.RootTree)
+ cbs.PostTree(treeName, btrfs.ROOT_TREE_OBJECTID, superblock.Data.RootTree)
}
treeName = "chunk tree"
if cbs.PreTree != nil {
- cbs.PreTree(treeName, superblock.Data.ChunkTree)
+ 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, superblock.Data.ChunkTree)
+ cbs.PostTree(treeName, btrfs.CHUNK_TREE_OBJECTID, superblock.Data.ChunkTree)
}
treeName = "log tree"
if cbs.PreTree != nil {
- cbs.PreTree(treeName, superblock.Data.LogTree)
+ 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, superblock.Data.LogTree)
+ cbs.PostTree(treeName, btrfs.TREE_LOG_OBJECTID, superblock.Data.LogTree)
}
treeName = "block group tree"
if cbs.PreTree != nil {
- cbs.PreTree(treeName, superblock.Data.BlockGroupRoot)
+ 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, superblock.Data.BlockGroupRoot)
+ cbs.PostTree(treeName, btrfs.BLOCK_GROUP_TREE_OBJECTID, superblock.Data.BlockGroupRoot)
}
for _, tree := range foundTrees {
treeName = tree.Name
if cbs.PreTree != nil {
- cbs.PreTree(treeName, tree.Root)
+ cbs.PreTree(treeName, tree.ID, tree.Root)
}
if err := fs.TreeWalk(tree.Root, cbs.TreeWalkHandler); err != nil {
handleErr(nil, err)
}
if cbs.PostTree != nil {
- cbs.PostTree(treeName, tree.Root)
+ cbs.PostTree(treeName, tree.ID, tree.Root)
}
}
}