]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_scrub: don't try any file repairs during phase 3 if AG metadata bad
authorDarrick J. Wong <djwong@kernel.org>
Wed, 18 May 2022 02:48:13 +0000 (22:48 -0400)
committerEric Sandeen <sandeen@sandeen.net>
Wed, 18 May 2022 02:48:13 +0000 (22:48 -0400)
Currently, phase 3 tries to repair file metadata even after phase 2
tells us that there are problems with the AG metadata.  While this
generally won't cause too many problems since the repair code will bail
out on any obvious corruptions it finds, this isn't totally foolproof.
If the filesystem space metadata are not in good shape, we want to queue
the file repairs to run /after/ the space metadata repairs in phase 4.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
scrub/phase3.c
scrub/repair.h

index d22758c1dc0f9c922cac97c592fae273433b1e3b..fd8e541940d2c14e94617f0008710b1e7cb99e4c 100644 (file)
 /* Phase 3: Scan all inodes. */
 
 struct scrub_inode_ctx {
+       struct scrub_ctx        *ctx;
+
+       /* Number of inodes scanned. */
        struct ptcounter        *icount;
+
+       /* Set to true to abort all threads. */
        bool                    aborted;
+
+       /* Set to true if we want to defer file repairs to phase 4. */
+       bool                    always_defer_repairs;
 };
 
 /* Report a filesystem error that the vfs fed us on close. */
@@ -40,6 +48,24 @@ report_close_error(
        str_errno(ctx, descr);
 }
 
+/* Run repair actions now and defer unfinished items for later. */
+static int
+try_inode_repair(
+       struct scrub_inode_ctx  *ictx,
+       xfs_agnumber_t          agno,
+       struct action_list      *alist)
+{
+       /*
+        * If at the start of phase 3 we already had ag/rt metadata repairs
+        * queued up for phase 4, leave the action list untouched so that file
+        * metadata repairs will be deferred in scan order until phase 4.
+        */
+       if (ictx->always_defer_repairs)
+               return 0;
+
+       return action_list_process_or_defer(ictx->ctx, agno, alist);
+}
+
 /* Verify the contents, xattrs, and extent maps of an inode. */
 static int
 scrub_inode(
@@ -91,7 +117,7 @@ scrub_inode(
        if (error)
                goto out;
 
-       error = action_list_process_or_defer(ctx, agno, &alist);
+       error = try_inode_repair(ictx, agno, &alist);
        if (error)
                goto out;
 
@@ -106,7 +132,7 @@ scrub_inode(
        if (error)
                goto out;
 
-       error = action_list_process_or_defer(ctx, agno, &alist);
+       error = try_inode_repair(ictx, agno, &alist);
        if (error)
                goto out;
 
@@ -132,7 +158,7 @@ scrub_inode(
                goto out;
 
        /* Try to repair the file while it's open. */
-       error = action_list_process_or_defer(ctx, agno, &alist);
+       error = try_inode_repair(ictx, agno, &alist);
        if (error)
                goto out;
 
@@ -147,7 +173,10 @@ out:
                ictx->aborted = true;
        }
        progress_add(1);
-       action_list_defer(ctx, agno, &alist);
+
+       if (!error && !ictx->aborted)
+               action_list_defer(ctx, agno, &alist);
+
        if (fd >= 0) {
                int     err2;
 
@@ -168,8 +197,9 @@ int
 phase3_func(
        struct scrub_ctx        *ctx)
 {
-       struct scrub_inode_ctx  ictx = { NULL };
+       struct scrub_inode_ctx  ictx = { .ctx = ctx };
        uint64_t                val;
+       xfs_agnumber_t          agno;
        int                     err;
 
        err = ptcounter_alloc(scrub_nproc(ctx), &ictx.icount);
@@ -178,6 +208,16 @@ phase3_func(
                return err;
        }
 
+       /*
+        * If we already have ag/fs metadata to repair from previous phases,
+        * we would rather not try to repair file metadata until we've tried
+        * to repair the space metadata.
+        */
+       for (agno = 0; agno < ctx->mnt.fsgeom.agcount; agno++) {
+               if (!action_list_empty(&ctx->action_lists[agno]))
+                       ictx.always_defer_repairs = true;
+       }
+
        err = scrub_scan_all_inodes(ctx, scrub_inode, &ictx);
        if (!err && ictx.aborted)
                err = ECANCELED;
index 1994c50a84068176609f6921ec022fcc3103e544..4261be4913c4ad491c1d4ef31449bebd6a3fb9e8 100644 (file)
@@ -16,6 +16,12 @@ int action_lists_alloc(size_t nr, struct action_list **listsp);
 void action_lists_free(struct action_list **listsp);
 
 void action_list_init(struct action_list *alist);
+
+static inline bool action_list_empty(const struct action_list *alist)
+{
+       return list_empty(&alist->list);
+}
+
 size_t action_list_length(struct action_list *alist);
 void action_list_add(struct action_list *dest, struct action_item *item);
 void action_list_splice(struct action_list *dest, struct action_list *src);