Currently while doing block allocation grp->bb_free may be getting
modified if discard is happening in parallel.
For e.g. consider a case where there are lot of threads who have
preallocated lot of blocks and there is a thread which is trying
to discard all of this group's PA. Now it could happen that
we see all of those group's bb_free is zero and fail the allocation
while there is sufficient space if we free up all the PA.

So this patch takes the ext4_lock_group() around calculations involving
grp->bb_free in ext4_mb_good_group() & ext4_mb_good_group_nolock()

Signed-off-by: Ritesh Harjani <rite...@linux.ibm.com>
---
 fs/ext4/mballoc.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index da11a4a738bd..dcd05ff7c012 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -2138,9 +2138,11 @@ static int ext4_mb_good_group_nolock(struct 
ext4_allocation_context *ac,
                                     ext4_group_t group, int cr)
 {
        struct ext4_group_info *grp = ext4_get_group_info(ac->ac_sb, group);
+       struct super_block *sb = ac->ac_sb;
        ext4_grpblk_t free;
        int ret = 0;
 
+       ext4_lock_group(sb, group);
        free = grp->bb_free;
        if (free == 0)
                goto out;
@@ -2148,6 +2150,7 @@ static int ext4_mb_good_group_nolock(struct 
ext4_allocation_context *ac,
                goto out;
        if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(grp)))
                goto out;
+       ext4_unlock_group(sb, group);
 
        /* We only do this if the grp has never been initialized */
        if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) {
@@ -2156,8 +2159,10 @@ static int ext4_mb_good_group_nolock(struct 
ext4_allocation_context *ac,
                        return ret;
        }
 
+       ext4_lock_group(sb, group);
        ret = ext4_mb_good_group(ac, group, cr);
 out:
+       ext4_unlock_group(sb, group);
        return ret;
 }
 
-- 
2.21.0

Reply via email to