Commit 4b0bf86c authored by Chandan Babu R's avatar Chandan Babu R

Merge tag 'repair-fixes-6.10_2024-04-23' of...

Merge tag 'repair-fixes-6.10_2024-04-23' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux into xfs-6.10-mergeC

xfs: minor fixes to online repair

Here are some miscellaneous bug fixes for the online repair code.
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Signed-off-by: default avatarChandan Babu R <chandanbabu@kernel.org>

* tag 'repair-fixes-6.10_2024-04-23' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux:
  xfs: invalidate dentries for a file before moving it to the orphanage
  xfs: exchange-range for repairs is no longer dynamic
  xfs: fix iunlock calls in xrep_adoption_trans_alloc
  xfs: drop the scrub file's iolock when transaction allocation fails
parents b878dbbe 5e1c7d0b
......@@ -1630,6 +1630,9 @@ xrep_xattr(
/* The rmapbt is required to reap the old attr fork. */
if (!xfs_has_rmapbt(sc->mp))
return -EOPNOTSUPP;
/* We require atomic file exchange range to rebuild anything. */
if (!xfs_has_exchange_range(sc->mp))
return -EOPNOTSUPP;
error = xrep_xattr_setup_scan(sc, &rx);
if (error)
......
......@@ -1993,6 +1993,9 @@ xrep_directory(
/* The rmapbt is required to reap the old data fork. */
if (!xfs_has_rmapbt(sc->mp))
return -EOPNOTSUPP;
/* We require atomic file exchange range to rebuild anything. */
if (!xfs_has_exchange_range(sc->mp))
return -EOPNOTSUPP;
error = xrep_dir_setup_scan(rd);
if (error)
......
......@@ -138,8 +138,10 @@ xrep_nlinks_repair_inode(
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_link, 0, 0, 0,
&sc->tp);
if (error)
if (error) {
xchk_iunlock(sc, XFS_IOLOCK_EXCL);
return error;
}
xchk_ilock(sc, XFS_ILOCK_EXCL);
xfs_trans_ijoin(sc->tp, ip, 0);
......
......@@ -382,7 +382,7 @@ xrep_adoption_trans_alloc(
out_cancel:
xchk_trans_cancel(sc);
xrep_orphanage_iunlock(sc, XFS_ILOCK_EXCL);
xrep_orphanage_iunlock(sc, XFS_IOLOCK_EXCL);
xchk_iunlock(sc, XFS_ILOCK_EXCL);
return error;
}
......@@ -434,16 +434,17 @@ xrep_adoption_check_dcache(
{
struct qstr qname = QSTR_INIT(adopt->xname->name,
adopt->xname->len);
struct xfs_scrub *sc = adopt->sc;
struct dentry *d_orphanage, *d_child;
int error = 0;
d_orphanage = d_find_alias(VFS_I(adopt->sc->orphanage));
d_orphanage = d_find_alias(VFS_I(sc->orphanage));
if (!d_orphanage)
return 0;
d_child = d_hash_and_lookup(d_orphanage, &qname);
if (d_child) {
trace_xrep_adoption_check_child(adopt->sc->mp, d_child);
trace_xrep_adoption_check_child(sc->mp, d_child);
if (d_is_positive(d_child)) {
ASSERT(d_is_negative(d_child));
......@@ -454,33 +455,15 @@ xrep_adoption_check_dcache(
}
dput(d_orphanage);
if (error)
return error;
/*
* Do we need to update d_parent of the dentry for the file being
* repaired? There shouldn't be a hashed dentry with a parent since
* the file had nonzero nlink but wasn't connected to any parent dir.
*/
d_child = d_find_alias(VFS_I(adopt->sc->ip));
if (!d_child)
return 0;
trace_xrep_adoption_check_alias(adopt->sc->mp, d_child);
if (d_child->d_parent && !d_unhashed(d_child)) {
ASSERT(d_child->d_parent == NULL || d_unhashed(d_child));
error = -EFSCORRUPTED;
}
dput(d_child);
return error;
}
/*
* Remove all negative dentries from the dcache. There should not be any
* positive entries, since we've maintained our lock on the orphanage
* directory.
* Invalidate all dentries for the name that was added to the orphanage
* directory, and all dentries pointing to the child inode that was moved.
*
* There should not be any positive entries for the name, since we've
* maintained our lock on the orphanage directory.
*/
static void
xrep_adoption_zap_dcache(
......@@ -488,15 +471,17 @@ xrep_adoption_zap_dcache(
{
struct qstr qname = QSTR_INIT(adopt->xname->name,
adopt->xname->len);
struct xfs_scrub *sc = adopt->sc;
struct dentry *d_orphanage, *d_child;
d_orphanage = d_find_alias(VFS_I(adopt->sc->orphanage));
/* Invalidate all dentries for the adoption name */
d_orphanage = d_find_alias(VFS_I(sc->orphanage));
if (!d_orphanage)
return;
d_child = d_hash_and_lookup(d_orphanage, &qname);
while (d_child != NULL) {
trace_xrep_adoption_invalidate_child(adopt->sc->mp, d_child);
trace_xrep_adoption_invalidate_child(sc->mp, d_child);
ASSERT(d_is_negative(d_child));
d_invalidate(d_child);
......@@ -505,6 +490,14 @@ xrep_adoption_zap_dcache(
}
dput(d_orphanage);
/* Invalidate all the dentries pointing down to this file. */
while ((d_child = d_find_alias(VFS_I(sc->ip))) != NULL) {
trace_xrep_adoption_invalidate_child(sc->mp, d_child);
d_invalidate(d_child);
dput(d_child);
}
}
/*
......
......@@ -1571,10 +1571,14 @@ xrep_parent(
/*
* When the parent pointers feature is enabled, repairs are committed
* by atomically committing a new xattr structure and reaping the old
* attr fork. Reaping requires rmap to be enabled.
* attr fork. Reaping requires rmap and exchange-range to be enabled.
*/
if (xfs_has_parent(sc->mp) && !xfs_has_rmapbt(sc->mp))
return -EOPNOTSUPP;
if (xfs_has_parent(sc->mp)) {
if (!xfs_has_rmapbt(sc->mp))
return -EOPNOTSUPP;
if (!xfs_has_exchange_range(sc->mp))
return -EOPNOTSUPP;
}
error = xrep_parent_setup_scan(rp);
if (error)
......
......@@ -62,12 +62,7 @@ xrep_setup_rtsummary(
return -EOPNOTSUPP;
rts->resblks += blocks;
/*
* Grab support for atomic file content exchanges before we allocate
* any transactions or grab ILOCKs.
*/
return xrep_tempexch_enable(sc);
return 0;
}
static int
......@@ -111,6 +106,9 @@ xrep_rtsummary(
/* We require the rmapbt to rebuild anything. */
if (!xfs_has_rmapbt(mp))
return -EOPNOTSUPP;
/* We require atomic file exchange range to rebuild anything. */
if (!xfs_has_exchange_range(mp))
return -EOPNOTSUPP;
/* Walk away if we disagree on the size of the rt bitmap. */
if (rts->rbmblocks != mp->m_sb.sb_rbmblocks)
......
......@@ -154,15 +154,14 @@ xchk_probe(
/* Scrub setup and teardown */
#define FSGATES_MASK (XCHK_FSGATES_ALL | XREP_FSGATES_ALL)
static inline void
xchk_fsgates_disable(
struct xfs_scrub *sc)
{
if (!(sc->flags & FSGATES_MASK))
if (!(sc->flags & XCHK_FSGATES_ALL))
return;
trace_xchk_fsgates_disable(sc, sc->flags & FSGATES_MASK);
trace_xchk_fsgates_disable(sc, sc->flags & XCHK_FSGATES_ALL);
if (sc->flags & XCHK_FSGATES_DRAIN)
xfs_drain_wait_disable();
......@@ -176,9 +175,8 @@ xchk_fsgates_disable(
if (sc->flags & XCHK_FSGATES_RMAP)
xfs_rmap_hook_disable();
sc->flags &= ~FSGATES_MASK;
sc->flags &= ~XCHK_FSGATES_ALL;
}
#undef FSGATES_MASK
/* Free the resources associated with a scrub subtype. */
void
......
......@@ -188,7 +188,6 @@ struct xfs_scrub {
#define XCHK_FSGATES_QUOTA (1U << 4) /* quota live update enabled */
#define XCHK_FSGATES_DIRENTS (1U << 5) /* directory live update enabled */
#define XCHK_FSGATES_RMAP (1U << 6) /* rmapbt live update enabled */
#define XREP_FSGATES_EXCHANGE_RANGE (1U << 29) /* uses file content exchange */
#define XREP_RESET_PERAG_RESV (1U << 30) /* must reset AG space reservation */
#define XREP_ALREADY_FIXED (1U << 31) /* checking our repair work */
......@@ -203,12 +202,6 @@ struct xfs_scrub {
XCHK_FSGATES_DIRENTS | \
XCHK_FSGATES_RMAP)
/*
* The sole XREP_FSGATES* flag reflects a log intent item that is protected
* by a log-incompat feature flag. No code patching in use here.
*/
#define XREP_FSGATES_ALL (XREP_FSGATES_EXCHANGE_RANGE)
struct xfs_scrub_subord {
struct xfs_scrub sc;
struct xfs_scrub *parent_sc;
......
......@@ -490,6 +490,9 @@ xrep_symlink(
/* The rmapbt is required to reap the old data fork. */
if (!xfs_has_rmapbt(sc->mp))
return -EOPNOTSUPP;
/* We require atomic file exchange range to rebuild anything. */
if (!xfs_has_exchange_range(sc->mp))
return -EOPNOTSUPP;
ASSERT(sc->ilock_flags & XFS_ILOCK_EXCL);
......
......@@ -11,7 +11,6 @@ struct xrep_tempexch {
struct xfs_exchmaps_req req;
};
int xrep_tempexch_enable(struct xfs_scrub *sc);
int xrep_tempexch_trans_reserve(struct xfs_scrub *sc, int whichfork,
struct xrep_tempexch *ti);
int xrep_tempexch_trans_alloc(struct xfs_scrub *sc, int whichfork,
......
......@@ -486,23 +486,6 @@ xrep_tempfile_roll_trans(
return 0;
}
/* Enable file content exchanges. */
int
xrep_tempexch_enable(
struct xfs_scrub *sc)
{
if (sc->flags & XREP_FSGATES_EXCHANGE_RANGE)
return 0;
if (!xfs_has_exchange_range(sc->mp))
return -EOPNOTSUPP;
trace_xchk_fsgates_enable(sc, XREP_FSGATES_EXCHANGE_RANGE);
sc->flags |= XREP_FSGATES_EXCHANGE_RANGE;
return 0;
}
/*
* Fill out the mapping exchange request in preparation for atomically
* committing the contents of a metadata file that we've rebuilt in the temp
......@@ -745,6 +728,7 @@ xrep_tempexch_trans_alloc(
int error;
ASSERT(sc->tp == NULL);
ASSERT(xfs_has_exchange_range(sc->mp));
error = xrep_tempexch_prep_request(sc, whichfork, tx);
if (error)
......@@ -757,10 +741,6 @@ xrep_tempexch_trans_alloc(
if (xfs_has_lazysbcount(sc->mp))
flags |= XFS_TRANS_RES_FDBLKS;
error = xrep_tempexch_enable(sc);
if (error)
return error;
error = xfs_trans_alloc(sc->mp, &M_RES(sc->mp)->tr_itruncate,
tx->req.resblks, 0, flags, &sc->tp);
if (error)
......@@ -785,7 +765,7 @@ xrep_tempexch_contents(
{
int error;
ASSERT(sc->flags & XREP_FSGATES_EXCHANGE_RANGE);
ASSERT(xfs_has_exchange_range(sc->mp));
xfs_exchange_mappings(sc->tp, &tx->req);
error = xfs_defer_finish(&sc->tp);
......
......@@ -122,7 +122,6 @@ TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_BARRIER);
{ XCHK_FSGATES_QUOTA, "fsgates_quota" }, \
{ XCHK_FSGATES_DIRENTS, "fsgates_dirents" }, \
{ XCHK_FSGATES_RMAP, "fsgates_rmap" }, \
{ XREP_FSGATES_EXCHANGE_RANGE, "fsgates_exchrange" }, \
{ XREP_RESET_PERAG_RESV, "reset_perag_resv" }, \
{ XREP_ALREADY_FIXED, "already_fixed" }
......@@ -3266,8 +3265,6 @@ DEFINE_EVENT(xrep_dentry_class, name, \
TP_PROTO(struct xfs_mount *mp, const struct dentry *dentry), \
TP_ARGS(mp, dentry))
DEFINE_REPAIR_DENTRY_EVENT(xrep_adoption_check_child);
DEFINE_REPAIR_DENTRY_EVENT(xrep_adoption_check_alias);
DEFINE_REPAIR_DENTRY_EVENT(xrep_adoption_check_dentry);
DEFINE_REPAIR_DENTRY_EVENT(xrep_adoption_invalidate_child);
DEFINE_REPAIR_DENTRY_EVENT(xrep_dirtree_delete_child);
......
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