]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blobdiff - scrub/phase2.c
libfrog: convert workqueue.c functions to negative error codes
[thirdparty/xfsprogs-dev.git] / scrub / phase2.c
index e8eb1cab33ed400b7ecf6551c2734ec43008ea0b..c40d9d3b17fc3339d3988f9ff04bd09d0b9ee44d 100644 (file)
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Copyright (C) 2018 Oracle.  All Rights Reserved.
- *
  * Author: Darrick J. Wong <darrick.wong@oracle.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
  */
-#include <stdio.h>
+#include "xfs.h"
 #include <stdint.h>
-#include <stdbool.h>
 #include <sys/types.h>
-#include <sys/stat.h>
 #include <sys/statvfs.h>
-#include "xfs.h"
-#include "path.h"
-#include "workqueue.h"
+#include "list.h"
+#include "libfrog/paths.h"
+#include "libfrog/workqueue.h"
 #include "xfs_scrub.h"
 #include "common.h"
 #include "scrub.h"
+#include "repair.h"
 
 /* Phase 2: Check internal metadata. */
 
 /* Scrub each AG's metadata btrees. */
 static void
-xfs_scan_ag_metadata(
+scan_ag_metadata(
        struct workqueue                *wq,
        xfs_agnumber_t                  agno,
        void                            *arg)
 {
        struct scrub_ctx                *ctx = (struct scrub_ctx *)wq->wq_ctx;
-       bool                            *pmoveon = arg;
-       bool                            moveon;
+       bool                            *aborted = arg;
+       struct action_list              alist;
+       struct action_list              immediate_alist;
+       unsigned long long              broken_primaries;
+       unsigned long long              broken_secondaries;
        char                            descr[DESCR_BUFSZ];
+       int                             ret;
+
+       if (*aborted)
+               return;
 
+       action_list_init(&alist);
+       action_list_init(&immediate_alist);
        snprintf(descr, DESCR_BUFSZ, _("AG %u"), agno);
 
        /*
         * First we scrub and fix the AG headers, because we need
         * them to work well enough to check the AG btrees.
         */
-       moveon = xfs_scrub_ag_headers(ctx, agno);
-       if (!moveon)
+       ret = xfs_scrub_ag_headers(ctx, agno, &alist);
+       if (ret)
+               goto err;
+
+       /* Repair header damage. */
+       ret = action_list_process_or_defer(ctx, agno, &alist);
+       if (ret)
                goto err;
 
        /* Now scrub the AG btrees. */
-       moveon = xfs_scrub_ag_metadata(ctx, agno);
-       if (!moveon)
+       ret = xfs_scrub_ag_metadata(ctx, agno, &alist);
+       if (ret)
                goto err;
 
+       /*
+        * Figure out if we need to perform early fixing.  The only
+        * reason we need to do this is if the inobt is broken, which
+        * prevents phase 3 (inode scan) from running.  We can rebuild
+        * the inobt from rmapbt data, but if the rmapbt is broken even
+        * at this early phase then we are sunk.
+        */
+       broken_secondaries = 0;
+       broken_primaries = 0;
+       action_list_find_mustfix(&alist, &immediate_alist,
+                       &broken_primaries, &broken_secondaries);
+       if (broken_secondaries && !debug_tweak_on("XFS_SCRUB_FORCE_REPAIR")) {
+               if (broken_primaries)
+                       str_info(ctx, descr,
+_("Corrupt primary and secondary block mapping metadata."));
+               else
+                       str_info(ctx, descr,
+_("Corrupt secondary block mapping metadata."));
+               str_info(ctx, descr,
+_("Filesystem might not be repairable."));
+       }
+
+       /* Repair (inode) btree damage. */
+       ret = action_list_process_or_defer(ctx, agno, &immediate_alist);
+       if (ret)
+               goto err;
+
+       /* Everything else gets fixed during phase 4. */
+       action_list_defer(ctx, agno, &alist);
        return;
 err:
-       *pmoveon = false;
+       *aborted = true;
 }
 
 /* Scrub whole-FS metadata btrees. */
 static void
-xfs_scan_fs_metadata(
+scan_fs_metadata(
        struct workqueue                *wq,
        xfs_agnumber_t                  agno,
        void                            *arg)
 {
        struct scrub_ctx                *ctx = (struct scrub_ctx *)wq->wq_ctx;
-       bool                            *pmoveon = arg;
-       bool                            moveon;
+       bool                            *aborted = arg;
+       struct action_list              alist;
+       int                             ret;
+
+       if (*aborted)
+               return;
+
+       action_list_init(&alist);
+       ret = xfs_scrub_fs_metadata(ctx, &alist);
+       if (ret) {
+               *aborted = true;
+               return;
+       }
 
-       moveon = xfs_scrub_fs_metadata(ctx);
-       if (!moveon)
-               *pmoveon = false;
+       action_list_defer(ctx, agno, &alist);
 }
 
 /* Scan all filesystem metadata. */
-bool
-xfs_scan_metadata(
+int
+phase2_func(
        struct scrub_ctx        *ctx)
 {
+       struct action_list      alist;
        struct workqueue        wq;
        xfs_agnumber_t          agno;
-       bool                    moveon = true;
-       int                     ret;
+       bool                    aborted = false;
+       int                     ret, ret2;
 
-       ret = workqueue_create(&wq, (struct xfs_mount *)ctx,
+       ret = -workqueue_create(&wq, (struct xfs_mount *)ctx,
                        scrub_nproc_workqueue(ctx));
        if (ret) {
-               str_error(ctx, ctx->mntpoint, _("Could not create workqueue."));
-               return false;
+               str_liberror(ctx, ret, _("creating scrub workqueue"));
+               return ret;
        }
 
        /*
@@ -102,46 +140,55 @@ xfs_scan_metadata(
         * upgrades (followed by a full scrub), do that before we launch
         * anything else.
         */
-       moveon = xfs_scrub_primary_super(ctx);
-       if (!moveon)
-               return moveon;
+       action_list_init(&alist);
+       ret = xfs_scrub_primary_super(ctx, &alist);
+       if (ret)
+               goto out;
+       ret = action_list_process_or_defer(ctx, 0, &alist);
+       if (ret)
+               goto out;
 
-       for (agno = 0; moveon && agno < ctx->geo.agcount; agno++) {
-               ret = workqueue_add(&wq, xfs_scan_ag_metadata, agno, &moveon);
+       for (agno = 0; !aborted && agno < ctx->mnt.fsgeom.agcount; agno++) {
+               ret = -workqueue_add(&wq, scan_ag_metadata, agno, &aborted);
                if (ret) {
-                       moveon = false;
-                       str_error(ctx, ctx->mntpoint,
-_("Could not queue AG %u scrub work."), agno);
+                       str_liberror(ctx, ret, _("queueing per-AG scrub work"));
                        goto out;
                }
        }
 
-       if (!moveon)
+       if (aborted)
                goto out;
 
-       ret = workqueue_add(&wq, xfs_scan_fs_metadata, 0, &moveon);
+       ret = -workqueue_add(&wq, scan_fs_metadata, 0, &aborted);
        if (ret) {
-               moveon = false;
-               str_error(ctx, ctx->mntpoint,
-_("Could not queue filesystem scrub work."));
+               str_liberror(ctx, ret, _("queueing per-FS scrub work"));
                goto out;
        }
 
 out:
+       ret2 = -workqueue_terminate(&wq);
+       if (ret2) {
+               str_liberror(ctx, ret2, _("finishing scrub work"));
+               if (!ret && ret2)
+                       ret = ret2;
+       }
        workqueue_destroy(&wq);
-       return moveon;
+
+       if (!ret && aborted)
+               ret = ECANCELED;
+       return ret;
 }
 
 /* Estimate how much work we're going to do. */
-bool
-xfs_estimate_metadata_work(
+int
+phase2_estimate(
        struct scrub_ctx        *ctx,
        uint64_t                *items,
        unsigned int            *nr_threads,
        int                     *rshift)
 {
-       *items = xfs_scrub_estimate_ag_work(ctx);
+       *items = scrub_estimate_ag_work(ctx);
        *nr_threads = scrub_nproc(ctx);
        *rshift = 0;
-       return true;
+       return 0;
 }