diff options
author | Josef Bacik <jbacik@fb.com> | 2014-10-03 10:54:26 -0400 |
---|---|---|
committer | David Sterba <dsterba@suse.cz> | 2014-10-14 11:10:36 +0200 |
commit | 01f868b5a99b412212ede924a81aa15e6d408381 (patch) | |
tree | 1bfc7d30e737f3fcb389c5021afb37af473a17ed /cmds-check.c | |
parent | f738a758af3b04c302dca2a1c50b9a021a40148c (diff) |
btrfs-progs: make fsck deal with bogus items
We can deal with corrupt items by deleting them in a few cases. Fsck can easily
recover from a missing extent item or a dir index item. So if we notice a item
is completely bogus and it is of a key that we know we can repair then just
delete it and carry on. Thanks,
Signed-off-by: Josef Bacik <jbacik@fb.com>
Signed-off-by: David Sterba <dsterba@suse.cz>
Diffstat (limited to 'cmds-check.c')
-rw-r--r-- | cmds-check.c | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/cmds-check.c b/cmds-check.c index db7f7452..acdf312f 100644 --- a/cmds-check.c +++ b/cmds-check.c @@ -2834,6 +2834,42 @@ static int fix_key_order(struct btrfs_trans_handle *trans, return ret; } +static int delete_bogus_item(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct btrfs_path *path, + struct extent_buffer *buf, int slot) +{ + struct btrfs_key key; + int nritems = btrfs_header_nritems(buf); + + btrfs_item_key_to_cpu(buf, &key, slot); + + /* These are all the keys we can deal with missing. */ + if (key.type != BTRFS_DIR_INDEX_KEY && + key.type != BTRFS_EXTENT_ITEM_KEY && + key.type != BTRFS_METADATA_ITEM_KEY && + key.type != BTRFS_TREE_BLOCK_REF_KEY && + key.type != BTRFS_EXTENT_DATA_REF_KEY) + return -1; + + printf("Deleting bogus item [%llu,%u,%llu] at slot %d on block %llu\n", + (unsigned long long)key.objectid, key.type, + (unsigned long long)key.offset, slot, buf->start); + memmove_extent_buffer(buf, btrfs_item_nr_offset(slot), + btrfs_item_nr_offset(slot + 1), + sizeof(struct btrfs_item) * + (nritems - slot - 1)); + btrfs_set_header_nritems(buf, nritems - 1); + if (slot == 0) { + struct btrfs_disk_key disk_key; + + btrfs_item_key(buf, &disk_key, 0); + btrfs_fixup_low_keys(root, path, &disk_key, 1); + } + btrfs_mark_buffer_dirty(buf); + return 0; +} + static int fix_item_offset(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf) @@ -2873,6 +2909,7 @@ static int fix_item_offset(struct btrfs_trans_handle *trans, } buf = path->nodes[level]; +again: for (i = 0; i < btrfs_header_nritems(buf); i++) { unsigned int shift = 0, offset; @@ -2880,6 +2917,10 @@ static int fix_item_offset(struct btrfs_trans_handle *trans, BTRFS_LEAF_DATA_SIZE(root)) { if (btrfs_item_end_nr(buf, i) > BTRFS_LEAF_DATA_SIZE(root)) { + ret = delete_bogus_item(trans, root, path, + buf, i); + if (!ret) + goto again; fprintf(stderr, "item is off the end of the " "leaf, can't fix\n"); ret = -EIO; @@ -2891,6 +2932,10 @@ static int fix_item_offset(struct btrfs_trans_handle *trans, btrfs_item_offset_nr(buf, i - 1)) { if (btrfs_item_end_nr(buf, i) > btrfs_item_offset_nr(buf, i - 1)) { + ret = delete_bogus_item(trans, root, path, + buf, i); + if (!ret) + goto again; fprintf(stderr, "items overlap, can't fix\n"); ret = -EIO; break; |