On Thu, Mar 17, 2022 at 02:21:17PM -0700, Darrick J. Wong wrote: > 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> > --- Reviewed-by: Brian Foster <bfoster@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 >