diff options
Diffstat (limited to 'fs/ext4/mballoc.c')
-rw-r--r-- | fs/ext4/mballoc.c | 32 |
1 files changed, 21 insertions, 11 deletions
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index def84082a9a9..4bbbf13bd743 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -2105,6 +2105,7 @@ repeat: | |||
2105 | group = ac->ac_g_ex.fe_group; | 2105 | group = ac->ac_g_ex.fe_group; |
2106 | 2106 | ||
2107 | for (i = 0; i < ngroups; group++, i++) { | 2107 | for (i = 0; i < ngroups; group++, i++) { |
2108 | cond_resched(); | ||
2108 | /* | 2109 | /* |
2109 | * Artificially restricted ngroups for non-extent | 2110 | * Artificially restricted ngroups for non-extent |
2110 | * files makes group > ngroups possible on first loop. | 2111 | * files makes group > ngroups possible on first loop. |
@@ -4405,17 +4406,20 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, | |||
4405 | repeat: | 4406 | repeat: |
4406 | /* allocate space in core */ | 4407 | /* allocate space in core */ |
4407 | *errp = ext4_mb_regular_allocator(ac); | 4408 | *errp = ext4_mb_regular_allocator(ac); |
4408 | if (*errp) { | 4409 | if (*errp) |
4409 | ext4_discard_allocated_blocks(ac); | 4410 | goto discard_and_exit; |
4410 | goto errout; | ||
4411 | } | ||
4412 | 4411 | ||
4413 | /* as we've just preallocated more space than | 4412 | /* as we've just preallocated more space than |
4414 | * user requested orinally, we store allocated | 4413 | * user requested originally, we store allocated |
4415 | * space in a special descriptor */ | 4414 | * space in a special descriptor */ |
4416 | if (ac->ac_status == AC_STATUS_FOUND && | 4415 | if (ac->ac_status == AC_STATUS_FOUND && |
4417 | ac->ac_o_ex.fe_len < ac->ac_b_ex.fe_len) | 4416 | ac->ac_o_ex.fe_len < ac->ac_b_ex.fe_len) |
4418 | ext4_mb_new_preallocation(ac); | 4417 | *errp = ext4_mb_new_preallocation(ac); |
4418 | if (*errp) { | ||
4419 | discard_and_exit: | ||
4420 | ext4_discard_allocated_blocks(ac); | ||
4421 | goto errout; | ||
4422 | } | ||
4419 | } | 4423 | } |
4420 | if (likely(ac->ac_status == AC_STATUS_FOUND)) { | 4424 | if (likely(ac->ac_status == AC_STATUS_FOUND)) { |
4421 | *errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_clstrs); | 4425 | *errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_clstrs); |
@@ -4612,10 +4616,11 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode, | |||
4612 | BUG_ON(bh && (count > 1)); | 4616 | BUG_ON(bh && (count > 1)); |
4613 | 4617 | ||
4614 | for (i = 0; i < count; i++) { | 4618 | for (i = 0; i < count; i++) { |
4619 | cond_resched(); | ||
4615 | if (!bh) | 4620 | if (!bh) |
4616 | tbh = sb_find_get_block(inode->i_sb, | 4621 | tbh = sb_find_get_block(inode->i_sb, |
4617 | block + i); | 4622 | block + i); |
4618 | if (unlikely(!tbh)) | 4623 | if (!tbh) |
4619 | continue; | 4624 | continue; |
4620 | ext4_forget(handle, flags & EXT4_FREE_BLOCKS_METADATA, | 4625 | ext4_forget(handle, flags & EXT4_FREE_BLOCKS_METADATA, |
4621 | inode, tbh, block + i); | 4626 | inode, tbh, block + i); |
@@ -4735,11 +4740,16 @@ do_more: | |||
4735 | * blocks being freed are metadata. these blocks shouldn't | 4740 | * blocks being freed are metadata. these blocks shouldn't |
4736 | * be used until this transaction is committed | 4741 | * be used until this transaction is committed |
4737 | */ | 4742 | */ |
4743 | retry: | ||
4738 | new_entry = kmem_cache_alloc(ext4_free_data_cachep, GFP_NOFS); | 4744 | new_entry = kmem_cache_alloc(ext4_free_data_cachep, GFP_NOFS); |
4739 | if (!new_entry) { | 4745 | if (!new_entry) { |
4740 | ext4_mb_unload_buddy(&e4b); | 4746 | /* |
4741 | err = -ENOMEM; | 4747 | * We use a retry loop because |
4742 | goto error_return; | 4748 | * ext4_free_blocks() is not allowed to fail. |
4749 | */ | ||
4750 | cond_resched(); | ||
4751 | congestion_wait(BLK_RW_ASYNC, HZ/50); | ||
4752 | goto retry; | ||
4743 | } | 4753 | } |
4744 | new_entry->efd_start_cluster = bit; | 4754 | new_entry->efd_start_cluster = bit; |
4745 | new_entry->efd_group = block_group; | 4755 | new_entry->efd_group = block_group; |