aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fusionio.com>2013-06-13 13:50:23 -0400
committerJosef Bacik <jbacik@fusionio.com>2013-07-01 08:52:30 -0400
commitaee68ee5f5427b91be5b23459993134ca64ecf00 (patch)
tree7f38e979667087148c27f48b9e9a6a7e20f1f31c /fs/btrfs
parentda61d31a78dc2116fa725c92d4eca36dfbc3da8b (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.c35
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 3324again:
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