]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_scrub: prepare phase3 for per-inogrp worker threads
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)
In the next patch, we're going to rewrite scrub_scan_all_inodes to
schedule per-inogrp workqueue items that will run the iterator function.
In other words, the worker threads in phase 3 wil soon cease to be
per-AG threads.

To prepare for this, we must modify phase 3 so that any writes to shared
state are protected by the appropriate per-AG locks.  As far as I can
tell, the only updates to shared state are the per-AG action lists, so
create some per-AG locks for phase 3 and create locked wrappers for the
action_list_* functions if we find things to repair.

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

index d659a7791825ca871713fa9bc0d091418407662e..65e903f23d2c8d606b553fad34ae1986c831c9f7 100644 (file)
@@ -26,6 +26,9 @@ struct scrub_inode_ctx {
        /* Number of inodes scanned. */
        struct ptcounter        *icount;
 
+       /* per-AG locks to protect the repair lists */
+       pthread_mutex_t         *locks;
+
        /* Set to true to abort all threads. */
        bool                    aborted;
 
@@ -48,6 +51,24 @@ report_close_error(
        str_errno(ctx, descr);
 }
 
+/*
+ * Defer all the repairs until phase 4, being careful about locking since the
+ * inode scrub threads are not per-AG.
+ */
+static void
+defer_inode_repair(
+       struct scrub_inode_ctx  *ictx,
+       xfs_agnumber_t          agno,
+       struct action_list      *alist)
+{
+       if (alist->nr == 0)
+               return;
+
+       pthread_mutex_lock(&ictx->locks[agno]);
+       action_list_defer(ictx->ctx, agno, alist);
+       pthread_mutex_unlock(&ictx->locks[agno]);
+}
+
 /* Run repair actions now and defer unfinished items for later. */
 static int
 try_inode_repair(
@@ -71,7 +92,7 @@ try_inode_repair(
        if (ret)
                return ret;
 
-       action_list_defer(ictx->ctx, agno, alist);
+       defer_inode_repair(ictx, agno, alist);
        return 0;
 }
 
@@ -184,7 +205,7 @@ out:
        progress_add(1);
 
        if (!error && !ictx->aborted)
-               action_list_defer(ctx, agno, &alist);
+               defer_inode_repair(ictx, agno, &alist);
 
        if (fd >= 0) {
                int     err2;
@@ -217,12 +238,21 @@ phase3_func(
                return err;
        }
 
+       ictx.locks = calloc(ctx->mnt.fsgeom.agcount, sizeof(pthread_mutex_t));
+       if (!ictx.locks) {
+               str_errno(ctx, _("creating per-AG repair list locks"));
+               err = ENOMEM;
+               goto out_ptcounter;
+       }
+
        /*
         * 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++) {
+               pthread_mutex_init(&ictx.locks[agno], NULL);
+
                if (!action_list_empty(&ctx->action_lists[agno]))
                        ictx.always_defer_repairs = true;
        }
@@ -231,17 +261,21 @@ phase3_func(
        if (!err && ictx.aborted)
                err = ECANCELED;
        if (err)
-               goto free;
+               goto out_locks;
 
        scrub_report_preen_triggers(ctx);
        err = ptcounter_value(ictx.icount, &val);
        if (err) {
                str_liberror(ctx, err, _("summing scanned inode counter"));
-               return err;
+               goto out_locks;
        }
 
        ctx->inodes_checked = val;
-free:
+out_locks:
+       for (agno = 0; agno < ctx->mnt.fsgeom.agcount; agno++)
+               pthread_mutex_destroy(&ictx.locks[agno]);
+       free(ictx.locks);
+out_ptcounter:
        ptcounter_free(ictx.icount);
        return err;
 }