summaryrefslogtreecommitdiff
path: root/cmd/btrfs-clear-bad-nodes
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2022-07-07 02:51:57 -0600
committerLuke Shumaker <lukeshu@lukeshu.com>2022-07-08 00:16:01 -0600
commit22c32850798c264b6a20539b9cd1699228368ce9 (patch)
treeeea4fe596bc584cba96245d8bfbe92503d1a4c61 /cmd/btrfs-clear-bad-nodes
parentfa98ff69f24545e1836201c30ab43cc2527c52e3 (diff)
write btrfs-clear-bad-nodes
Diffstat (limited to 'cmd/btrfs-clear-bad-nodes')
-rw-r--r--cmd/btrfs-clear-bad-nodes/main.go94
1 files changed, 94 insertions, 0 deletions
diff --git a/cmd/btrfs-clear-bad-nodes/main.go b/cmd/btrfs-clear-bad-nodes/main.go
new file mode 100644
index 0000000..754e08b
--- /dev/null
+++ b/cmd/btrfs-clear-bad-nodes/main.go
@@ -0,0 +1,94 @@
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "lukeshu.com/btrfs-tools/pkg/btrfs"
+ "lukeshu.com/btrfs-tools/pkg/btrfs/btrfsvol"
+ "lukeshu.com/btrfs-tools/pkg/btrfsmisc"
+ "lukeshu.com/btrfs-tools/pkg/util"
+)
+
+func main() {
+ if err := Main(os.Args[1:]...); err != nil {
+ fmt.Fprintf(os.Stderr, "%v: error: %v\n", os.Args[0], err)
+ os.Exit(1)
+ }
+}
+
+func Main(imgfilenames ...string) (err error) {
+ maybeSetErr := func(_err error) {
+ if _err != nil && err == nil {
+ err = _err
+ }
+ }
+
+ fs, err := btrfsmisc.Open(os.O_RDWR, imgfilenames...)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ maybeSetErr(fs.Close())
+ }()
+
+ var treeName string
+ btrfsmisc.WalkFS(fs, btrfsmisc.WalkFSHandler{
+ PreTree: func(name string, _ btrfsvol.LogicalAddr) {
+ treeName = name
+ },
+ Err: func(err error) {
+ fmt.Printf("error: %v\n", err)
+ },
+ 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 {
+ return nil
+ }
+ 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,
+ },
+ }
+ node.Data.Head.Checksum, err = node.Data.CalculateChecksum()
+ if err != nil {
+ return btrfsmisc.WalkErr{
+ TreeName: treeName,
+ Path: path,
+ Err: err,
+ }
+ }
+ if err := node.Write(); err != nil {
+ return err
+ }
+
+ fmt.Printf("fixed node@%v (err was %v)\n", node.Addr, origErr)
+ return nil
+ },
+ },
+ })
+
+ return nil
+}