Skip to content

Commit b878dbb

Browse files
author
Chandan Babu R
committed
Merge tag 'reduce-scrub-iget-overhead-6.10_2024-04-23' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux into xfs-6.10-mergeC
xfs: reduce iget overhead in scrub This patchset looks to reduce iget overhead in two ways: First, a previous patch conditionally set DONTCACHE on inodes during xchk_irele on the grounds that we knew better at irele time if an inode should be dropped. Unfortunately, over time that patch morphed into a call to d_mark_dontcache, which resulted in inodes being dropped even if they were referenced by the dcache. This actually caused *more* recycle overhead than if we'd simply called xfs_iget to set DONTCACHE only on misses. The second patch reduces the cost of untrusted iget for a vectored scrub call by having the scrubv code maintain a separate refcount to the inode so that the cache will always hit. Signed-off-by: Darrick J. Wong <[email protected]> Signed-off-by: Chandan Babu R <[email protected]> * tag 'reduce-scrub-iget-overhead-6.10_2024-04-23' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux: xfs: only iget the file once when doing vectored scrub-by-handle xfs: use dontcache for grabbing inodes during scrub
2 parents 496baa2 + 4ad350a commit b878dbb

File tree

4 files changed

+66
-11
lines changed

4 files changed

+66
-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.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,37 @@ xfs_scrubv_check_barrier(
792792
return 0;
793793
}
794794

795+
/*
796+
* If the caller provided us with a nonzero inode number that isn't the ioctl
797+
* file, try to grab a reference to it to eliminate all further untrusted inode
798+
* lookups. If we can't get the inode, let each scrub function try again.
799+
*/
800+
STATIC struct xfs_inode *
801+
xchk_scrubv_open_by_handle(
802+
struct xfs_mount *mp,
803+
const struct xfs_scrub_vec_head *head)
804+
{
805+
struct xfs_trans *tp;
806+
struct xfs_inode *ip;
807+
int error;
808+
809+
error = xfs_trans_alloc_empty(mp, &tp);
810+
if (error)
811+
return NULL;
812+
813+
error = xfs_iget(mp, tp, head->svh_ino, XCHK_IGET_FLAGS, 0, &ip);
814+
xfs_trans_cancel(tp);
815+
if (error)
816+
return NULL;
817+
818+
if (VFS_I(ip)->i_generation != head->svh_gen) {
819+
xfs_irele(ip);
820+
return NULL;
821+
}
822+
823+
return ip;
824+
}
825+
795826
/* Vectored scrub implementation to reduce ioctl calls. */
796827
int
797828
xfs_ioc_scrubv_metadata(
@@ -804,6 +835,7 @@ xfs_ioc_scrubv_metadata(
804835
struct xfs_scrub_vec __user *uvectors;
805836
struct xfs_inode *ip_in = XFS_I(file_inode(file));
806837
struct xfs_mount *mp = ip_in->i_mount;
838+
struct xfs_inode *handle_ip = NULL;
807839
struct xfs_scrub_vec *v;
808840
size_t vec_bytes;
809841
unsigned int i;
@@ -848,6 +880,17 @@ xfs_ioc_scrubv_metadata(
848880
trace_xchk_scrubv_item(mp, &head, i, v);
849881
}
850882

883+
/*
884+
* If the caller wants us to do a scrub-by-handle and the file used to
885+
* call the ioctl is not the same file, load the incore inode and pin
886+
* it across all the scrubv actions to avoid repeated UNTRUSTED
887+
* lookups. The reference is not passed to deeper layers of scrub
888+
* because each scrubber gets to decide its own strategy and return
889+
* values for getting an inode.
890+
*/
891+
if (head.svh_ino && head.svh_ino != ip_in->i_ino)
892+
handle_ip = xchk_scrubv_open_by_handle(mp, &head);
893+
851894
/* Run all the scrubbers. */
852895
for (i = 0, v = vectors; i < head.svh_nr; i++, v++) {
853896
struct xfs_scrub_metadata sm = {
@@ -895,6 +938,8 @@ xfs_ioc_scrubv_metadata(
895938
}
896939

897940
out_free:
941+
if (handle_ip)
942+
xfs_irele(handle_ip);
898943
kfree(vectors);
899944
return error;
900945
}

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)