mirror of
https://github.com/torvalds/linux.git
synced 2026-06-01 11:03:43 +02:00
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: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
parent
5f204051d9
commit
1a5f6e08d4
|
|
@ -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(
|
||||||
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(
|
||||||
* 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(
|
||||||
* 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(
|
||||||
}
|
}
|
||||||
#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)
|
||||||
}
|
}
|
||||||
#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 {
|
||||||
*/
|
*/
|
||||||
#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);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user