Skip to content

Commit b27ce0d

Browse files
author
Darrick J. Wong
committed
xfs: use dontcache for grabbing inodes during scrub
Back when I wrote commit a03297a, I had thought that we'd be doing users a favor by only marking inodes dontcache at the end of a scrub operation, and only if there's only one reference to that inode. This was more or less true back when I_DONTCACHE was an XFS iflag and the only thing it did was change the outcome of xfs_fs_drop_inode to 1. Note: If there are dentries pointing to the inode when scrub finishes, the inode will have positive i_count and stay around in cache until dentry reclaim. But now we have d_mark_dontcache, which cause the inode *and* the dentries attached to it all to be marked I_DONTCACHE, which means that we drop the dentries ASAP, which drops the inode ASAP. This is bad if scrub found problems with the inode, because now they can be scheduled for inactivation, which can cause inodegc to trip on it and shut down the filesystem. Even if the inode isn't bad, this is still suboptimal because phases 3-7 each initiate inode scans. Dropping the inode immediately during phase 3 is silly because phase 5 will reload it and drop it immediately, etc. It's fine to mark the inodes dontcache, but if there have been accesses to the file that set up dentries, we should keep them. I validated this by setting up ftrace to capture xfs_iget_recycle* tracepoints and ran xfs/285 for 30 seconds. With current djwong-wtf I saw ~30,000 recycle events. I then dropped the d_mark_dontcache calls and set XFS_IGET_DONTCACHE, and the recycle events dropped to ~5,000 per 30 seconds. Therefore, grab the inode with XFS_IGET_DONTCACHE, which only has the effect of setting I_DONTCACHE for cache misses. Remove the d_mark_dontcache call that can happen in xchk_irele. Fixes: a03297a ("xfs: manage inode DONTCACHE status at irele time") Signed-off-by: Darrick J. Wong <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]>
1 parent c77b375 commit b27ce0d

File tree

3 files changed

+21
-11
lines changed

3 files changed

+21
-11
lines changed

fs/xfs/scrub/common.c

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -783,7 +783,7 @@ xchk_iget(
783783
{
784784
ASSERT(sc->tp != NULL);
785785

786-
return xfs_iget(sc->mp, sc->tp, inum, XFS_IGET_UNTRUSTED, 0, ipp);
786+
return xfs_iget(sc->mp, sc->tp, inum, XCHK_IGET_FLAGS, 0, ipp);
787787
}
788788

789789
/*
@@ -834,8 +834,8 @@ xchk_iget_agi(
834834
if (error)
835835
return error;
836836

837-
error = xfs_iget(mp, tp, inum,
838-
XFS_IGET_NORETRY | XFS_IGET_UNTRUSTED, 0, ipp);
837+
error = xfs_iget(mp, tp, inum, XFS_IGET_NORETRY | XCHK_IGET_FLAGS, 0,
838+
ipp);
839839
if (error == -EAGAIN) {
840840
/*
841841
* The inode may be in core but temporarily unavailable and may
@@ -1062,12 +1062,6 @@ xchk_irele(
10621062
spin_lock(&VFS_I(ip)->i_lock);
10631063
VFS_I(ip)->i_state &= ~I_DONTCACHE;
10641064
spin_unlock(&VFS_I(ip)->i_lock);
1065-
} else if (atomic_read(&VFS_I(ip)->i_count) == 1) {
1066-
/*
1067-
* If this is the last reference to the inode and the caller
1068-
* permits it, set DONTCACHE to avoid thrashing.
1069-
*/
1070-
d_mark_dontcache(VFS_I(ip));
10711065
}
10721066

10731067
xfs_irele(ip);

fs/xfs/scrub/iscan.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,15 @@ xchk_iscan_iget_retry(
407407
return -EAGAIN;
408408
}
409409

410+
/*
411+
* For an inode scan, we hold the AGI and want to try to grab a batch of
412+
* inodes. Holding the AGI prevents inodegc from clearing freed inodes,
413+
* so we must use noretry here. For every inode after the first one in the
414+
* batch, we don't want to wait, so we use retry there too. Finally, use
415+
* dontcache to avoid polluting the cache.
416+
*/
417+
#define ISCAN_IGET_FLAGS (XFS_IGET_NORETRY | XFS_IGET_DONTCACHE)
418+
410419
/*
411420
* Grab an inode as part of an inode scan. While scanning this inode, the
412421
* caller must ensure that no other threads can modify the inode until a call
@@ -434,7 +443,7 @@ xchk_iscan_iget(
434443
ASSERT(iscan->__inodes[0] == NULL);
435444

436445
/* Fill the first slot in the inode array. */
437-
error = xfs_iget(sc->mp, sc->tp, ino, XFS_IGET_NORETRY, 0,
446+
error = xfs_iget(sc->mp, sc->tp, ino, ISCAN_IGET_FLAGS, 0,
438447
&iscan->__inodes[idx]);
439448

440449
trace_xchk_iscan_iget(iscan, error);
@@ -507,7 +516,7 @@ xchk_iscan_iget(
507516

508517
ASSERT(iscan->__inodes[idx] == NULL);
509518

510-
error = xfs_iget(sc->mp, sc->tp, ino, XFS_IGET_NORETRY, 0,
519+
error = xfs_iget(sc->mp, sc->tp, ino, ISCAN_IGET_FLAGS, 0,
511520
&iscan->__inodes[idx]);
512521
if (error)
513522
break;

fs/xfs/scrub/scrub.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ static inline int xchk_maybe_relax(struct xchk_relax *widget)
6060
#define XCHK_GFP_FLAGS ((__force gfp_t)(GFP_KERNEL | __GFP_NOWARN | \
6161
__GFP_RETRY_MAYFAIL))
6262

63+
/*
64+
* For opening files by handle for fsck operations, we don't trust the inumber
65+
* or the allocation state; therefore, perform an untrusted lookup. We don't
66+
* want these inodes to pollute the cache, so mark them for immediate removal.
67+
*/
68+
#define XCHK_IGET_FLAGS (XFS_IGET_UNTRUSTED | XFS_IGET_DONTCACHE)
69+
6370
/* Type info and names for the scrub types. */
6471
enum xchk_type {
6572
ST_NONE = 1, /* disabled */

0 commit comments

Comments
 (0)