xfs_scrub: serialize the scan-happy repair functions
Some of the metadata repair functions require full scans of the
filesystem. Use a rwlock to make sure that these repair functions only
run one at a time.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
diff --git a/scrub/scrub.c b/scrub/scrub.c
index 365e441..2a4db6b 100644
--- a/scrub/scrub.c
+++ b/scrub/scrub.c
@@ -690,6 +690,24 @@
/* General repair routines. */
+/*
+ * Decide if this repair item should be run one at a time. The only types
+ * requiring serialization are the ones that need to freeze the filesystem
+ * and the ones that have to use trylocking to avoid ABBA deadlocks.
+ */
+static inline bool
+repair_needs_excl(const struct xfs_scrub_metadata *meta)
+{
+ switch (meta->sm_type) {
+ case XFS_SCRUB_TYPE_PARENT:
+ case XFS_SCRUB_TYPE_RMAPBT:
+ case XFS_SCRUB_TYPE_RTRMAPBT:
+ return true;
+ }
+
+ return false;
+}
+
/* Repair some metadata. */
enum check_outcome
xfs_repair_metadata(
@@ -732,7 +750,19 @@
str_info(ctx, descr_render(&dsc),
_("Attempting optimization."));
retry:
+ /*
+ * Certain types of repairs involve full filesystem scans and
+ * trylocking. These repair activities are substantially more likely
+ * to succeed if they don't have to compete with other activity. Use a
+ * exclusive lock to serialize the repair functions that require it,
+ * and a shared lock for those that can run concurrently.
+ */
+ if (repair_needs_excl(&meta))
+ pthread_rwlock_wrlock(&ctx->repair_rwlock);
+ else
+ pthread_rwlock_rdlock(&ctx->repair_rwlock);
error = -xfrog_scrub_metadata(&ctx->mnt, &meta);
+ pthread_rwlock_unlock(&ctx->repair_rwlock);
switch (error) {
case 0:
/* No operational errors encountered. */
diff --git a/scrub/xfs_scrub.c b/scrub/xfs_scrub.c
index 1dde402..538e16d 100644
--- a/scrub/xfs_scrub.c
+++ b/scrub/xfs_scrub.c
@@ -618,6 +618,7 @@
textdomain(PACKAGE);
pthread_mutex_init(&ctx.lock, NULL);
+ pthread_rwlock_init(&ctx.repair_rwlock, NULL);
ctx.mode = SCRUB_MODE_REPAIR;
ctx.error_action = ERRORS_CONTINUE;
ctx.freeze_ok = true;
diff --git a/scrub/xfs_scrub.h b/scrub/xfs_scrub.h
index 8e4ca16..d6c9286 100644
--- a/scrub/xfs_scrub.h
+++ b/scrub/xfs_scrub.h
@@ -85,6 +85,9 @@
unsigned long long slow_ops_skipped;
bool scrub_setup_succeeded;
bool preen_triggers[XFS_SCRUB_TYPE_NR];
+
+ /* Used to serialize certain scan-happy repair operations. */
+ pthread_rwlock_t repair_rwlock;
};
/* Phase helper functions */