]> git-server-git.apps.pok.os.sepia.ceph.com Git - xfsprogs-dev.git/commitdiff
xfs_healer: use the autofsck fsproperty to select mode
authorDarrick J. Wong <djwong@kernel.org>
Sun, 22 Feb 2026 22:41:15 +0000 (14:41 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Thu, 9 Apr 2026 22:30:17 +0000 (15:30 -0700)
Make the xfs_healer background service query the autofsck filesystem
property to figure out which operating mode it should use.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
healer/xfs_healer.c
healer/xfs_healer.h
libfrog/fsproperties.h

index cf26f9c04ef225bf3046a40d65ab95989545d922..95e952ed5cb94023715ca1582f6c19d0dc1b3e91 100644 (file)
@@ -6,6 +6,7 @@
 #include "xfs.h"
 #include <pthread.h>
 #include <stdlib.h>
+#include <sys/xattr.h>
 
 #include "platform_defs.h"
 #include "libfrog/fsgeom.h"
@@ -13,6 +14,7 @@
 #include "libfrog/healthevent.h"
 #include "libfrog/workqueue.h"
 #include "libfrog/systemd.h"
+#include "libfrog/fsproperties.h"
 #include "xfs_healer.h"
 
 /* Program name; needed for libfrog error reports. */
@@ -195,6 +197,63 @@ healer_nproc(
        return ctx->foreground ? platform_nproc() : 1;
 }
 
+enum want_repair {
+       WR_REPAIR,
+       WR_LOG_ONLY,
+       WR_EXIT,
+};
+
+/* Determine want_repair from the autofsck filesystem property. */
+static enum want_repair
+want_repair_from_autofsck(
+       struct healer_ctx       *ctx)
+{
+       char                    valuebuf[FSPROP_MAX_VALUELEN + 1] = { 0 };
+       enum fsprop_autofsck    shval;
+       ssize_t                 ret;
+
+       /*
+        * Any OS error (including ENODATA) or string parsing error is treated
+        * the same as an unrecognized value.
+        */
+       ret = fgetxattr(ctx->mnt.fd, VFS_FSPROP_AUTOFSCK_NAME, valuebuf,
+                       FSPROP_MAX_VALUELEN);
+       if (ret < 0)
+               goto no_advice;
+
+       shval = fsprop_autofsck_read(valuebuf);
+       switch (shval) {
+       case FSPROP_AUTOFSCK_NONE:
+               /* don't run at all */
+               ret = WR_EXIT;
+               break;
+       case FSPROP_AUTOFSCK_CHECK:
+       case FSPROP_AUTOFSCK_OPTIMIZE:
+               /* log events, do not repair */
+               ret = WR_LOG_ONLY;
+               break;
+       case FSPROP_AUTOFSCK_REPAIR:
+               /* repair stuff */
+               ret = WR_REPAIR;
+               break;
+       case FSPROP_AUTOFSCK_UNSET:
+               goto no_advice;
+       }
+
+       return ret;
+
+no_advice:
+       /*
+        * For an unrecognized value, log but do not fix runtime corruption if
+        * backref metadata are enabled.  If no backref metadata are available,
+        * the fs is too old so don't run at all.
+        */
+       if (healer_has_rmapbt(ctx) || healer_has_parent(ctx))
+               return WR_LOG_ONLY;
+
+       return WR_EXIT;
+}
+
 enum mon_state {
        MON_START,
        MON_EXIT,
@@ -225,14 +284,46 @@ setup_monitor(
                goto out_mnt_fd;
        }
 
-       if (ctx->want_repair) {
-               /* Check that the kernel supports repairs at all. */
-               if (!healer_can_repair(ctx)) {
+       if (ctx->autofsck) {
+               switch (want_repair_from_autofsck(ctx)) {
+               case WR_EXIT:
+                       printf("%s: %s\n", ctx->mntpoint,
+ _("Disabling daemon per autofsck directive."));
+                       fflush(stdout);
+                       close(ctx->mnt.fd);
+                       return MON_UNSUPPORTED;
+               case WR_REPAIR:
+                       ctx->want_repair = 1;
+                       printf("%s: %s\n", ctx->mntpoint,
+ _("Automatically repairing per autofsck directive."));
+                       fflush(stdout);
+                       break;
+               case WR_LOG_ONLY:
+                       ctx->want_repair = 0;
+                       if (ctx->log != 0) {
+                               printf("%s: %s\n", ctx->mntpoint,
+ _("Only logging errors per autofsck directive."));
+                               fflush(stdout);
+                       }
+                       break;
+               }
+       }
+
+       /* Check that the kernel supports repairs at all. */
+       if (ctx->want_repair && !healer_can_repair(ctx)) {
+               if (!ctx->autofsck) {
                        fprintf(stderr, "%s: %s\n", ctx->mntpoint,
  _("XFS online repair is not supported, exiting"));
                        goto out_mnt_fd;
                }
 
+               printf("%s: %s\n", ctx->mntpoint,
+ _("XFS online repair is not supported, will report only"));
+               fflush(stdout);
+               ctx->want_repair = 0;
+       }
+
+       if (ctx->want_repair) {
                /* Check for backref metadata that makes repair effective. */
                if (!healer_has_rmapbt(ctx))
                        fprintf(stderr, "%s: %s\n", ctx->mntpoint,
@@ -429,6 +520,7 @@ usage(void)
        fprintf(stderr, _("  --debug       Enable debugging messages.\n"));
        fprintf(stderr, _("  --everything  Capture all events.\n"));
        fprintf(stderr, _("  --foreground  Process events as soon as possible.\n"));
+       fprintf(stderr, _("  --no-autofsck Do not use the \"autofsck\" fs property to decide to repair.\n"));
        fprintf(stderr, _("  --quiet       Do not log health events to stdout.\n"));
        fprintf(stderr, _("  --repair      Repair corrupt metadata found at runtime.\n"));
        fprintf(stderr, _("  --supported   Check that health monitoring is supported.\n"));
@@ -442,6 +534,7 @@ enum long_opt_nr {
        LOPT_EVERYTHING,
        LOPT_FOREGROUND,
        LOPT_HELP,
+       LOPT_NO_AUTOFSCK,
        LOPT_QUIET,
        LOPT_REPAIR,
        LOPT_SUPPORTED,
@@ -459,6 +552,7 @@ main(
                .conlock        = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER,
                .log            = 1,
                .mnt.fd         = -1,
+               .autofsck       = 1,
        };
        int                     option_index;
        int                     vflag = 0;
@@ -475,6 +569,7 @@ main(
                [LOPT_EVERYTHING]  = {"everything", no_argument, &ctx.everything, 1 },
                [LOPT_FOREGROUND]  = {"foreground", no_argument, &ctx.foreground, 1 },
                [LOPT_HELP]        = {"help", no_argument, NULL, 0 },
+               [LOPT_NO_AUTOFSCK] = {"no-autofsck", no_argument, &ctx.autofsck, 0 },
                [LOPT_QUIET]       = {"quiet", no_argument, &ctx.log, 0 },
                [LOPT_REPAIR]      = {"repair", no_argument, &ctx.want_repair, 1 },
                [LOPT_SUPPORTED]   = {"supported", no_argument, &ctx.support_check, 1 },
@@ -512,6 +607,8 @@ main(
 
        if (optind != argc - 1)
                usage();
+       if (ctx.want_repair)
+               ctx.autofsck = 0;
 
        ctx.mntpoint = argv[optind];
 
index 7caa6c66a59c6fb39a9757768d0e019836cd8a46..a2a46053928e337b5d2f518bf922ae1b4de82b69 100644 (file)
@@ -28,6 +28,7 @@ struct healer_ctx {
        int                     want_repair;
        int                     print_svcname;
        int                     support_check;
+       int                     autofsck;
 
        /* fd and fs geometry for mount */
        struct xfs_fd           mnt;
index 11d6530bc9a6d67587fee87f5f85ddc8a959f49e..1cf90d058765b29830ed3e36d7878d0975170bb0 100644 (file)
@@ -52,6 +52,11 @@ bool fsprop_validate(const char *name, const char *value);
 
 #define FSPROP_AUTOFSCK_NAME           "autofsck"
 
+/* filesystem property name for fgetxattr */
+#define VFS_FSPROP_AUTOFSCK_NAME       (FSPROP_NAMESPACE \
+                                        FSPROP_NAME_PREFIX \
+                                        FSPROP_AUTOFSCK_NAME)
+
 enum fsprop_autofsck {
        FSPROP_AUTOFSCK_UNSET = 0,      /* do not set property */
        FSPROP_AUTOFSCK_NONE,           /* no background scrubs */