From: yangerkun yangerkun@huawei.com
hulk inclusion category: bugfix bugzilla: 188788, https://gitee.com/openeuler/kernel/issues/I76JSK CVE: NA
--------------------------------
xfs_alloc_space_available need to make sure the longest free extent can satisfy extra blocks needed for agfl fixup and also the really needed block for the latter allocation. Or the latter agfl filling may consume some blocks within the longest free extent, which can lead to that all the free extent can not satisfy the really block allocation.
The arg 'min_free' show that actually blocks we need fill agfl up to. But after commit aa1ab9a77d89 ("xfs: fix xfs shutdown since we reserve more blocks in agfl fixup"), the 'min_free' will add the reserve blocks for second fixup, but leave agfl blocks does not include this.
Actually, what we want was just reserve more blocks to satisfy second fixup, we will not fill agfl with that so many blocks, so the args for xfs_alloc_longest_free_extent should not consider postalloc. And fix agflcount in xfs_alloc_space_available too.
Fixes: aa1ab9a77d89 ("xfs: fix xfs shutdown since we reserve more blocks in agfl fixup") Signed-off-by: yangerkun yangerkun@huawei.com Signed-off-by: Long Li leo.lilong@huawei.com --- fs/xfs/libxfs/xfs_alloc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c index d4d7a99114c7..b901eedf3bb8 100644 --- a/fs/xfs/libxfs/xfs_alloc.c +++ b/fs/xfs/libxfs/xfs_alloc.c @@ -2339,6 +2339,7 @@ xfs_alloc_min_freelist( static bool xfs_alloc_space_available( struct xfs_alloc_arg *args, + xfs_extlen_t need, xfs_extlen_t min_free, int flags) { @@ -2355,7 +2356,7 @@ xfs_alloc_space_available(
/* do we have enough contiguous free space for the allocation? */ alloc_len = args->minlen + (args->alignment - 1) + args->minalignslop; - longest = xfs_alloc_longest_free_extent(pag, min_free, reservation); + longest = xfs_alloc_longest_free_extent(pag, need, reservation); if (longest < alloc_len) return false;
@@ -2364,7 +2365,7 @@ xfs_alloc_space_available( * account extra agfl blocks because we are about to defer free them, * making them unavailable until the current transaction commits. */ - agflcount = min_t(xfs_extlen_t, pag->pagf_flcount, min_free); + agflcount = min_t(xfs_extlen_t, pag->pagf_flcount, need); available = (int)(pag->pagf_freeblks + agflcount - reservation - min_free - args->minleft); if (available < (int)max(args->total, alloc_len)) @@ -2651,7 +2652,7 @@ xfs_alloc_fix_freelist( if (args->postallocs) minfree += xfs_ag_fixup_aside(mp);
- if (!xfs_alloc_space_available(args, minfree, alloc_flags | + if (!xfs_alloc_space_available(args, need, minfree, alloc_flags | XFS_ALLOC_FLAG_CHECK)) goto out_agbp_relse;
@@ -2678,7 +2679,7 @@ xfs_alloc_fix_freelist( if (args->postallocs) minfree += xfs_ag_fixup_aside(mp);
- if (!xfs_alloc_space_available(args, minfree, alloc_flags)) + if (!xfs_alloc_space_available(args, need, minfree, alloc_flags)) goto out_agbp_relse;
/*