| From 0cefc6f5e36f95f34aa6e66a9290cddc5eee772a Mon Sep 17 00:00:00 2001 |
| From: Josef Bacik <josef@toxicpanda.com> |
| Date: Tue, 19 Nov 2019 13:59:00 -0500 |
| Subject: [PATCH] btrfs: handle error in btrfs_cache_block_group |
| |
| commit db8fe64f9ce61d1d89d3c3c34d111a43afb9f053 upstream. |
| |
| We have a BUG_ON(ret < 0) in find_free_extent from |
| btrfs_cache_block_group. If we fail to allocate our ctl we'll just |
| panic, which is not good. Instead just go on to another block group. |
| If we fail to find a block group we don't want to return ENOSPC, because |
| really we got a ENOMEM and that's the root of the problem. Save our |
| return from btrfs_cache_block_group(), and then if we still fail to make |
| our allocation return that ret so we get the right error back. |
| |
| Tested with inject-error.py from bcc. |
| |
| Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de> |
| Signed-off-by: Josef Bacik <josef@toxicpanda.com> |
| Reviewed-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c |
| index 2fdb72ac3f6e..87219f38a2dc 100644 |
| --- a/fs/btrfs/extent-tree.c |
| +++ b/fs/btrfs/extent-tree.c |
| @@ -7727,6 +7727,7 @@ static noinline int find_free_extent(struct btrfs_fs_info *fs_info, |
| u64 flags, int delalloc) |
| { |
| int ret = 0; |
| + int cache_block_group_error = 0; |
| struct btrfs_free_cluster *last_ptr = NULL; |
| struct btrfs_block_group_cache *block_group = NULL; |
| struct find_free_extent_ctl ffe_ctl = {0}; |
| @@ -7887,7 +7888,20 @@ static noinline int find_free_extent(struct btrfs_fs_info *fs_info, |
| if (unlikely(!ffe_ctl.cached)) { |
| ffe_ctl.have_caching_bg = true; |
| ret = cache_block_group(block_group, 0); |
| - BUG_ON(ret < 0); |
| + |
| + /* |
| + * If we get ENOMEM here or something else we want to |
| + * try other block groups, because it may not be fatal. |
| + * However if we can't find anything else we need to |
| + * save our return here so that we return the actual |
| + * error that caused problems, not ENOSPC. |
| + */ |
| + if (ret < 0) { |
| + if (!cache_block_group_error) |
| + cache_block_group_error = ret; |
| + ret = 0; |
| + goto loop; |
| + } |
| ret = 0; |
| } |
| |
| @@ -7974,7 +7988,7 @@ static noinline int find_free_extent(struct btrfs_fs_info *fs_info, |
| if (ret > 0) |
| goto search; |
| |
| - if (ret == -ENOSPC) { |
| + if (ret == -ENOSPC && !cache_block_group_error) { |
| /* |
| * Use ffe_ctl->total_free_space as fallback if we can't find |
| * any contiguous hole. |
| @@ -7985,6 +7999,8 @@ static noinline int find_free_extent(struct btrfs_fs_info *fs_info, |
| space_info->max_extent_size = ffe_ctl.max_extent_size; |
| spin_unlock(&space_info->lock); |
| ins->offset = ffe_ctl.max_extent_size; |
| + } else if (ret == -ENOSPC) { |
| + ret = cache_block_group_error; |
| } |
| return ret; |
| } |
| -- |
| 2.7.4 |
| |