btrfs-progs: add shift_items to btrfs-corrupt-block

A user had a corrupted fs where his items where shifted oddly.  This adds the
functionality I needed to btrfs-corrupt-block in order to reproduce this
corruption in order to make fsck fix this sort of problem.  Thanks,

Signed-off-by: Josef Bacik <jbacik@fb.com>
Signed-off-by: David Sterba <dsterba@suse.cz>
master
Josef Bacik 2014-10-03 10:38:41 -04:00 committed by David Sterba
parent 3e944ce894
commit 94b2966daf
1 changed files with 27 additions and 0 deletions

View File

@ -312,6 +312,7 @@ enum btrfs_dir_item_field {
enum btrfs_metadata_block_field {
BTRFS_METADATA_BLOCK_GENERATION,
BTRFS_METADATA_BLOCK_SHIFT_ITEMS,
BTRFS_METADATA_BLOCK_BAD,
};
@ -346,6 +347,8 @@ convert_metadata_block_field(char *field)
{
if (!strncmp(field, "generation", FIELD_BUF_LEN))
return BTRFS_METADATA_BLOCK_GENERATION;
if (!strncmp(field, "shift_items", FIELD_BUF_LEN))
return BTRFS_METADATA_BLOCK_SHIFT_ITEMS;
return BTRFS_METADATA_BLOCK_BAD;
}
@ -651,6 +654,27 @@ out:
return ret;
}
static void shift_items(struct btrfs_root *root, struct extent_buffer *eb)
{
int nritems = btrfs_header_nritems(eb);
int shift_space = btrfs_leaf_free_space(root, eb) / 2;
int slot = nritems / 2;
int i = 0;
unsigned int data_end = btrfs_item_offset_nr(eb, nritems - 1);
/* Shift the item data up to and including slot back by shift space */
memmove_extent_buffer(eb, btrfs_leaf_data(eb) + data_end - shift_space,
btrfs_leaf_data(eb) + data_end,
btrfs_item_offset_nr(eb, slot - 1) - data_end);
/* Now update the item pointers. */
for (i = nritems - 1; i >= slot; i--) {
u32 offset = btrfs_item_offset_nr(eb, i);
offset -= shift_space;
btrfs_set_item_offset(eb, btrfs_item_nr(i), offset);
}
}
static int corrupt_metadata_block(struct btrfs_root *root, u64 block,
char *field)
{
@ -721,6 +745,9 @@ static int corrupt_metadata_block(struct btrfs_root *root, u64 block,
bogus = generate_u64(orig);
btrfs_set_header_generation(eb, bogus);
break;
case BTRFS_METADATA_BLOCK_SHIFT_ITEMS:
shift_items(root, path->nodes[level]);
break;
default:
ret = -EINVAL;
break;