Commit 1a5f6e08 authored by Darrick J. Wong's avatar Darrick J. Wong

xfs: create subordinate scrub contexts for xchk_metadata_inode_subtype

When a file-based metadata structure is being scrubbed in
xchk_metadata_inode_subtype, we should create an entirely new scrub
context so that each scrubber doesn't trip over another's buffers.
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 5f204051
...@@ -1203,27 +1203,12 @@ xchk_metadata_inode_subtype( ...@@ -1203,27 +1203,12 @@ xchk_metadata_inode_subtype(
struct xfs_scrub *sc, struct xfs_scrub *sc,
unsigned int scrub_type) unsigned int scrub_type)
{ {
__u32 smtype = sc->sm->sm_type; struct xfs_scrub_subord *sub;
unsigned int sick_mask = sc->sick_mask;
int error; int error;
sc->sm->sm_type = scrub_type; sub = xchk_scrub_create_subord(sc, scrub_type);
error = sub->sc.ops->scrub(&sub->sc);
switch (scrub_type) { xchk_scrub_free_subord(sub);
case XFS_SCRUB_TYPE_INODE:
error = xchk_inode(sc);
break;
case XFS_SCRUB_TYPE_BMBTD:
error = xchk_bmap_data(sc);
break;
default:
ASSERT(0);
error = -EFSCORRUPTED;
break;
}
sc->sick_mask = sick_mask;
sc->sm->sm_type = smtype;
return error; return error;
} }
......
...@@ -1009,55 +1009,27 @@ xrep_metadata_inode_subtype( ...@@ -1009,55 +1009,27 @@ xrep_metadata_inode_subtype(
struct xfs_scrub *sc, struct xfs_scrub *sc,
unsigned int scrub_type) unsigned int scrub_type)
{ {
__u32 smtype = sc->sm->sm_type; struct xfs_scrub_subord *sub;
__u32 smflags = sc->sm->sm_flags;
unsigned int sick_mask = sc->sick_mask;
int error; int error;
/* /*
* Let's see if the inode needs repair. We're going to open-code calls * Let's see if the inode needs repair. Use a subordinate scrub context
* to the scrub and repair functions so that we can hang on to the * to call the scrub and repair functions so that we can hang on to the
* resources that we already acquired instead of using the standard * resources that we already acquired instead of using the standard
* setup/teardown routines. * setup/teardown routines.
*/ */
sc->sm->sm_flags &= ~XFS_SCRUB_FLAGS_OUT; sub = xchk_scrub_create_subord(sc, scrub_type);
sc->sm->sm_type = scrub_type; error = sub->sc.ops->scrub(&sub->sc);
switch (scrub_type) {
case XFS_SCRUB_TYPE_INODE:
error = xchk_inode(sc);
break;
case XFS_SCRUB_TYPE_BMBTD:
error = xchk_bmap_data(sc);
break;
case XFS_SCRUB_TYPE_BMBTA:
error = xchk_bmap_attr(sc);
break;
default:
ASSERT(0);
error = -EFSCORRUPTED;
}
if (error) if (error)
goto out; goto out;
if (!xrep_will_attempt(&sub->sc))
if (!xrep_will_attempt(sc))
goto out; goto out;
/* /*
* Repair some part of the inode. This will potentially join the inode * Repair some part of the inode. This will potentially join the inode
* to the transaction. * to the transaction.
*/ */
switch (scrub_type) { error = sub->sc.ops->repair(&sub->sc);
case XFS_SCRUB_TYPE_INODE:
error = xrep_inode(sc);
break;
case XFS_SCRUB_TYPE_BMBTD:
error = xrep_bmap(sc, XFS_DATA_FORK, false);
break;
case XFS_SCRUB_TYPE_BMBTA:
error = xrep_bmap(sc, XFS_ATTR_FORK, false);
break;
}
if (error) if (error)
goto out; goto out;
...@@ -1066,10 +1038,10 @@ xrep_metadata_inode_subtype( ...@@ -1066,10 +1038,10 @@ xrep_metadata_inode_subtype(
* that the inode will not be joined to the transaction when we exit * that the inode will not be joined to the transaction when we exit
* the function. * the function.
*/ */
error = xfs_defer_finish(&sc->tp); error = xfs_defer_finish(&sub->sc.tp);
if (error) if (error)
goto out; goto out;
error = xfs_trans_roll(&sc->tp); error = xfs_trans_roll(&sub->sc.tp);
if (error) if (error)
goto out; goto out;
...@@ -1077,31 +1049,18 @@ xrep_metadata_inode_subtype( ...@@ -1077,31 +1049,18 @@ xrep_metadata_inode_subtype(
* Clear the corruption flags and re-check the metadata that we just * Clear the corruption flags and re-check the metadata that we just
* repaired. * repaired.
*/ */
sc->sm->sm_flags &= ~XFS_SCRUB_FLAGS_OUT; sub->sc.sm->sm_flags &= ~XFS_SCRUB_FLAGS_OUT;
error = sub->sc.ops->scrub(&sub->sc);
switch (scrub_type) {
case XFS_SCRUB_TYPE_INODE:
error = xchk_inode(sc);
break;
case XFS_SCRUB_TYPE_BMBTD:
error = xchk_bmap_data(sc);
break;
case XFS_SCRUB_TYPE_BMBTA:
error = xchk_bmap_attr(sc);
break;
}
if (error) if (error)
goto out; goto out;
/* If corruption persists, the repair has failed. */ /* If corruption persists, the repair has failed. */
if (xchk_needs_repair(sc->sm)) { if (xchk_needs_repair(sub->sc.sm)) {
error = -EFSCORRUPTED; error = -EFSCORRUPTED;
goto out; goto out;
} }
out: out:
sc->sick_mask = sick_mask; xchk_scrub_free_subord(sub);
sc->sm->sm_type = smtype;
sc->sm->sm_flags = smflags;
return error; return error;
} }
......
...@@ -177,6 +177,39 @@ xchk_fsgates_disable( ...@@ -177,6 +177,39 @@ xchk_fsgates_disable(
} }
#undef FSGATES_MASK #undef FSGATES_MASK
/* Free the resources associated with a scrub subtype. */
void
xchk_scrub_free_subord(
struct xfs_scrub_subord *sub)
{
struct xfs_scrub *sc = sub->parent_sc;
ASSERT(sc->ip == sub->sc.ip);
ASSERT(sc->orphanage == sub->sc.orphanage);
ASSERT(sc->tempip == sub->sc.tempip);
sc->sm->sm_type = sub->old_smtype;
sc->sm->sm_flags = sub->old_smflags |
(sc->sm->sm_flags & XFS_SCRUB_FLAGS_OUT);
sc->tp = sub->sc.tp;
if (sub->sc.buf) {
if (sub->sc.buf_cleanup)
sub->sc.buf_cleanup(sub->sc.buf);
kvfree(sub->sc.buf);
}
if (sub->sc.xmbtp)
xmbuf_free(sub->sc.xmbtp);
if (sub->sc.xfile)
xfile_destroy(sub->sc.xfile);
sc->ilock_flags = sub->sc.ilock_flags;
sc->orphanage_ilock_flags = sub->sc.orphanage_ilock_flags;
sc->temp_ilock_flags = sub->sc.temp_ilock_flags;
kfree(sub);
}
/* Free all the resources and finish the transactions. */ /* Free all the resources and finish the transactions. */
STATIC int STATIC int
xchk_teardown( xchk_teardown(
...@@ -505,6 +538,36 @@ static inline void xchk_postmortem(struct xfs_scrub *sc) ...@@ -505,6 +538,36 @@ static inline void xchk_postmortem(struct xfs_scrub *sc)
} }
#endif /* CONFIG_XFS_ONLINE_REPAIR */ #endif /* CONFIG_XFS_ONLINE_REPAIR */
/*
* Create a new scrub context from an existing one, but with a different scrub
* type.
*/
struct xfs_scrub_subord *
xchk_scrub_create_subord(
struct xfs_scrub *sc,
unsigned int subtype)
{
struct xfs_scrub_subord *sub;
sub = kzalloc(sizeof(*sub), XCHK_GFP_FLAGS);
if (!sub)
return ERR_PTR(-ENOMEM);
sub->old_smtype = sc->sm->sm_type;
sub->old_smflags = sc->sm->sm_flags;
sub->parent_sc = sc;
memcpy(&sub->sc, sc, sizeof(struct xfs_scrub));
sub->sc.ops = &meta_scrub_ops[subtype];
sub->sc.sm->sm_type = subtype;
sub->sc.sm->sm_flags &= ~XFS_SCRUB_FLAGS_OUT;
sub->sc.buf = NULL;
sub->sc.buf_cleanup = NULL;
sub->sc.xfile = NULL;
sub->sc.xmbtp = NULL;
return sub;
}
/* Dispatch metadata scrubbing. */ /* Dispatch metadata scrubbing. */
int int
xfs_scrub_metadata( xfs_scrub_metadata(
......
...@@ -156,6 +156,17 @@ struct xfs_scrub { ...@@ -156,6 +156,17 @@ struct xfs_scrub {
*/ */
#define XREP_FSGATES_ALL (XREP_FSGATES_EXCHANGE_RANGE) #define XREP_FSGATES_ALL (XREP_FSGATES_EXCHANGE_RANGE)
struct xfs_scrub_subord {
struct xfs_scrub sc;
struct xfs_scrub *parent_sc;
unsigned int old_smtype;
unsigned int old_smflags;
};
struct xfs_scrub_subord *xchk_scrub_create_subord(struct xfs_scrub *sc,
unsigned int subtype);
void xchk_scrub_free_subord(struct xfs_scrub_subord *sub);
/* Metadata scrubbers */ /* Metadata scrubbers */
int xchk_tester(struct xfs_scrub *sc); int xchk_tester(struct xfs_scrub *sc);
int xchk_superblock(struct xfs_scrub *sc); int xchk_superblock(struct xfs_scrub *sc);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment