summaryrefslogtreecommitdiff
path: root/cmds-check.c
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fusionio.com>2013-10-01 09:00:19 -0400
committerChris Mason <chris.mason@fusionio.com>2013-10-16 08:23:12 -0400
commitc64485544baa9ffc5fbedd5661a05bdee1b37598 (patch)
tree4461ef770a41b3056a0f0763d308d4f6a53e07b6 /cmds-check.c
parent2454473dd1647e83d6eba9852eeb08d331e9ea9a (diff)
Btrfs-progs: keep track of transid failures and fix them if possible
A user was reporting an issue with bad transid errors on his blocks. The thing is that btrfs-progs will ignore transid failures for things like restore and fsck so we can do a best effort to fix a users file system. So fsck can put together a coherent view of the file system with stale blocks. So if everything else is ok in the mind of fsck then we can recow these blocks to fix the generation and the user can get their file system back. Thanks, Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: David Sterba <dsterba@suse.cz> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'cmds-check.c')
-rw-r--r--cmds-check.c58
1 files changed, 58 insertions, 0 deletions
diff --git a/cmds-check.c b/cmds-check.c
index 7c21358d..59ae4ecc 100644
--- a/cmds-check.c
+++ b/cmds-check.c
@@ -5958,6 +5958,47 @@ static int reinit_extent_tree(struct btrfs_fs_info *fs_info)
return btrfs_commit_transaction(trans, fs_info->extent_root);
}
+static int recow_extent_buffer(struct btrfs_root *root, struct extent_buffer *eb)
+{
+ struct btrfs_path *path;
+ struct btrfs_trans_handle *trans;
+ struct btrfs_key key;
+ int ret;
+
+ printf("Recowing metadata block %llu\n", eb->start);
+ key.objectid = btrfs_header_owner(eb);
+ key.type = BTRFS_ROOT_ITEM_KEY;
+ key.offset = (u64)-1;
+
+ root = btrfs_read_fs_root(root->fs_info, &key);
+ if (IS_ERR(root)) {
+ fprintf(stderr, "Couldn't find owner root %llu\n",
+ key.objectid);
+ return PTR_ERR(root);
+ }
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+
+ trans = btrfs_start_transaction(root, 1);
+ if (IS_ERR(trans)) {
+ btrfs_free_path(path);
+ return PTR_ERR(trans);
+ }
+
+ path->lowest_level = btrfs_header_level(eb);
+ if (path->lowest_level)
+ btrfs_node_key_to_cpu(eb, &key, 0);
+ else
+ btrfs_item_key_to_cpu(eb, &key, 0);
+
+ ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
+ btrfs_commit_transaction(trans, root);
+ btrfs_free_path(path);
+ return ret;
+}
+
static struct option long_options[] = {
{ "super", 1, NULL, 's' },
{ "repair", 0, NULL, 0 },
@@ -6108,6 +6149,23 @@ int cmd_check(int argc, char **argv)
fprintf(stderr, "checking root refs\n");
ret = check_root_refs(root, &root_cache);
+ if (ret)
+ goto out;
+
+ while (repair && !list_empty(&root->fs_info->recow_ebs)) {
+ struct extent_buffer *eb;
+
+ eb = list_first_entry(&root->fs_info->recow_ebs,
+ struct extent_buffer, recow);
+ ret = recow_extent_buffer(root, eb);
+ if (ret)
+ break;
+ }
+
+ if (!list_empty(&root->fs_info->recow_ebs)) {
+ fprintf(stderr, "Transid errors in file system\n");
+ ret = 1;
+ }
out:
free_root_recs_tree(&root_cache);
close_ctree(root);