diff options
author | Josef Bacik <jbacik@fusionio.com> | 2013-06-13 13:50:23 -0400 |
---|---|---|
committer | Josef Bacik <jbacik@fusionio.com> | 2013-07-01 08:52:30 -0400 |
commit | aee68ee5f5427b91be5b23459993134ca64ecf00 (patch) | |
tree | 7f38e979667087148c27f48b9e9a6a7e20f1f31c /fs/btrfs | |
parent | da61d31a78dc2116fa725c92d4eca36dfbc3da8b (diff) |
Btrfs: fix not being able to find skinny extents during relocate
We unconditionally search for the EXTENT_ITEM_KEY for metadata during balance,
and then check the key that we found to see if it is actually a
METADATA_ITEM_KEY, but this doesn't work right because METADATA is a higher key
value, so if what we are looking for happens to be the first item in the leaf
the search will dump us out at the previous leaf, and we won't find our item.
So instead do what we do everywhere else, search for the skinny extent first and
if we don't find it go back and re-search for the extent item. This patch fixes
the panic I was hitting when balancing a large file system with skinny extents.
Thanks,
Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/relocation.c | 35 |
1 files changed, 27 insertions, 8 deletions
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 4a404b44b0ad..d91f106df665 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c | |||
@@ -3309,6 +3309,8 @@ static int __add_tree_block(struct reloc_control *rc, | |||
3309 | struct btrfs_path *path; | 3309 | struct btrfs_path *path; |
3310 | struct btrfs_key key; | 3310 | struct btrfs_key key; |
3311 | int ret; | 3311 | int ret; |
3312 | bool skinny = btrfs_fs_incompat(rc->extent_root->fs_info, | ||
3313 | SKINNY_METADATA); | ||
3312 | 3314 | ||
3313 | if (tree_block_processed(bytenr, blocksize, rc)) | 3315 | if (tree_block_processed(bytenr, blocksize, rc)) |
3314 | return 0; | 3316 | return 0; |
@@ -3319,10 +3321,15 @@ static int __add_tree_block(struct reloc_control *rc, | |||
3319 | path = btrfs_alloc_path(); | 3321 | path = btrfs_alloc_path(); |
3320 | if (!path) | 3322 | if (!path) |
3321 | return -ENOMEM; | 3323 | return -ENOMEM; |
3322 | 3324 | again: | |
3323 | key.objectid = bytenr; | 3325 | key.objectid = bytenr; |
3324 | key.type = BTRFS_EXTENT_ITEM_KEY; | 3326 | if (skinny) { |
3325 | key.offset = blocksize; | 3327 | key.type = BTRFS_METADATA_ITEM_KEY; |
3328 | key.offset = (u64)-1; | ||
3329 | } else { | ||
3330 | key.type = BTRFS_EXTENT_ITEM_KEY; | ||
3331 | key.offset = blocksize; | ||
3332 | } | ||
3326 | 3333 | ||
3327 | path->search_commit_root = 1; | 3334 | path->search_commit_root = 1; |
3328 | path->skip_locking = 1; | 3335 | path->skip_locking = 1; |
@@ -3330,11 +3337,23 @@ static int __add_tree_block(struct reloc_control *rc, | |||
3330 | if (ret < 0) | 3337 | if (ret < 0) |
3331 | goto out; | 3338 | goto out; |
3332 | 3339 | ||
3333 | btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); | 3340 | if (ret > 0 && skinny) { |
3334 | if (ret > 0) { | 3341 | if (path->slots[0]) { |
3335 | if (key.objectid == bytenr && | 3342 | path->slots[0]--; |
3336 | key.type == BTRFS_METADATA_ITEM_KEY) | 3343 | btrfs_item_key_to_cpu(path->nodes[0], &key, |
3337 | ret = 0; | 3344 | path->slots[0]); |
3345 | if (key.objectid == bytenr && | ||
3346 | (key.type == BTRFS_METADATA_ITEM_KEY || | ||
3347 | (key.type == BTRFS_EXTENT_ITEM_KEY && | ||
3348 | key.offset == blocksize))) | ||
3349 | ret = 0; | ||
3350 | } | ||
3351 | |||
3352 | if (ret) { | ||
3353 | skinny = false; | ||
3354 | btrfs_release_path(path); | ||
3355 | goto again; | ||
3356 | } | ||
3338 | } | 3357 | } |
3339 | BUG_ON(ret); | 3358 | BUG_ON(ret); |
3340 | 3359 | ||