@@ -58,7 +58,6 @@ xfs_repair_metadata(
struct xfs_scrub_metadata oldm;
DEFINE_DESCR(dsc, ctx, format_scrub_descr);
bool repair_only;
- unsigned int tries = 0;
int error;
/*
@@ -100,7 +99,6 @@ xfs_repair_metadata(
str_info(ctx, descr_render(&dsc),
_("Attempting optimization."));
-retry:
error = -xfrog_scrub_metadata(xfdp, &meta);
switch (error) {
case 0:
@@ -187,10 +185,8 @@ _("Read-only filesystem; cannot make changes."));
* the repair again, just in case the fs was busy. Only retry so many
* times.
*/
- if (want_retry(&meta) && tries < 10) {
- tries++;
- goto retry;
- }
+ if (want_retry(&meta) && scrub_item_schedule_retry(sri, scrub_type))
+ return 0;
if (repair_flags & XRM_FINAL_WARNING)
scrub_warn_incomplete_scrub(ctx, &dsc, &meta);
@@ -541,6 +537,7 @@ repair_item_class(
unsigned int flags)
{
struct xfs_fd xfd;
+ struct scrub_item old_sri;
struct xfs_fd *xfdp = &ctx->mnt;
unsigned int scrub_type;
int error = 0;
@@ -575,9 +572,15 @@ repair_item_class(
!repair_item_dependencies_ok(sri, scrub_type))
continue;
- error = xfs_repair_metadata(ctx, xfdp, scrub_type, sri, flags);
- if (error)
- break;
+ sri->sri_tries[scrub_type] = SCRUB_ITEM_MAX_RETRIES;
+ do {
+ memcpy(&old_sri, sri, sizeof(old_sri));
+ error = xfs_repair_metadata(ctx, xfdp, scrub_type, sri,
+ flags);
+ if (error)
+ return error;
+ } while (scrub_item_call_kernel_again(sri, scrub_type,
+ repair_mask, &old_sri));
/* Maybe update progress if we fixed the problem. */
if (!(flags & XRM_NOPROGRESS) &&
@@ -268,6 +268,34 @@ scrub_item_schedule_group(
}
}
+/* Decide if we call the kernel again to finish scrub/repair activity. */
+bool
+scrub_item_call_kernel_again(
+ struct scrub_item *sri,
+ unsigned int scrub_type,
+ uint8_t work_mask,
+ const struct scrub_item *old)
+{
+ uint8_t statex;
+
+ /* If there's nothing to do, we're done. */
+ if (!(sri->sri_state[scrub_type] & work_mask))
+ return false;
+
+ /*
+ * We are willing to go again if the last call had any effect on the
+ * state of the scrub item that the caller cares about, if the freeze
+ * flag got set, or if the kernel asked us to try again...
+ */
+ statex = sri->sri_state[scrub_type] ^ old->sri_state[scrub_type];
+ if (statex & work_mask)
+ return true;
+ if (sri->sri_tries[scrub_type] != old->sri_tries[scrub_type])
+ return true;
+
+ return false;
+}
+
/* Run all the incomplete scans on this scrub principal. */
int
scrub_item_check_file(
@@ -383,9 +411,9 @@ scrub_item_dump(
unsigned int g = 1U << xfrog_scrubbers[i].group;
if (g & group_mask)
- printf("[%u]: type '%s' state 0x%x\n", i,
+ printf("[%u]: type '%s' state 0x%x tries %u\n", i,
xfrog_scrubbers[i].name,
- sri->sri_state[i]);
+ sri->sri_state[i], sri->sri_tries[i]);
}
fflush(stdout);
}
@@ -45,6 +45,9 @@ enum xfrog_scrub_group;
SCRUB_ITEM_XFAIL | \
SCRUB_ITEM_XCORRUPT)
+/* Maximum number of times we'll retry a scrub ioctl call. */
+#define SCRUB_ITEM_MAX_RETRIES 10
+
struct scrub_item {
/*
* Information we need to call the scrub and repair ioctls. Per-AG
@@ -58,6 +61,9 @@ struct scrub_item {
/* Scrub item state flags, one for each XFS_SCRUB_TYPE. */
__u8 sri_state[XFS_SCRUB_TYPE_NR];
+
+ /* Track scrub and repair call retries for each scrub type. */
+ __u8 sri_tries[XFS_SCRUB_TYPE_NR];
};
#define foreach_scrub_type(loopvar) \
@@ -89,4 +89,18 @@ scrub_item_type_boosted(
return sri->sri_state[scrub_type] & SCRUB_ITEM_BOOST_REPAIR;
}
+/* Decide if we want to retry this operation and update bookkeeping if yes. */
+static inline bool
+scrub_item_schedule_retry(struct scrub_item *sri, unsigned int scrub_type)
+{
+ if (sri->sri_tries[scrub_type] == 0)
+ return false;
+ sri->sri_tries[scrub_type]--;
+ return true;
+}
+
+bool scrub_item_call_kernel_again(struct scrub_item *sri,
+ unsigned int scrub_type, uint8_t work_mask,
+ const struct scrub_item *old);
+
#endif /* XFS_SCRUB_SCRUB_PRIVATE_H_ */