diff options
author | Theodore Ts'o <tytso@mit.edu> | 2013-07-13 00:40:35 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2013-07-13 00:40:35 -0400 |
commit | e7676a704ee0a1ef71a6b23760b5a8f6896cb1a1 (patch) | |
tree | a0baabd652713be5622578c8783dabfaf1141687 /fs/ext4/mballoc.c | |
parent | bdafe42aaf72859166f784f0fad3e6b4a815fa6d (diff) |
ext4: don't allow ext4_free_blocks() to fail due to ENOMEM
The filesystem should not be marked inconsistent if ext4_free_blocks()
is not able to allocate memory. Unfortunately some callers (most
notably ext4_truncate) don't have a way to reflect an error back up to
the VFS. And even if we did, most userspace applications won't deal
with most system calls returning ENOMEM anyway.
Reported-by: Nagachandra P <nagachandra@gmail.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Cc: stable@vger.kernel.org
Diffstat (limited to 'fs/ext4/mballoc.c')
-rw-r--r-- | fs/ext4/mballoc.c | 11 |
1 files changed, 8 insertions, 3 deletions
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index a9ff5e5137ca..4bbbf13bd743 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -4740,11 +4740,16 @@ do_more: | |||
4740 | * blocks being freed are metadata. these blocks shouldn't | 4740 | * blocks being freed are metadata. these blocks shouldn't |
4741 | * be used until this transaction is committed | 4741 | * be used until this transaction is committed |
4742 | */ | 4742 | */ |
4743 | retry: | ||
4743 | new_entry = kmem_cache_alloc(ext4_free_data_cachep, GFP_NOFS); | 4744 | new_entry = kmem_cache_alloc(ext4_free_data_cachep, GFP_NOFS); |
4744 | if (!new_entry) { | 4745 | if (!new_entry) { |
4745 | ext4_mb_unload_buddy(&e4b); | 4746 | /* |
4746 | err = -ENOMEM; | 4747 | * We use a retry loop because |
4747 | 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; | ||
4748 | } | 4753 | } |
4749 | new_entry->efd_start_cluster = bit; | 4754 | new_entry->efd_start_cluster = bit; |
4750 | new_entry->efd_group = block_group; | 4755 | new_entry->efd_group = block_group; |