btrfsck: add --init-csum-tree to replace the csum root with an empty one
authorChris Mason <chris.mason@oracle.com>
Thu, 9 Feb 2012 15:38:05 +0000 (10:38 -0500)
committerChris Mason <chris.mason@oracle.com>
Thu, 9 Feb 2012 15:38:05 +0000 (10:38 -0500)
This will effectively delete all of your crcs, but at least you'll
be able to mount the FS with nodatasum.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
btrfsck.c
ctree.c
ctree.h
disk-io.c

index a5dbbee..606ebfc 100644 (file)
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -3171,6 +3171,7 @@ static void print_usage(void)
 static struct option long_options[] = {
        { "super", 1, NULL, 's' },
        { "repair", 0, NULL, 0 },
+       { "init-csum-tree", 0, NULL, 0 },
        { 0, 0, 0, 0}
 };
 
@@ -3185,6 +3186,8 @@ int main(int ac, char **av)
        int num;
        int repair = 0;
        int option_index = 0;
+       int init_csum_tree = 0;
+       int rw = 0;
 
        while(1) {
                int c;
@@ -3205,6 +3208,11 @@ int main(int ac, char **av)
                if (option_index == 1) {
                        printf("enabling repair mode\n");
                        repair = 1;
+                       rw = 1;
+               } else if (option_index == 2) {
+                       printf("Creating a new CRC tree\n");
+                       init_csum_tree = 1;
+                       rw = 1;
                }
 
        }
@@ -3224,7 +3232,7 @@ int main(int ac, char **av)
                return -EBUSY;
        }
 
-       info = open_ctree_fs_info(av[optind], bytenr, repair, 1);
+       info = open_ctree_fs_info(av[optind], bytenr, rw, 1);
 
        if (info == NULL)
                return 1;
@@ -3240,9 +3248,19 @@ int main(int ac, char **av)
        root = info->fs_root;
 
        fprintf(stderr, "checking extents\n");
-       if (repair)
+       if (rw)
                trans = btrfs_start_transaction(root, 1);
 
+       if (init_csum_tree) {
+               fprintf(stderr, "Reinit crc root\n");
+               ret = btrfs_fsck_reinit_root(trans, info->csum_root);
+               if (ret) {
+                       fprintf(stderr, "crc root initialization failed\n");
+                       return -EIO;
+               }
+               goto out;
+       }
+
        ret = check_extents(trans, root, repair);
        if (ret)
                goto out;
@@ -3259,15 +3277,14 @@ int main(int ac, char **av)
        ret = check_root_refs(root, &root_cache);
 out:
        free_root_recs(&root_cache);
-       if (repair) {
+       if (rw) {
                ret = btrfs_commit_transaction(trans, root);
                if (ret)
                        exit(1);
        }
        close_ctree(root);
 
-       if (found_old_backref) {
-               /*
+       if (found_old_backref) { /*
                 * there was a disk format change when mixed
                 * backref was in testing tree. The old format
                 * existed about one week.
diff --git a/ctree.c b/ctree.c
index 005550f..282c868 100644 (file)
--- a/ctree.c
+++ b/ctree.c
@@ -138,6 +138,46 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
        return 0;
 }
 
+int btrfs_fsck_reinit_root(struct btrfs_trans_handle *trans,
+                     struct btrfs_root *root)
+{
+       struct extent_buffer *c;
+       struct extent_buffer *old = root->node;
+       int level;
+       struct btrfs_disk_key disk_key = {0,0,0};
+
+       level = 0;
+
+       c = btrfs_alloc_free_block(trans, root,
+                                  btrfs_level_size(root, 0),
+                                  root->root_key.objectid,
+                                  &disk_key, level, 0, 0);
+       if (IS_ERR(c))
+               return PTR_ERR(c);
+
+       memset_extent_buffer(c, 0, 0, sizeof(struct btrfs_header));
+       btrfs_set_header_level(c, level);
+       btrfs_set_header_bytenr(c, c->start);
+       btrfs_set_header_generation(c, trans->transid);
+       btrfs_set_header_backref_rev(c, BTRFS_MIXED_BACKREF_REV);
+       btrfs_set_header_owner(c, root->root_key.objectid);
+
+       write_extent_buffer(c, root->fs_info->fsid,
+                           (unsigned long)btrfs_header_fsid(c),
+                           BTRFS_FSID_SIZE);
+
+       write_extent_buffer(c, root->fs_info->chunk_tree_uuid,
+                           (unsigned long)btrfs_header_chunk_tree_uuid(c),
+                           BTRFS_UUID_SIZE);
+
+       btrfs_mark_buffer_dirty(c);
+
+       free_extent_buffer(old);
+       root->node = c;
+       add_root_to_dirty_list(root);
+       return 0;
+}
+
 /*
  * check if the tree block can be shared by multiple trees
  */
diff --git a/ctree.h b/ctree.h
index 6f12869..c53f65a 100644 (file)
--- a/ctree.h
+++ b/ctree.h
@@ -1851,6 +1851,8 @@ int btrfs_update_block_group(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root, u64 bytenr, u64 num,
                             int alloc, int mark_free);
 /* ctree.c */
+int btrfs_fsck_reinit_root(struct btrfs_trans_handle *trans,
+                     struct btrfs_root *root);
 void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
                             int level, int slot, u64 objectid);
 struct extent_buffer *read_node_slot(struct btrfs_root *root,
index 58aec02..b21a87f 100644 (file)
--- a/disk-io.c
+++ b/disk-io.c
@@ -787,7 +787,8 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path,
                                  BTRFS_CSUM_TREE_OBJECTID, csum_root);
        if (ret) {
                printk("Couldn't setup csum tree\n");
-               goto out_failed;
+               if (!partial)
+                       goto out_failed;
        }
        csum_root->track_dirty = 1;