]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - scrub/xfs_scrub.c
1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2018 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
11 #include <sys/resource.h>
12 #include <sys/statvfs.h>
13 #include "platform_defs.h"
15 #include "libfrog/paths.h"
16 #include "xfs_scrub.h"
23 * XFS Online Metadata Scrub (and Repair)
25 * The XFS scrubber uses custom XFS ioctls to probe more deeply into the
26 * internals of the filesystem. It takes advantage of scrubbing ioctls
27 * to check all the records stored in a metadata object and to
28 * cross-reference those records against the other filesystem metadata.
30 * After the program gathers command line arguments to figure out
31 * exactly what the program is going to do, scrub execution is split up
32 * into several separate phases:
34 * The "find geometry" phase queries XFS for the filesystem geometry.
35 * The block devices for the data, realtime, and log devices are opened.
36 * Kernel ioctls are test-queried to see if they actually work (the scrub
37 * ioctl in particular), and any other filesystem-specific information
40 * In the "check internal metadata" phase, we call the metadata scrub
41 * ioctl to check the filesystem's internal per-AG btrees. This
42 * includes the AG superblock, AGF, AGFL, and AGI headers, freespace
43 * btrees, the regular and free inode btrees, the reverse mapping
44 * btrees, and the reference counting btrees. If the realtime device is
45 * enabled, the realtime bitmap and reverse mapping btrees are checked.
46 * Quotas, if enabled, are also checked in this phase.
48 * Each AG (and the realtime device) has its metadata checked in a
49 * separate thread for better performance. Errors in the internal
50 * metadata can be fixed here prior to the inode scan; refer to the
51 * section about the "repair filesystem" phase for more information.
53 * The "scan all inodes" phase uses BULKSTAT to scan all the inodes in
54 * an AG in disk order. The BULKSTAT information provides enough
55 * information to construct a file handle that is used to check the
56 * following parts of every file:
59 * - All three block forks (data, attr, CoW)
60 * - If it's a symlink, the symlink target.
61 * - If it's a directory, the directory entries.
62 * - All extended attributes
63 * - The parent pointer
65 * Multiple threads are started to check each the inodes of each AG in
66 * parallel. Errors in file metadata can be fixed here; see the section
67 * about the "repair filesystem" phase for more information.
69 * Next comes the (configurable) "repair filesystem" phase. The user
70 * can instruct this program to fix all problems encountered; to fix
71 * only optimality problems and leave the corruptions; or not to touch
72 * the filesystem at all. Any metadata repairs that did not succeed in
73 * the previous two phases are retried here; if there are uncorrectable
74 * errors, xfs_scrub stops here.
76 * To perform the actual repairs (or optimizations), we iterate all the
77 * items on the per-AG action item list and ask the kernel to repair
78 * them. Items which are successfully repaired are removed from the
79 * list. If an item is not acted upon successfully (or the kernel asks us
80 * to try again), we retry the actions until there is nothing left to
81 * fix or we fail to make forward progress. In that event, the
82 * unfinished items are recorded as errors. If there are no errors at
83 * this point, we call FSTRIM on the filesystem.
85 * The next phase is the "check directory tree" phase. In this phase,
86 * every directory is opened (via file handle) to confirm that each
87 * directory is connected to the root. Directory entries are checked
88 * for ambiguous Unicode normalization mappings, which is to say that we
89 * look for pairs of entries whose utf-8 strings normalize to the same
90 * code point sequence and map to different inodes, because that could
91 * be used to trick a user into opening the wrong file. The names of
92 * extended attributes are checked for Unicode normalization collisions.
94 * In the "verify data file integrity" phase, we employ GETFSMAP to read
95 * the reverse-mappings of all AGs and issue direct-reads of the
96 * underlying disk blocks. We rely on the underlying storage to have
97 * checksummed the data blocks appropriately. Multiple threads are
98 * started to check each AG in parallel; a separate thread pool is used
99 * to handle the direct reads.
101 * In the "check summary counters" phase, use GETFSMAP to tally up the
102 * blocks and BULKSTAT to tally up the inodes we saw and compare that to
103 * the statfs output. This gives the user a rough estimate of how
104 * thorough the scrub was.
108 * Known debug tweaks (pass -d and set the environment variable):
109 * XFS_SCRUB_FORCE_ERROR -- pretend all metadata is corrupt
110 * XFS_SCRUB_FORCE_REPAIR -- repair all metadata even if it's ok
111 * XFS_SCRUB_NO_KERNEL -- pretend there is no kernel ioctl
112 * XFS_SCRUB_NO_SCSI_VERIFY -- disable SCSI VERIFY (if present)
113 * XFS_SCRUB_PHASE -- run only this scrub phase
114 * XFS_SCRUB_THREADS -- start exactly this number of threads
115 * XFS_SCRUB_DISK_ERROR_INTERVAL-- simulate a disk error every this many bytes
116 * XFS_SCRUB_DISK_VERIFY_SKIP -- pretend disk verify read calls succeeded
118 * Available even in non-debug mode:
119 * SERVICE_MODE -- compress all error codes to 1 for LSB
120 * service action compliance
123 /* Program name; needed for libfrog error reports. */
124 char *progname
= "xfs_scrub";
126 /* Debug level; higher values mean more verbosity. */
129 /* Display resource usage at the end of each phase? */
130 static bool display_rusage
;
132 /* Background mode; higher values insert more pauses between scrub calls. */
133 unsigned int bg_mode
;
135 /* Number of threads we're allowed to use. */
136 unsigned int force_nr_threads
;
138 /* Verbosity; higher values print more information. */
141 /* Should we scrub the data blocks? */
142 static bool scrub_data
;
144 /* Size of a memory page. */
147 /* Should we FSTRIM after a successful run? */
148 bool want_fstrim
= true;
150 /* If stdout/stderr are ttys, we can use richer terminal control. */
155 * If we are running as a service, we need to be careful about what
156 * error codes we return to the calling process.
160 #define SCRUB_RET_SUCCESS (0) /* no problems left behind */
161 #define SCRUB_RET_CORRUPT (1) /* corruption remains on fs */
162 #define SCRUB_RET_UNOPTIMIZED (2) /* fs could be optimized */
163 #define SCRUB_RET_OPERROR (4) /* operational problems */
164 #define SCRUB_RET_SYNTAX (8) /* cmdline args rejected */
166 static void __attribute__((noreturn
))
169 fprintf(stderr
, _("Usage: %s [OPTIONS] mountpoint\n"), progname
);
170 fprintf(stderr
, "\n");
171 fprintf(stderr
, _("Options:\n"));
172 fprintf(stderr
, _(" -a count Stop after this many errors are found.\n"));
173 fprintf(stderr
, _(" -b Background mode.\n"));
174 fprintf(stderr
, _(" -C fd Print progress information to this fd.\n"));
175 fprintf(stderr
, _(" -e behavior What to do if errors are found.\n"));
176 fprintf(stderr
, _(" -k Do not FITRIM the free space.\n"));
177 fprintf(stderr
, _(" -m path Path to /etc/mtab.\n"));
178 fprintf(stderr
, _(" -n Dry run. Do not modify anything.\n"));
179 fprintf(stderr
, _(" -T Display timing/usage information.\n"));
180 fprintf(stderr
, _(" -v Verbose output.\n"));
181 fprintf(stderr
, _(" -V Print version.\n"));
182 fprintf(stderr
, _(" -x Scrub file data too.\n"));
184 exit(SCRUB_RET_SYNTAX
);
188 # define RUSAGE_BOTH (-2)
191 /* Get resource usage for ourselves and all children. */
194 struct rusage
*usage
)
196 struct rusage cusage
;
199 err
= getrusage(RUSAGE_BOTH
, usage
);
203 err
= getrusage(RUSAGE_SELF
, usage
);
207 err
= getrusage(RUSAGE_CHILDREN
, &cusage
);
211 usage
->ru_minflt
+= cusage
.ru_minflt
;
212 usage
->ru_majflt
+= cusage
.ru_majflt
;
213 usage
->ru_nswap
+= cusage
.ru_nswap
;
214 usage
->ru_inblock
+= cusage
.ru_inblock
;
215 usage
->ru_oublock
+= cusage
.ru_oublock
;
216 usage
->ru_msgsnd
+= cusage
.ru_msgsnd
;
217 usage
->ru_msgrcv
+= cusage
.ru_msgrcv
;
218 usage
->ru_nsignals
+= cusage
.ru_nsignals
;
219 usage
->ru_nvcsw
+= cusage
.ru_nvcsw
;
220 usage
->ru_nivcsw
+= cusage
.ru_nivcsw
;
225 * Scrub Phase Dispatch
227 * The operations of the scrub program are split up into several
228 * different phases. Each phase builds upon the metadata checked in the
229 * previous phase, which is to say that we may skip phase (X + 1) if our
230 * scans in phase (X) reveal corruption. A phase may be skipped
234 /* Resource usage for each phase. */
235 struct phase_rusage
{
238 unsigned long long verified_bytes
;
243 /* Operations for each phase. */
244 #define DATASCAN_DUMMY_FN ((void *)1)
245 #define REPAIR_DUMMY_FN ((void *)2)
248 int (*fn
)(struct scrub_ctx
*ctx
);
249 int (*estimate_work
)(struct scrub_ctx
*ctx
, uint64_t *items
,
250 unsigned int *threads
, int *rshift
);
254 /* Start tracking resource usage for a phase. */
257 struct phase_rusage
*pi
,
263 memset(pi
, 0, sizeof(*pi
));
264 error
= scrub_getrusage(&pi
->ruse
);
266 perror(_("getrusage"));
269 pi
->brk_start
= sbrk(0);
271 error
= gettimeofday(&pi
->time
, NULL
);
273 perror(_("gettimeofday"));
278 if ((verbose
|| display_rusage
) && descr
) {
279 fprintf(stdout
, _("Phase %u: %s\n"), phase
, descr
);
285 static inline unsigned long long
286 kbytes(unsigned long long x
)
288 return (x
+ 1023) / 1024;
294 const struct phase_rusage
*pi
)
296 #if defined(HAVE_MALLINFO2) || defined(HAVE_MALLINFO)
297 # ifdef HAVE_MALLINFO2
298 struct mallinfo2 mall_now
= mallinfo2();
300 struct mallinfo mall_now
= mallinfo();
302 fprintf(stdout
, _("%sMemory used: %lluk/%lluk (%lluk/%lluk), "),
304 kbytes(mall_now
.arena
), kbytes(mall_now
.hblkhd
),
305 kbytes(mall_now
.uordblks
), kbytes(mall_now
.fordblks
));
307 fprintf(stdout
, _("%sMemory used: %lluk, "),
309 kbytes(((char *) sbrk(0)) - ((char *) pi
->brk_start
)));
313 /* Report usage stats. */
316 struct phase_rusage
*pi
,
319 struct rusage ruse_now
;
320 struct timeval time_now
;
321 char phasebuf
[DESCR_BUFSZ
];
323 unsigned long long in
, out
;
324 unsigned long long io
;
326 double din
, dout
, dtot
;
327 char *iu
, *ou
, *tu
, *dinu
, *doutu
, *dtotu
;
333 error
= gettimeofday(&time_now
, NULL
);
335 perror(_("gettimeofday"));
338 dt
= timeval_subtract(&time_now
, &pi
->time
);
340 error
= scrub_getrusage(&ruse_now
);
342 perror(_("getrusage"));
347 snprintf(phasebuf
, DESCR_BUFSZ
, _("Phase %u: "), phase
);
351 report_mem_usage(phasebuf
, pi
);
353 fprintf(stdout
, _("time: %5.2f/%5.2f/%5.2fs\n"),
354 timeval_subtract(&time_now
, &pi
->time
),
355 timeval_subtract(&ruse_now
.ru_utime
, &pi
->ruse
.ru_utime
),
356 timeval_subtract(&ruse_now
.ru_stime
, &pi
->ruse
.ru_stime
));
359 in
= ((unsigned long long)ruse_now
.ru_inblock
-
360 pi
->ruse
.ru_inblock
) << BBSHIFT
;
361 out
= ((unsigned long long)ruse_now
.ru_oublock
-
362 pi
->ruse
.ru_oublock
) << BBSHIFT
;
365 i
= auto_space_units(in
, &iu
);
366 o
= auto_space_units(out
, &ou
);
367 t
= auto_space_units(io
, &tu
);
368 din
= auto_space_units(in
/ dt
, &dinu
);
369 dout
= auto_space_units(out
/ dt
, &doutu
);
370 dtot
= auto_space_units(io
/ dt
, &dtotu
);
372 _("%sI/O: %.1f%s in, %.1f%s out, %.1f%s tot\n"),
373 phasebuf
, i
, iu
, o
, ou
, t
, tu
);
375 _("%sI/O rate: %.1f%s/s in, %.1f%s/s out, %.1f%s/s tot\n"),
376 phasebuf
, din
, dinu
, dout
, doutu
, dtot
, dtotu
);
383 /* Run all the phases of the scrubber. */
386 struct scrub_ctx
*ctx
,
389 struct phase_ops phases
[] =
392 .descr
= _("Find filesystem geometry."),
397 .descr
= _("Check internal metadata."),
399 .estimate_work
= phase2_estimate
,
402 .descr
= _("Scan all inodes."),
404 .estimate_work
= phase3_estimate
,
407 .descr
= _("Defer filesystem repairs."),
408 .fn
= REPAIR_DUMMY_FN
,
409 .estimate_work
= phase4_estimate
,
412 .descr
= _("Check directory tree."),
414 .estimate_work
= phase5_estimate
,
417 .descr
= _("Verify data file integrity."),
418 .fn
= DATASCAN_DUMMY_FN
,
419 .estimate_work
= phase6_estimate
,
422 .descr
= _("Check summary counters."),
430 struct phase_rusage pi
;
431 struct phase_ops
*sp
;
433 unsigned int debug_phase
= 0;
438 if (debug_tweak_on("XFS_SCRUB_PHASE"))
439 debug_phase
= atoi(getenv("XFS_SCRUB_PHASE"));
441 /* Run all phases of the scrub tool. */
442 for (phase
= 1, sp
= phases
; sp
->fn
; sp
++, phase
++) {
443 /* Turn on certain phases if user said to. */
444 if (sp
->fn
== DATASCAN_DUMMY_FN
&& scrub_data
) {
445 sp
->fn
= phase6_func
;
446 } else if (sp
->fn
== REPAIR_DUMMY_FN
&&
447 ctx
->mode
== SCRUB_MODE_REPAIR
) {
448 sp
->descr
= _("Repair filesystem.");
449 sp
->fn
= phase4_func
;
453 /* Skip certain phases unless they're turned on. */
454 if (sp
->fn
== REPAIR_DUMMY_FN
||
455 sp
->fn
== DATASCAN_DUMMY_FN
)
458 /* Allow debug users to force a particular phase. */
459 if (debug_phase
&& phase
!= debug_phase
&& !sp
->must_run
)
462 /* Run this phase. */
463 ret
= phase_start(&pi
, phase
, sp
->descr
);
466 if (sp
->estimate_work
) {
467 unsigned int work_threads
;
469 ret
= sp
->estimate_work(ctx
, &max_work
,
470 &work_threads
, &rshift
);
475 * The thread that starts the worker threads is also
476 * allowed to contribute to the progress counters and
477 * whatever other per-thread data we need to allocate.
480 ret
= progress_init_phase(ctx
, progress_fp
, phase
,
481 max_work
, rshift
, work_threads
);
484 ret
= descr_init_phase(ctx
, work_threads
);
486 ret
= progress_init_phase(ctx
, NULL
, phase
, 0, 0, 0);
489 ret
= descr_init_phase(ctx
, 1);
495 str_info(ctx
, ctx
->mntpoint
,
496 _("Scrub aborted after phase %d."),
500 progress_end_phase();
502 ret
= phase_end(&pi
, phase
);
506 /* Too many errors? */
507 if (scrub_excessive_errors(ctx
)) {
517 report_modifications(
518 struct scrub_ctx
*ctx
)
520 if (ctx
->repairs
== 0 && ctx
->preens
== 0)
523 if (ctx
->repairs
&& ctx
->preens
)
525 _("%s: repairs made: %llu; optimizations made: %llu.\n"),
526 ctx
->mntpoint
, ctx
->repairs
, ctx
->preens
);
527 else if (ctx
->preens
== 0)
529 _("%s: repairs made: %llu.\n"),
530 ctx
->mntpoint
, ctx
->repairs
);
531 else if (ctx
->repairs
== 0)
533 _("%s: optimizations made: %llu.\n"),
534 ctx
->mntpoint
, ctx
->preens
);
539 struct scrub_ctx
*ctx
)
541 unsigned long long actionable_errors
;
543 actionable_errors
= ctx
->corruptions_found
+ ctx
->runtime_errors
;
545 if (actionable_errors
== 0 &&
546 ctx
->unfixable_errors
== 0 &&
547 ctx
->warnings_found
== 0) {
548 log_info(ctx
, _("No problems found."));
552 if (ctx
->unfixable_errors
) {
553 fprintf(stderr
, _("%s: unfixable errors found: %llu\n"),
554 ctx
->mntpoint
, ctx
->unfixable_errors
);
555 log_err(ctx
, _("unfixable errors found: %llu"),
556 ctx
->unfixable_errors
);
559 if (ctx
->corruptions_found
> 0) {
560 fprintf(stderr
, _("%s: corruptions found: %llu\n"),
561 ctx
->mntpoint
, ctx
->corruptions_found
);
562 log_err(ctx
, _("corruptions found: %llu"),
563 ctx
->corruptions_found
);
566 if (ctx
->runtime_errors
> 0) {
567 fprintf(stderr
, _("%s: operational errors found: %llu\n"),
568 ctx
->mntpoint
, ctx
->runtime_errors
);
569 log_err(ctx
, _("operational errors found: %llu"),
570 ctx
->runtime_errors
);
573 if (ctx
->warnings_found
> 0) {
574 fprintf(stderr
, _("%s: warnings found: %llu\n"), ctx
->mntpoint
,
575 ctx
->warnings_found
);
576 log_warn(ctx
, _("warnings found: %llu"), ctx
->warnings_found
);
580 * Don't advise the user to run repair unless we were successful in
581 * setting up the scrub and we actually saw corruptions. Warnings
582 * are not corruptions.
584 if (ctx
->scrub_setup_succeeded
&& actionable_errors
> 0) {
587 if (ctx
->mode
== SCRUB_MODE_DRY_RUN
)
588 msg
= _("%s: Re-run xfs_scrub without -n.\n");
590 msg
= _("%s: Unmount and run xfs_repair.\n");
592 fprintf(stderr
, msg
, ctx
->mntpoint
);
596 /* Compile-time features discoverable via version strings */
598 # define XFS_SCRUB_HAVE_UNICODE "+"
600 # define XFS_SCRUB_HAVE_UNICODE "-"
608 struct scrub_ctx ctx
= {0};
609 struct phase_rusage all_pi
;
611 FILE *progress_fp
= NULL
;
616 int ret
= SCRUB_RET_SUCCESS
;
619 fprintf(stdout
, "EXPERIMENTAL xfs_scrub program in use! Use at your own risk!\n");
621 progname
= basename(argv
[0]);
622 setlocale(LC_ALL
, "");
623 bindtextdomain(PACKAGE
, LOCALEDIR
);
625 if (unicrash_load()) {
627 _("%s: couldn't initialize Unicode library.\n"),
632 pthread_mutex_init(&ctx
.lock
, NULL
);
633 ctx
.mode
= SCRUB_MODE_REPAIR
;
634 ctx
.error_action
= ERRORS_CONTINUE
;
635 while ((c
= getopt(argc
, argv
, "a:bC:de:km:nTvxV")) != EOF
) {
638 ctx
.max_errors
= cvt_u64(optarg
, 10);
645 force_nr_threads
= 1;
650 fd
= cvt_u32(optarg
, 10);
655 progress_fp
= fdopen(fd
, "w");
665 if (!strcmp("continue", optarg
))
666 ctx
.error_action
= ERRORS_CONTINUE
;
667 else if (!strcmp("shutdown", optarg
))
668 ctx
.error_action
= ERRORS_SHUTDOWN
;
671 _("Unknown error behavior \"%s\".\n"),
683 ctx
.mode
= SCRUB_MODE_DRY_RUN
;
686 display_rusage
= true;
704 fprintf(stdout
, _("%s version %s\n"),
707 fprintf(stdout
, _("%s version %s %sUnicode\n"),
709 XFS_SCRUB_HAVE_UNICODE
);
711 return SCRUB_RET_SUCCESS
;
714 /* Override thread count if debugger */
715 if (debug_tweak_on("XFS_SCRUB_THREADS")) {
718 x
= cvt_u32(getenv("XFS_SCRUB_THREADS"), 10);
720 perror("nr_threads");
723 force_nr_threads
= x
;
726 if (optind
!= argc
- 1)
729 ctx
.mntpoint
= argv
[optind
];
731 stdout_isatty
= isatty(STDOUT_FILENO
);
732 stderr_isatty
= isatty(STDERR_FILENO
);
734 /* If interactive, start the progress bar. */
735 if (stdout_isatty
&& !progress_fp
)
736 progress_fp
= fdopen(1, "w+");
738 if (getenv("SERVICE_MODE"))
741 /* Initialize overall phase stats. */
742 error
= phase_start(&all_pi
, 0, NULL
);
744 return SCRUB_RET_OPERROR
;
746 /* Find the mount record for the passed-in argument. */
747 if (stat(argv
[optind
], &ctx
.mnt_sb
) < 0) {
749 _("%s: could not stat: %s: %s\n"),
750 progname
, argv
[optind
], strerror(errno
));
751 ctx
.runtime_errors
++;
756 * If the user did not specify an explicit mount table, try to use
757 * /proc/mounts if it is available, else /etc/mtab. We prefer
758 * /proc/mounts because it is kernel controlled, while /etc/mtab
759 * may contain garbage that userspace tools like pam_mounts wrote
763 if (access(_PATH_PROC_MOUNTS
, R_OK
) == 0)
764 mtab
= _PATH_PROC_MOUNTS
;
766 mtab
= _PATH_MOUNTED
;
769 fs_table_initialise(0, NULL
, 0, NULL
);
770 fsp
= fs_table_lookup_mount(ctx
.mntpoint
);
772 fprintf(stderr
, _("%s: Not a XFS mount point.\n"),
774 ret
|= SCRUB_RET_SYNTAX
;
777 memcpy(&ctx
.fsinfo
, fsp
, sizeof(struct fs_path
));
779 /* Set up a page-aligned buffer for read verification. */
780 page_size
= sysconf(_SC_PAGESIZE
);
782 str_errno(&ctx
, ctx
.mntpoint
);
786 if (debug_tweak_on("XFS_SCRUB_FORCE_REPAIR"))
787 ctx
.mode
= SCRUB_MODE_REPAIR
;
789 /* Scrub a filesystem. */
790 error
= run_scrub_phases(&ctx
, progress_fp
);
791 if (error
&& ctx
.runtime_errors
== 0)
792 ctx
.runtime_errors
++;
795 * Excessive errors will cause the scrub phases to bail out early.
796 * We don't want every thread yelling that into the output, so check
797 * if we hit the threshold and tell the user *once*.
799 if (scrub_excessive_errors(&ctx
))
800 str_info(&ctx
, ctx
.mntpoint
, _("Too many errors; aborting."));
802 if (debug_tweak_on("XFS_SCRUB_FORCE_ERROR"))
803 str_info(&ctx
, ctx
.mntpoint
, _("Injecting error."));
805 /* Clean up scan data. */
806 error
= scrub_cleanup(&ctx
);
807 if (error
&& ctx
.runtime_errors
== 0)
808 ctx
.runtime_errors
++;
811 report_modifications(&ctx
);
812 report_outcome(&ctx
);
814 if (ctx
.corruptions_found
) {
815 if (ctx
.error_action
== ERRORS_SHUTDOWN
)
816 xfs_shutdown_fs(&ctx
);
817 ret
|= SCRUB_RET_CORRUPT
;
819 if (ctx
.warnings_found
)
820 ret
|= SCRUB_RET_UNOPTIMIZED
;
821 if (ctx
.runtime_errors
)
822 ret
|= SCRUB_RET_OPERROR
;
823 phase_end(&all_pi
, 0);
829 * If we're being run as a service, the return code must fit the LSB
830 * init script action error guidelines, which is to say that we
831 * compress all errors to 1 ("generic or unspecified error", LSB 5.0
832 * section 22.2) and hope the admin will scan the log for what
835 * We have to sleep 2 seconds here because journald uses the pid to
836 * connect our log messages to the systemd service. This is critical
837 * for capturing all the log messages if the scrub fails, because the
838 * fail service uses the service name to gather log messages for the
841 * Note: We don't count a lack of kernel support as a service failure
842 * because we haven't determined that there's anything wrong with the
847 if (!ctx
.scrub_setup_succeeded
)
849 if (ret
!= SCRUB_RET_SUCCESS
)