diff options
-rw-r--r-- | cmd/btrfs-clear-bad-nodes/main.go | 81 | ||||
-rw-r--r-- | cmd/btrfs-ls-trees/main.go | 4 | ||||
-rw-r--r-- | pkg/btrfs/btrfsitem/item_uuid.go | 34 | ||||
-rw-r--r-- | pkg/btrfs/io4_fs.go | 2 | ||||
-rw-r--r-- | pkg/btrfsmisc/print_tree.go | 5 | ||||
-rw-r--r-- | pkg/btrfsmisc/walk.go | 27 |
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) } } } |