Skip to content

Commit 2d3de8a

Browse files
author
Josef Bacik
committed
Btrfs-progs: corrupt btrfs items in btrfs-corrup-block
For testing fsck against completely broken btrfs_items. Signed-off-by: Josef Bacik <jbacik@fb.com>
1 parent 86a8d6e commit 2d3de8a

File tree

1 file changed

+88
-2
lines changed

1 file changed

+88
-2
lines changed

btrfs-corrupt-block.c

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ static void print_usage(void)
109109
"<num>,<num>,<num> (must also specify -f for the field)\n");
110110
fprintf(stderr, "\t-f The field in the item to corrupt\n");
111111
fprintf(stderr, "\t-d Delete this item (must specify -K)\n");
112+
fprintf(stderr, "\t-I An item to corrupt (must also specify the field "
113+
"to corrupt and a root+key for the item)\n");
112114
exit(1);
113115
}
114116

@@ -308,6 +310,11 @@ enum btrfs_metadata_block_field {
308310
BTRFS_METADATA_BLOCK_BAD,
309311
};
310312

313+
enum btrfs_item_field {
314+
BTRFS_ITEM_OFFSET,
315+
BTRFS_ITEM_BAD,
316+
};
317+
311318
enum btrfs_key_field {
312319
BTRFS_KEY_OBJECTID,
313320
BTRFS_KEY_TYPE,
@@ -350,6 +357,13 @@ static enum btrfs_key_field convert_key_field(char *field)
350357
return BTRFS_KEY_BAD;
351358
}
352359

360+
static enum btrfs_item_field convert_item_field(char *field)
361+
{
362+
if (!strncmp(field, "offset", FIELD_BUF_LEN))
363+
return BTRFS_ITEM_OFFSET;
364+
return BTRFS_ITEM_BAD;
365+
}
366+
353367
static u64 generate_u64(u64 orig)
354368
{
355369
u64 ret;
@@ -359,6 +373,15 @@ static u64 generate_u64(u64 orig)
359373
return ret;
360374
}
361375

376+
static u32 generate_u32(u32 orig)
377+
{
378+
u32 ret;
379+
do {
380+
ret = rand();
381+
} while (ret == orig);
382+
return ret;
383+
}
384+
362385
static u8 generate_u8(u8 orig)
363386
{
364387
u8 ret;
@@ -680,6 +703,58 @@ static int delete_item(struct btrfs_root *root, struct btrfs_key *key)
680703
return ret;
681704
}
682705

706+
static int corrupt_btrfs_item(struct btrfs_root *root, struct btrfs_key *key,
707+
char *field)
708+
{
709+
struct btrfs_trans_handle *trans;
710+
struct btrfs_path *path;
711+
enum btrfs_item_field corrupt_field;
712+
u32 orig, bogus;
713+
int ret;
714+
715+
corrupt_field = convert_item_field(field);
716+
if (corrupt_field == BTRFS_ITEM_BAD) {
717+
fprintf(stderr, "Invalid field %s\n", field);
718+
return -EINVAL;
719+
}
720+
721+
path = btrfs_alloc_path();
722+
if (!path)
723+
return -ENOMEM;
724+
725+
trans = btrfs_start_transaction(root, 1);
726+
if (IS_ERR(trans)) {
727+
btrfs_free_path(path);
728+
fprintf(stderr, "Couldn't start transaction %ld\n",
729+
PTR_ERR(trans));
730+
return PTR_ERR(trans);
731+
}
732+
733+
ret = btrfs_search_slot(trans, root, key, path, 0, 1);
734+
if (ret != 0) {
735+
fprintf(stderr, "Error searching to node %d\n", ret);
736+
goto out;
737+
}
738+
739+
ret = 0;
740+
switch (corrupt_field) {
741+
case BTRFS_ITEM_OFFSET:
742+
orig = btrfs_item_offset_nr(path->nodes[0], path->slots[0]);
743+
bogus = generate_u32(orig);
744+
btrfs_set_item_offset(path->nodes[0],
745+
btrfs_item_nr(path->slots[0]), bogus);
746+
break;
747+
default:
748+
ret = -EINVAL;
749+
break;
750+
}
751+
btrfs_mark_buffer_dirty(path->nodes[0]);
752+
out:
753+
btrfs_commit_transaction(trans, root);
754+
btrfs_free_path(path);
755+
return ret;
756+
}
757+
683758
static struct option long_options[] = {
684759
/* { "byte-count", 1, NULL, 'b' }, */
685760
{ "logical", 1, NULL, 'l' },
@@ -696,6 +771,7 @@ static struct option long_options[] = {
696771
{ "field", 1, NULL, 'f'},
697772
{ "key", 1, NULL, 'K'},
698773
{ "delete", 0, NULL, 'd'},
774+
{ "item", 0, NULL, 'I'},
699775
{ 0, 0, 0, 0}
700776
};
701777

@@ -860,6 +936,7 @@ int main(int ac, char **av)
860936
int chunk_rec = 0;
861937
int chunk_tree = 0;
862938
int delete = 0;
939+
int corrupt_item = 0;
863940
u64 metadata_block = 0;
864941
u64 inode = 0;
865942
u64 file_extent = (u64)-1;
@@ -871,8 +948,8 @@ int main(int ac, char **av)
871948

872949
while(1) {
873950
int c;
874-
c = getopt_long(ac, av, "l:c:b:eEkuUi:f:x:m:K:d", long_options,
875-
&option_index);
951+
c = getopt_long(ac, av, "l:c:b:eEkuUi:f:x:m:K:dI",
952+
long_options, &option_index);
876953
if (c < 0)
877954
break;
878955
switch(c) {
@@ -925,6 +1002,9 @@ int main(int ac, char **av)
9251002
case 'd':
9261003
delete = 1;
9271004
break;
1005+
case 'I':
1006+
corrupt_item = 1;
1007+
break;
9281008
default:
9291009
print_usage();
9301010
}
@@ -1027,6 +1107,12 @@ int main(int ac, char **av)
10271107
ret = delete_item(root, &key);
10281108
goto out_close;
10291109
}
1110+
if (corrupt_item) {
1111+
if (!key.objectid)
1112+
print_usage();
1113+
ret = corrupt_btrfs_item(root, &key, field);
1114+
goto out_close;
1115+
}
10301116
if (key.objectid || key.offset || key.type) {
10311117
if (!strlen(field))
10321118
print_usage();

0 commit comments

Comments
 (0)