]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_scrub: hoist repair retry loop to repair_item_class
authorDarrick J. Wong <djwong@kernel.org>
Mon, 29 Jul 2024 23:23:08 +0000 (16:23 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 30 Jul 2024 00:01:08 +0000 (17:01 -0700)
For metadata repair calls, move the ioctl retry and freeze permission
tracking into scrub_item.  This enables us to move the repair retry loop
out of xfs_repair_metadata and into its caller to remove a long
backwards jump, and gets us closer to vectorizing scrub calls.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
scrub/repair.c
scrub/scrub.c
scrub/scrub.h
scrub/scrub_private.h

index f888441aad0f6a41db7b469b157bff9bb5c5bf5a..c427e6e95f07f23f075a482981c17e10c164eac4 100644 (file)
@@ -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) &&
index 5f0cacbde6724d05fdad190d6e9b2fec984b94f7..8c6bf845fd979225644804c662bcdf535a58751e 100644 (file)
@@ -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);
 }
index 24fb244494331d86c45033b113df78b575be8c34..246c923f4905ed77a80d182433a03a15fbfe8624 100644 (file)
@@ -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) \
index 53372e1f322bc945a511be968c892ac50ed5933b..234b30ef2b811d99f8578e099ff83fb997e2cece 100644 (file)
@@ -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_ */