Skip to content

Commit 15f04fd

Browse files
author
Darrick J. Wong
committed
xfs: remove infinite loop when reserving free block pool
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: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Dave Chinner <dchinner@redhat.com>
1 parent c8c5682 commit 15f04fd

1 file changed

Lines changed: 20 additions & 30 deletions

File tree

fs/xfs/xfs_fsops.c

Lines changed: 20 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -430,46 +430,36 @@ xfs_reserve_blocks(
430430
* If the request is larger than the current reservation, reserve the
431431
* blocks before we update the reserve counters. Sample m_fdblocks and
432432
* perform a partial reservation if the request exceeds free space.
433+
*
434+
* The code below estimates how many blocks it can request from
435+
* fdblocks to stash in the reserve pool. This is a classic TOCTOU
436+
* race since fdblocks updates are not always coordinated via
437+
* m_sb_lock.
433438
*/
434-
error = -ENOSPC;
435-
do {
436-
free = percpu_counter_sum(&mp->m_fdblocks) -
439+
free = percpu_counter_sum(&mp->m_fdblocks) -
437440
xfs_fdblocks_unavailable(mp);
438-
if (free <= 0)
439-
break;
440-
441-
delta = request - mp->m_resblks;
442-
lcounter = free - delta;
443-
if (lcounter < 0)
444-
/* We can't satisfy the request, just get what we can */
445-
fdblks_delta = free;
446-
else
447-
fdblks_delta = delta;
448-
441+
delta = request - mp->m_resblks;
442+
if (delta > 0 && free > 0) {
449443
/*
450444
* We'll either succeed in getting space from the free block
451-
* count or we'll get an ENOSPC. If we get a ENOSPC, it means
452-
* things changed while we were calculating fdblks_delta and so
453-
* we should try again to see if there is anything left to
454-
* reserve.
455-
*
456-
* Don't set the reserved flag here - we don't want to reserve
457-
* the extra reserve blocks from the reserve.....
445+
* count or we'll get an ENOSPC. Don't set the reserved flag
446+
* here - we don't want to reserve the extra reserve blocks
447+
* from the reserve.
458448
*/
449+
fdblks_delta = min(free, delta);
459450
spin_unlock(&mp->m_sb_lock);
460451
error = xfs_mod_fdblocks(mp, -fdblks_delta, 0);
461452
spin_lock(&mp->m_sb_lock);
462-
} while (error == -ENOSPC);
463453

464-
/*
465-
* Update the reserve counters if blocks have been successfully
466-
* allocated.
467-
*/
468-
if (!error && fdblks_delta) {
469-
mp->m_resblks += fdblks_delta;
470-
mp->m_resblks_avail += fdblks_delta;
454+
/*
455+
* Update the reserve counters if blocks have been successfully
456+
* allocated.
457+
*/
458+
if (!error) {
459+
mp->m_resblks += fdblks_delta;
460+
mp->m_resblks_avail += fdblks_delta;
461+
}
471462
}
472-
473463
out:
474464
if (outval) {
475465
outval->resblks = mp->m_resblks;

0 commit comments

Comments
 (0)