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>
This commit is contained in:
Josef Bacik 2014-10-03 10:54:26 -04:00 committed by David Sterba
parent f738a758af
commit 01f868b5a9
2 changed files with 45 additions and 0 deletions

View File

@ -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;

Binary file not shown.