summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2021-02-20 08:18:20 -0800
committerDarrick J. Wong <djwong@kernel.org>2021-03-25 17:08:55 -0700
commit13a296999ea49dd4cb16cab75c3aef5e691ed124 (patch)
tree01352ba13312a481be236c65046f47c8d569bbc4
parent2fc33b20316a173c7de3451b6cb6c64d6ca900b2 (diff)
xfs: experiment with dontcache when scanning inodesvectorized-scrub_2021-03-25
Add some experimental flags to drop inodes from the cache after a scan. Signed-off-by: Darrick J. Wong <djwong@kernel.org>
-rw-r--r--fs/xfs/libxfs/xfs_fs.h17
-rw-r--r--fs/xfs/scrub/common.c25
-rw-r--r--fs/xfs/scrub/common.h3
-rw-r--r--fs/xfs/scrub/dir.c2
-rw-r--r--fs/xfs/scrub/dir_repair.c4
-rw-r--r--fs/xfs/scrub/inode_repair.c3
-rw-r--r--fs/xfs/scrub/parent.c6
-rw-r--r--fs/xfs/scrub/parent_repair.c9
-rw-r--r--fs/xfs/scrub/quotacheck.c4
-rw-r--r--fs/xfs/scrub/rmap_repair.c5
-rw-r--r--fs/xfs/scrub/rtrmap_repair.c5
-rw-r--r--fs/xfs/scrub/scrub.c11
-rw-r--r--fs/xfs/xfs_ioctl.c3
-rw-r--r--fs/xfs/xfs_itable.c8
-rw-r--r--fs/xfs/xfs_itable.h3
-rw-r--r--fs/xfs/xfs_iwalk.h6
16 files changed, 77 insertions, 37 deletions
diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index 831c1b5a5a1c..f70b05dd9abf 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -499,9 +499,13 @@ struct xfs_bulk_ireq {
*/
#define XFS_BULK_IREQ_METADIR (1 << 2)
+/* Don't mark inodes DONTCACHE */
+#define XFS_BULK_IREQ_RETAIN_INODES (1 << 3)
+
#define XFS_BULK_IREQ_FLAGS_ALL (XFS_BULK_IREQ_AGNO | \
XFS_BULK_IREQ_SPECIAL | \
- XFS_BULK_IREQ_METADIR)
+ XFS_BULK_IREQ_METADIR | \
+ XFS_BULK_IREQ_RETAIN_INODES)
/* Operate on the root directory inode. */
#define XFS_BULK_IREQ_SPECIAL_ROOT (1)
@@ -785,8 +789,12 @@ struct xfs_scrub_metadata {
/* i: Allow scrub to freeze the filesystem to perform global scans. */
#define XFS_SCRUB_IFLAG_FREEZE_OK (1 << 8)
+/* i: Don't mark inodes DONTCACHE at the end. */
+#define XFS_SCRUB_IFLAG_RETAIN_INODES (1 << 9)
+
#define XFS_SCRUB_FLAGS_IN (XFS_SCRUB_IFLAG_REPAIR | \
- XFS_SCRUB_IFLAG_FREEZE_OK)
+ XFS_SCRUB_IFLAG_FREEZE_OK | \
+ XFS_SCRUB_IFLAG_RETAIN_INODES)
#define XFS_SCRUB_FLAGS_OUT (XFS_SCRUB_OFLAG_CORRUPT | \
XFS_SCRUB_OFLAG_PREEN | \
XFS_SCRUB_OFLAG_XFAIL | \
@@ -815,7 +823,10 @@ struct xfs_scrub_vec_head {
struct xfs_scrub_vec svh_vecs[0];
};
-#define XFS_SCRUB_VEC_FLAGS_ALL (0)
+/* i: Don't mark inodes DONTCACHE at the end. */
+#define XFS_SCRUB_VEC_IFLAG_RETAIN_INODES (1 << 0)
+
+#define XFS_SCRUB_VEC_FLAGS_ALL (XFS_SCRUB_VEC_IFLAG_RETAIN_INODES)
static inline size_t sizeof_xfs_scrub_vec(unsigned int nr)
{
diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
index 6113b6c3d5c4..c28444d10188 100644
--- a/fs/xfs/scrub/common.c
+++ b/fs/xfs/scrub/common.c
@@ -849,8 +849,7 @@ xchk_get_inode(
/* Look up the inode, see if the generation number matches. */
if (xfs_internal_inum(mp, sc->sm->sm_ino))
return -ENOENT;
- error = xfs_iget(mp, NULL, sc->sm->sm_ino,
- XFS_IGET_UNTRUSTED | XFS_IGET_DONTCACHE, 0, &ip);
+ error = xfs_iget(mp, NULL, sc->sm->sm_ino, XFS_IGET_UNTRUSTED, 0, &ip);
switch (error) {
case -ENOENT:
/* Inode doesn't exist, just bail out. */
@@ -872,7 +871,7 @@ xchk_get_inode(
* that it no longer exists.
*/
error = xfs_imap(sc->mp, sc->tp, sc->sm->sm_ino, &imap,
- XFS_IGET_UNTRUSTED | XFS_IGET_DONTCACHE);
+ XFS_IGET_UNTRUSTED);
if (error)
return -ENOENT;
error = -EFSCORRUPTED;
@@ -897,7 +896,7 @@ xchk_get_inode(
*/
if (VFS_I(ip)->i_generation != sc->sm->sm_gen ||
(xfs_is_metadata_inode(ip) && !S_ISDIR(VFS_I(ip)->i_mode))) {
- xfs_irele(ip);
+ xchk_irele(sc, ip);
return -ENOENT;
}
@@ -905,6 +904,24 @@ xchk_get_inode(
return 0;
}
+void
+__xchk_irele(
+ struct xfs_inode *ip,
+ bool set_dontcache)
+{
+ if (set_dontcache && atomic_read(&VFS_I(ip)->i_count) == 1)
+ d_mark_dontcache(VFS_I(ip));
+ xfs_irele(ip);
+}
+
+void
+xchk_irele(
+ struct xfs_scrub *sc,
+ struct xfs_inode *ip)
+{
+ __xchk_irele(ip, !(sc->sm->sm_flags & XFS_SCRUB_IFLAG_RETAIN_INODES));
+}
+
/* Set us up to scrub a file's contents. */
int
xchk_setup_inode_contents(
diff --git a/fs/xfs/scrub/common.h b/fs/xfs/scrub/common.h
index 4e92bb89ef5d..08bf69610288 100644
--- a/fs/xfs/scrub/common.h
+++ b/fs/xfs/scrub/common.h
@@ -152,6 +152,9 @@ int xchk_install_inode(struct xfs_scrub *sc, struct xfs_inode *ip);
void xchk_buffer_recheck(struct xfs_scrub *sc, struct xfs_buf *bp);
void xchk_whine(const struct xfs_mount *mp, const char *fmt, ...);
+void __xchk_irele(struct xfs_inode *ip, bool set_dontcache);
+void xchk_irele(struct xfs_scrub *sc, struct xfs_inode *ip);
+
/*
* Don't bother cross-referencing if we already found corruption or cross
* referencing discrepancies.
diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c
index 7881ff4754f4..81d2c8427f85 100644
--- a/fs/xfs/scrub/dir.c
+++ b/fs/xfs/scrub/dir.c
@@ -142,7 +142,7 @@ xchk_dir_check_ftype(
if (xfs_is_metadata_inode(ip) ^ xfs_is_metadata_inode(sdc->sc->ip))
xchk_fblock_set_corrupt(sdc->sc, XFS_DATA_FORK, 0);
- xfs_irele(ip);
+ xchk_irele(sdc->sc, ip);
out:
return error;
}
diff --git a/fs/xfs/scrub/dir_repair.c b/fs/xfs/scrub/dir_repair.c
index 2d91194c83e2..00aa095535e8 100644
--- a/fs/xfs/scrub/dir_repair.c
+++ b/fs/xfs/scrub/dir_repair.c
@@ -173,12 +173,12 @@ xrep_dir_salvage_entry(
/* Don't mix metadata and regular directory trees. */
if (xfs_is_metadata_inode(ip) ^ xfs_is_metadata_inode(rd->sc->ip)) {
- xfs_irele(ip);
+ xchk_irele(rd->sc, ip);
return 0;
}
key.ftype = xfs_mode_to_ftype(VFS_I(ip)->i_mode);
- xfs_irele(ip);
+ xchk_irele(rd->sc, ip);
/* Remember this for later. */
error = xblob_put(rd->dir_names, &key.name_cookie, name, key.namelen);
diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
index ab1a94147286..9d92fc0203a7 100644
--- a/fs/xfs/scrub/inode_repair.c
+++ b/fs/xfs/scrub/inode_repair.c
@@ -1162,8 +1162,7 @@ xrep_dinode_core(
sc->tp = NULL;
/* ...and reload it? */
- error = xfs_iget(sc->mp, sc->tp, ino,
- XFS_IGET_UNTRUSTED | XFS_IGET_DONTCACHE, 0, &sc->ip);
+ error = xfs_iget(sc->mp, sc->tp, ino, XFS_IGET_UNTRUSTED, 0, &sc->ip);
if (error)
return error;
sc->ilock_flags = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL;
diff --git a/fs/xfs/scrub/parent.c b/fs/xfs/scrub/parent.c
index 06ce60b73a9d..a0f94c5a1e26 100644
--- a/fs/xfs/scrub/parent.c
+++ b/fs/xfs/scrub/parent.c
@@ -285,11 +285,11 @@ xchk_parent_validate(
/* Drat, parent changed. Try again! */
if (dnum != dp->i_ino) {
- xfs_irele(dp);
+ xchk_irele(sc, dp);
*try_again = true;
return 0;
}
- xfs_irele(dp);
+ xchk_irele(sc, dp);
/*
* '..' didn't change, so check that there was only one entry
@@ -302,7 +302,7 @@ xchk_parent_validate(
out_unlock:
xfs_iunlock(dp, XFS_IOLOCK_SHARED);
out_rele:
- xfs_irele(dp);
+ xchk_irele(sc, dp);
out:
return error;
}
diff --git a/fs/xfs/scrub/parent_repair.c b/fs/xfs/scrub/parent_repair.c
index 579754a51a88..382cccf128a3 100644
--- a/fs/xfs/scrub/parent_repair.c
+++ b/fs/xfs/scrub/parent_repair.c
@@ -179,7 +179,7 @@ xrep_parents_iwalk(
out_unlock:
xfs_iunlock(dp, XFS_IOLOCK_SHARED);
out_rele:
- xfs_irele(dp);
+ xchk_irele(rps->sc, dp);
return error;
}
@@ -221,8 +221,9 @@ xrep_parents_walk(
/* Check the dentry cache to see if it thinks it knows of a parent. */
STATIC xfs_ino_t
xrep_parent_check_dcache(
- struct xfs_inode *dp)
+ struct xfs_scrub *sc)
{
+ struct xfs_inode *dp = sc->ip;
struct inode *pip = NULL;
struct dentry *dentry, *parent;
xfs_ino_t ret = NULLFSINO;
@@ -248,7 +249,7 @@ xrep_parent_check_dcache(
if (S_ISDIR(pip->i_mode))
ret = XFS_I(pip)->i_ino;
- xfs_irele(XFS_I(pip));
+ xchk_irele(sc, XFS_I(pip));
out_dput:
dput(dentry);
@@ -377,7 +378,7 @@ xrep_dir_parent_find(
}
/* Maybe the dcache will supply us with a parent? */
- suggestion = xrep_parent_check_dcache(sc->ip);
+ suggestion = xrep_parent_check_dcache(sc);
if (!xfs_verify_dir_ino(sc->mp, suggestion)) {
error = xrep_dir_parent_check(sc, suggestion, &is_parent);
if (error)
diff --git a/fs/xfs/scrub/quotacheck.c b/fs/xfs/scrub/quotacheck.c
index 1717e0f30cdd..b0baa76cef1e 100644
--- a/fs/xfs/scrub/quotacheck.c
+++ b/fs/xfs/scrub/quotacheck.c
@@ -493,7 +493,7 @@ xqcheck_collect_counts(
struct xfs_scrub *sc = xqc->sc;
struct xfs_inode *ip;
xfs_ino_t ino = 0;
- int flags = XFS_IGET_UNTRUSTED | XFS_IGET_DONTCACHE;
+ int flags = XFS_IGET_UNTRUSTED;
unsigned int retries = 20;
int error;
@@ -505,7 +505,7 @@ xqcheck_collect_counts(
switch (error) {
case 0:
error = xqcheck_inode(xqc, ip);
- xfs_irele(ip);
+ xchk_irele(sc, ip);
if (error)
return error;
retries = 20;
diff --git a/fs/xfs/scrub/rmap_repair.c b/fs/xfs/scrub/rmap_repair.c
index 6d40d6fbf1fa..c5212686f257 100644
--- a/fs/xfs/scrub/rmap_repair.c
+++ b/fs/xfs/scrub/rmap_repair.c
@@ -616,8 +616,7 @@ xrep_rmap_scan_inode(
int error;
/* Grab inode and lock it so we can scan it. */
- error = xfs_iget(mp, rr->sc->tp, ino,
- XFS_IGET_DONTCACHE | XFS_IGET_UNLINKED, 0, &ip);
+ error = xfs_iget(mp, rr->sc->tp, ino, XFS_IGET_UNLINKED, 0, &ip);
if (error)
return error;
@@ -637,7 +636,7 @@ xrep_rmap_scan_inode(
out_unlock:
xfs_iunlock(ip, lock_mode);
- xfs_irele(ip);
+ xchk_irele(rr->sc, ip);
return error;
}
diff --git a/fs/xfs/scrub/rtrmap_repair.c b/fs/xfs/scrub/rtrmap_repair.c
index 34b1ed463cdd..1605364a4403 100644
--- a/fs/xfs/scrub/rtrmap_repair.c
+++ b/fs/xfs/scrub/rtrmap_repair.c
@@ -351,8 +351,7 @@ xrep_rtrmap_scan_inode(
return 0;
/* Grab inode and lock it so we can scan it. */
- error = xfs_iget(mp, rr->sc->tp, ino,
- XFS_IGET_DONTCACHE | XFS_IGET_UNLINKED, 0, &ip);
+ error = xfs_iget(mp, rr->sc->tp, ino, XFS_IGET_UNLINKED, 0, &ip);
if (error)
return error;
@@ -379,7 +378,7 @@ xrep_rtrmap_scan_inode(
out_unlock:
xfs_iunlock(ip, XFS_ILOCK_SHARED);
out_rele:
- xfs_irele(ip);
+ xchk_irele(rr->sc, ip);
return error;
}
diff --git a/fs/xfs/scrub/scrub.c b/fs/xfs/scrub/scrub.c
index e54bbe98a8c5..e1a2367e9042 100644
--- a/fs/xfs/scrub/scrub.c
+++ b/fs/xfs/scrub/scrub.c
@@ -170,7 +170,7 @@ xchk_teardown(
if (sc->ip) {
if (sc->ilock_flags)
xfs_iunlock(sc->ip, sc->ilock_flags);
- xfs_irele(sc->ip);
+ xchk_irele(sc, sc->ip);
sc->ip = NULL;
}
if (sc->flags & XREP_ATOMIC_SWAPEXT) {
@@ -725,7 +725,8 @@ xfs_scrubv_metadata(
* consider setting dontcache at the end.
*/
if (v->sv_type < XFS_SCRUB_TYPE_NR &&
- meta_scrub_ops[v->sv_type].type == ST_INODE)
+ meta_scrub_ops[v->sv_type].type == ST_INODE &&
+ !(vhead->svh_flags & XFS_SCRUB_VEC_IFLAG_RETAIN_INODES))
set_dontcache = true;
trace_xchk_scrubv_item(mp, vhead, v);
@@ -742,7 +743,7 @@ xfs_scrubv_metadata(
if (ip && (VFS_I(ip)->i_generation != vhead->svh_gen ||
(xfs_is_metadata_inode(ip) &&
!S_ISDIR(VFS_I(ip)->i_mode)))) {
- xfs_irele(ip);
+ __xchk_irele(ip, set_dontcache);
ip = NULL;
}
}
@@ -797,8 +798,6 @@ xfs_scrubv_metadata(
* If we're holding the only reference to this inode and the scan was
* clean, mark it dontcache so that we don't pollute the cache.
*/
- if (set_dontcache && atomic_read(&VFS_I(ip)->i_count) == 1)
- d_mark_dontcache(VFS_I(ip));
- xfs_irele(ip);
+ __xchk_irele(ip, set_dontcache);
return error;
}
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index ce0f2340db4c..19b5eb082574 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -896,6 +896,9 @@ xfs_bulk_ireq_setup(
if (hdr->flags & XFS_BULK_IREQ_METADIR)
breq->flags |= XFS_IWALK_METADIR;
+ if (hdr->flags & XFS_BULK_IREQ_RETAIN_INODES)
+ breq->flags |= XFS_IWALK_RETAIN_INODES;
+
return 0;
}
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index 4d1a9b5d975b..bee985fe525f 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -74,11 +74,13 @@ xfs_bulkstat_one_int(
struct xfs_inode *ip; /* incore inode pointer */
struct inode *inode;
struct xfs_bulkstat *buf = bc->buf;
+ int flags = XFS_IGET_UNTRUSTED;
int error = -EINVAL;
- error = xfs_iget(mp, tp, ino,
- (XFS_IGET_DONTCACHE | XFS_IGET_UNTRUSTED),
- XFS_ILOCK_SHARED, &ip);
+ if (!(bc->breq->flags & XFS_IBULK_RETAIN_INODES))
+ flags |= XFS_IGET_DONTCACHE;
+
+ error = xfs_iget(mp, tp, ino, flags, XFS_ILOCK_SHARED, &ip);
if (error == -ENOENT || error == -EINVAL)
goto out_advance;
if (error)
diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h
index f5a13f69883a..7fc2e40d30bd 100644
--- a/fs/xfs/xfs_itable.h
+++ b/fs/xfs/xfs_itable.h
@@ -22,6 +22,9 @@ struct xfs_ibulk {
/* Signal that we can return metadata directories. */
#define XFS_IBULK_METADIR (XFS_IWALK_METADIR)
+/* Don't drop inodes. */
+#define XFS_IBULK_RETAIN_INODES (XFS_IWALK_RETAIN_INODES)
+
/*
* Advance the user buffer pointer by one record of the given size. If the
* buffer is now full, return the appropriate error code.
diff --git a/fs/xfs/xfs_iwalk.h b/fs/xfs/xfs_iwalk.h
index d9df721b05f2..a448e54afb1a 100644
--- a/fs/xfs/xfs_iwalk.h
+++ b/fs/xfs/xfs_iwalk.h
@@ -31,8 +31,12 @@ int xfs_iwalk_threaded(struct xfs_mount *mp, xfs_ino_t startino,
/* Signal that we can return metadata directories. */
#define XFS_IWALK_METADIR (0x2)
+/* Don't drop inodes. */
+#define XFS_IWALK_RETAIN_INODES (0x4)
+
#define XFS_IWALK_FLAGS_ALL (XFS_IWALK_SAME_AG | \
- XFS_IWALK_METADIR)
+ XFS_IWALK_METADIR | \
+ XFS_IWALK_RETAIN_INODES)
/* Walk all inode btree records in the filesystem starting from @startino. */
typedef int (*xfs_inobt_walk_fn)(struct xfs_mount *mp, struct xfs_trans *tp,