diff options
author | Vegard Nossum <vegard.nossum@oracle.com> | 2016-07-14 23:02:47 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2016-07-14 23:02:47 -0400 |
commit | 554a5ccc4e4a20c5f3ec859de0842db4b4b9c77e (patch) | |
tree | eabafe736e7e667f02a1e7b6f8a0e1721099beb7 | |
parent | 598c7d7abc832e35677b851f6afb93141c09993b (diff) |
ext4: fix reference counting bug on block allocation error
If we hit this error when mounted with errors=continue or
errors=remount-ro:
EXT4-fs error (device loop0): ext4_mb_mark_diskspace_used:2940: comm ext4.exe: Allocating blocks 5090-6081 which overlap fs metadata
then ext4_mb_new_blocks() will call ext4_mb_release_context() and try to
continue. However, ext4_mb_release_context() is the wrong thing to call
here since we are still actually using the allocation context.
Instead, just error out. We could retry the allocation, but there is a
possibility of getting stuck in an infinite loop instead, so this seems
safer.
[ Fixed up so we don't return EAGAIN to userspace. --tytso ]
Fixes: 8556e8f3b6 ("ext4: Don't allow new groups to be added during block allocation")
Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Cc: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Cc: stable@vger.kernel.org
-rw-r--r-- | fs/ext4/mballoc.c | 17 |
1 files changed, 3 insertions, 14 deletions
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 77249e1f5c3a..11562161e24a 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -2943,7 +2943,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, | |||
2943 | ext4_error(sb, "Allocating blocks %llu-%llu which overlap " | 2943 | ext4_error(sb, "Allocating blocks %llu-%llu which overlap " |
2944 | "fs metadata", block, block+len); | 2944 | "fs metadata", block, block+len); |
2945 | /* File system mounted not to panic on error | 2945 | /* File system mounted not to panic on error |
2946 | * Fix the bitmap and repeat the block allocation | 2946 | * Fix the bitmap and return EFSCORRUPTED |
2947 | * We leak some of the blocks here. | 2947 | * We leak some of the blocks here. |
2948 | */ | 2948 | */ |
2949 | ext4_lock_group(sb, ac->ac_b_ex.fe_group); | 2949 | ext4_lock_group(sb, ac->ac_b_ex.fe_group); |
@@ -2952,7 +2952,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, | |||
2952 | ext4_unlock_group(sb, ac->ac_b_ex.fe_group); | 2952 | ext4_unlock_group(sb, ac->ac_b_ex.fe_group); |
2953 | err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh); | 2953 | err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh); |
2954 | if (!err) | 2954 | if (!err) |
2955 | err = -EAGAIN; | 2955 | err = -EFSCORRUPTED; |
2956 | goto out_err; | 2956 | goto out_err; |
2957 | } | 2957 | } |
2958 | 2958 | ||
@@ -4517,18 +4517,7 @@ repeat: | |||
4517 | } | 4517 | } |
4518 | if (likely(ac->ac_status == AC_STATUS_FOUND)) { | 4518 | if (likely(ac->ac_status == AC_STATUS_FOUND)) { |
4519 | *errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_clstrs); | 4519 | *errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_clstrs); |
4520 | if (*errp == -EAGAIN) { | 4520 | if (*errp) { |
4521 | /* | ||
4522 | * drop the reference that we took | ||
4523 | * in ext4_mb_use_best_found | ||
4524 | */ | ||
4525 | ext4_mb_release_context(ac); | ||
4526 | ac->ac_b_ex.fe_group = 0; | ||
4527 | ac->ac_b_ex.fe_start = 0; | ||
4528 | ac->ac_b_ex.fe_len = 0; | ||
4529 | ac->ac_status = AC_STATUS_CONTINUE; | ||
4530 | goto repeat; | ||
4531 | } else if (*errp) { | ||
4532 | ext4_discard_allocated_blocks(ac); | 4521 | ext4_discard_allocated_blocks(ac); |
4533 | goto errout; | 4522 | goto errout; |
4534 | } else { | 4523 | } else { |