Skip to content

Commit f6a2dae

Browse files
author
Darrick J. Wong
committed
xfs: make sure maxlen is still congruent with prod when rounding down
In commit 2a6ca4b, we tried to fix an overflow problem in the realtime allocator that was caused by an overly large maxlen value causing xfs_rtcheck_range to run off the end of the realtime bitmap. Unfortunately, there is a subtle bug here -- maxlen (and minlen) both have to be aligned with @prod, but @prod can be larger than 1 if the user has set an extent size hint on the file, and that extent size hint is larger than the realtime extent size. If the rt free space extents are not aligned to this file's extszhint because other files without extent size hints allocated space (or the number of rt extents is similarly not aligned), then it's possible that maxlen after clamping to sb_rextents will no longer be aligned to prod. The allocation will succeed just fine, but we still trip the assertion. Fix the problem by reducing maxlen by any misalignment with prod. While we're at it, split the assertions into two so that we can tell which value had the bad alignment. Fixes: 2a6ca4b ("xfs: make sure the rt allocator doesn't run off the end") Signed-off-by: Darrick J. Wong <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]>
1 parent ddd9807 commit f6a2dae

File tree

1 file changed

+26
-5
lines changed

1 file changed

+26
-5
lines changed

fs/xfs/xfs_rtalloc.c

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,23 @@ xfs_rtallocate_range(
211211
return error;
212212
}
213213

214+
/*
215+
* Make sure we don't run off the end of the rt volume. Be careful that
216+
* adjusting maxlen downwards doesn't cause us to fail the alignment checks.
217+
*/
218+
static inline xfs_extlen_t
219+
xfs_rtallocate_clamp_len(
220+
struct xfs_mount *mp,
221+
xfs_rtblock_t startrtx,
222+
xfs_extlen_t rtxlen,
223+
xfs_extlen_t prod)
224+
{
225+
xfs_extlen_t ret;
226+
227+
ret = min(mp->m_sb.sb_rextents, startrtx + rtxlen) - startrtx;
228+
return rounddown(ret, prod);
229+
}
230+
214231
/*
215232
* Attempt to allocate an extent minlen<=len<=maxlen starting from
216233
* bitmap block bbno. If we don't get maxlen then use prod to trim
@@ -248,7 +265,7 @@ xfs_rtallocate_extent_block(
248265
i <= end;
249266
i++) {
250267
/* Make sure we don't scan off the end of the rt volume. */
251-
maxlen = min(mp->m_sb.sb_rextents, i + maxlen) - i;
268+
maxlen = xfs_rtallocate_clamp_len(mp, i, maxlen, prod);
252269

253270
/*
254271
* See if there's a free extent of maxlen starting at i.
@@ -355,7 +372,8 @@ xfs_rtallocate_extent_exact(
355372
int isfree; /* extent is free */
356373
xfs_rtblock_t next; /* next block to try (dummy) */
357374

358-
ASSERT(minlen % prod == 0 && maxlen % prod == 0);
375+
ASSERT(minlen % prod == 0);
376+
ASSERT(maxlen % prod == 0);
359377
/*
360378
* Check if the range in question (for maxlen) is free.
361379
*/
@@ -438,7 +456,9 @@ xfs_rtallocate_extent_near(
438456
xfs_rtblock_t n; /* next block to try */
439457
xfs_rtblock_t r; /* result block */
440458

441-
ASSERT(minlen % prod == 0 && maxlen % prod == 0);
459+
ASSERT(minlen % prod == 0);
460+
ASSERT(maxlen % prod == 0);
461+
442462
/*
443463
* If the block number given is off the end, silently set it to
444464
* the last block.
@@ -447,7 +467,7 @@ xfs_rtallocate_extent_near(
447467
bno = mp->m_sb.sb_rextents - 1;
448468

449469
/* Make sure we don't run off the end of the rt volume. */
450-
maxlen = min(mp->m_sb.sb_rextents, bno + maxlen) - bno;
470+
maxlen = xfs_rtallocate_clamp_len(mp, bno, maxlen, prod);
451471
if (maxlen < minlen) {
452472
*rtblock = NULLRTBLOCK;
453473
return 0;
@@ -638,7 +658,8 @@ xfs_rtallocate_extent_size(
638658
xfs_rtblock_t r; /* result block number */
639659
xfs_suminfo_t sum; /* summary information for extents */
640660

641-
ASSERT(minlen % prod == 0 && maxlen % prod == 0);
661+
ASSERT(minlen % prod == 0);
662+
ASSERT(maxlen % prod == 0);
642663
ASSERT(maxlen != 0);
643664

644665
/*

0 commit comments

Comments
 (0)