summaryrefslogtreecommitdiff
path: root/btrfs-corrupt-block.c
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fb.com>2014-01-07 15:19:35 -0500
committerChris Mason <clm@fb.com>2014-01-31 08:22:15 -0800
commit70749a77fe2b1c69d2ebe732de0d0ae53b967171 (patch)
tree9d750cf2568195033aeba0dd803fb52a7a2b8e2e /btrfs-corrupt-block.c
parentd04707f78735d6bb119a2d088f99547949a65f3c (diff)
Btrfs-progs: deal with invalid key orderings and bad orphan items V2
A user had a fs where the objectid of an orphan item was not the actual orphan item objectid. This screwed up fsck because the block has keys in the wrong order, also the fs scanning stuff will freak out because we have an inode with nlink 0 and no orphan item. So this patch is pretty big but is all related. 1) Deal with bad key ordering. We can easily fix this up, so fix the checking stuff to tell us exactly what it found when it said there was a problem. Then if it's bad key ordering we can reorder the keys and restart the scan. 2) Deal with bad keys. If we find an orphan item with the wrong objectid it's likely to screw with stuff, so keep track of these sort of things with a bad_item list and just run through and delete any objects that don't make sense. So far we just do this for orphan items but we could extend this as new stuff pops up. 3) Deal with missing orphan items. This is easy, if we have a file with i_nlink set to 0 and no orphan item we can just add an orphan item. 4) Add the infrastructure to corrupt actual key values. Needed this to create a test image to verify I was fixing things properly. This patch fixes the corrupt image I'm adding and passes the other make test tests. Thanks, Signed-off-by: Josef Bacik <jbacik@fb.com> Signed-off-by: David Sterba <dsterba@suse.cz> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'btrfs-corrupt-block.c')
-rw-r--r--btrfs-corrupt-block.c109
1 files changed, 108 insertions, 1 deletions
diff --git a/btrfs-corrupt-block.c b/btrfs-corrupt-block.c
index f0c14a9d..10cae00a 100644
--- a/btrfs-corrupt-block.c
+++ b/btrfs-corrupt-block.c
@@ -105,6 +105,8 @@ static void print_usage(void)
"specify -i for the inode and -f for the field to corrupt)\n");
fprintf(stderr, "\t-m The metadata block to corrupt (must also "
"specify -f for the field to corrupt)\n");
+ fprintf(stderr, "\t-K The key to corrupt in the format "
+ "<num>,<num>,<num> (must also specify -f for the field)\n");
fprintf(stderr, "\t-f The field in the item to corrupt\n");
exit(1);
}
@@ -306,6 +308,13 @@ enum btrfs_metadata_block_field {
BTRFS_METADATA_BLOCK_BAD,
};
+enum btrfs_key_field {
+ BTRFS_KEY_OBJECTID,
+ BTRFS_KEY_TYPE,
+ BTRFS_KEY_OFFSET,
+ BTRFS_KEY_BAD,
+};
+
static enum btrfs_inode_field convert_inode_field(char *field)
{
if (!strncmp(field, "isize", FIELD_BUF_LEN))
@@ -328,6 +337,17 @@ convert_metadata_block_field(char *field)
return BTRFS_METADATA_BLOCK_BAD;
}
+static enum btrfs_key_field convert_key_field(char *field)
+{
+ if (!strncmp(field, "objectid", FIELD_BUF_LEN))
+ return BTRFS_KEY_OBJECTID;
+ if (!strncmp(field, "type", FIELD_BUF_LEN))
+ return BTRFS_KEY_TYPE;
+ if (!strncmp(field, "offset", FIELD_BUF_LEN))
+ return BTRFS_KEY_OFFSET;
+ return BTRFS_KEY_BAD;
+}
+
static u64 generate_u64(u64 orig)
{
u64 ret;
@@ -337,6 +357,73 @@ static u64 generate_u64(u64 orig)
return ret;
}
+static u8 generate_u8(u8 orig)
+{
+ u8 ret;
+ do {
+ ret = rand();
+ } while (ret == orig);
+ return ret;
+}
+
+static int corrupt_key(struct btrfs_root *root, struct btrfs_key *key,
+ char *field)
+{
+ enum btrfs_key_field corrupt_field = convert_key_field(field);
+ struct btrfs_path *path;
+ struct btrfs_trans_handle *trans;
+ int ret;
+
+ root = root->fs_info->fs_root;
+ if (corrupt_field == BTRFS_KEY_BAD) {
+ fprintf(stderr, "Invalid field %s\n", field);
+ return -EINVAL;
+ }
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+
+ trans = btrfs_start_transaction(root, 1);
+ if (IS_ERR(trans)) {
+ btrfs_free_path(path);
+ return PTR_ERR(trans);
+ }
+
+ ret = btrfs_search_slot(trans, root, key, path, 0, 1);
+ if (ret < 0)
+ goto out;
+ if (ret > 0) {
+ fprintf(stderr, "Couldn't find the key to corrupt\n");
+ ret = -ENOENT;
+ goto out;
+ }
+
+ switch (corrupt_field) {
+ case BTRFS_KEY_OBJECTID:
+ key->objectid = generate_u64(key->objectid);
+ break;
+ case BTRFS_KEY_TYPE:
+ key->type = generate_u8(key->type);
+ break;
+ case BTRFS_KEY_OFFSET:
+ key->offset = generate_u64(key->objectid);
+ break;
+ default:
+ fprintf(stderr, "Invalid field %s, %d\n", field,
+ corrupt_field);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ btrfs_set_item_key_unsafe(root, path, key);
+out:
+ btrfs_free_path(path);
+ btrfs_commit_transaction(trans, root);
+ return ret;
+}
+
+
static int corrupt_inode(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 inode, char *field)
{
@@ -548,6 +635,7 @@ static struct option long_options[] = {
{ "file-extent", 1, NULL, 'x'},
{ "metadata-block", 1, NULL, 'm'},
{ "field", 1, NULL, 'f'},
+ { "key", 1, NULL, 'K'},
{ 0, 0, 0, 0}
};
@@ -696,6 +784,7 @@ out:
int main(int ac, char **av)
{
struct cache_tree root_cache;
+ struct btrfs_key key;
struct btrfs_root *root;
struct extent_buffer *eb;
char *dev;
@@ -717,10 +806,11 @@ int main(int ac, char **av)
field[0] = '\0';
srand(128);
+ memset(&key, 0, sizeof(key));
while(1) {
int c;
- c = getopt_long(ac, av, "l:c:b:eEkuUi:f:x:m:", long_options,
+ c = getopt_long(ac, av, "l:c:b:eEkuUi:f:x:m:K:", long_options,
&option_index);
if (c < 0)
break;
@@ -787,6 +877,17 @@ int main(int ac, char **av)
print_usage();
}
break;
+ case 'K':
+ ret = sscanf(optarg, "%llu,%u,%llu",
+ &key.objectid,
+ (unsigned int *)&key.type,
+ &key.offset);
+ if (ret != 3) {
+ fprintf(stderr, "error reading key "
+ "%d\n", errno);
+ print_usage();
+ }
+ break;
default:
print_usage();
}
@@ -882,6 +983,12 @@ int main(int ac, char **av)
ret = corrupt_metadata_block(root, metadata_block, field);
goto out_close;
}
+ if (key.objectid || key.offset || key.type) {
+ if (!strlen(field))
+ print_usage();
+ ret = corrupt_key(root, &key, field);
+ goto out_close;
+ }
/*
* If we made it here and we have extent set then we didn't specify
* inode and we're screwed.