diff options
-rw-r--r-- | btrfsck.c | 27 | ||||
-rw-r--r-- | ctree.c | 40 | ||||
-rw-r--r-- | ctree.h | 2 | ||||
-rw-r--r-- | disk-io.c | 3 |
4 files changed, 66 insertions, 6 deletions
@@ -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. @@ -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 */ @@ -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, @@ -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; |