summaryrefslogtreecommitdiffstats
path: root/fs/xfs/scrub/scrub.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/scrub/scrub.c')
-rw-r--r--fs/xfs/scrub/scrub.c42
1 files changed, 24 insertions, 18 deletions
diff --git a/fs/xfs/scrub/scrub.c b/fs/xfs/scrub/scrub.c
index 8ebf35b115ce..0e542636227c 100644
--- a/fs/xfs/scrub/scrub.c
+++ b/fs/xfs/scrub/scrub.c
@@ -149,9 +149,10 @@ xchk_probe(
STATIC int
xchk_teardown(
struct xfs_scrub *sc,
- struct xfs_inode *ip_in,
int error)
{
+ struct xfs_inode *ip_in = XFS_I(file_inode(sc->file));
+
xchk_ag_free(sc, &sc->sa);
if (sc->tp) {
if (error == 0 && (sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR))
@@ -168,7 +169,8 @@ xchk_teardown(
xfs_irele(sc->ip);
sc->ip = NULL;
}
- sb_end_write(sc->mp->m_super);
+ if (sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR)
+ mnt_drop_write_file(sc->file);
if (sc->flags & XCHK_REAPING_DISABLED)
xchk_start_reaping(sc);
if (sc->flags & XCHK_HAS_QUOTAOFFLOCK) {
@@ -456,23 +458,25 @@ static inline void xchk_postmortem(struct xfs_scrub *sc)
/* Dispatch metadata scrubbing. */
int
xfs_scrub_metadata(
- struct xfs_inode *ip,
+ struct file *file,
struct xfs_scrub_metadata *sm)
{
struct xfs_scrub sc = {
- .mp = ip->i_mount,
+ .file = file,
.sm = sm,
.sa = {
.agno = NULLAGNUMBER,
},
};
- struct xfs_mount *mp = ip->i_mount;
+ struct xfs_mount *mp = XFS_I(file_inode(file))->i_mount;
int error = 0;
+ sc.mp = mp;
+
BUILD_BUG_ON(sizeof(meta_scrub_ops) !=
(sizeof(struct xchk_meta_ops) * XFS_SCRUB_TYPE_NR));
- trace_xchk_start(ip, sm, error);
+ trace_xchk_start(XFS_I(file_inode(file)), sm, error);
/* Forbidden if we are shut down or mounted norecovery. */
error = -ESHUTDOWN;
@@ -492,15 +496,17 @@ xfs_scrub_metadata(
sc.sick_mask = xchk_health_mask_for_scrub_type(sm->sm_type);
retry_op:
/*
- * If freeze runs concurrently with a scrub, the freeze can be delayed
- * indefinitely as we walk the filesystem and iterate over metadata
- * buffers. Freeze quiesces the log (which waits for the buffer LRU to
- * be emptied) and that won't happen while checking is running.
+ * When repairs are allowed, prevent freezing or readonly remount while
+ * scrub is running with a real transaction.
*/
- sb_start_write(mp->m_super);
+ if (sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR) {
+ error = mnt_want_write_file(sc.file);
+ if (error)
+ goto out;
+ }
/* Set up for the operation. */
- error = sc.ops->setup(&sc, ip);
+ error = sc.ops->setup(&sc);
if (error)
goto out_teardown;
@@ -512,12 +518,12 @@ retry_op:
* Tear down everything we hold, then set up again with
* preparation for worst-case scenarios.
*/
- error = xchk_teardown(&sc, ip, 0);
+ error = xchk_teardown(&sc, 0);
if (error)
goto out;
sc.flags |= XCHK_TRY_HARDER;
goto retry_op;
- } else if (error)
+ } else if (error || (sm->sm_flags & XFS_SCRUB_OFLAG_INCOMPLETE))
goto out_teardown;
xchk_update_health(&sc);
@@ -546,14 +552,14 @@ retry_op:
* If it's broken, userspace wants us to fix it, and we haven't
* already tried to fix it, then attempt a repair.
*/
- error = xrep_attempt(ip, &sc);
+ error = xrep_attempt(&sc);
if (error == -EAGAIN) {
/*
* Either the repair function succeeded or it couldn't
* get all the resources it needs; either way, we go
* back to the beginning and call the scrub function.
*/
- error = xchk_teardown(&sc, ip, 0);
+ error = xchk_teardown(&sc, 0);
if (error) {
xrep_failure(mp);
goto out;
@@ -565,9 +571,9 @@ retry_op:
out_nofix:
xchk_postmortem(&sc);
out_teardown:
- error = xchk_teardown(&sc, ip, error);
+ error = xchk_teardown(&sc, error);
out:
- trace_xchk_done(ip, sm, error);
+ trace_xchk_done(XFS_I(file_inode(file)), sm, error);
if (error == -EFSCORRUPTED || error == -EFSBADCRC) {
sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
error = 0;