Skip to content

Commit 2e545d6

Browse files
committed
Merge tag 'xfs-6.3-fixes-1' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
Pull xfs fixes from Darrick Wong: - Fix a crash if mount time quotacheck fails when there are inodes queued for garbage collection. - Fix an off by one error when discarding folios after writeback failure. * tag 'xfs-6.3-fixes-1' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: xfs: fix off-by-one-block in xfs_discard_folio() xfs: quotacheck failure can race with background inode inactivation
2 parents 1342316 + 8ac5b99 commit 2e545d6

File tree

2 files changed

+40
-21
lines changed

2 files changed

+40
-21
lines changed

fs/xfs/xfs_aops.c

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -449,15 +449,17 @@ xfs_prepare_ioend(
449449
}
450450

451451
/*
452-
* If the page has delalloc blocks on it, we need to punch them out before we
453-
* invalidate the page. If we don't, we leave a stale delalloc mapping on the
454-
* inode that can trip up a later direct I/O read operation on the same region.
452+
* If the folio has delalloc blocks on it, the caller is asking us to punch them
453+
* out. If we don't, we can leave a stale delalloc mapping covered by a clean
454+
* page that needs to be dirtied again before the delalloc mapping can be
455+
* converted. This stale delalloc mapping can trip up a later direct I/O read
456+
* operation on the same region.
455457
*
456-
* We prevent this by truncating away the delalloc regions on the page. Because
458+
* We prevent this by truncating away the delalloc regions on the folio. Because
457459
* they are delalloc, we can do this without needing a transaction. Indeed - if
458460
* we get ENOSPC errors, we have to be able to do this truncation without a
459-
* transaction as there is no space left for block reservation (typically why we
460-
* see a ENOSPC in writeback).
461+
* transaction as there is no space left for block reservation (typically why
462+
* we see a ENOSPC in writeback).
461463
*/
462464
static void
463465
xfs_discard_folio(
@@ -475,8 +477,13 @@ xfs_discard_folio(
475477
"page discard on page "PTR_FMT", inode 0x%llx, pos %llu.",
476478
folio, ip->i_ino, pos);
477479

480+
/*
481+
* The end of the punch range is always the offset of the the first
482+
* byte of the next folio. Hence the end offset is only dependent on the
483+
* folio itself and not the start offset that is passed in.
484+
*/
478485
error = xfs_bmap_punch_delalloc_range(ip, pos,
479-
round_up(pos, folio_size(folio)));
486+
folio_pos(folio) + folio_size(folio));
480487

481488
if (error && !xfs_is_shutdown(mp))
482489
xfs_alert(mp, "page discard unable to remove delalloc mapping.");

fs/xfs/xfs_qm.c

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,15 +1321,14 @@ xfs_qm_quotacheck(
13211321

13221322
error = xfs_iwalk_threaded(mp, 0, 0, xfs_qm_dqusage_adjust, 0, true,
13231323
NULL);
1324-
if (error) {
1325-
/*
1326-
* The inode walk may have partially populated the dquot
1327-
* caches. We must purge them before disabling quota and
1328-
* tearing down the quotainfo, or else the dquots will leak.
1329-
*/
1330-
xfs_qm_dqpurge_all(mp);
1331-
goto error_return;
1332-
}
1324+
1325+
/*
1326+
* On error, the inode walk may have partially populated the dquot
1327+
* caches. We must purge them before disabling quota and tearing down
1328+
* the quotainfo, or else the dquots will leak.
1329+
*/
1330+
if (error)
1331+
goto error_purge;
13331332

13341333
/*
13351334
* We've made all the changes that we need to make incore. Flush them
@@ -1363,10 +1362,8 @@ xfs_qm_quotacheck(
13631362
* and turn quotaoff. The dquots won't be attached to any of the inodes
13641363
* at this point (because we intentionally didn't in dqget_noattach).
13651364
*/
1366-
if (error) {
1367-
xfs_qm_dqpurge_all(mp);
1368-
goto error_return;
1369-
}
1365+
if (error)
1366+
goto error_purge;
13701367

13711368
/*
13721369
* If one type of quotas is off, then it will lose its
@@ -1376,7 +1373,7 @@ xfs_qm_quotacheck(
13761373
mp->m_qflags &= ~XFS_ALL_QUOTA_CHKD;
13771374
mp->m_qflags |= flags;
13781375

1379-
error_return:
1376+
error_return:
13801377
xfs_buf_delwri_cancel(&buffer_list);
13811378

13821379
if (error) {
@@ -1395,6 +1392,21 @@ xfs_qm_quotacheck(
13951392
} else
13961393
xfs_notice(mp, "Quotacheck: Done.");
13971394
return error;
1395+
1396+
error_purge:
1397+
/*
1398+
* On error, we may have inodes queued for inactivation. This may try
1399+
* to attach dquots to the inode before running cleanup operations on
1400+
* the inode and this can race with the xfs_qm_destroy_quotainfo() call
1401+
* below that frees mp->m_quotainfo. To avoid this race, flush all the
1402+
* pending inodegc operations before we purge the dquots from memory,
1403+
* ensuring that background inactivation is idle whilst we turn off
1404+
* quotas.
1405+
*/
1406+
xfs_inodegc_flush(mp);
1407+
xfs_qm_dqpurge_all(mp);
1408+
goto error_return;
1409+
13981410
}
13991411

14001412
/*

0 commit comments

Comments
 (0)