diff options
Diffstat (limited to 'fs/xfs/scrub')
-rw-r--r-- | fs/xfs/scrub/common.c | 41 | ||||
-rw-r--r-- | fs/xfs/scrub/common.h | 3 | ||||
-rw-r--r-- | fs/xfs/scrub/dir.c | 2 | ||||
-rw-r--r-- | fs/xfs/scrub/dir_repair.c | 4 | ||||
-rw-r--r-- | fs/xfs/scrub/inode_repair.c | 3 | ||||
-rw-r--r-- | fs/xfs/scrub/iscan.c | 4 | ||||
-rw-r--r-- | fs/xfs/scrub/parent.c | 2 | ||||
-rw-r--r-- | fs/xfs/scrub/parent_repair.c | 6 | ||||
-rw-r--r-- | fs/xfs/scrub/quotacheck.c | 2 | ||||
-rw-r--r-- | fs/xfs/scrub/rmap_repair.c | 2 | ||||
-rw-r--r-- | fs/xfs/scrub/rtrmap_repair.c | 2 | ||||
-rw-r--r-- | fs/xfs/scrub/scrub.c | 11 | ||||
-rw-r--r-- | fs/xfs/scrub/trace.h | 3 |
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, |