Commit a0a575a8 authored by Darrick J. Wong's avatar Darrick J. Wong Committed by Zheng Zengkai
Browse files

xfs: remove infinite loop when reserving free block pool

stable inclusion
from stable-v5.10.141
commit cb41f22df3ec7b0b4f7cd9a730a538645e324f2f
category: bugfix
bugzilla: 188251,https://gitee.com/openeuler/kernel/issues/I685FC
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=cb41f22df3ec7b0b4f7cd9a730a538645e324f2f



--------------------------------

commit 15f04fdc upstream.

[Added wrapper xfs_fdblocks_unavailable() for 5.10.y backport]

Infinite loops in kernel code are scary.  Calls to xfs_reserve_blocks
should be rare (people should just use the defaults!) so we really don't
need to try so hard.  Simplify the logic here by removing the infinite
loop.

Cc: Brian Foster <bfoster@redhat.com>
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
Signed-off-by: default avatarAmir Goldstein <amir73il@gmail.com>
Acked-by: default avatarDarrick J. Wong <djwong@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>

Conflicts:
	fs/xfs/xfs_mount.h

Signed-off-by: default avataryangerkun <yangerkun@huawei.com>
Reviewed-by: default avatarZhang Yi <yi.zhang@huawei.com>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parent 74737d9b
Loading
Loading
Loading
Loading
+21 −31
Original line number Diff line number Diff line
@@ -374,46 +374,36 @@ xfs_reserve_blocks(
	 * If the request is larger than the current reservation, reserve the
	 * blocks before we update the reserve counters. Sample m_fdblocks and
	 * perform a partial reservation if the request exceeds free space.
	 *
	 * The code below estimates how many blocks it can request from
	 * fdblocks to stash in the reserve pool.  This is a classic TOCTOU
	 * race since fdblocks updates are not always coordinated via
	 * m_sb_lock.
	 */
	error = -ENOSPC;
	do {
	free = percpu_counter_sum(&mp->m_fdblocks) -
						mp->m_alloc_set_aside;
		if (free <= 0)
			break;

						xfs_fdblocks_unavailable(mp);
	delta = request - mp->m_resblks;
		lcounter = free - delta;
		if (lcounter < 0)
			/* We can't satisfy the request, just get what we can */
			fdblks_delta = free;
		else
			fdblks_delta = delta;

	if (delta > 0 && free > 0) {
		/*
		 * We'll either succeed in getting space from the free block
		 * count or we'll get an ENOSPC. If we get a ENOSPC, it means
		 * things changed while we were calculating fdblks_delta and so
		 * we should try again to see if there is anything left to
		 * reserve.
		 *
		 * Don't set the reserved flag here - we don't want to reserve
		 * the extra reserve blocks from the reserve.....
		 * count or we'll get an ENOSPC.  Don't set the reserved flag
		 * here - we don't want to reserve the extra reserve blocks
		 * from the reserve.
		 */
		fdblks_delta = min(free, delta);
		spin_unlock(&mp->m_sb_lock);
		error = xfs_mod_fdblocks(mp, -fdblks_delta, 0);
		spin_lock(&mp->m_sb_lock);
	} while (error == -ENOSPC);

		/*
		 * Update the reserve counters if blocks have been successfully
		 * allocated.
		 */
	if (!error && fdblks_delta) {
		if (!error) {
			mp->m_resblks += fdblks_delta;
			mp->m_resblks_avail += fdblks_delta;
		}

	}
out:
	if (outval) {
		outval->resblks = mp->m_resblks;
+8 −0
Original line number Diff line number Diff line
@@ -467,6 +467,14 @@ extern void xfs_unmountfs(xfs_mount_t *);
 */
#define XFS_FDBLOCKS_BATCH	1024

/* Accessor added for 5.10.y backport */
static inline uint64_t
xfs_fdblocks_unavailable(
	struct xfs_mount	*mp)
{
	return mp->m_alloc_set_aside;
}

extern int	xfs_mod_fdblocks(struct xfs_mount *mp, int64_t delta,
				 bool reserved);
extern int	xfs_mod_frextents(struct xfs_mount *mp, int64_t delta);