aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosef Bacik <josef@redhat.com>2009-10-06 10:04:28 -0400
committerChris Mason <chris.mason@oracle.com>2009-10-06 10:04:28 -0400
commit1cdda9b81ac0e6ee986f034fa02f221679e1c11a (patch)
treeae9394e50bc2418e8c3054de12ed44962d6f261a
parent61d92c328c16419fc96dc50dd16f8b8c695409ec (diff)
Btrfs: fix possible softlockup in the allocator
Like the cluster allocating stuff, we can lockup the box with the normal allocation path. This happens when we 1) Start to cache a block group that is severely fragmented, but has a decent amount of free space. 2) Start to commit a transaction 3) Have the commit try and empty out some of the delalloc inodes with extents that are relatively large. The inodes will not be able to make the allocations because they will ask for allocations larger than a contiguous area in the free space cache. So we will wait for more progress to be made on the block group, but since we're in a commit the caching kthread won't make any more progress and it already has enough free space that wait_block_group_cache_progress will just return. So, if we wait and fail to make the allocation the next time around, just loop and go to the next block group. This keeps us from getting stuck in a softlockup. Thanks, Signed-off-by: Josef Bacik <jbacik@redhat.com> Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r--fs/btrfs/extent-tree.c23
1 files changed, 17 insertions, 6 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index d119c0388af1..2f82fabd7011 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -4028,6 +4028,7 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
4028 int loop = 0; 4028 int loop = 0;
4029 bool found_uncached_bg = false; 4029 bool found_uncached_bg = false;
4030 bool failed_cluster_refill = false; 4030 bool failed_cluster_refill = false;
4031 bool failed_alloc = false;
4031 4032
4032 WARN_ON(num_bytes < root->sectorsize); 4033 WARN_ON(num_bytes < root->sectorsize);
4033 btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY); 4034 btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);
@@ -4232,14 +4233,23 @@ refill_cluster:
4232 4233
4233 offset = btrfs_find_space_for_alloc(block_group, search_start, 4234 offset = btrfs_find_space_for_alloc(block_group, search_start,
4234 num_bytes, empty_size); 4235 num_bytes, empty_size);
4235 if (!offset && (cached || (!cached && 4236 /*
4236 loop == LOOP_CACHING_NOWAIT))) { 4237 * If we didn't find a chunk, and we haven't failed on this
4237 goto loop; 4238 * block group before, and this block group is in the middle of
4238 } else if (!offset && (!cached && 4239 * caching and we are ok with waiting, then go ahead and wait
4239 loop > LOOP_CACHING_NOWAIT)) { 4240 * for progress to be made, and set failed_alloc to true.
4241 *
4242 * If failed_alloc is true then we've already waited on this
4243 * block group once and should move on to the next block group.
4244 */
4245 if (!offset && !failed_alloc && !cached &&
4246 loop > LOOP_CACHING_NOWAIT) {
4240 wait_block_group_cache_progress(block_group, 4247 wait_block_group_cache_progress(block_group,
4241 num_bytes + empty_size); 4248 num_bytes + empty_size);
4249 failed_alloc = true;
4242 goto have_block_group; 4250 goto have_block_group;
4251 } else if (!offset) {
4252 goto loop;
4243 } 4253 }
4244checks: 4254checks:
4245 search_start = stripe_align(root, offset); 4255 search_start = stripe_align(root, offset);
@@ -4287,6 +4297,7 @@ checks:
4287 break; 4297 break;
4288loop: 4298loop:
4289 failed_cluster_refill = false; 4299 failed_cluster_refill = false;
4300 failed_alloc = false;
4290 btrfs_put_block_group(block_group); 4301 btrfs_put_block_group(block_group);
4291 } 4302 }
4292 up_read(&space_info->groups_sem); 4303 up_read(&space_info->groups_sem);