summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--btrfsck.c27
-rw-r--r--ctree.c40
-rw-r--r--ctree.h2
-rw-r--r--disk-io.c3
4 files changed, 66 insertions, 6 deletions
diff --git a/btrfsck.c b/btrfsck.c
index a5dbbee1..606ebfca 100644
--- 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 005550f1..282c868c 100644
--- 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 6f128696..c53f65a8 100644
--- 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,
diff --git a/disk-io.c b/disk-io.c
index 58aec02b..b21a87f8 100644
--- 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;