aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorLiu Bo <bo.li.liu@oracle.com>2016-07-12 14:24:21 -0400
committerDavid Sterba <dsterba@suse.com>2016-07-26 07:52:25 -0400
commit5a488b9d2c25d98cdd11d09de311bfc83ba09fbd (patch)
tree3058eb9d14b1e7268b54f1d2f754e598d3c3e22a /fs/btrfs
parent0fd8c3dae14fb64947842472940b807ca0781da9 (diff)
Btrfs: fix unexpected balance crash due to BUG_ON
Mounting a btrfs can resume previous balance operations asynchronously. An user got a crash when one drive has some corrupt sectors. Since balance can cancel itself in case of any error, we can gracefully return errors to upper layers and let balance do the cancel job. Reported-by: sash <master.b.at.raven@chefmail.de> Signed-off-by: Liu Bo <bo.li.liu@oracle.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/volumes.c28
1 files changed, 24 insertions, 4 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 51bd3ee8e64f..05aec96e4c96 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -3460,7 +3460,7 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
3460 u64 size_to_free; 3460 u64 size_to_free;
3461 u64 chunk_type; 3461 u64 chunk_type;
3462 struct btrfs_chunk *chunk; 3462 struct btrfs_chunk *chunk;
3463 struct btrfs_path *path; 3463 struct btrfs_path *path = NULL;
3464 struct btrfs_key key; 3464 struct btrfs_key key;
3465 struct btrfs_key found_key; 3465 struct btrfs_key found_key;
3466 struct btrfs_trans_handle *trans; 3466 struct btrfs_trans_handle *trans;
@@ -3494,13 +3494,33 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
3494 ret = btrfs_shrink_device(device, old_size - size_to_free); 3494 ret = btrfs_shrink_device(device, old_size - size_to_free);
3495 if (ret == -ENOSPC) 3495 if (ret == -ENOSPC)
3496 break; 3496 break;
3497 BUG_ON(ret); 3497 if (ret) {
3498 /* btrfs_shrink_device never returns ret > 0 */
3499 WARN_ON(ret > 0);
3500 goto error;
3501 }
3498 3502
3499 trans = btrfs_start_transaction(dev_root, 0); 3503 trans = btrfs_start_transaction(dev_root, 0);
3500 BUG_ON(IS_ERR(trans)); 3504 if (IS_ERR(trans)) {
3505 ret = PTR_ERR(trans);
3506 btrfs_info_in_rcu(fs_info,
3507 "resize: unable to start transaction after shrinking device %s (error %d), old size %llu, new size %llu",
3508 rcu_str_deref(device->name), ret,
3509 old_size, old_size - size_to_free);
3510 goto error;
3511 }
3501 3512
3502 ret = btrfs_grow_device(trans, device, old_size); 3513 ret = btrfs_grow_device(trans, device, old_size);
3503 BUG_ON(ret); 3514 if (ret) {
3515 btrfs_end_transaction(trans, dev_root);
3516 /* btrfs_grow_device never returns ret > 0 */
3517 WARN_ON(ret > 0);
3518 btrfs_info_in_rcu(fs_info,
3519 "resize: unable to grow device after shrinking device %s (error %d), old size %llu, new size %llu",
3520 rcu_str_deref(device->name), ret,
3521 old_size, old_size - size_to_free);
3522 goto error;
3523 }
3504 3524
3505 btrfs_end_transaction(trans, dev_root); 3525 btrfs_end_transaction(trans, dev_root);
3506 } 3526 }