summaryrefslogtreecommitdiff
path: root/fs/xfs/scrub
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/scrub')
-rw-r--r--fs/xfs/scrub/common.c41
-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/iscan.c4
-rw-r--r--fs/xfs/scrub/parent.c2
-rw-r--r--fs/xfs/scrub/parent_repair.c6
-rw-r--r--fs/xfs/scrub/quotacheck.c2
-rw-r--r--fs/xfs/scrub/rmap_repair.c2
-rw-r--r--fs/xfs/scrub/rtrmap_repair.c2
-rw-r--r--fs/xfs/scrub/scrub.c11
-rw-r--r--fs/xfs/scrub/trace.h3
13 files changed, 60 insertions, 25 deletions
diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
index c81ee424553e..246d33ac46b9 100644
--- a/fs/xfs/scrub/common.c
+++ b/fs/xfs/scrub/common.c
@@ -857,8 +857,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. */
@@ -880,7 +879,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;
@@ -905,7 +904,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;
}
@@ -913,6 +912,40 @@ xchk_get_inode(
return 0;
}
+void
+__xchk_irele(
+ struct xfs_inode *ip,
+ bool set_dontcache)
+{
+ if (current->journal_info != NULL) {
+ /*
+ * If we are in a transaction, we /cannot/ drop the inode
+ * ourselves, because the VFS will trigger writeback, which
+ * can require a transaction. Clear DONTCACHE to force the
+ * inode to the LRU, where someone else can take care of that.
+ */
+ spin_lock(&VFS_I(ip)->i_lock);
+ VFS_I(ip)->i_state &= ~I_DONTCACHE;
+ spin_unlock(&VFS_I(ip)->i_lock);
+ } else if (set_dontcache && atomic_read(&VFS_I(ip)->i_count) == 1) {
+ /*
+ * Otherwise, if this is the last reference to the inode and
+ * the caller permits it, set DONTCACHE to avoid thrashing.
+ */
+ 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 6da0ab14d315..04f7e1731458 100644
--- a/fs/xfs/scrub/common.h
+++ b/fs/xfs/scrub/common.h
@@ -177,6 +177,9 @@ void xchk_iunlock(struct xfs_scrub *sc, unsigned int ilock_flags);
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 0f94f94d3918..584a2c4d6961 100644
--- a/fs/xfs/scrub/dir.c
+++ b/fs/xfs/scrub/dir.c
@@ -104,7 +104,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 791ec9b5d991..a83ef0bd40d8 100644
--- a/fs/xfs/scrub/dir_repair.c
+++ b/fs/xfs/scrub/dir_repair.c
@@ -215,12 +215,12 @@ xrep_directory_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;
}
entry.ftype = xfs_mode_to_ftype(VFS_I(ip)->i_mode);
- xfs_irele(ip);
+ xchk_irele(rd->sc, ip);
/* Remember this for later. */
error = xfblob_store(rd->dir_names, &entry.name_cookie, name,
diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
index c64adde40dce..97605313f097 100644
--- a/fs/xfs/scrub/inode_repair.c
+++ b/fs/xfs/scrub/inode_repair.c
@@ -1182,8 +1182,7 @@ xrep_dinode_core(
return error;
/* ...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;
diff --git a/fs/xfs/scrub/iscan.c b/fs/xfs/scrub/iscan.c
index d9a7971d1934..1351c94a6852 100644
--- a/fs/xfs/scrub/iscan.c
+++ b/fs/xfs/scrub/iscan.c
@@ -292,8 +292,8 @@ xchk_iscan_iget(
struct xfs_mount *mp = sc->mp;
int error;
- error = xfs_iget(mp, sc->tp, iscan->cursor_ino,
- XFS_IGET_DONTCACHE | XFS_IGET_UNTRUSTED, 0, ipp);
+ error = xfs_iget(mp, sc->tp, iscan->cursor_ino, XFS_IGET_UNTRUSTED, 0,
+ ipp);
trace_xchk_iscan_iget(mp, iscan, error);
diff --git a/fs/xfs/scrub/parent.c b/fs/xfs/scrub/parent.c
index e4de4cb6ea19..ec351a393b2d 100644
--- a/fs/xfs/scrub/parent.c
+++ b/fs/xfs/scrub/parent.c
@@ -270,7 +270,7 @@ xchk_parent_validate(
out_unlock:
xfs_iunlock(dp, XFS_IOLOCK_SHARED);
out_rele:
- xfs_irele(dp);
+ xchk_irele(sc, dp);
return error;
}
diff --git a/fs/xfs/scrub/parent_repair.c b/fs/xfs/scrub/parent_repair.c
index 743476192cf8..6e43e4e4e388 100644
--- a/fs/xfs/scrub/parent_repair.c
+++ b/fs/xfs/scrub/parent_repair.c
@@ -298,7 +298,7 @@ xrep_parent_confirm(
*parent_ino = fpi.found_parent;
out_rele:
- xfs_irele(fpi.dp);
+ xchk_irele(sc, fpi.dp);
return error;
}
@@ -332,7 +332,7 @@ xrep_parent_from_dcache(
ret = XFS_I(pip)->i_ino;
}
- xfs_irele(XFS_I(pip));
+ xchk_irele(sc, XFS_I(pip));
out_dput:
dput(dentry);
@@ -376,7 +376,7 @@ xrep_parent_scan(
if (S_ISDIR(VFS_I(fpi.dp)->i_mode))
ret = xrep_findparent_walk_directory(&fpi);
xchk_iscan_mark_visited(&iscan, fpi.dp);
- xfs_irele(fpi.dp);
+ xchk_irele(sc, fpi.dp);
if (ret)
break;
diff --git a/fs/xfs/scrub/quotacheck.c b/fs/xfs/scrub/quotacheck.c
index a52a46e328be..68eb96987643 100644
--- a/fs/xfs/scrub/quotacheck.c
+++ b/fs/xfs/scrub/quotacheck.c
@@ -473,7 +473,7 @@ xqcheck_collect_counts(
break;
error = xqcheck_inode(xqc, ip);
- xfs_irele(ip);
+ xchk_irele(sc, ip);
if (error)
break;
diff --git a/fs/xfs/scrub/rmap_repair.c b/fs/xfs/scrub/rmap_repair.c
index f3e23b016142..738d24bc7013 100644
--- a/fs/xfs/scrub/rmap_repair.c
+++ b/fs/xfs/scrub/rmap_repair.c
@@ -946,7 +946,7 @@ end_agscan:
break;
error = xrep_rmap_scan_inode(rr, ip);
- xfs_irele(ip);
+ xchk_irele(sc, ip);
if (error)
break;
diff --git a/fs/xfs/scrub/rtrmap_repair.c b/fs/xfs/scrub/rtrmap_repair.c
index 03a28e733877..edcdc407f6cb 100644
--- a/fs/xfs/scrub/rtrmap_repair.c
+++ b/fs/xfs/scrub/rtrmap_repair.c
@@ -565,7 +565,7 @@ xrep_rtrmap_find_rmaps(
break;
error = xrep_rtrmap_scan_inode(rr, ip);
- xfs_irele(ip);
+ xchk_irele(sc, ip);
if (error)
break;
diff --git a/fs/xfs/scrub/scrub.c b/fs/xfs/scrub/scrub.c
index 93a4da52b599..e60f2e71dac0 100644
--- a/fs/xfs/scrub/scrub.c
+++ b/fs/xfs/scrub/scrub.c
@@ -172,7 +172,7 @@ xchk_teardown(
if (sc->ip) {
if (sc->ilock_flags)
xchk_iunlock(sc, sc->ilock_flags);
- xfs_irele(sc->ip);
+ xchk_irele(sc, sc->ip);
sc->ip = NULL;
}
if (sc->flags & XREP_ATOMIC_EXCHANGE) {
@@ -734,7 +734,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);
@@ -751,7 +752,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;
}
}
@@ -806,8 +807,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/scrub/trace.h b/fs/xfs/scrub/trace.h
index 6e5746d563fd..10c43e03e133 100644
--- a/fs/xfs/scrub/trace.h
+++ b/fs/xfs/scrub/trace.h
@@ -108,7 +108,8 @@ TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_BARRIER);
{ XFS_SCRUB_OFLAG_INCOMPLETE, "incomplete" }, \
{ XFS_SCRUB_OFLAG_WARNING, "warning" }, \
{ XFS_SCRUB_OFLAG_NO_REPAIR_NEEDED, "norepair" }, \
- { XFS_SCRUB_IFLAG_FREEZE_OK, "freeze" }
+ { XFS_SCRUB_IFLAG_FREEZE_OK, "freeze" }, \
+ { XFS_SCRUB_IFLAG_RETAIN_INODES, "icache" }
DECLARE_EVENT_CLASS(xchk_class,
TP_PROTO(struct xfs_inode *ip, struct xfs_scrub_metadata *sm,