From: Josef Bacik Date: Fri, 3 Oct 2014 14:54:26 +0000 (-0400) Subject: btrfs-progs: make fsck deal with bogus items X-Git-Tag: upstream/4.16.1~2640 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=01f868b5a99b412212ede924a81aa15e6d408381;p=platform%2Fupstream%2Fbtrfs-progs.git 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 Signed-off-by: David Sterba --- diff --git a/cmds-check.c b/cmds-check.c index db7f745..acdf312 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; diff --git a/tests/fsck-tests/005-bad-item-offset.img b/tests/fsck-tests/005-bad-item-offset.img new file mode 100644 index 0000000..e11e1e3 Binary files /dev/null and b/tests/fsck-tests/005-bad-item-offset.img differ