From: Darrick J. Wong <djwong@xxxxxxxxxx> Don't spin in an infinite loop trying to reserve blocks -- if we can't do it after 30 tries, we're racing with a nearly full filesystem, so just give up. Cc: Brian Foster <bfoster@xxxxxxxxxx> Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> --- fs/xfs/xfs_fsops.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index b71799a3acd3..4076b9004077 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -379,6 +379,7 @@ xfs_reserve_blocks( int64_t fdblks_delta = 0; uint64_t request; int64_t free; + unsigned int tries; int error = 0; /* If inval is null, report current values and return */ @@ -430,9 +431,16 @@ 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 loop body 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. We also + * cannot tell if @free remaining unchanged between iterations is due + * to an idle system or freed blocks being consumed immediately, so + * we'll try a finite number of times to satisfy the request. */ error = -ENOSPC; - do { + for (tries = 0; tries < 30 && error == -ENOSPC; tries++) { /* * The reservation pool cannot take space that xfs_mod_fdblocks * will not give us. @@ -462,7 +470,7 @@ xfs_reserve_blocks( 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