Skip to contentSkip to conversation

xfsprogs: online scrub/repair support

PATCH In review Darrick J. Wong 3 participants 41 messages Jan 31, 2018 – Feb 1, 2018 Kbuild

lore
Share & tools
lore
#0 lore raw

cover xfsprogs: online scrub/repair support

Hi all,

This is the eleventh revision (+ more fixes suggested by Eric Sandeen) of a patchset that adds to XFS userland tools support for online metadata scrubbing and repair. Since v10 I've rebased to the latest for-next, fixed some wonky error messages, and fixed a few minor problems I found via code inspection. This patch series is more or less the same as a couple of weeks ago.

We start by creating the basic shell of the program that can do argument parsing and error reporting, create some abstractions for the XFS ioctls that we use to iterate and scrub metadata, and then tie together all the in-kernel scrubbing in separate scrub phases.

Next, we move on to checking the directory tree for connectivity and naming problems and add the infrastructure to perform an (optional) scan of the in-use parts of the disk media. We also implement a minimal preen -- if the fs checks out, we can try to run fstrim; and some basic progress reporting if the program is running interactively.

Finally, we add some wrapper scripts to schedule scrubs of all the mounted filesystems; and the necessary systemd / cron infrastructure that is needed to automatically scan everything once a week. All of this is disabled by default. The systemd integration allows us to give scrub exactly the privileges it needs while walling off the rest of the system.

If you're going to start using this mess, you probably ought to just pull from my git tree for xfsprogs[1]. This series relies on the libfrog patches sent earlier. Kernel support appeared in 4.15 and will become substantially more robust in 4.16.

Comments and questions are, as always, welcome.

--D

[1] https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=djwong-devel

#1 lore raw

PATCH 1/29 xfs_scrub: create online filesystem scrub program

From: Darrick J. Wong <[email protected]>

Create the foundations of a filesystem scrubbing tool that asks the kernel to inspect all metadata in the filesystem and (ultimately) to repair anything that's broken. Also create the man page for the utility.

---
 .gitignore                   |    1 
 Makefile                     |    3 +
 man/man8/xfs_scrub.8         |  135 ++++++++++++++++++++++++++++++++++++++++++
 scrub/Makefile               |   42 +++++++++++++
 scrub/common.c               |   20 ++++++
 scrub/common.h               |   23 +++++++
 scrub/xfs_scrub.c            |  109 ++++++++++++++++++++++++++++++++++
 scrub/xfs_scrub.h            |   23 +++++++
 tools/find-api-violations.sh |    2 -
 9 files changed, 356 insertions(+), 2 deletions(-)
 create mode 100644 man/man8/xfs_scrub.8
 create mode 100644 scrub/Makefile
 create mode 100644 scrub/common.c
 create mode 100644 scrub/common.h
 create mode 100644 scrub/xfs_scrub.c
 create mode 100644 scrub/xfs_scrub.h
.gitignore +1 -0
index e839e2a..a3db640 100644
@@ -68,6 +68,7 @@ cscope.*
 /repair/xfs_repair
 /rtcp/xfs_rtcp
 /spaceman/xfs_spaceman
+/scrub/xfs_scrub
 
 # generated crc files
 /libxfs/crc32selftest
Makefile +2 -1
index 0dce80a..3bd0796 100644
@@ -48,7 +48,7 @@ LIBFROG_SUBDIR = libfrog
 DLIB_SUBDIRS = libxlog libxcmd libhandle
 LIB_SUBDIRS = libxfs $(DLIB_SUBDIRS)
 TOOL_SUBDIRS = copy db estimate fsck growfs io logprint mkfs quota \
-		mdrestore repair rtcp m4 man doc debian spaceman
+		mdrestore repair rtcp m4 man doc debian spaceman scrub
 
 ifneq ("$(PKG_PLATFORM)","darwin")
 TOOL_SUBDIRS += fsr
@@ -91,6 +91,7 @@ repair: libxlog libxcmd
 copy: libxlog
 mkfs: libxcmd
 spaceman: libxcmd
+scrub: libhandle libxcmd
 
 ifeq ($(HAVE_BUILDDEFS), yes)
 include $(BUILDRULES)
man/man8/xfs_scrub.8 new file +135 -0

135 lines not on this page · raw message

scrub/Makefile new file +42 -0

42 lines not on this page · raw message

scrub/common.c new file +20 -0
new file mode 100644
index 0000000..0a58c16
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2018 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <[email protected]>
+ *
+ * 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 "common.h"
scrub/common.h new file +23 -0
new file mode 100644
index 0000000..1082296
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2018 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <[email protected]>
+ *
+ * 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.
+ */
+#ifndef XFS_SCRUB_COMMON_H_
+#define XFS_SCRUB_COMMON_H_
+
+#endif /* XFS_SCRUB_COMMON_H_ */
scrub/xfs_scrub.c new file +109 -0

109 lines not on this page · raw message

scrub/xfs_scrub.h new file +23 -0
new file mode 100644
index 0000000..ff9c24d
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2018 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <[email protected]>
+ *
+ * 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.
+ */
+#ifndef XFS_SCRUB_XFS_SCRUB_H_
+#define XFS_SCRUB_XFS_SCRUB_H_
+
+#endif /* XFS_SCRUB_XFS_SCRUB_H_ */
tools/find-api-violations.sh +1 -1
index 3b976d3..cb075ba 100755
@@ -6,7 +6,7 @@
 
 # NOTE: This script doesn't look for API violations in function parameters.
 
-tool_dirs="copy db estimate fsck fsr growfs io logprint mdrestore mkfs quota repair rtcp"
+tool_dirs="copy db estimate fsck fsr growfs io logprint mdrestore mkfs quota repair rtcp scrub"
 
 # Calls to xfs_* functions in libxfs/*.c without the libxfs_ prefix
 find_possible_api_calls() {
#2 lore raw

PATCH 2/29 xfs_scrub: common error handling

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Standardize how we record and report errors.

---
 scrub/common.c    |   87 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/common.h    |   30 ++++++++++++++++++
 scrub/xfs_scrub.c |    5 +++
 scrub/xfs_scrub.h |   11 +++++++
 4 files changed, 133 insertions(+)
scrub/common.c +87 -0
index 0a58c16..8137881 100644
@@ -17,4 +17,91 @@
  * 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 <pthread.h>
+#include <stdbool.h>
+#include "platform_defs.h"
+#include "xfs.h"
+#include "xfs_scrub.h"
 #include "common.h"
+
+/*
+ * Reporting Status to the Console
+ *
+ * We aim for a roughly standard reporting format -- the severity of the
+ * status being reported, a textual description of the object being
+ * reported, and whatever the status happens to be.
+ *
+ * Errors are the most severe and reflect filesystem corruption.
+ * Warnings indicate that something is amiss and needs the attention of
+ * the administrator, but does not constitute a corruption.  Information
+ * is merely advisory.
+ */
+
+/* Too many errors? Bail out. */
+bool
+xfs_scrub_excessive_errors(
+	struct scrub_ctx	*ctx)
+{
+	bool			ret;
+
+	pthread_mutex_lock(&ctx->lock);
+	ret = ctx->max_errors > 0 && ctx->errors_found >= ctx->max_errors;
+	pthread_mutex_unlock(&ctx->lock);
+
+	return ret;
+}
+
+static const char *err_str[] = {
+	[S_ERROR]	= "Error",
+	[S_WARN]	= "Warning",
+	[S_INFO]	= "Info",
+};
+
+/* Print a warning string and some warning text. */
+void
+__str_out(
+	struct scrub_ctx	*ctx,
+	const char		*descr,
+	enum error_level	level,
+	int			error,
+	const char		*file,
+	int			line,
+	const char		*format,
+	...)
+{
+	FILE			*stream = stderr;
+	va_list			args;
+	char			buf[DESCR_BUFSZ];
+
+	/* print strerror or format of choice but not both */
+	assert(!(error && format));
+
+	if (level >= S_INFO)
+		stream = stdout;
+
+	pthread_mutex_lock(&ctx->lock);
+	fprintf(stream, "%s: %s: ", _(err_str[level]), descr);
+	if (error) {
+		fprintf(stream, _("%s."), strerror_r(error, buf, DESCR_BUFSZ));
+	} else {
+		va_start(args, format);
+		vfprintf(stream, format, args);
+		va_end(args);
+	}
+
+	if (debug)
+		fprintf(stream, _(" (%s line %d)"), file, line);
+	fprintf(stream, "\n");
+	if (stream == stdout)
+		fflush(stream);
+
+	if (error)      /* A syscall failed */
+		ctx->runtime_errors++;
+	else if (level == S_ERROR)
+		ctx->errors_found++;
+	else if (level == S_WARN)
+		ctx->warnings_found++;
+
+	pthread_mutex_unlock(&ctx->lock);
+}
scrub/common.h +30 -0
index 1082296..b383767 100644
@@ -20,4 +20,34 @@
 #ifndef XFS_SCRUB_COMMON_H_
 #define XFS_SCRUB_COMMON_H_
 
+/*
+ * When reporting a defective metadata object to the console, this
+ * is the size of the buffer to use to store the description of that
+ * item.
+ */
+#define DESCR_BUFSZ	256
+
+bool xfs_scrub_excessive_errors(struct scrub_ctx *ctx);
+
+enum error_level {
+	S_ERROR	= 0,
+	S_WARN,
+	S_INFO,
+};
+
+void __str_out(struct scrub_ctx *ctx, const char *descr, enum error_level level,
+	       int error, const char *file, int line, const char *format, ...);
+
+#define str_errno(ctx, str) \
+	__str_out(ctx, str, S_ERROR,	errno,	__FILE__, __LINE__, NULL)
+#define str_error(ctx, str, ...) \
+	__str_out(ctx, str, S_ERROR,	0,	__FILE__, __LINE__, __VA_ARGS__)
+#define str_warn(ctx, str, ...) \
+	__str_out(ctx, str, S_WARN,	0,	__FILE__, __LINE__, __VA_ARGS__)
+#define str_info(ctx, str, ...) \
+	__str_out(ctx, str, S_INFO,	0,	__FILE__, __LINE__, __VA_ARGS__)
+
+#define dbg_printf(fmt, ...) \
+	do {if (debug > 1) {printf(fmt, __VA_ARGS__);}} while (0)
+
 #endif /* XFS_SCRUB_COMMON_H_ */
scrub/xfs_scrub.c +5 -0
index a4b9c71..6ed7bf6 100644
@@ -18,6 +18,8 @@
  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 #include <stdio.h>
+#include <pthread.h>
+#include <stdbool.h>
 #include "xfs_scrub.h"
 
 /*
@@ -99,6 +101,9 @@
 /* Program name; needed for libfrog error reports. */
 char				*progname = "xfs_scrub";
 
+/* Debug level; higher values mean more verbosity. */
+unsigned int			debug;
+
 int
 main(
 	int			argc,
scrub/xfs_scrub.h +11 -0
index ff9c24d..811bc2d 100644
@@ -20,4 +20,15 @@
 #ifndef XFS_SCRUB_XFS_SCRUB_H_
 #define XFS_SCRUB_XFS_SCRUB_H_
 
+extern unsigned int		debug;
+
+struct scrub_ctx {
+	/* Mutable scrub state; use lock. */
+	pthread_mutex_t		lock;
+	unsigned long long	max_errors;
+	unsigned long long	runtime_errors;
+	unsigned long long	errors_found;
+	unsigned long long	warnings_found;
+};
+
 #endif /* XFS_SCRUB_XFS_SCRUB_H_ */
#3 lore raw

PATCH 3/29 xfs_scrub: set up command line argument parsing

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Parse command line options in order to set up the context in which we will scrub the filesystem.

---
 scrub/common.h    |    8 ++
 scrub/xfs_scrub.c |  227 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/xfs_scrub.h |   32 +++++++
 3 files changed, 266 insertions(+), 1 deletion(-)
scrub/common.h +8 -0
index b383767..7a7e362 100644
@@ -50,4 +50,12 @@ void __str_out(struct scrub_ctx *ctx, const char *descr, enum error_level level,
 #define dbg_printf(fmt, ...) \
 	do {if (debug > 1) {printf(fmt, __VA_ARGS__);}} while (0)
 
+/* Is this debug tweak enabled? */
+static inline bool
+debug_tweak_on(
+	const char		*name)
+{
+	return debug && getenv(name) != NULL;
+}
+
 #endif /* XFS_SCRUB_COMMON_H_ */
scrub/xfs_scrub.c +226 -1

250 lines not on this page · raw message

scrub/xfs_scrub.h +32 -0
index 811bc2d..51b8b7a 100644
@@ -20,15 +20,47 @@
 #ifndef XFS_SCRUB_XFS_SCRUB_H_
 #define XFS_SCRUB_XFS_SCRUB_H_
 
+#define _PATH_PROC_MOUNTS	"/proc/mounts"
+
+extern unsigned int		nr_threads;
+extern unsigned int		bg_mode;
 extern unsigned int		debug;
+extern int			nproc;
+extern bool			verbose;
+extern long			page_size;
+
+enum scrub_mode {
+	SCRUB_MODE_DRY_RUN,
+	SCRUB_MODE_PREEN,
+	SCRUB_MODE_REPAIR,
+};
+#define SCRUB_MODE_DEFAULT			SCRUB_MODE_PREEN
+
+enum error_action {
+	ERRORS_CONTINUE,
+	ERRORS_SHUTDOWN,
+};
 
 struct scrub_ctx {
+	/* Immutable scrub state. */
+
+	/* Strings we need for presentation */
+	char			*mntpoint;
+	char			*blkdev;
+
+	/* What does the user want us to do? */
+	enum scrub_mode		mode;
+
+	/* How does the user want us to react to errors? */
+	enum error_action	error_action;
+
 	/* Mutable scrub state; use lock. */
 	pthread_mutex_t		lock;
 	unsigned long long	max_errors;
 	unsigned long long	runtime_errors;
 	unsigned long long	errors_found;
 	unsigned long long	warnings_found;
+	bool			need_repair;
 };
 
 #endif /* XFS_SCRUB_XFS_SCRUB_H_ */
#4 lore raw

PATCH 4/29 xfs_scrub: dispatch the various phases of the scrub program

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Create the dispatching routines that we'll use to call out to each separate phase of the program.

---
 configure.ac          |    1 
 include/builddefs.in  |    1 
 m4/package_libcdev.m4 |   18 +++
 scrub/Makefile        |    4 +
 scrub/common.c        |   63 +++++++++++
 scrub/common.h        |    4 +
 scrub/xfs_scrub.c     |  280 +++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 371 insertions(+)
configure.ac +1 -0
index f83d581..796a91b 100644
@@ -165,6 +165,7 @@ AC_HAVE_GETFSMAP
 AC_HAVE_STATFS_FLAGS
 AC_HAVE_MAP_SYNC
 AC_HAVE_DEVMAPPER
+AC_HAVE_MALLINFO
 
 if test "$enable_blkid" = yes; then
 AC_HAVE_BLKID_TOPO
include/builddefs.in +1 -0
index 9470703..28cf0d8 100644
@@ -119,6 +119,7 @@ HAVE_GETFSMAP = @have_getfsmap@
 HAVE_STATFS_FLAGS = @have_statfs_flags@
 HAVE_MAP_SYNC = @have_map_sync@
 HAVE_DEVMAPPER = @have_devmapper@
+HAVE_MALLINFO = @have_mallinfo@
 
 GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall
 #	   -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-decl
m4/package_libcdev.m4 +18 -0
index 71cedc5..d3955f0 100644
@@ -344,3 +344,21 @@ AC_DEFUN([AC_HAVE_MAP_SYNC],
 	AC_MSG_RESULT(no))
     AC_SUBST(have_map_sync)
   ])
+
+#
+# Check if we have a mallinfo libc call
+#
+AC_DEFUN([AC_HAVE_MALLINFO],
+  [ AC_MSG_CHECKING([for mallinfo ])
+    AC_TRY_COMPILE([
+#include <malloc.h>
+    ], [
+         struct mallinfo test;
+
+         test.arena = 0; test.hblkhd = 0; test.uordblks = 0; test.fordblks = 0;
+         test = mallinfo();
+    ], have_mallinfo=yes
+       AC_MSG_RESULT(yes),
+       AC_MSG_RESULT(no))
+    AC_SUBST(have_mallinfo)
+  ])
scrub/Makefile +4 -0
index 62cca3b..097ec84 100644
@@ -27,6 +27,10 @@ LLDLIBS += $(LIBHANDLE) $(LIBFROG) $(LIBPTHREAD)
 LTDEPENDENCIES += $(LIBHANDLE) $(LIBFROG)
 LLDFLAGS = -static
 
+ifeq ($(HAVE_MALLINFO),yes)
+LCFLAGS += -DHAVE_MALLINFO
+endif
+
 default: depend $(LTCOMMAND)
 
 include $(BUILDRULES)
scrub/common.c +63 -0

66 lines not on this page · raw message

scrub/common.h +4 -0
index 7a7e362..e26e0e8 100644
@@ -58,4 +58,8 @@ debug_tweak_on(
 	return debug && getenv(name) != NULL;
 }
 
+double timeval_subtract(struct timeval *tv1, struct timeval *tv2);
+double auto_space_units(unsigned long long kilobytes, char **units);
+double auto_units(unsigned long long number, char **units);
+
 #endif /* XFS_SCRUB_COMMON_H_ */
scrub/xfs_scrub.c +280 -0

316 lines not on this page · raw message

#5 lore raw

PATCH 5/29 xfs_scrub: figure out how many threads we're going to need

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Create the plumbing to figure out how many threads we're going to want to do all of our scrubbing.

---
 scrub/common.c    |   26 ++++++++++++++++++++++++++
 scrub/common.h    |    2 ++
 scrub/xfs_scrub.h |    3 +++
 3 files changed, 31 insertions(+)
scrub/common.c +26 -0
index 37ccd4a..05bb89b 100644
@@ -168,3 +168,29 @@ auto_units(
 	*units = "";
 	return number;
 }
+
+/* How many threads to kick off? */
+unsigned int
+scrub_nproc(
+	struct scrub_ctx	*ctx)
+{
+	if (nr_threads)
+		return nr_threads;
+	return ctx->nr_io_threads;
+}
+
+/*
+ * How many threads to kick off for a workqueue?  If we only want one
+ * thread, save ourselves the overhead and just run it in the main thread.
+ */
+unsigned int
+scrub_nproc_workqueue(
+	struct scrub_ctx	*ctx)
+{
+	unsigned int		x;
+
+	x = scrub_nproc(ctx);
+	if (x == 1)
+		x = 0;
+	return x;
+}
scrub/common.h +2 -0
index e26e0e8..4779dbd 100644
@@ -61,5 +61,7 @@ debug_tweak_on(
 double timeval_subtract(struct timeval *tv1, struct timeval *tv2);
 double auto_space_units(unsigned long long kilobytes, char **units);
 double auto_units(unsigned long long number, char **units);
+unsigned int scrub_nproc(struct scrub_ctx *ctx);
+unsigned int scrub_nproc_workqueue(struct scrub_ctx *ctx);
 
 #endif /* XFS_SCRUB_COMMON_H_ */
scrub/xfs_scrub.h +3 -0
index 51b8b7a..6d9f0c1 100644
@@ -54,6 +54,9 @@ struct scrub_ctx {
 	/* How does the user want us to react to errors? */
 	enum error_action	error_action;
 
+	/* Number of threads for metadata scrubbing */
+	unsigned int		nr_io_threads;
+
 	/* Mutable scrub state; use lock. */
 	pthread_mutex_t		lock;
 	unsigned long long	max_errors;
#6 lore raw

PATCH 6/29 xfs_scrub: create an abstraction for a block device

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Create an abstraction to handle all of our low level disk operations. We'll eventually use it to bind to a fs mount point and block device.

---
 scrub/Makefile |    2 +
 scrub/disk.c   |  168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/disk.h   |   39 +++++++++++++
 3 files changed, 209 insertions(+)
 create mode 100644 scrub/disk.c
 create mode 100644 scrub/disk.h
scrub/Makefile +2 -0
index 097ec84..c3a9986 100644
@@ -17,10 +17,12 @@ endif	# scrub_prereqs
 
 HFILES = \
 common.h \
+disk.h \
 xfs_scrub.h
 
 CFILES = \
 common.c \
+disk.c \
 xfs_scrub.c
 
 LLDLIBS += $(LIBHANDLE) $(LIBFROG) $(LIBPTHREAD)
scrub/disk.c new file +168 -0

168 lines not on this page · raw message

scrub/disk.h new file +39 -0
new file mode 100644
index 0000000..834678e
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <[email protected]>
+ *
+ * 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.
+ */
+#ifndef XFS_SCRUB_DISK_H_
+#define XFS_SCRUB_DISK_H_
+
+struct disk {
+	struct stat	d_sb;
+	int		d_fd;
+	int		d_lbalog;
+	unsigned int	d_flags;
+	unsigned int	d_blksize;	/* bytes */
+	uint64_t	d_size;		/* bytes */
+	uint64_t	d_start;	/* bytes */
+};
+
+unsigned int disk_heads(struct disk *disk);
+struct disk *disk_open(const char *pathname);
+int disk_close(struct disk *disk);
+ssize_t disk_read_verify(struct disk *disk, void *buf, uint64_t startblock,
+		uint64_t blockcount);
+
+#endif /* XFS_SCRUB_DISK_H_ */
#7 lore raw

PATCH 7/29 xfs_scrub: find XFS filesystem geometry

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Discover the geometry of the XFS filesystem that we've been told to scan, and set up some common functions that will be used by the scrub phases.

---
 scrub/Makefile    |    5 +
 scrub/common.c    |   72 +++++++++++++++++
 scrub/common.h    |   10 ++
 scrub/disk.c      |    3 +
 scrub/phase1.c    |  223 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/xfs_scrub.c |   35 ++++++++
 scrub/xfs_scrub.h |   29 +++++++
 7 files changed, 376 insertions(+), 1 deletion(-)
 create mode 100644 scrub/phase1.c
scrub/Makefile +5 -0
index c3a9986..5239dae 100644
@@ -23,6 +23,7 @@ xfs_scrub.h
 CFILES = \
 common.c \
 disk.c \
+phase1.c \
 xfs_scrub.c
 
 LLDLIBS += $(LIBHANDLE) $(LIBFROG) $(LIBPTHREAD)
@@ -33,6 +34,10 @@ ifeq ($(HAVE_MALLINFO),yes)
 LCFLAGS += -DHAVE_MALLINFO
 endif
 
+ifeq ($(HAVE_SYNCFS),yes)
+LCFLAGS += -DHAVE_SYNCFS
+endif
+
 default: depend $(LTCOMMAND)
 
 include $(BUILDRULES)
scrub/common.c +72 -0

83 lines not on this page · raw message

scrub/common.h +10 -0
index 4779dbd..3af63fb 100644
@@ -64,4 +64,14 @@ double auto_units(unsigned long long number, char **units);
 unsigned int scrub_nproc(struct scrub_ctx *ctx);
 unsigned int scrub_nproc_workqueue(struct scrub_ctx *ctx);
 
+#ifndef HAVE_SYNCFS
+static inline int syncfs(int fd)
+{
+	sync();
+	return 0;
+}
+#endif
+
+bool find_mountpoint(char *mtab, struct scrub_ctx *ctx);
+
 #endif /* XFS_SCRUB_COMMON_H_ */
scrub/disk.c +3 -0
index fe9dff7..e36ed6b 100644
@@ -31,6 +31,9 @@
 #include <linux/fs.h>
 #include "platform_defs.h"
 #include "libfrog.h"
+#include "xfs.h"
+#include "path.h"
+#include "xfs_fs.h"
 #include "xfs_scrub.h"
 #include "disk.h"
 
scrub/phase1.c new file +223 -0

223 lines not on this page · raw message

scrub/xfs_scrub.c +34 -1
index 14e5fe0..577e0b2 100644
@@ -23,9 +23,12 @@
 #include <stdlib.h>
 #include <sys/time.h>
 #include <sys/resource.h>
+#include <sys/statvfs.h>
 #include "platform_defs.h"
 #include "xfs.h"
+#include "xfs_fs.h"
 #include "input.h"
+#include "path.h"
 #include "xfs_scrub.h"
 #include "common.h"
 
@@ -360,6 +363,8 @@ run_scrub_phases(
 	{
 		{
 			.descr = _("Find filesystem geometry."),
+			.fn = xfs_setup_fs,
+			.must_run = true,
 		},
 		{
 			.descr = _("Check internal metadata."),
@@ -440,6 +445,7 @@ main(
 	char			*repairstr = "";
 	unsigned long long	total_errors;
 	bool			moveon = true;
+	bool			ismnt;
 	int			c;
 	int			ret = SCRUB_RET_SUCCESS;
 
@@ -539,6 +545,15 @@ _("Only one of the options -n or -y may be specified.\n"));
 
 	ctx.mntpoint = strdup(argv[optind]);
 
+	/* Find the mount record for the passed-in argument. */
+	if (stat(argv[optind], &ctx.mnt_sb) < 0) {
+		fprintf(stderr,
+			_("%s: could not stat: %s: %s\n"),
+			progname, argv[optind], strerror(errno));
+		ctx.runtime_errors++;
+		goto out;
+	}
+
 	/*
 	 * If the user did not specify an explicit mount table, try to use
 	 * /proc/mounts if it is available, else /etc/mtab.  We prefer
@@ -558,6 +573,15 @@ _("Only one of the options -n or -y may be specified.\n"));
 	if (!moveon)
 		goto out;
 
+	ismnt = find_mountpoint(mtab, &ctx);
+	if (!ismnt) {
+		fprintf(stderr,
+_("%s: Not a XFS mount point or block device.\n"),
+			ctx.mntpoint);
+		ret |= SCRUB_RET_SYNTAX;
+		goto out;
+	}
+
 	/* How many CPUs? */
 	nproc = sysconf(_SC_NPROCESSORS_ONLN);
 	if (nproc < 1)
@@ -589,6 +613,11 @@ _("Only one of the options -n or -y may be specified.\n"));
 	if (debug_tweak_on("XFS_SCRUB_FORCE_ERROR"))
 		str_error(&ctx, ctx.mntpoint, _("Injecting error."));
 
+	/* Clean up scan data. */
+	moveon = xfs_cleanup_fs(&ctx);
+	if (!moveon && ctx.runtime_errors == 0)
+		ctx.runtime_errors++;
+
 out:
 	total_errors = ctx.errors_found + ctx.runtime_errors;
 	if (ctx.need_repair)
@@ -606,13 +635,17 @@ _("%s: %llu errors found.%s\n"),
 		fprintf(stderr,
 _("%s: %llu warnings found.\n"),
 			ctx.mntpoint, ctx.warnings_found);
-	if (ctx.errors_found)
+	if (ctx.errors_found) {
+		if (ctx.error_action == ERRORS_SHUTDOWN)
+			xfs_shutdown_fs(&ctx);
 		ret |= SCRUB_RET_CORRUPT;
+	}
 	if (ctx.warnings_found)
 		ret |= SCRUB_RET_UNOPTIMIZED;
 	if (ctx.runtime_errors)
 		ret |= SCRUB_RET_OPERROR;
 	phase_end(&all_pi, 0);
+	free(ctx.blkdev);
 	free(ctx.mntpoint);
 
 	return ret;
scrub/xfs_scrub.h +29 -0
index 6d9f0c1..914490a 100644
@@ -48,15 +48,38 @@ struct scrub_ctx {
 	char			*mntpoint;
 	char			*blkdev;
 
+	/* Mountpoint info */
+	struct stat		mnt_sb;
+	struct statvfs		mnt_sv;
+	struct statfs		mnt_sf;
+
+	/* Open block devices */
+	struct disk		*datadev;
+	struct disk		*logdev;
+	struct disk		*rtdev;
+
 	/* What does the user want us to do? */
 	enum scrub_mode		mode;
 
 	/* How does the user want us to react to errors? */
 	enum error_action	error_action;
 
+	/* fd to filesystem mount point */
+	int			mnt_fd;
+
 	/* Number of threads for metadata scrubbing */
 	unsigned int		nr_io_threads;
 
+	/* XFS specific geometry */
+	struct xfs_fsop_geom	geo;
+	struct fs_path		fsinfo;
+	unsigned int		agblklog;
+	unsigned int		blocklog;
+	unsigned int		inodelog;
+	unsigned int		inopblog;
+	void			*fshandle;
+	size_t			fshandle_len;
+
 	/* Mutable scrub state; use lock. */
 	pthread_mutex_t		lock;
 	unsigned long long	max_errors;
@@ -64,6 +87,12 @@ struct scrub_ctx {
 	unsigned long long	errors_found;
 	unsigned long long	warnings_found;
 	bool			need_repair;
+	bool			preen_triggers[XFS_SCRUB_TYPE_NR];
 };
 
+/* Phase helper functions */
+void xfs_shutdown_fs(struct scrub_ctx *ctx);
+bool xfs_cleanup_fs(struct scrub_ctx *ctx);
+bool xfs_setup_fs(struct scrub_ctx *ctx);
+
 #endif /* XFS_SCRUB_XFS_SCRUB_H_ */
#8 lore raw

PATCH 8/29 xfs_scrub: add inode iteration functions

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

These helpers enable userspace to count or iterate all inodes in a filesystem. The counting function uses INUMBERS, while the inode iterator uses INUMBERS and BULKSTAT to iterate over every inode that should be in the filesystem.

---
 scrub/Makefile |    2 
 scrub/inodes.c |  297 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/inodes.h |   32 ++++++
 3 files changed, 331 insertions(+)
 create mode 100644 scrub/inodes.c
 create mode 100644 scrub/inodes.h
scrub/Makefile +2 -0
index 5239dae..4d1c908 100644
@@ -18,11 +18,13 @@ endif	# scrub_prereqs
 HFILES = \
 common.h \
 disk.h \
+inodes.h \
 xfs_scrub.h
 
 CFILES = \
 common.c \
 disk.c \
+inodes.c \
 phase1.c \
 xfs_scrub.c
 
scrub/inodes.c new file +297 -0

297 lines not on this page · raw message

scrub/inodes.h new file +32 -0
new file mode 100644
index 0000000..693cb05
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <[email protected]>
+ *
+ * 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.
+ */
+#ifndef XFS_SCRUB_INODES_H_
+#define XFS_SCRUB_INODES_H_
+
+typedef int (*xfs_inode_iter_fn)(struct scrub_ctx *ctx,
+		struct xfs_handle *handle, struct xfs_bstat *bs, void *arg);
+
+#define XFS_ITERATE_INODES_ABORT	(-1)
+bool xfs_scan_all_inodes(struct scrub_ctx *ctx, xfs_inode_iter_fn fn,
+		void *arg);
+
+int xfs_open_handle(struct xfs_handle *handle);
+
+#endif /* XFS_SCRUB_INODES_H_ */
#9 lore raw

PATCH 9/29 xfs_scrub: add space map iteration functions

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

These helpers enable userspace to iterate all the space map information in a filesystem. The iteration function uses GETFSMAP.

---
 scrub/Makefile   |    2 
 scrub/spacemap.c |  256 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/spacemap.h |   31 +++++++
 3 files changed, 289 insertions(+)
 create mode 100644 scrub/spacemap.c
 create mode 100644 scrub/spacemap.h
scrub/Makefile +2 -0
index 4d1c908..24e0c44 100644
@@ -19,6 +19,7 @@ HFILES = \
 common.h \
 disk.h \
 inodes.h \
+spacemap.h \
 xfs_scrub.h
 
 CFILES = \
@@ -26,6 +27,7 @@ common.c \
 disk.c \
 inodes.c \
 phase1.c \
+spacemap.c \
 xfs_scrub.c
 
 LLDLIBS += $(LIBHANDLE) $(LIBFROG) $(LIBPTHREAD)
scrub/spacemap.c new file +256 -0

256 lines not on this page · raw message

scrub/spacemap.h new file +31 -0
new file mode 100644
index 0000000..9ee46f7
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <[email protected]>
+ *
+ * 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.
+ */
+#ifndef XFS_SCRUB_SPACEMAP_H_
+#define XFS_SCRUB_SPACEMAP_H_
+
+typedef bool (*xfs_fsmap_iter_fn)(struct scrub_ctx *ctx, const char *descr,
+		struct fsmap *fsr, void *arg);
+
+bool xfs_iterate_fsmap(struct scrub_ctx *ctx, const char *descr,
+		struct fsmap *keys, xfs_fsmap_iter_fn fn, void *arg);
+bool xfs_scan_all_spacemaps(struct scrub_ctx *ctx, xfs_fsmap_iter_fn fn,
+		void *arg);
+
+#endif /* XFS_SCRUB_SPACEMAP_H_ */
#10 lore raw

PATCH 10/29 xfs_scrub: add file space map iteration functions

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

These helpers enable userspace to iterate all the space map information for a file. The iteration function uses GETBMAPX.

---
 scrub/Makefile  |    2 +
 scrub/filemap.c |  157 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/filemap.h |   39 ++++++++++++++
 3 files changed, 198 insertions(+)
 create mode 100644 scrub/filemap.c
 create mode 100644 scrub/filemap.h
scrub/Makefile +2 -0
index 24e0c44..a3534e6 100644
@@ -18,6 +18,7 @@ endif	# scrub_prereqs
 HFILES = \
 common.h \
 disk.h \
+filemap.h \
 inodes.h \
 spacemap.h \
 xfs_scrub.h
@@ -25,6 +26,7 @@ xfs_scrub.h
 CFILES = \
 common.c \
 disk.c \
+filemap.c \
 inodes.c \
 phase1.c \
 spacemap.c \
scrub/filemap.c new file +157 -0

157 lines not on this page · raw message

scrub/filemap.h new file +39 -0
new file mode 100644
index 0000000..30d53d0
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <[email protected]>
+ *
+ * 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.
+ */
+#ifndef XFS_SCRUB_FILEMAP_H_
+#define XFS_SCRUB_FILEMAP_H_
+
+/* inode fork block mapping */
+struct xfs_bmap {
+	uint64_t	bm_offset;	/* file offset of segment in bytes */
+	uint64_t	bm_physical;	/* physical starting byte  */
+	uint64_t	bm_length;	/* length of segment, bytes */
+	uint32_t	bm_flags;	/* output flags */
+};
+
+typedef bool (*xfs_bmap_iter_fn)(struct scrub_ctx *ctx, const char *descr,
+		int fd, int whichfork, struct fsxattr *fsx,
+		struct xfs_bmap *bmap, void *arg);
+
+bool xfs_iterate_filemaps(struct scrub_ctx *ctx, const char *descr, int fd,
+		int whichfork, struct xfs_bmap *key, xfs_bmap_iter_fn fn,
+		void *arg);
+
+#endif /* XFS_SCRUB_FILEMAP_H_ */
#11 lore raw

PATCH 11/29 xfs_scrub: filesystem counter collection functions

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Add a couple of helper functions to estimate the inode and block counters on the filesystem.

---
 scrub/Makefile     |    2 
 scrub/fscounters.c |  212 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/fscounters.h |   29 +++++++
 3 files changed, 243 insertions(+)
 create mode 100644 scrub/fscounters.c
 create mode 100644 scrub/fscounters.h
scrub/Makefile +2 -0
index a3534e6..5397339 100644
@@ -19,6 +19,7 @@ HFILES = \
 common.h \
 disk.h \
 filemap.h \
+fscounters.h \
 inodes.h \
 spacemap.h \
 xfs_scrub.h
@@ -27,6 +28,7 @@ CFILES = \
 common.c \
 disk.c \
 filemap.c \
+fscounters.c \
 inodes.c \
 phase1.c \
 spacemap.c \
scrub/fscounters.c new file +212 -0

212 lines not on this page · raw message

scrub/fscounters.h new file +29 -0
new file mode 100644
index 0000000..40a4c05
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <[email protected]>
+ *
+ * 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.
+ */
+#ifndef XFS_SCRUB_FSCOUNTERS_H_
+#define XFS_SCRUB_FSCOUNTERS_H_
+
+bool xfs_scan_estimate_blocks(struct scrub_ctx *ctx,
+		unsigned long long *d_blocks, unsigned long long *d_bfree,
+		unsigned long long *r_blocks, unsigned long long *r_bfree,
+		unsigned long long *f_files, unsigned long long *f_free);
+bool xfs_count_all_inodes(struct scrub_ctx *ctx, uint64_t *count);
+
+#endif /* XFS_SCRUB_FSCOUNTERS_H_ */
#12 lore raw

PATCH 12/29 xfs_scrub: wrap the scrub ioctl

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Create some wrappers to call the scrub ioctls.

---
 scrub/Makefile |    2 
 scrub/common.c |   19 ++
 scrub/common.h |    1 
 scrub/phase1.c |   11 +
 scrub/scrub.c  |  621 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/scrub.h  |   62 ++++++
 6 files changed, 716 insertions(+)
 create mode 100644 scrub/scrub.c
 create mode 100644 scrub/scrub.h
scrub/Makefile +2 -0
index 5397339..915b801 100644
@@ -21,6 +21,7 @@ disk.h \
 filemap.h \
 fscounters.h \
 inodes.h \
+scrub.h \
 spacemap.h \
 xfs_scrub.h
 
@@ -31,6 +32,7 @@ filemap.c \
 fscounters.c \
 inodes.c \
 phase1.c \
+scrub.c \
 spacemap.c \
 xfs_scrub.c
 
scrub/common.c +19 -0
index e9ebb04..81869e4 100644
@@ -266,3 +266,22 @@ find_mountpoint(
 	platform_mntent_close(&cursor);
 	return found;
 }
+
+/*
+ * Sleep for 100ms * however many -b we got past the initial one.
+ * This is an (albeit clumsy) way to throttle scrub activity.
+ */
+void
+background_sleep(void)
+{
+	unsigned long long	time;
+	struct timespec		tv;
+
+	if (bg_mode < 2)
+		return;
+
+	time = 100000ULL * (bg_mode - 1);
+	tv.tv_sec = time / 1000000;
+	tv.tv_nsec = time % 1000000;
+	nanosleep(&tv, NULL);
+}
scrub/common.h +1 -0
index 3af63fb..96fc870 100644
@@ -73,5 +73,6 @@ static inline int syncfs(int fd)
 #endif
 
 bool find_mountpoint(char *mtab, struct scrub_ctx *ctx);
+void background_sleep(void);
 
 #endif /* XFS_SCRUB_COMMON_H_ */
scrub/phase1.c +11 -0
index cb25754..6b986dd 100644
@@ -46,6 +46,7 @@
 #include "xfs_scrub.h"
 #include "common.h"
 #include "disk.h"
+#include "scrub.h"
 
 /* Phase 1: Find filesystem geometry (and clean up after) */
 
@@ -168,6 +169,16 @@ _("Does not appear to be an XFS filesystem!"));
 		return false;
 	}
 
+	/* Do we have kernel-assisted metadata scrubbing? */
+	if (!xfs_can_scrub_fs_metadata(ctx) || !xfs_can_scrub_inode(ctx) ||
+	    !xfs_can_scrub_bmap(ctx) || !xfs_can_scrub_dir(ctx) ||
+	    !xfs_can_scrub_attr(ctx) || !xfs_can_scrub_symlink(ctx) ||
+	    !xfs_can_scrub_parent(ctx)) {
+		str_error(ctx, ctx->mntpoint,
+_("Kernel metadata scrubbing facility is required."));
+		return false;
+	}
+
 	/* Go find the XFS devices if we have a usable fsmap. */
 	fs_table_initialise(0, NULL, 0, NULL);
 	errno = 0;
scrub/scrub.c new file +621 -0

621 lines not on this page · raw message

scrub/scrub.h new file +62 -0

62 lines not on this page · raw message

#13 lore raw

PATCH 13/29 xfs_scrub: scan filesystem and AG metadata

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Scrub the filesystem and per-AG metadata.

---
 scrub/Makefile    |    1 
 scrub/phase2.c    |  133 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/xfs_scrub.c |    1 
 scrub/xfs_scrub.h |    1 
 4 files changed, 136 insertions(+)
 create mode 100644 scrub/phase2.c
scrub/Makefile +1 -0
index 915b801..9edc933 100644
@@ -32,6 +32,7 @@ filemap.c \
 fscounters.c \
 inodes.c \
 phase1.c \
+phase2.c \
 scrub.c \
 spacemap.c \
 xfs_scrub.c
scrub/phase2.c new file +133 -0

133 lines not on this page · raw message

scrub/xfs_scrub.c +1 -0
index 577e0b2..4c32dd7 100644
@@ -368,6 +368,7 @@ run_scrub_phases(
 		},
 		{
 			.descr = _("Check internal metadata."),
+			.fn = xfs_scan_metadata,
 		},
 		{
 			.descr = _("Scan all inodes."),
scrub/xfs_scrub.h +1 -0
index 914490a..7802101 100644
@@ -94,5 +94,6 @@ struct scrub_ctx {
 void xfs_shutdown_fs(struct scrub_ctx *ctx);
 bool xfs_cleanup_fs(struct scrub_ctx *ctx);
 bool xfs_setup_fs(struct scrub_ctx *ctx);
+bool xfs_scan_metadata(struct scrub_ctx *ctx);
 
 #endif /* XFS_SCRUB_XFS_SCRUB_H_ */
#14 lore raw

PATCH 14/29 xfs_scrub: thread-safe stats counter

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Create a threaded stats counter that we'll use to track scan progress. This includes things like how much of the disk blocks we've scanned, or later how much progress we've made in each phase.

---
 include/ptvar.h  |   32 +++++++++++++
 libfrog/Makefile |    1 
 libfrog/ptvar.c  |  133 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/Makefile   |    2 +
 scrub/counter.c  |  104 ++++++++++++++++++++++++++++++++++++++++++
 scrub/counter.h  |   29 ++++++++++++
 6 files changed, 301 insertions(+)
 create mode 100644 include/ptvar.h
 create mode 100644 libfrog/ptvar.c
 create mode 100644 scrub/counter.c
 create mode 100644 scrub/counter.h
include/ptvar.h new file +32 -0
new file mode 100644
index 0000000..6308228
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <[email protected]>
+ *
+ * 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.
+ */
+#ifndef LIBFROG_PERCPU_H_
+#define LIBFROG_PERCPU_H_
+
+struct ptvar;
+
+typedef bool (*ptvar_iter_fn)(struct ptvar *ptv, void *data, void *foreach_arg);
+
+struct ptvar *ptvar_init(size_t nr, size_t size);
+void ptvar_free(struct ptvar *ptv);
+void *ptvar_get(struct ptvar *ptv);
+bool ptvar_foreach(struct ptvar *ptv, ptvar_iter_fn fn, void *foreach_arg);
+
+#endif /* LIBFROG_PERCPU_H_ */
libfrog/Makefile +1 -0
index 4c15605..230b08f 100644
@@ -16,6 +16,7 @@ convert.c \
 list_sort.c \
 paths.c \
 projects.c \
+ptvar.c \
 radix-tree.c \
 topology.c \
 util.c \
libfrog/ptvar.c new file +133 -0

133 lines not on this page · raw message

scrub/Makefile +2 -0
index 9edc933..30dbe54 100644
@@ -17,6 +17,7 @@ endif	# scrub_prereqs
 
 HFILES = \
 common.h \
+counter.h \
 disk.h \
 filemap.h \
 fscounters.h \
@@ -27,6 +28,7 @@ xfs_scrub.h
 
 CFILES = \
 common.c \
+counter.c \
 disk.c \
 filemap.c \
 fscounters.c \
scrub/counter.c new file +104 -0

104 lines not on this page · raw message

scrub/counter.h new file +29 -0
new file mode 100644
index 0000000..2aac795
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <[email protected]>
+ *
+ * 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.
+ */
+#ifndef XFS_SCRUB_COUNTER_H_
+#define XFS_SCRUB_COUNTER_H_
+
+struct ptcounter;
+struct ptcounter *ptcounter_init(size_t nr);
+void ptcounter_free(struct ptcounter *ptc);
+void ptcounter_add(struct ptcounter *ptc, int64_t nr);
+uint64_t ptcounter_value(struct ptcounter *ptc);
+
+#endif /* XFS_SCRUB_COUNTER_H_ */
#15 lore raw

PATCH 15/29 xfs_scrub: scan inodes

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Scan all the inodes in the system for problems.

---
 scrub/Makefile    |    1 
 scrub/phase3.c    |  152 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/xfs_scrub.c |    1 
 scrub/xfs_scrub.h |    2 +
 4 files changed, 156 insertions(+)
 create mode 100644 scrub/phase3.c
scrub/Makefile +1 -0
index 30dbe54..e0d15d8 100644
@@ -35,6 +35,7 @@ fscounters.c \
 inodes.c \
 phase1.c \
 phase2.c \
+phase3.c \
 scrub.c \
 spacemap.c \
 xfs_scrub.c
scrub/phase3.c new file +152 -0

152 lines not on this page · raw message

scrub/xfs_scrub.c +1 -0
index 4c32dd7..be809fc 100644
@@ -372,6 +372,7 @@ run_scrub_phases(
 		},
 		{
 			.descr = _("Scan all inodes."),
+			.fn = xfs_scan_inodes,
 		},
 		{
 			.descr = _("Defer filesystem repairs."),
scrub/xfs_scrub.h +2 -0
index 7802101..462b590 100644
@@ -86,6 +86,7 @@ struct scrub_ctx {
 	unsigned long long	runtime_errors;
 	unsigned long long	errors_found;
 	unsigned long long	warnings_found;
+	unsigned long long	inodes_checked;
 	bool			need_repair;
 	bool			preen_triggers[XFS_SCRUB_TYPE_NR];
 };
@@ -95,5 +96,6 @@ void xfs_shutdown_fs(struct scrub_ctx *ctx);
 bool xfs_cleanup_fs(struct scrub_ctx *ctx);
 bool xfs_setup_fs(struct scrub_ctx *ctx);
 bool xfs_scan_metadata(struct scrub_ctx *ctx);
+bool xfs_scan_inodes(struct scrub_ctx *ctx);
 
 #endif /* XFS_SCRUB_XFS_SCRUB_H_ */
#16 lore raw

PATCH 16/29 xfs_scrub: check directory connectivity

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Opening directories by file handle will cause the kernel to perform parent lookups all the way to the root directory. Take advantage of this to ensure that directories actually connect to the root. Some day we'll have parent pointers and can make this more comprehensive.

---
 scrub/Makefile    |    1 +
 scrub/phase5.c    |  101 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/xfs_scrub.c |    1 +
 scrub/xfs_scrub.h |    1 +
 4 files changed, 104 insertions(+)
 create mode 100644 scrub/phase5.c
scrub/Makefile +1 -0
index e0d15d8..adb868e 100644
@@ -36,6 +36,7 @@ inodes.c \
 phase1.c \
 phase2.c \
 phase3.c \
+phase5.c \
 scrub.c \
 spacemap.c \
 xfs_scrub.c
scrub/phase5.c new file +101 -0

101 lines not on this page · raw message

scrub/xfs_scrub.c +1 -0
index be809fc..2530d69 100644
@@ -380,6 +380,7 @@ run_scrub_phases(
 		},
 		{
 			.descr = _("Check directory tree."),
+			.fn = xfs_scan_connections,
 		},
 		{
 			.descr = _("Verify data file integrity."),
scrub/xfs_scrub.h +1 -0
index 462b590..fd7d7aa 100644
@@ -97,5 +97,6 @@ bool xfs_cleanup_fs(struct scrub_ctx *ctx);
 bool xfs_setup_fs(struct scrub_ctx *ctx);
 bool xfs_scan_metadata(struct scrub_ctx *ctx);
 bool xfs_scan_inodes(struct scrub_ctx *ctx);
+bool xfs_scan_connections(struct scrub_ctx *ctx);
 
 #endif /* XFS_SCRUB_XFS_SCRUB_H_ */
#17 lore raw

PATCH 17/29 xfs_scrub: warn about suspicious characters in directory/xattr names

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Look for control characters and punctuation that interfere with shell globbing in directory entry names and extended attribute key names. Technically these aren't filesystem corruptions because names are arbitrary sequences of bytes, but they've been known to cause problems in the Unix environment so warn if we see them.

---
 configure.ac         |    2 +
 debian/control       |    2 -
 include/builddefs.in |    1 
 m4/Makefile          |    1 
 m4/package_attr.m4   |   23 ++++++
 scrub/Makefile       |    6 ++
 scrub/common.c       |   54 ++++++++++++++
 scrub/common.h       |    4 +
 scrub/phase5.c       |  192 ++++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/xfs_scrub.h    |    1 
 10 files changed, 285 insertions(+), 1 deletion(-)
 create mode 100644 m4/package_attr.m4
configure.ac +2 -0
index 796a91b..e2e3f66 100644
@@ -166,6 +166,8 @@ AC_HAVE_STATFS_FLAGS
 AC_HAVE_MAP_SYNC
 AC_HAVE_DEVMAPPER
 AC_HAVE_MALLINFO
+AC_PACKAGE_WANT_ATTRIBUTES_H
+AC_HAVE_LIBATTR
 
 if test "$enable_blkid" = yes; then
 AC_HAVE_BLKID_TOPO
debian/control +1 -1
index f5980b2..f664a6b 100644
@@ -3,7 +3,7 @@ Section: admin
 Priority: optional
 Maintainer: XFS Development Team <[email protected]>
 Uploaders: Nathan Scott <[email protected]>, Anibal Monsalve Salazar <[email protected]>
-Build-Depends: uuid-dev, dh-autoreconf, debhelper (>= 5), gettext, libtool, libreadline-gplv2-dev | libreadline5-dev, libblkid-dev (>= 2.17), linux-libc-dev, libdevmapper-dev
+Build-Depends: uuid-dev, dh-autoreconf, debhelper (>= 5), gettext, libtool, libreadline-gplv2-dev | libreadline5-dev, libblkid-dev (>= 2.17), linux-libc-dev, libdevmapper-dev, libattr1-dev
 Standards-Version: 3.9.1
 Homepage: https://xfs.wiki.kernel.org/
 
include/builddefs.in +1 -0
index 28cf0d8..cc1b7e2 100644
@@ -120,6 +120,7 @@ HAVE_STATFS_FLAGS = @have_statfs_flags@
 HAVE_MAP_SYNC = @have_map_sync@
 HAVE_DEVMAPPER = @have_devmapper@
 HAVE_MALLINFO = @have_mallinfo@
+HAVE_LIBATTR = @have_libattr@
 
 GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall
 #	   -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-decl
m4/Makefile +1 -0
index 77f2edd..d5f1d2f 100644
@@ -17,6 +17,7 @@ LSRCFILES = \
 	package_blkid.m4 \
 	package_devmapper.m4 \
 	package_globals.m4 \
+	package_attr.m4 \
 	package_libcdev.m4 \
 	package_pthread.m4 \
 	package_sanitizer.m4 \
m4/package_attr.m4 new file +23 -0
new file mode 100644
index 0000000..4324923
@@ -0,0 +1,23 @@
+AC_DEFUN([AC_PACKAGE_WANT_ATTRIBUTES_H],
+  [
+    AC_CHECK_HEADERS(attr/attributes.h)
+  ])
+
+#
+# Check if we have a ATTR_ROOT flag and libattr structures
+#
+AC_DEFUN([AC_HAVE_LIBATTR],
+  [ AC_MSG_CHECKING([for struct attrlist_cursor])
+    AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <attr/attributes.h>
+       ], [
+struct attrlist_cursor *cur;
+struct attrlist *list;
+struct attrlist_ent *ent;
+int flags = ATTR_ROOT;
+       ], have_libattr=yes
+          AC_MSG_RESULT(yes),
+          AC_MSG_RESULT(no))
+    AC_SUBST(have_libattr)
+  ])
scrub/Makefile +6 -0
index adb868e..67ac6af 100644
@@ -53,8 +53,14 @@ ifeq ($(HAVE_SYNCFS),yes)
 LCFLAGS += -DHAVE_SYNCFS
 endif
 
+ifeq ($(HAVE_LIBATTR),yes)
+LCFLAGS += -DHAVE_LIBATTR
+endif
+
 default: depend $(LTCOMMAND)
 
+phase5.o: $(TOPDIR)/include/builddefs
+
 include $(BUILDRULES)
 
 install: default $(INSTALL_SCRUB)
scrub/common.c +54 -0

57 lines not on this page · raw message

scrub/common.h +4 -0
index 96fc870..336fc40 100644
@@ -74,5 +74,9 @@ static inline int syncfs(int fd)
 
 bool find_mountpoint(char *mtab, struct scrub_ctx *ctx);
 void background_sleep(void);
+char *string_escape(const char *in);
+
+#define TOO_MANY_NAME_WARNINGS	10000
+bool should_warn_about_name(struct scrub_ctx *ctx);
 
 #endif /* XFS_SCRUB_COMMON_H_ */
scrub/phase5.c +192 -0

220 lines not on this page · raw message

scrub/xfs_scrub.h +1 -0
index fd7d7aa..0aef76b 100644
@@ -87,6 +87,7 @@ struct scrub_ctx {
 	unsigned long long	errors_found;
 	unsigned long long	warnings_found;
 	unsigned long long	inodes_checked;
+	unsigned long long	naming_warnings;
 	bool			need_repair;
 	bool			preen_triggers[XFS_SCRUB_TYPE_NR];
 };
#18 lore raw

PATCH 18/29 xfs_scrub: warn about normalized Unicode name collisions

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Iterate all directory and xattr names to look for name collisions amongst Unicode normalized names. This is generally a sign of buggy programs or malicious duplicate files.

---
 configure.ac            |    2 
 debian/control          |    2 
 include/builddefs.in    |    2 
 m4/Makefile             |    1 
 m4/package_unistring.m4 |   19 ++
 scrub/Makefile          |   12 +
 scrub/phase5.c          |   62 +++++--
 scrub/unicrash.c        |  392 +++++++++++++++++++++++++++++++++++++++++++++++
 scrub/unicrash.h        |   47 ++++++
 scrub/xfs_scrub.c       |    1 
 10 files changed, 514 insertions(+), 26 deletions(-)
 create mode 100644 m4/package_unistring.m4
 create mode 100644 scrub/unicrash.c
 create mode 100644 scrub/unicrash.h
configure.ac +2 -0
index e2e3f66..fc44bd5 100644
@@ -168,6 +168,8 @@ AC_HAVE_DEVMAPPER
 AC_HAVE_MALLINFO
 AC_PACKAGE_WANT_ATTRIBUTES_H
 AC_HAVE_LIBATTR
+AC_PACKAGE_WANT_UNINORM_H
+AC_HAVE_U8NORMALIZE
 
 if test "$enable_blkid" = yes; then
 AC_HAVE_BLKID_TOPO
debian/control +1 -1
index f664a6b..36d1bd8 100644
@@ -3,7 +3,7 @@ Section: admin
 Priority: optional
 Maintainer: XFS Development Team <[email protected]>
 Uploaders: Nathan Scott <[email protected]>, Anibal Monsalve Salazar <[email protected]>
-Build-Depends: uuid-dev, dh-autoreconf, debhelper (>= 5), gettext, libtool, libreadline-gplv2-dev | libreadline5-dev, libblkid-dev (>= 2.17), linux-libc-dev, libdevmapper-dev, libattr1-dev
+Build-Depends: uuid-dev, dh-autoreconf, debhelper (>= 5), gettext, libtool, libreadline-gplv2-dev | libreadline5-dev, libblkid-dev (>= 2.17), linux-libc-dev, libdevmapper-dev, libattr1-dev, libunistring-dev
 Standards-Version: 3.9.1
 Homepage: https://xfs.wiki.kernel.org/
 
include/builddefs.in +2 -0
index cc1b7e2..1c264a0 100644
@@ -36,6 +36,7 @@ LIBEDITLINE = @libeditline@
 LIBREADLINE = @libreadline@
 LIBBLKID = @libblkid@
 LIBDEVMAPPER = @libdevmapper@
+LIBUNISTRING = @libunistring@
 LIBXFS = $(TOPDIR)/libxfs/libxfs.la
 LIBFROG = $(TOPDIR)/libfrog/libfrog.la
 LIBXCMD = $(TOPDIR)/libxcmd/libxcmd.la
@@ -121,6 +122,7 @@ HAVE_MAP_SYNC = @have_map_sync@
 HAVE_DEVMAPPER = @have_devmapper@
 HAVE_MALLINFO = @have_mallinfo@
 HAVE_LIBATTR = @have_libattr@
+HAVE_U8NORMALIZE = @have_u8normalize@
 
 GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall
 #	   -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-decl
m4/Makefile +1 -0
index d5f1d2f..61d617e 100644
@@ -22,6 +22,7 @@ LSRCFILES = \
 	package_pthread.m4 \
 	package_sanitizer.m4 \
 	package_types.m4 \
+	package_unistring.m4 \
 	package_utilies.m4 \
 	package_uuiddev.m4 \
 	multilib.m4 \
m4/package_unistring.m4 new file +19 -0
new file mode 100644
index 0000000..9cbfcb0
@@ -0,0 +1,19 @@
+AC_DEFUN([AC_PACKAGE_WANT_UNINORM_H],
+  [ AC_CHECK_HEADERS(uninorm.h)
+    if test $ac_cv_header_uninorm_h = no; then
+	AC_CHECK_HEADERS(uninorm.h,, [
+	echo
+	echo 'WARNING: could not find a valid uninorm.h header.'])
+    fi
+  ])
+
+AC_DEFUN([AC_HAVE_U8NORMALIZE],
+  [ AC_CHECK_LIB(unistring, u8_normalize,[
+	libunistring=-lunistring
+	have_u8normalize=yes
+    ],[
+	echo
+	echo 'WARNING: xfs_scrub will not be built with Unicode libraries.'])
+    AC_SUBST(libunistring)
+    AC_SUBST(have_u8normalize)
+  ])
scrub/Makefile +9 -3
index 67ac6af..858bc40 100644
@@ -24,6 +24,7 @@ fscounters.h \
 inodes.h \
 scrub.h \
 spacemap.h \
+unicrash.h \
 xfs_scrub.h
 
 CFILES = \
@@ -41,8 +42,8 @@ scrub.c \
 spacemap.c \
 xfs_scrub.c
 
-LLDLIBS += $(LIBHANDLE) $(LIBFROG) $(LIBPTHREAD)
-LTDEPENDENCIES += $(LIBHANDLE) $(LIBFROG)
+LLDLIBS += $(LIBHANDLE) $(LIBFROG) $(LIBPTHREAD) $(LIBUNISTRING)
+LTDEPENDENCIES += $(LIBHANDLE) $(LIBFROG) $(LIBUNISTRING)
 LLDFLAGS = -static
 
 ifeq ($(HAVE_MALLINFO),yes)
@@ -57,9 +58,14 @@ ifeq ($(HAVE_LIBATTR),yes)
 LCFLAGS += -DHAVE_LIBATTR
 endif
 
+ifeq ($(HAVE_U8NORMALIZE),yes)
+CFILES += unicrash.c
+LCFLAGS += -DHAVE_U8NORMALIZE
+endif
+
 default: depend $(LTCOMMAND)
 
-phase5.o: $(TOPDIR)/include/builddefs
+phase5.o unicrash.o xfs.o: $(TOPDIR)/include/builddefs
 
 include $(BUILDRULES)
 
scrub/phase5.c +40 -22

160 lines not on this page · raw message

scrub/unicrash.c new file +392 -0

392 lines not on this page · raw message

scrub/unicrash.h new file +47 -0

47 lines not on this page · raw message

scrub/xfs_scrub.c +1 -0
index 2530d69..46babea 100644
@@ -31,6 +31,7 @@
 #include "path.h"
 #include "xfs_scrub.h"
 #include "common.h"
+#include "unicrash.h"
 
 /*
  * XFS Online Metadata Scrub (and Repair)
#19 lore raw

PATCH 19/29 xfs_scrub: create a bitmap data structure

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Create an efficient tree-based bitmap data structure. We will use this during the data block scan to record the LBAs of IO errors so that we can report broken files to userspace.

---
 scrub/Makefile |    2 
 scrub/bitmap.c |  410 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/bitmap.h |   38 +++++
 3 files changed, 450 insertions(+)
 create mode 100644 scrub/bitmap.c
 create mode 100644 scrub/bitmap.h
scrub/Makefile +2 -0
index 858bc40..a9aaa99 100644
@@ -16,6 +16,7 @@ INSTALL_SCRUB = install-scrub
 endif	# scrub_prereqs
 
 HFILES = \
+bitmap.h \
 common.h \
 counter.h \
 disk.h \
@@ -28,6 +29,7 @@ unicrash.h \
 xfs_scrub.h
 
 CFILES = \
+bitmap.c \
 common.c \
 counter.c \
 disk.c \
scrub/bitmap.c new file +410 -0

410 lines not on this page · raw message

scrub/bitmap.h new file +38 -0
new file mode 100644
index 0000000..e8dcd4f
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <[email protected]>
+ *
+ * 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.
+ */
+#ifndef XFS_SCRUB_BITMAP_H_
+#define XFS_SCRUB_BITMAP_H_
+
+struct bitmap {
+	pthread_mutex_t		bt_lock;
+	struct avl64tree_desc	*bt_tree;
+};
+
+bool bitmap_init(struct bitmap **bmap);
+void bitmap_free(struct bitmap **bmap);
+bool bitmap_set(struct bitmap *bmap, uint64_t start, uint64_t length);
+bool bitmap_iterate(struct bitmap *bmap,
+		bool (*fn)(uint64_t, uint64_t, void *), void *arg);
+bool bitmap_test(struct bitmap *bmap, uint64_t start,
+		uint64_t len);
+bool bitmap_empty(struct bitmap *bmap);
+void bitmap_dump(struct bitmap *bmap);
+
+#endif /* XFS_SCRUB_BITMAP_H_ */
#20 lore raw

PATCH 20/29 xfs_scrub: create infrastructure to read verify data blocks

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Manage the scheduling, issuance, and reporting of data block verification reads. This enables us to combine adjacent (or nearly adjacent) read requests, and to take advantage of high-IOPS devices by issuing IO from multiple threads.

---
 scrub/Makefile      |    2 
 scrub/read_verify.c |  268 +++++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/read_verify.h |   50 ++++++++++
 scrub/xfs_scrub.h   |    3 +
 4 files changed, 323 insertions(+)
 create mode 100644 scrub/read_verify.c
 create mode 100644 scrub/read_verify.h
scrub/Makefile +2 -0
index a9aaa99..3b3eb95 100644
@@ -23,6 +23,7 @@ disk.h \
 filemap.h \
 fscounters.h \
 inodes.h \
+read_verify.h \
 scrub.h \
 spacemap.h \
 unicrash.h \
@@ -40,6 +41,7 @@ phase1.c \
 phase2.c \
 phase3.c \
 phase5.c \
+read_verify.c \
 scrub.c \
 spacemap.c \
 xfs_scrub.c
scrub/read_verify.c new file +268 -0

268 lines not on this page · raw message

scrub/read_verify.h new file +50 -0

50 lines not on this page · raw message

scrub/xfs_scrub.h +3 -0
index 0aef76b..c883bdb 100644
@@ -80,6 +80,9 @@ struct scrub_ctx {
 	void			*fshandle;
 	size_t			fshandle_len;
 
+	/* Data block read verification buffer */
+	void			*readbuf;
+
 	/* Mutable scrub state; use lock. */
 	pthread_mutex_t		lock;
 	unsigned long long	max_errors;
#21 lore raw

PATCH 21/29 xfs_scrub: scrub file data blocks

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Read all data blocks from the disk, hoping to catch IO errors.

---
 configure.ac          |    2 
 include/builddefs.in  |    2 
 m4/package_libcdev.m4 |   28 +++
 scrub/Makefile        |    7 -
 scrub/phase6.c        |  516 +++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/vfs.c           |  225 +++++++++++++++++++++
 scrub/vfs.h           |   31 +++
 scrub/xfs_scrub.c     |    4 
 scrub/xfs_scrub.h     |    2 
 9 files changed, 815 insertions(+), 2 deletions(-)
 create mode 100644 scrub/phase6.c
 create mode 100644 scrub/vfs.c
 create mode 100644 scrub/vfs.h
configure.ac +2 -0
index fc44bd5..8eda010 100644
@@ -170,6 +170,8 @@ AC_PACKAGE_WANT_ATTRIBUTES_H
 AC_HAVE_LIBATTR
 AC_PACKAGE_WANT_UNINORM_H
 AC_HAVE_U8NORMALIZE
+AC_HAVE_OPENAT
+AC_HAVE_FSTATAT
 
 if test "$enable_blkid" = yes; then
 AC_HAVE_BLKID_TOPO
include/builddefs.in +2 -0
index 1c264a0..2f8d33f 100644
@@ -123,6 +123,8 @@ HAVE_DEVMAPPER = @have_devmapper@
 HAVE_MALLINFO = @have_mallinfo@
 HAVE_LIBATTR = @have_libattr@
 HAVE_U8NORMALIZE = @have_u8normalize@
+HAVE_OPENAT = @have_openat@
+HAVE_FSTATAT = @have_fstatat@
 
 GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall
 #	   -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-decl
m4/package_libcdev.m4 +28 -0
index d3955f0..e0abc12 100644
@@ -362,3 +362,31 @@ AC_DEFUN([AC_HAVE_MALLINFO],
        AC_MSG_RESULT(no))
     AC_SUBST(have_mallinfo)
   ])
+
+#
+# Check if we have a openat call
+#
+AC_DEFUN([AC_HAVE_OPENAT],
+  [ AC_CHECK_DECL([openat],
+       have_openat=yes,
+       [],
+       [#include <sys/types.h>
+        #include <sys/stat.h>
+        #include <fcntl.h>]
+       )
+    AC_SUBST(have_openat)
+  ])
+
+#
+# Check if we have a fstatat call
+#
+AC_DEFUN([AC_HAVE_FSTATAT],
+  [ AC_CHECK_DECL([fstatat],
+       have_fstatat=yes,
+       [],
+       [#define _GNU_SOURCE
+       #include <sys/types.h>
+       #include <sys/stat.h>
+       #include <unistd.h>])
+    AC_SUBST(have_fstatat)
+  ])
scrub/Makefile +5 -2
index 3b3eb95..4b70efa 100644
@@ -8,9 +8,9 @@ include $(TOPDIR)/include/builddefs
 # On linux we get fsmap from the system or define it ourselves
 # so include this based on platform type.  If this reverts to only
 # the autoconf check w/o local definition, change to testing HAVE_GETFSMAP
-SCRUB_PREREQS=$(PKG_PLATFORM)
+SCRUB_PREREQS=$(PKG_PLATFORM)$(HAVE_OPENAT)$(HAVE_FSTATAT)
 
-ifeq ($(SCRUB_PREREQS),linux)
+ifeq ($(SCRUB_PREREQS),linuxyesyes)
 LTCOMMAND = xfs_scrub
 INSTALL_SCRUB = install-scrub
 endif	# scrub_prereqs
@@ -27,6 +27,7 @@ read_verify.h \
 scrub.h \
 spacemap.h \
 unicrash.h \
+vfs.h \
 xfs_scrub.h
 
 CFILES = \
@@ -41,9 +42,11 @@ phase1.c \
 phase2.c \
 phase3.c \
 phase5.c \
+phase6.c \
 read_verify.c \
 scrub.c \
 spacemap.c \
+vfs.c \
 xfs_scrub.c
 
 LLDLIBS += $(LIBHANDLE) $(LIBFROG) $(LIBPTHREAD) $(LIBUNISTRING)
scrub/phase6.c new file +516 -0

516 lines not on this page · raw message

scrub/vfs.c new file +225 -0

225 lines not on this page · raw message

scrub/vfs.h new file +31 -0
new file mode 100644
index 0000000..100eb18
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <[email protected]>
+ *
+ * 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.
+ */
+#ifndef XFS_SCRUB_VFS_H_
+#define XFS_SCRUB_VFS_H_
+
+typedef bool (*scan_fs_tree_dir_fn)(struct scrub_ctx *, const char *,
+		int, void *);
+typedef bool (*scan_fs_tree_dirent_fn)(struct scrub_ctx *, const char *,
+		int, struct dirent *, struct stat *, void *);
+
+bool scan_fs_tree(struct scrub_ctx *ctx, scan_fs_tree_dir_fn dir_fn,
+		scan_fs_tree_dirent_fn dirent_fn, void *arg);
+
+#endif /* XFS_SCRUB_VFS_H_ */
scrub/xfs_scrub.c +4 -0
index 46babea..296b492 100644
@@ -405,6 +405,10 @@ run_scrub_phases(
 
 	/* Run all phases of the scrub tool. */
 	for (phase = 1, sp = phases; sp->fn; sp++, phase++) {
+		/* Turn on certain phases if user said to. */
+		if (sp->fn == DATASCAN_DUMMY_FN && scrub_data)
+			sp->fn = xfs_scan_blocks;
+
 		/* Skip certain phases unless they're turned on. */
 		if (sp->fn == REPAIR_DUMMY_FN ||
 		    sp->fn == DATASCAN_DUMMY_FN)
scrub/xfs_scrub.h +2 -0
index c883bdb..997bedd 100644
@@ -90,6 +90,7 @@ struct scrub_ctx {
 	unsigned long long	errors_found;
 	unsigned long long	warnings_found;
 	unsigned long long	inodes_checked;
+	unsigned long long	bytes_checked;
 	unsigned long long	naming_warnings;
 	bool			need_repair;
 	bool			preen_triggers[XFS_SCRUB_TYPE_NR];
@@ -102,5 +103,6 @@ bool xfs_setup_fs(struct scrub_ctx *ctx);
 bool xfs_scan_metadata(struct scrub_ctx *ctx);
 bool xfs_scan_inodes(struct scrub_ctx *ctx);
 bool xfs_scan_connections(struct scrub_ctx *ctx);
+bool xfs_scan_blocks(struct scrub_ctx *ctx);
 
 #endif /* XFS_SCRUB_XFS_SCRUB_H_ */
#22 lore raw

PATCH 22/29 xfs_scrub: optionally use SCSI READ VERIFY commands to scrub data blocks on disk

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

If we sense that we're talking to a raw SCSI disk, use the SCSI READ VERIFY command to ask the disk to verify a disk internally. This can sharply reduce the runtime of the data block verification phase on devices whose internal bandwidth exceeds their link bandwidth.

---
 configure.ac          |    2 +
 include/builddefs.in  |    2 +
 m4/package_libcdev.m4 |   30 ++++++++++
 scrub/Makefile        |    8 +++
 scrub/disk.c          |  146 +++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/disk.h          |    1 
 6 files changed, 188 insertions(+), 1 deletion(-)
configure.ac +2 -0
index 8eda010..bb032e5 100644
@@ -172,6 +172,8 @@ AC_PACKAGE_WANT_UNINORM_H
 AC_HAVE_U8NORMALIZE
 AC_HAVE_OPENAT
 AC_HAVE_FSTATAT
+AC_HAVE_SG_IO
+AC_HAVE_HDIO_GETGEO
 
 if test "$enable_blkid" = yes; then
 AC_HAVE_BLKID_TOPO
include/builddefs.in +2 -0
index 2f8d33f..d44faf9 100644
@@ -125,6 +125,8 @@ HAVE_LIBATTR = @have_libattr@
 HAVE_U8NORMALIZE = @have_u8normalize@
 HAVE_OPENAT = @have_openat@
 HAVE_FSTATAT = @have_fstatat@
+HAVE_SG_IO = @have_sg_io@
+HAVE_HDIO_GETGEO = @have_hdio_getgeo@
 
 GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall
 #	   -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-decl
m4/package_libcdev.m4 +30 -0
index e0abc12..9258c27 100644
@@ -390,3 +390,33 @@ AC_DEFUN([AC_HAVE_FSTATAT],
        #include <unistd.h>])
     AC_SUBST(have_fstatat)
   ])
+
+#
+# Check if we have the SG_IO ioctl
+#
+AC_DEFUN([AC_HAVE_SG_IO],
+  [ AC_MSG_CHECKING([for struct sg_io_hdr ])
+    AC_TRY_COMPILE([#include <scsi/sg.h>],
+    [
+         struct sg_io_hdr hdr;
+         ioctl(0, SG_IO, &hdr);
+    ], have_sg_io=yes
+       AC_MSG_RESULT(yes),
+       AC_MSG_RESULT(no))
+    AC_SUBST(have_sg_io)
+  ])
+
+#
+# Check if we have the HDIO_GETGEO ioctl
+#
+AC_DEFUN([AC_HAVE_HDIO_GETGEO],
+  [ AC_MSG_CHECKING([for struct hd_geometry ])
+    AC_TRY_COMPILE([#include <linux/hdreg.h>],
+    [
+         struct hd_geometry hdr;
+         ioctl(0, HDIO_GETGEO, &hdr);
+    ], have_hdio_getgeo=yes
+       AC_MSG_RESULT(yes),
+       AC_MSG_RESULT(no))
+    AC_SUBST(have_hdio_getgeo)
+  ])
scrub/Makefile +8 -0
index 4b70efa..1fb6e84 100644
@@ -70,6 +70,14 @@ CFILES += unicrash.c
 LCFLAGS += -DHAVE_U8NORMALIZE
 endif
 
+ifeq ($(HAVE_SG_IO),yes)
+LCFLAGS += -DHAVE_SG_IO
+endif
+
+ifeq ($(HAVE_HDIO_GETGEO),yes)
+LCFLAGS += -DHAVE_HDIO_GETGEO
+endif
+
 default: depend $(LTCOMMAND)
 
 phase5.o unicrash.o xfs.o: $(TOPDIR)/include/builddefs
scrub/disk.c +145 -1

193 lines not on this page · raw message

scrub/disk.h +1 -0
index 834678e..8a00144 100644
@@ -20,6 +20,7 @@
 #ifndef XFS_SCRUB_DISK_H_
 #define XFS_SCRUB_DISK_H_
 
+#define DISK_FLAG_SCSI_VERIFY	0x1
 struct disk {
 	struct stat	d_sb;
 	int		d_fd;
#23 lore raw

PATCH 23/29 xfs_scrub: check summary counters

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Make sure the filesystem summary counters are somewhat close to what we can find by scanning the filesystem.

---
 scrub/Makefile    |    1 
 scrub/common.c    |   28 ++++++
 scrub/common.h    |    4 +
 scrub/phase7.c    |  266 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/xfs_scrub.c |    3 -
 scrub/xfs_scrub.h |    1 
 6 files changed, 302 insertions(+), 1 deletion(-)
 create mode 100644 scrub/phase7.c
scrub/Makefile +1 -0
index 1fb6e84..fd26624 100644
@@ -43,6 +43,7 @@ phase2.c \
 phase3.c \
 phase5.c \
 phase6.c \
+phase7.c \
 read_verify.c \
 scrub.c \
 spacemap.c \
scrub/common.c +28 -0
index 5e2d7c6..c4fb339 100644
@@ -339,3 +339,31 @@ _("More than %u naming warnings, shutting up."),
 
 	return debug || verbose || res;
 }
+
+/* Decide if a value is within +/- (n/d) of a desired value. */
+bool
+within_range(
+	struct scrub_ctx	*ctx,
+	unsigned long long	value,
+	unsigned long long	desired,
+	unsigned long long	abs_threshold,
+	unsigned int		n,
+	unsigned int		d,
+	const char		*descr)
+{
+	assert(n < d);
+
+	/* Don't complain if difference does not exceed an absolute value. */
+	if (value < desired && desired - value < abs_threshold)
+		return true;
+	if (value > desired && value - desired < abs_threshold)
+		return true;
+
+	/* Complain if the difference exceeds a certain percentage. */
+	if (value < desired * (d - n) / d)
+		return false;
+	if (value > desired * (d + n) / d)
+		return false;
+
+	return true;
+}
scrub/common.h +4 -0
index 336fc40..29b4332 100644
@@ -79,4 +79,8 @@ char *string_escape(const char *in);
 #define TOO_MANY_NAME_WARNINGS	10000
 bool should_warn_about_name(struct scrub_ctx *ctx);
 
+bool within_range(struct scrub_ctx *ctx, unsigned long long value,
+		unsigned long long desired, unsigned long long abs_threshold,
+		unsigned int n, unsigned int d, const char *descr);
+
 #endif /* XFS_SCRUB_COMMON_H_ */
scrub/phase7.c new file +266 -0

266 lines not on this page · raw message

scrub/xfs_scrub.c +2 -1
index 296b492..f6f5f0d 100644
@@ -389,6 +389,8 @@ run_scrub_phases(
 		},
 		{
 			.descr = _("Check summary counters."),
+			.fn = xfs_scan_summary,
+			.must_run = true,
 		},
 		{
 			NULL
@@ -458,7 +460,6 @@ main(
 	int			ret = SCRUB_RET_SUCCESS;
 
 	fprintf(stdout, "EXPERIMENTAL xfs_scrub program in use! Use at your own risk!\n");
-	return SCRUB_RET_OPERROR;
 
 	progname = basename(argv[0]);
 	setlocale(LC_ALL, "");
scrub/xfs_scrub.h +1 -0
index 997bedd..91f4577 100644
@@ -104,5 +104,6 @@ bool xfs_scan_metadata(struct scrub_ctx *ctx);
 bool xfs_scan_inodes(struct scrub_ctx *ctx);
 bool xfs_scan_connections(struct scrub_ctx *ctx);
 bool xfs_scan_blocks(struct scrub_ctx *ctx);
+bool xfs_scan_summary(struct scrub_ctx *ctx);
 
 #endif /* XFS_SCRUB_XFS_SCRUB_H_ */
#24 lore raw

PATCH 24/29 xfs_scrub: fstrim the free areas if there are no errors on the filesystem

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

If the filesystem scan comes out clean or fixes all the problems, call fstrim to clean out the free areas (if it's an ssd/thinp/whatever).

---
 man/man8/xfs_scrub.8 |    3 ++
 scrub/Makefile       |    1 +
 scrub/phase4.c       |   79 ++++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/vfs.c          |   23 +++++++++++++++
 scrub/vfs.h          |    2 +
 scrub/xfs_scrub.c    |   22 +++++++++++++-
 scrub/xfs_scrub.h    |    3 ++
 7 files changed, 131 insertions(+), 2 deletions(-)
 create mode 100644 scrub/phase4.c
man/man8/xfs_scrub.8 +3 -0
index c9df7d6..b6e1560 100644
@@ -63,6 +63,9 @@ If
 is given, no action is taken if errors are found; this is the default
 behavior.
 .TP
+.B \-k
+Do not call FITRIM on the free space.
+.TP
 .BI \-m " file"
 Search this file for mounted filesystems instead of /etc/mtab.
 .TP
scrub/Makefile +1 -0
index fd26624..91f99ff 100644
@@ -41,6 +41,7 @@ inodes.c \
 phase1.c \
 phase2.c \
 phase3.c \
+phase4.c \
 phase5.c \
 phase6.c \
 phase7.c \
scrub/phase4.c new file +79 -0

79 lines not on this page · raw message

scrub/vfs.c +23 -0
index 3c0c2f3..e3c8e62 100644
@@ -223,3 +223,26 @@ _("Could not queue directory scan work."));
 	free(sftd);
 	return false;
 }
+
+#ifndef FITRIM
+struct fstrim_range {
+	__u64 start;
+	__u64 len;
+	__u64 minlen;
+};
+#define FITRIM		_IOWR('X', 121, struct fstrim_range)	/* Trim */
+#endif
+
+/* Call FITRIM to trim all the unused space in a filesystem. */
+void
+fstrim(
+	struct scrub_ctx	*ctx)
+{
+	struct fstrim_range	range = {0};
+	int			error;
+
+	range.len = ULLONG_MAX;
+	error = ioctl(ctx->mnt_fd, FITRIM, &range);
+	if (error && errno != EOPNOTSUPP && errno != ENOTTY)
+		perror(_("fstrim"));
+}
scrub/vfs.h +2 -0
index 100eb18..3305159 100644
@@ -28,4 +28,6 @@ typedef bool (*scan_fs_tree_dirent_fn)(struct scrub_ctx *, const char *,
 bool scan_fs_tree(struct scrub_ctx *ctx, scan_fs_tree_dir_fn dir_fn,
 		scan_fs_tree_dirent_fn dirent_fn, void *arg);
 
+void fstrim(struct scrub_ctx *ctx);
+
 #endif /* XFS_SCRUB_VFS_H_ */
scrub/xfs_scrub.c +20 -2
index f6f5f0d..85fd893 100644
@@ -146,6 +146,9 @@ static bool			scrub_data;
 /* Size of a memory page. */
 long				page_size;
 
+/* Should we FSTRIM after a successful run? */
+bool				want_fstrim = true;
+
 #define SCRUB_RET_SUCCESS	(0)	/* no problems left behind */
 #define SCRUB_RET_CORRUPT	(1)	/* corruption remains on fs */
 #define SCRUB_RET_UNOPTIMIZED	(2)	/* fs could be optimized */
@@ -161,6 +164,7 @@ usage(void)
 	fprintf(stderr, _("  -a count     Stop after this many errors are found.\n"));
 	fprintf(stderr, _("  -b           Background mode.\n"));
 	fprintf(stderr, _("  -e behavior  What to do if errors are found.\n"));
+	fprintf(stderr, _("  -k           Do not FITRIM the free space.\n"));
 	fprintf(stderr, _("  -m path      Path to /etc/mtab.\n"));
 	fprintf(stderr, _("  -n           Dry run.  Do not modify anything.\n"));
 	fprintf(stderr, _("  -T           Display timing/usage information.\n"));
@@ -408,8 +412,19 @@ run_scrub_phases(
 	/* Run all phases of the scrub tool. */
 	for (phase = 1, sp = phases; sp->fn; sp++, phase++) {
 		/* Turn on certain phases if user said to. */
-		if (sp->fn == DATASCAN_DUMMY_FN && scrub_data)
+		if (sp->fn == DATASCAN_DUMMY_FN && scrub_data) {
 			sp->fn = xfs_scan_blocks;
+		} else if (sp->fn == REPAIR_DUMMY_FN) {
+			if (ctx->mode == SCRUB_MODE_PREEN) {
+				sp->descr = _("Optimize filesystem.");
+				sp->fn = xfs_optimize_fs;
+				sp->must_run = true;
+			} else if (ctx->mode == SCRUB_MODE_REPAIR) {
+				sp->descr = _("Repair filesystem.");
+				sp->fn = xfs_repair_fs;
+				sp->must_run = true;
+			}
+		}
 
 		/* Skip certain phases unless they're turned on. */
 		if (sp->fn == REPAIR_DUMMY_FN ||
@@ -469,7 +484,7 @@ main(
 	pthread_mutex_init(&ctx.lock, NULL);
 	ctx.mode = SCRUB_MODE_DEFAULT;
 	ctx.error_action = ERRORS_CONTINUE;
-	while ((c = getopt(argc, argv, "a:bde:m:nTvxVy")) != EOF) {
+	while ((c = getopt(argc, argv, "a:bde:km:nTvxVy")) != EOF) {
 		switch (c) {
 		case 'a':
 			ctx.max_errors = cvt_u64(optarg, 10);
@@ -497,6 +512,9 @@ main(
 				usage();
 			}
 			break;
+		case 'k':
+			want_fstrim = false;
+			break;
 		case 'm':
 			mtab = optarg;
 			break;
scrub/xfs_scrub.h +3 -0
index 91f4577..47d63de 100644
@@ -28,6 +28,7 @@ extern unsigned int		debug;
 extern int			nproc;
 extern bool			verbose;
 extern long			page_size;
+extern bool			want_fstrim;
 
 enum scrub_mode {
 	SCRUB_MODE_DRY_RUN,
@@ -105,5 +106,7 @@ bool xfs_scan_inodes(struct scrub_ctx *ctx);
 bool xfs_scan_connections(struct scrub_ctx *ctx);
 bool xfs_scan_blocks(struct scrub_ctx *ctx);
 bool xfs_scan_summary(struct scrub_ctx *ctx);
+bool xfs_repair_fs(struct scrub_ctx *ctx);
+bool xfs_optimize_fs(struct scrub_ctx *ctx);
 
 #endif /* XFS_SCRUB_XFS_SCRUB_H_ */
#25 lore raw

PATCH 25/29 xfs_scrub: progress indicator

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Implement a progress indicator.

---
 man/man8/xfs_scrub.8 |   11 ++
 scrub/Makefile       |    6 +
 scrub/common.c       |   12 ++-
 scrub/phase2.c       |   14 +++
 scrub/phase3.c       |   16 ++++
 scrub/phase4.c       |   19 ++++
 scrub/phase5.c       |    2 
 scrub/phase6.c       |   28 ++++++
 scrub/progress.c     |  223 ++++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/progress.h     |   33 +++++++
 scrub/read_verify.c  |    2 
 scrub/scrub.c        |   28 ++++++
 scrub/xfs_scrub.c    |   60 +++++++++++++
 scrub/xfs_scrub.h    |   14 +++
 14 files changed, 460 insertions(+), 8 deletions(-)
 create mode 100644 scrub/progress.c
 create mode 100644 scrub/progress.h
man/man8/xfs_scrub.8 +10 -1
index b6e1560..4c394a5 100644
@@ -4,7 +4,7 @@ xfs_scrub \- scrub the contents of an XFS filesystem
 .SH SYNOPSIS
 .B xfs_scrub
 [
-.B \-abemnTvxy
+.B \-abCemnTvxy
 ]
 .RI "[" mount-point " | " block-device "]"
 .br
@@ -53,6 +53,15 @@ time.
 If given more than once, an artificial delay of 100us is added to each
 scrub call to reduce CPU overhead even further.
 .TP
+.BI \-C " fd"
+This option causes xfs_scrub to write progress information to the
+specified file description so that the progress of the filesystem check
+can be monitored.
+If the file description is a tty, a fancy progress bar is rendered.
+Otherwise, a simple numeric status dump compatible with the
+.B fsck -C
+format is output.
+.TP
 .B \-e
 Specifies what happens when errors are detected.
 If
scrub/Makefile +4 -2
index 91f99ff..39abdf6 100644
@@ -23,6 +23,7 @@ disk.h \
 filemap.h \
 fscounters.h \
 inodes.h \
+progress.h \
 read_verify.h \
 scrub.h \
 spacemap.h \
@@ -45,14 +46,15 @@ phase4.c \
 phase5.c \
 phase6.c \
 phase7.c \
+progress.c \
 read_verify.c \
 scrub.c \
 spacemap.c \
 vfs.c \
 xfs_scrub.c
 
-LLDLIBS += $(LIBHANDLE) $(LIBFROG) $(LIBPTHREAD) $(LIBUNISTRING)
-LTDEPENDENCIES += $(LIBHANDLE) $(LIBFROG) $(LIBUNISTRING)
+LLDLIBS += $(LIBHANDLE) $(LIBFROG) $(LIBPTHREAD) $(LIBUNISTRING) $(LIBRT)
+LTDEPENDENCIES += $(LIBHANDLE) $(LIBFROG) $(LIBUNISTRING) $(LIBRT)
 LLDFLAGS = -static
 
 ifeq ($(HAVE_MALLINFO),yes)
scrub/common.c +11 -1
index c4fb339..18171d1 100644
@@ -27,6 +27,7 @@
 #include "path.h"
 #include "xfs_scrub.h"
 #include "common.h"
+#include "progress.h"
 
 /*
  * Reporting Status to the Console
@@ -61,6 +62,14 @@ static const char *err_str[] = {
 	[S_INFO]	= "Info",
 };
 
+/* If stream is a tty, clear to end of line to clean up progress bar. */
+static inline const char *stream_start(FILE *stream)
+{
+	if (stream == stderr)
+		return stderr_isatty ? CLEAR_EOL : "";
+	return stdout_isatty ? CLEAR_EOL : "";
+}
+
 /* Print a warning string and some warning text. */
 void
 __str_out(
@@ -84,7 +93,8 @@ __str_out(
 		stream = stdout;
 
 	pthread_mutex_lock(&ctx->lock);
-	fprintf(stream, "%s: %s: ", _(err_str[level]), descr);
+	fprintf(stream, "%s%s: %s: ", stream_start(stream), _(err_str[level]),
+			descr);
 	if (error) {
 		fprintf(stream, _("%s."), strerror_r(error, buf, DESCR_BUFSZ));
 	} else {
scrub/phase2.c +14 -0
index 153ae02..e8eb1ca 100644
@@ -131,3 +131,17 @@ _("Could not queue filesystem scrub work."));
 	workqueue_destroy(&wq);
 	return moveon;
 }
+
+/* Estimate how much work we're going to do. */
+bool
+xfs_estimate_metadata_work(
+	struct scrub_ctx	*ctx,
+	uint64_t		*items,
+	unsigned int		*nr_threads,
+	int			*rshift)
+{
+	*items = xfs_scrub_estimate_ag_work(ctx);
+	*nr_threads = scrub_nproc(ctx);
+	*rshift = 0;
+	return true;
+}
scrub/phase3.c +16 -0
index b3fc510..43697c6 100644
@@ -30,6 +30,7 @@
 #include "common.h"
 #include "counter.h"
 #include "inodes.h"
+#include "progress.h"
 #include "scrub.h"
 
 /* Phase 3: Scan all inodes. */
@@ -116,6 +117,7 @@ xfs_scrub_inode(
 
 out:
 	ptcounter_add(icount, 1);
+	progress_add(1);
 	if (fd >= 0)
 		close(fd);
 	if (!moveon)
@@ -150,3 +152,17 @@ xfs_scan_inodes(
 	ptcounter_free(ictx.icount);
 	return ictx.moveon;
 }
+
+/* Estimate how much work we're going to do. */
+bool
+xfs_estimate_inodes_work(
+	struct scrub_ctx	*ctx,
+	uint64_t		*items,
+	unsigned int		*nr_threads,
+	int			*rshift)
+{
+	*items = ctx->mnt_sv.f_files - ctx->mnt_sv.f_ffree;
+	*nr_threads = scrub_nproc(ctx);
+	*rshift = 0;
+	return true;
+}
scrub/phase4.c +18 -1
index 31211f6..3100d75 100644
@@ -31,6 +31,7 @@
 #include "workqueue.h"
 #include "xfs_scrub.h"
 #include "common.h"
+#include "progress.h"
 #include "scrub.h"
 #include "vfs.h"
 
@@ -44,8 +45,10 @@ xfs_process_action_items(
 	bool				moveon = true;
 
 	pthread_mutex_lock(&ctx->lock);
-	if (moveon && ctx->errors_found == 0 && want_fstrim)
+	if (moveon && ctx->errors_found == 0 && want_fstrim) {
 		fstrim(ctx);
+		progress_add(1);
+	}
 	pthread_mutex_unlock(&ctx->lock);
 
 	return moveon;
@@ -77,3 +80,17 @@ _("Errors found, please re-run with -y."));
 
 	return xfs_process_action_items(ctx);
 }
+
+/* Estimate how much work we're going to do. */
+bool
+xfs_estimate_repair_work(
+	struct scrub_ctx	*ctx,
+	uint64_t		*items,
+	unsigned int		*nr_threads,
+	int			*rshift)
+{
+	*items = 1;
+	*nr_threads = 1;
+	*rshift = 0;
+	return true;
+}
scrub/phase5.c +2 -0
index d09a3d0..fc3308b 100644
@@ -34,6 +34,7 @@
 #include "xfs_scrub.h"
 #include "common.h"
 #include "inodes.h"
+#include "progress.h"
 #include "scrub.h"
 #include "unicrash.h"
 
@@ -280,6 +281,7 @@ xfs_scrub_connections(
 	}
 
 out:
+	progress_add(1);
 	if (fd >= 0)
 		close(fd);
 	if (!moveon)
scrub/phase6.c +28 -0
index a558b10..9795bf3 100644
@@ -33,6 +33,7 @@
 #include "bitmap.h"
 #include "disk.h"
 #include "filemap.h"
+#include "fscounters.h"
 #include "inodes.h"
 #include "read_verify.h"
 #include "spacemap.h"
@@ -514,3 +515,30 @@ _("Could not create media verifier."));
 	ptvar_free(ve.rvstate);
 	return moveon;
 }
+
+/* Estimate how much work we're going to do. */
+bool
+xfs_estimate_verify_work(
+	struct scrub_ctx	*ctx,
+	uint64_t		*items,
+	unsigned int		*nr_threads,
+	int			*rshift)
+{
+	unsigned long long	d_blocks;
+	unsigned long long	d_bfree;
+	unsigned long long	r_blocks;
+	unsigned long long	r_bfree;
+	unsigned long long	f_files;
+	unsigned long long	f_free;
+	bool			moveon;
+
+	moveon = xfs_scan_estimate_blocks(ctx, &d_blocks, &d_bfree,
+				&r_blocks, &r_bfree, &f_files, &f_free);
+	if (!moveon)
+		return moveon;
+
+	*items = ((d_blocks - d_bfree) + (r_blocks - r_bfree)) << ctx->blocklog;
+	*nr_threads = disk_heads(ctx->datadev);
+	*rshift = 20;
+	return moveon;
+}
scrub/progress.c new file +223 -0

223 lines not on this page · raw message

scrub/progress.h new file +33 -0
new file mode 100644
index 0000000..29a3e83
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <[email protected]>
+ *
+ * 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.
+ */
+#ifndef XFS_SCRUB_PROGRESS_H_
+#define XFS_SCRUB_PROGRESS_H_
+
+#define CLEAR_EOL	"\033[K"
+#define START_IGNORE	'\001'
+#define END_IGNORE	'\002'
+
+bool progress_init_phase(struct scrub_ctx *ctx, FILE *progress_fp,
+			 unsigned int phase, uint64_t max, int rshift,
+			 unsigned int nr_threads);
+void progress_end_phase(void);
+void progress_add(uint64_t x);
+
+#endif /* XFS_SCRUB_PROGRESS_H_ */
scrub/read_verify.c +2 -0
index 244626d..e816688 100644
@@ -31,6 +31,7 @@
 #include "counter.h"
 #include "disk.h"
 #include "read_verify.h"
+#include "progress.h"
 
 /*
  * Read Verify Pool
@@ -154,6 +155,7 @@ read_verify(
 					errno, rv->io_end_arg);
 		}
 
+		progress_add(len);
 		verified += len;
 		rv->io_start += len;
 		rv->io_length -= len;
scrub/scrub.c +28 -0
index 93a94da..c4b7694 100644
@@ -31,6 +31,7 @@
 #include "path.h"
 #include "xfs_scrub.h"
 #include "common.h"
+#include "progress.h"
 #include "scrub.h"
 #include "xfs_errortag.h"
 
@@ -343,6 +344,7 @@ xfs_scrub_metadata(
 
 		/* Check the item. */
 		fix = xfs_check_metadata(ctx, ctx->mnt_fd, &meta, false);
+		progress_add(1);
 		switch (fix) {
 		case CHECK_ABORT:
 			return false;
@@ -416,6 +418,32 @@ xfs_scrub_fs_metadata(
 	return xfs_scrub_metadata(ctx, ST_FS, 0);
 }
 
+/* How many items do we have to check? */
+unsigned int
+xfs_scrub_estimate_ag_work(
+	struct scrub_ctx		*ctx)
+{
+	const struct scrub_descr	*sc;
+	int				type;
+	unsigned int			estimate = 0;
+
+	sc = scrubbers;
+	for (type = 0; type < XFS_SCRUB_TYPE_NR; type++, sc++) {
+		switch (sc->type) {
+		case ST_AGHEADER:
+		case ST_PERAG:
+			estimate += ctx->geo.agcount;
+			break;
+		case ST_FS:
+			estimate++;
+			break;
+		default:
+			break;
+		}
+	}
+	return estimate;
+}
+
 /* Scrub inode metadata. */
 static bool
 __xfs_scrub_file(
scrub/xfs_scrub.c +57 -3

173 lines not on this page · raw message

scrub/xfs_scrub.h +14 -0
index 47d63de..16cd1aa 100644
@@ -29,6 +29,8 @@ extern int			nproc;
 extern bool			verbose;
 extern long			page_size;
 extern bool			want_fstrim;
+extern bool			stderr_isatty;
+extern bool			stdout_isatty;
 
 enum scrub_mode {
 	SCRUB_MODE_DRY_RUN,
@@ -109,4 +111,16 @@ bool xfs_scan_summary(struct scrub_ctx *ctx);
 bool xfs_repair_fs(struct scrub_ctx *ctx);
 bool xfs_optimize_fs(struct scrub_ctx *ctx);
 
+/* Progress estimator functions */
+uint64_t xfs_estimate_inodes(struct scrub_ctx *ctx);
+unsigned int xfs_scrub_estimate_ag_work(struct scrub_ctx *ctx);
+bool xfs_estimate_metadata_work(struct scrub_ctx *ctx, uint64_t *items,
+				unsigned int *nr_threads, int *rshift);
+bool xfs_estimate_inodes_work(struct scrub_ctx *ctx, uint64_t *items,
+			      unsigned int *nr_threads, int *rshift);
+bool xfs_estimate_repair_work(struct scrub_ctx *ctx, uint64_t *items,
+			      unsigned int *nr_threads, int *rshift);
+bool xfs_estimate_verify_work(struct scrub_ctx *ctx, uint64_t *items,
+			      unsigned int *nr_threads, int *rshift);
+
 #endif /* XFS_SCRUB_XFS_SCRUB_H_ */
#26 lore raw

PATCH 26/29 xfs_scrub: create a script to scrub all xfs filesystems

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Create an xfs_scrub_all command to find all XFS filesystems and run an online scrub against them all.

---
 debian/control           |    3 +
 debian/rules             |    1 
 man/man8/xfs_scrub_all.8 |   32 ++++++++++
 scrub/Makefile           |   15 ++++
 scrub/xfs_scrub_all.in   |  154 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 201 insertions(+), 4 deletions(-)
 create mode 100644 man/man8/xfs_scrub_all.8
 create mode 100644 scrub/xfs_scrub_all.in
debian/control +2 -1
index 36d1bd8..801744b 100644
@@ -3,12 +3,13 @@ Section: admin
 Priority: optional
 Maintainer: XFS Development Team <[email protected]>
 Uploaders: Nathan Scott <[email protected]>, Anibal Monsalve Salazar <[email protected]>
-Build-Depends: uuid-dev, dh-autoreconf, debhelper (>= 5), gettext, libtool, libreadline-gplv2-dev | libreadline5-dev, libblkid-dev (>= 2.17), linux-libc-dev, libdevmapper-dev, libattr1-dev, libunistring-dev
+Build-Depends: uuid-dev, dh-autoreconf, debhelper (>= 5), gettext, libtool, libreadline-gplv2-dev | libreadline5-dev, libblkid-dev (>= 2.17), linux-libc-dev, libdevmapper-dev, libattr1-dev, libunistring-dev, dh-python
 Standards-Version: 3.9.1
 Homepage: https://xfs.wiki.kernel.org/
 
 Package: xfsprogs
 Depends: ${shlibs:Depends}, ${misc:Depends}
+Recommends: ${python3:Depends}, util-linux
 Provides: fsck-backend
 Suggests: xfsdump, acl, attr, quota
 Breaks: xfsdump (<< 3.0.0)
debian/rules +1 -0
index baefdba..abb794e 100755
@@ -76,6 +76,7 @@ binary-arch: checkroot built
 	$(pkgdi)  $(MAKE) -C debian install-d-i
 	$(pkgme)  $(MAKE) dist
 	rmdir debian/xfslibs-dev/usr/share/doc/xfsprogs
+	dh_python3
 	dh_installdocs
 	dh_installchangelogs
 	dh_strip
man/man8/xfs_scrub_all.8 new file +32 -0
new file mode 100644
index 0000000..5e1420b
@@ -0,0 +1,32 @@
+.TH xfs_scrub_all 8
+.SH NAME
+xfs_scrub_all \- scrub all mounted XFS filesystems
+.SH SYNOPSIS
+.B xfs_scrub_all
+.SH DESCRIPTION
+.B xfs_scrub_all
+attempts to read and check all the metadata on all mounted XFS filesystems.
+The online scrub is performed via the
+.B xfs_scrub
+tool, either by running it directly or by using systemd to start it
+in a restricted fashion.
+Mounted filesystems are mapped to physical storage devices so that scrub
+operations can be run in parallel so long as no two scrubbers access
+the same device simultaneously.
+.SH EXIT CODE
+The exit code returned by
+.B xfs_scrub_all
+is the sum of the following conditions:
+.br
+\	0\	\-\ No errors
+.br
+\	4\	\-\ File system errors left uncorrected
+.br
+\	8\	\-\ Operational error
+.br
+\	16\	\-\ Usage or syntax error
+.TP
+These are the same error codes returned by xfs_scrub.
+.br
+.SH SEE ALSO
+.BR xfs_scrub (8).
scrub/Makefile +12 -3
index 39abdf6..ca6dab0 100644
@@ -13,6 +13,8 @@ SCRUB_PREREQS=$(PKG_PLATFORM)$(HAVE_OPENAT)$(HAVE_FSTATAT)
 ifeq ($(SCRUB_PREREQS),linuxyesyes)
 LTCOMMAND = xfs_scrub
 INSTALL_SCRUB = install-scrub
+XFS_SCRUB_ALL_PROG = xfs_scrub_all
+XFS_SCRUB_ARGS = -b -n
 endif	# scrub_prereqs
 
 HFILES = \
@@ -82,17 +84,24 @@ ifeq ($(HAVE_HDIO_GETGEO),yes)
 LCFLAGS += -DHAVE_HDIO_GETGEO
 endif
 
-default: depend $(LTCOMMAND)
+default: depend $(LTCOMMAND) $(XFS_SCRUB_ALL_PROG)
+
+xfs_scrub_all: xfs_scrub_all.in
+	@echo "    [SED]    $@"
+	$(Q)$(SED) -e "s|@sbindir@|$(PKG_ROOT_SBIN_DIR)|g" \
+		   -e "s|@scrub_args@|$(XFS_SCRUB_ARGS)|g" < $< > $@
+	$(Q)chmod a+x $@
 
 phase5.o unicrash.o xfs.o: $(TOPDIR)/include/builddefs
 
 include $(BUILDRULES)
 
-install: default $(INSTALL_SCRUB)
+install: $(INSTALL_SCRUB)
 
-install-scrub:
+install-scrub: default
 	$(INSTALL) -m 755 -d $(PKG_ROOT_SBIN_DIR)
 	$(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_ROOT_SBIN_DIR)
+	$(INSTALL) -m 755 $(XFS_SCRUB_ALL_PROG) $(PKG_ROOT_SBIN_DIR)
 
 install-dev:
 
scrub/xfs_scrub_all.in new file +154 -0

154 lines not on this page · raw message

#27 lore raw

PATCH v2 26/29 xfs_scrub: create a script to scrub all xfs filesystems

From: Darrick J. Wong <[email protected]>
Subject: [PATCH] xfs_scrub: create a script to scrub all xfs filesystems

Create an xfs_scrub_all command to find all XFS filesystems and run an online scrub against them all.

---
v2: fix some of the debian packaging weirdness, kudos to Nathan Scott!

---
 debian/control           |    4 +
 man/man8/xfs_scrub_all.8 |   32 ++++++++++
 scrub/Makefile           |   15 ++++
 scrub/xfs_scrub_all.in   |  154 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 200 insertions(+), 5 deletions(-)
 create mode 100644 man/man8/xfs_scrub_all.8
 create mode 100644 scrub/xfs_scrub_all.in
debian/control +2 -2
index 36d1bd8..a833571 100644
@@ -3,12 +3,12 @@ Section: admin
 Priority: optional
 Maintainer: XFS Development Team <[email protected]>
 Uploaders: Nathan Scott <[email protected]>, Anibal Monsalve Salazar <[email protected]>
-Build-Depends: uuid-dev, dh-autoreconf, debhelper (>= 5), gettext, libtool, libreadline-gplv2-dev | libreadline5-dev, libblkid-dev (>= 2.17), linux-libc-dev, libdevmapper-dev, libattr1-dev, libunistring-dev
+Build-Depends: uuid-dev, dh-autoreconf, debhelper (>= 5), gettext, libtool, libreadline-gplv2-dev | libreadline5-dev, libblkid-dev (>= 2.17), linux-libc-dev, libdevmapper-dev, libattr1-dev, libunistring-dev, dh-python
 Standards-Version: 3.9.1
 Homepage: https://xfs.wiki.kernel.org/
 
 Package: xfsprogs
-Depends: ${shlibs:Depends}, ${misc:Depends}
+Depends: ${shlibs:Depends}, ${misc:Depends}, python3:any
 Provides: fsck-backend
 Suggests: xfsdump, acl, attr, quota
 Breaks: xfsdump (<< 3.0.0)
man/man8/xfs_scrub_all.8 new file +32 -0
new file mode 100644
index 0000000..5e1420b
@@ -0,0 +1,32 @@
+.TH xfs_scrub_all 8
+.SH NAME
+xfs_scrub_all \- scrub all mounted XFS filesystems
+.SH SYNOPSIS
+.B xfs_scrub_all
+.SH DESCRIPTION
+.B xfs_scrub_all
+attempts to read and check all the metadata on all mounted XFS filesystems.
+The online scrub is performed via the
+.B xfs_scrub
+tool, either by running it directly or by using systemd to start it
+in a restricted fashion.
+Mounted filesystems are mapped to physical storage devices so that scrub
+operations can be run in parallel so long as no two scrubbers access
+the same device simultaneously.
+.SH EXIT CODE
+The exit code returned by
+.B xfs_scrub_all
+is the sum of the following conditions:
+.br
+\	0\	\-\ No errors
+.br
+\	4\	\-\ File system errors left uncorrected
+.br
+\	8\	\-\ Operational error
+.br
+\	16\	\-\ Usage or syntax error
+.TP
+These are the same error codes returned by xfs_scrub.
+.br
+.SH SEE ALSO
+.BR xfs_scrub (8).
scrub/Makefile +12 -3
index 39abdf6..ca6dab0 100644
@@ -13,6 +13,8 @@ SCRUB_PREREQS=$(PKG_PLATFORM)$(HAVE_OPENAT)$(HAVE_FSTATAT)
 ifeq ($(SCRUB_PREREQS),linuxyesyes)
 LTCOMMAND = xfs_scrub
 INSTALL_SCRUB = install-scrub
+XFS_SCRUB_ALL_PROG = xfs_scrub_all
+XFS_SCRUB_ARGS = -b -n
 endif	# scrub_prereqs
 
 HFILES = \
@@ -82,17 +84,24 @@ ifeq ($(HAVE_HDIO_GETGEO),yes)
 LCFLAGS += -DHAVE_HDIO_GETGEO
 endif
 
-default: depend $(LTCOMMAND)
+default: depend $(LTCOMMAND) $(XFS_SCRUB_ALL_PROG)
+
+xfs_scrub_all: xfs_scrub_all.in
+	@echo "    [SED]    $@"
+	$(Q)$(SED) -e "s|@sbindir@|$(PKG_ROOT_SBIN_DIR)|g" \
+		   -e "s|@scrub_args@|$(XFS_SCRUB_ARGS)|g" < $< > $@
+	$(Q)chmod a+x $@
 
 phase5.o unicrash.o xfs.o: $(TOPDIR)/include/builddefs
 
 include $(BUILDRULES)
 
-install: default $(INSTALL_SCRUB)
+install: $(INSTALL_SCRUB)
 
-install-scrub:
+install-scrub: default
 	$(INSTALL) -m 755 -d $(PKG_ROOT_SBIN_DIR)
 	$(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_ROOT_SBIN_DIR)
+	$(INSTALL) -m 755 $(XFS_SCRUB_ALL_PROG) $(PKG_ROOT_SBIN_DIR)
 
 install-dev:
 
scrub/xfs_scrub_all.in new file +154 -0

154 lines not on this page · raw message

#28 lore raw

PATCH 27/29 xfs_scrub: integrate services with systemd

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Create a systemd service unit so that we can run the online scrubber under systemd with (somewhat) appropriate containment.

---
 .gitignore                       |    4 ++
 configure.ac                     |    2 +
 debian/postinst                  |    3 ++
 include/builddefs.in             |    4 ++
 m4/Makefile                      |    1 +
 m4/package_services.m4           |   73 ++++++++++++++++++++++++++++++++++++++
 scrub/Makefile                   |   36 ++++++++++++++++++-
 scrub/xfs_scrub.c                |   32 +++++++++++++++++
 scrub/[email protected]      |   19 ++++++++++
 scrub/xfs_scrub_all.cron.in      |    1 +
 scrub/xfs_scrub_all.in           |   49 ++++++++++++++++++++++++++
 scrub/xfs_scrub_all.service.in   |    9 +++++
 scrub/xfs_scrub_all.timer        |   11 ++++++
 scrub/xfs_scrub_fail             |   26 ++++++++++++++
 scrub/[email protected] |   10 +++++
 15 files changed, 279 insertions(+), 1 deletion(-)
 create mode 100644 m4/package_services.m4
 create mode 100644 scrub/[email protected]
 create mode 100644 scrub/xfs_scrub_all.cron.in
 create mode 100644 scrub/xfs_scrub_all.service.in
 create mode 100644 scrub/xfs_scrub_all.timer
 create mode 100755 scrub/xfs_scrub_fail
 create mode 100644 scrub/[email protected]
.gitignore +4 -0
index a3db640..d887451 100644
@@ -69,6 +69,10 @@ cscope.*
 /rtcp/xfs_rtcp
 /spaceman/xfs_spaceman
 /scrub/xfs_scrub
+/scrub/[email protected]
+/scrub/xfs_scrub_all
+/scrub/xfs_scrub_all.service
+/scrub/[email protected]
 
 # generated crc files
 /libxfs/crc32selftest
configure.ac +2 -0
index bb032e5..b438165 100644
@@ -174,6 +174,8 @@ AC_HAVE_OPENAT
 AC_HAVE_FSTATAT
 AC_HAVE_SG_IO
 AC_HAVE_HDIO_GETGEO
+AC_CONFIG_SYSTEMD_SYSTEM_UNIT_DIR
+AC_CONFIG_CROND_DIR
 
 if test "$enable_blkid" = yes; then
 AC_HAVE_BLKID_TOPO
debian/postinst +3 -0
index d11c8d9..11693a6 100644
@@ -8,6 +8,9 @@ case "${1}" in
 		then
 			update-initramfs -u
 		fi
+		if [ -x /bin/systemctl ]; then
+			/bin/systemctl daemon-reload
+		fi
 		;;
 
 	abort-upgrade|abort-remove|abort-deconfigure)
include/builddefs.in +4 -0
index d44faf9..df76b2c 100644
@@ -127,6 +127,10 @@ HAVE_OPENAT = @have_openat@
 HAVE_FSTATAT = @have_fstatat@
 HAVE_SG_IO = @have_sg_io@
 HAVE_HDIO_GETGEO = @have_hdio_getgeo@
+HAVE_SYSTEMD = @have_systemd@
+SYSTEMD_SYSTEM_UNIT_DIR = @systemd_system_unit_dir@
+HAVE_CROND = @have_crond@
+CROND_DIR = @crond_dir@
 
 GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall
 #	   -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-decl
m4/Makefile +1 -0
index 61d617e..a6d11e9 100644
@@ -21,6 +21,7 @@ LSRCFILES = \
 	package_libcdev.m4 \
 	package_pthread.m4 \
 	package_sanitizer.m4 \
+	package_services.m4 \
 	package_types.m4 \
 	package_unistring.m4 \
 	package_utilies.m4 \
m4/package_services.m4 new file +73 -0

73 lines not on this page · raw message

scrub/Makefile +35 -1
index ca6dab0..0632794 100644
@@ -15,6 +15,19 @@ LTCOMMAND = xfs_scrub
 INSTALL_SCRUB = install-scrub
 XFS_SCRUB_ALL_PROG = xfs_scrub_all
 XFS_SCRUB_ARGS = -b -n
+ifeq ($(HAVE_SYSTEMD),yes)
+INSTALL_SCRUB += install-systemd
+SYSTEMD_SERVICES = [email protected] xfs_scrub_all.service xfs_scrub_all.timer [email protected]
+OPTIONAL_TARGETS += $(SYSTEMD_SERVICES)
+endif
+ifeq ($(HAVE_CROND),yes)
+INSTALL_SCRUB += install-crond
+CRONTABS = xfs_scrub_all.cron
+OPTIONAL_TARGETS += $(CRONTABS)
+# Don't enable the crontab by default for now
+CROND_DIR = $(PKG_LIB_DIR)/$(PKG_NAME)
+endif
+
 endif	# scrub_prereqs
 
 HFILES = \
@@ -84,7 +97,7 @@ ifeq ($(HAVE_HDIO_GETGEO),yes)
 LCFLAGS += -DHAVE_HDIO_GETGEO
 endif
 
-default: depend $(LTCOMMAND) $(XFS_SCRUB_ALL_PROG)
+default: depend $(LTCOMMAND) $(XFS_SCRUB_ALL_PROG) $(OPTIONAL_TARGETS)
 
 xfs_scrub_all: xfs_scrub_all.in
 	@echo "    [SED]    $@"
@@ -98,6 +111,27 @@ include $(BUILDRULES)
 
 install: $(INSTALL_SCRUB)
 
+%.service: %.service.in
+	@echo "    [SED]    $@"
+	$(Q)$(SED) -e "s|@sbindir@|$(PKG_ROOT_SBIN_DIR)|g" \
+		   -e "s|@scrub_args@|$(XFS_SCRUB_ARGS)|g" \
+		   -e "s|@pkg_lib_dir@|$(PKG_LIB_DIR)|g" \
+		   -e "s|@pkg_name@|$(PKG_NAME)|g" < $< > $@
+
+%.cron: %.cron.in
+	@echo "    [SED]    $@"
+	$(Q)$(SED) -e "s|@sbindir@|$(PKG_ROOT_SBIN_DIR)|g" < $< > $@
+
+install-systemd: default $(SYSTEMD_SERVICES)
+	$(INSTALL) -m 755 -d $(SYSTEMD_SYSTEM_UNIT_DIR)
+	$(INSTALL) -m 644 $(SYSTEMD_SERVICES) $(SYSTEMD_SYSTEM_UNIT_DIR)
+	$(INSTALL) -m 755 -d $(PKG_LIB_DIR)/$(PKG_NAME)
+	$(INSTALL) -m 755 xfs_scrub_fail $(PKG_LIB_DIR)/$(PKG_NAME)
+
+install-crond: default $(CRONTABS)
+	$(INSTALL) -m 755 -d $(CROND_DIR)
+	$(INSTALL) -m 644 $(CRONTABS) $(CROND_DIR)
+
 install-scrub: default
 	$(INSTALL) -m 755 -d $(PKG_ROOT_SBIN_DIR)
 	$(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_ROOT_SBIN_DIR)
scrub/xfs_scrub.c +32 -0
index 47e1381..5ab557d 100644
@@ -118,6 +118,10 @@
  * XFS_SCRUB_NO_SCSI_VERIFY	-- disable SCSI VERIFY (if present)
  * XFS_SCRUB_PHASE		-- run only this scrub phase
  * XFS_SCRUB_THREADS		-- start exactly this number of threads
+ *
+ * Available even in non-debug mode:
+ * SERVICE_MODE			-- compress all error codes to 1 for LSB
+ *				   service action compliance
  */
 
 /* Program name; needed for libfrog error reports. */
@@ -154,6 +158,12 @@ bool				want_fstrim = true;
 bool				stderr_isatty;
 bool				stdout_isatty;
 
+/*
+ * If we are running as a service, we need to be careful about what
+ * error codes we return to the calling process.
+ */
+static bool			is_service;
+
 #define SCRUB_RET_SUCCESS	(0)	/* no problems left behind */
 #define SCRUB_RET_CORRUPT	(1)	/* corruption remains on fs */
 #define SCRUB_RET_UNOPTIMIZED	(2)	/* fs could be optimized */
@@ -624,6 +634,9 @@ _("Only one of the options -n or -y may be specified.\n"));
 	if (stdout_isatty && !progress_fp)
 		progress_fp = fdopen(1, "w+");
 
+	if (getenv("SERVICE_MODE"))
+		is_service = true;
+
 	/* Find the mount record for the passed-in argument. */
 	if (stat(argv[optind], &ctx.mnt_sb) < 0) {
 		fprintf(stderr,
@@ -729,5 +742,24 @@ _("%s: %llu warnings found.\n"),
 	free(ctx.blkdev);
 	free(ctx.mntpoint);
 
+	/*
+	 * If we're being run as a service, the return code must fit the LSB
+	 * init script action error guidelines, which is to say that we
+	 * compress all errors to 1 ("generic or unspecified error", LSB 5.0
+	 * section 22.2) and hope the admin will scan the log for what
+	 * actually happened.
+	 *
+	 * We have to sleep 2 seconds here because journald uses the pid to
+	 * connect our log messages to the systemd service.  This is critical
+	 * for capturing all the log messages if the scrub fails, because the
+	 * fail service uses the service name to gather log messages for the
+	 * error report.
+	 */
+	if (is_service) {
+		sleep(2);
+		if (ret != SCRUB_RET_SUCCESS)
+			return 1;
+	}
+
 	return ret;
 }
scrub/[email protected] new file +19 -0
new file mode 100644
index 0000000..a868a27
@@ -0,0 +1,19 @@
+[Unit]
+Description=Online XFS Metadata Check for %I
+OnFailure=xfs_scrub_fail@%i.service
+
+[Service]
+Type=oneshot
+WorkingDirectory=%I
+PrivateNetwork=true
+ProtectSystem=full
+ProtectHome=read-only
+PrivateTmp=yes
+AmbientCapabilities=CAP_SYS_ADMIN CAP_FOWNER CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_SYS_RAWIO
+NoNewPrivileges=yes
+User=nobody
+IOSchedulingClass=idle
+CPUSchedulingPolicy=idle
+Environment=SERVICE_MODE=1
+ExecStart=@sbindir@/xfs_scrub @scrub_args@ %I
+SyslogIdentifier=%N
scrub/xfs_scrub_all.cron.in new file +1 -0
new file mode 100644
index 0000000..3dea929
@@ -0,0 +1 @@
+10 3 * * 0 root test -e /run/systemd/system || @sbindir@/xfs_scrub_all
scrub/xfs_scrub_all.in +49 -0

83 lines not on this page · raw message

scrub/xfs_scrub_all.service.in new file +9 -0
new file mode 100644
index 0000000..2831691
@@ -0,0 +1,9 @@
+[Unit]
+Description=Online XFS Metadata Check for All Filesystems
+ConditionACPower=true
+
+[Service]
+Type=oneshot
+Environment=SERVICE_MODE=1
+ExecStart=@sbindir@/xfs_scrub_all
+SyslogIdentifier=xfs_scrub_all
scrub/xfs_scrub_all.timer new file +11 -0
new file mode 100644
index 0000000..2e4a33b
@@ -0,0 +1,11 @@
+[Unit]
+Description=Periodic XFS Online Metadata Check for All Filesystems
+
+[Timer]
+# Run on Sunday at 3:10am, to avoid running afoul of DST changes
+OnCalendar=Sun *-*-* 03:10:00
+RandomizedDelaySec=60
+Persistent=true
+
+[Install]
+WantedBy=timers.target
scrub/xfs_scrub_fail new file +26 -0
new file mode 100755
index 0000000..36dd50e
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# Email logs of failed xfs_scrub unit runs
+
+mailer=/usr/sbin/sendmail
+recipient="$1"
+test -z "${recipient}" && exit 0
+mntpoint="$2"
+test -z "${mntpoint}" && exit 0
+hostname="$(hostname -f 2>/dev/null)"
+test -z "${hostname}" && hostname="${HOSTNAME}"
+if [ ! -x "${mailer}" ]; then
+	echo "${mailer}: Mailer program not found."
+	exit 1
+fi
+
+(cat << ENDL
+To: $1
+From: <xfs_scrub@${hostname}>
+Subject: xfs_scrub failure on ${mntpoint}
+
+So sorry, the automatic xfs_scrub of ${mntpoint} on ${hostname} failed.
+
+A log of what happened follows:
+ENDL
+systemctl status --full --lines 4294967295 "xfs_scrub@${mntpoint}") | "${mailer}" -t -i
scrub/[email protected] new file +10 -0
new file mode 100644
index 0000000..785f881
@@ -0,0 +1,10 @@
+[Unit]
+Description=Online XFS Metadata Check Failure Reporting for %I
+
+[Service]
+Type=oneshot
+Environment=EMAIL_ADDR=root
+ExecStart=@pkg_lib_dir@/@pkg_name@/xfs_scrub_fail "${EMAIL_ADDR}" %I
+User=mail
+Group=mail
+SupplementaryGroups=systemd-journal
#29 lore raw

PATCH v2 27/29 xfs_scrub: integrate services with systemd

From: Darrick J. Wong <[email protected]>

Create a systemd service unit so that we can run the online scrubber under systemd with (somewhat) appropriate containment.

---
v2: fix some of the debian packaging weirdness, kudos to Nathan Scott!

---
 .gitignore                       |    4 ++
 configure.ac                     |    2 +
 debian/postinst                  |    3 ++
 include/builddefs.in             |    4 ++
 m4/Makefile                      |    1 +
 m4/package_services.m4           |   73 ++++++++++++++++++++++++++++++++++++++
 scrub/Makefile                   |   36 ++++++++++++++++++-
 scrub/xfs_scrub.c                |   32 +++++++++++++++++
 scrub/[email protected]      |   20 ++++++++++
 scrub/xfs_scrub_all.cron.in      |    1 +
 scrub/xfs_scrub_all.in           |   49 ++++++++++++++++++++++++++
 scrub/xfs_scrub_all.service.in   |   10 +++++
 scrub/xfs_scrub_all.timer        |   11 ++++++
 scrub/xfs_scrub_fail             |   26 ++++++++++++++
 scrub/[email protected] |   10 +++++
 15 files changed, 281 insertions(+), 1 deletion(-)
 create mode 100644 m4/package_services.m4
 create mode 100644 scrub/[email protected]
 create mode 100644 scrub/xfs_scrub_all.cron.in
 create mode 100644 scrub/xfs_scrub_all.service.in
 create mode 100644 scrub/xfs_scrub_all.timer
 create mode 100755 scrub/xfs_scrub_fail
 create mode 100644 scrub/[email protected]
.gitignore +4 -0
index a3db640..d887451 100644
@@ -69,6 +69,10 @@ cscope.*
 /rtcp/xfs_rtcp
 /spaceman/xfs_spaceman
 /scrub/xfs_scrub
+/scrub/[email protected]
+/scrub/xfs_scrub_all
+/scrub/xfs_scrub_all.service
+/scrub/[email protected]
 
 # generated crc files
 /libxfs/crc32selftest
configure.ac +2 -0
index bb032e5..b438165 100644
@@ -174,6 +174,8 @@ AC_HAVE_OPENAT
 AC_HAVE_FSTATAT
 AC_HAVE_SG_IO
 AC_HAVE_HDIO_GETGEO
+AC_CONFIG_SYSTEMD_SYSTEM_UNIT_DIR
+AC_CONFIG_CROND_DIR
 
 if test "$enable_blkid" = yes; then
 AC_HAVE_BLKID_TOPO
debian/postinst +3 -0
index d11c8d9..11693a6 100644
@@ -8,6 +8,9 @@ case "${1}" in
 		then
 			update-initramfs -u
 		fi
+		if [ -x /bin/systemctl ]; then
+			/bin/systemctl daemon-reload
+		fi
 		;;
 
 	abort-upgrade|abort-remove|abort-deconfigure)
include/builddefs.in +4 -0
index d44faf9..df76b2c 100644
@@ -127,6 +127,10 @@ HAVE_OPENAT = @have_openat@
 HAVE_FSTATAT = @have_fstatat@
 HAVE_SG_IO = @have_sg_io@
 HAVE_HDIO_GETGEO = @have_hdio_getgeo@
+HAVE_SYSTEMD = @have_systemd@
+SYSTEMD_SYSTEM_UNIT_DIR = @systemd_system_unit_dir@
+HAVE_CROND = @have_crond@
+CROND_DIR = @crond_dir@
 
 GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall
 #	   -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-decl
m4/Makefile +1 -0
index 61d617e..a6d11e9 100644
@@ -21,6 +21,7 @@ LSRCFILES = \
 	package_libcdev.m4 \
 	package_pthread.m4 \
 	package_sanitizer.m4 \
+	package_services.m4 \
 	package_types.m4 \
 	package_unistring.m4 \
 	package_utilies.m4 \
m4/package_services.m4 new file +73 -0

73 lines not on this page · raw message

scrub/Makefile +35 -1
index ca6dab0..0632794 100644
@@ -15,6 +15,19 @@ LTCOMMAND = xfs_scrub
 INSTALL_SCRUB = install-scrub
 XFS_SCRUB_ALL_PROG = xfs_scrub_all
 XFS_SCRUB_ARGS = -b -n
+ifeq ($(HAVE_SYSTEMD),yes)
+INSTALL_SCRUB += install-systemd
+SYSTEMD_SERVICES = [email protected] xfs_scrub_all.service xfs_scrub_all.timer [email protected]
+OPTIONAL_TARGETS += $(SYSTEMD_SERVICES)
+endif
+ifeq ($(HAVE_CROND),yes)
+INSTALL_SCRUB += install-crond
+CRONTABS = xfs_scrub_all.cron
+OPTIONAL_TARGETS += $(CRONTABS)
+# Don't enable the crontab by default for now
+CROND_DIR = $(PKG_LIB_DIR)/$(PKG_NAME)
+endif
+
 endif	# scrub_prereqs
 
 HFILES = \
@@ -84,7 +97,7 @@ ifeq ($(HAVE_HDIO_GETGEO),yes)
 LCFLAGS += -DHAVE_HDIO_GETGEO
 endif
 
-default: depend $(LTCOMMAND) $(XFS_SCRUB_ALL_PROG)
+default: depend $(LTCOMMAND) $(XFS_SCRUB_ALL_PROG) $(OPTIONAL_TARGETS)
 
 xfs_scrub_all: xfs_scrub_all.in
 	@echo "    [SED]    $@"
@@ -98,6 +111,27 @@ include $(BUILDRULES)
 
 install: $(INSTALL_SCRUB)
 
+%.service: %.service.in
+	@echo "    [SED]    $@"
+	$(Q)$(SED) -e "s|@sbindir@|$(PKG_ROOT_SBIN_DIR)|g" \
+		   -e "s|@scrub_args@|$(XFS_SCRUB_ARGS)|g" \
+		   -e "s|@pkg_lib_dir@|$(PKG_LIB_DIR)|g" \
+		   -e "s|@pkg_name@|$(PKG_NAME)|g" < $< > $@
+
+%.cron: %.cron.in
+	@echo "    [SED]    $@"
+	$(Q)$(SED) -e "s|@sbindir@|$(PKG_ROOT_SBIN_DIR)|g" < $< > $@
+
+install-systemd: default $(SYSTEMD_SERVICES)
+	$(INSTALL) -m 755 -d $(SYSTEMD_SYSTEM_UNIT_DIR)
+	$(INSTALL) -m 644 $(SYSTEMD_SERVICES) $(SYSTEMD_SYSTEM_UNIT_DIR)
+	$(INSTALL) -m 755 -d $(PKG_LIB_DIR)/$(PKG_NAME)
+	$(INSTALL) -m 755 xfs_scrub_fail $(PKG_LIB_DIR)/$(PKG_NAME)
+
+install-crond: default $(CRONTABS)
+	$(INSTALL) -m 755 -d $(CROND_DIR)
+	$(INSTALL) -m 644 $(CRONTABS) $(CROND_DIR)
+
 install-scrub: default
 	$(INSTALL) -m 755 -d $(PKG_ROOT_SBIN_DIR)
 	$(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_ROOT_SBIN_DIR)
scrub/xfs_scrub.c +32 -0
index 47e1381..5ab557d 100644
@@ -118,6 +118,10 @@
  * XFS_SCRUB_NO_SCSI_VERIFY	-- disable SCSI VERIFY (if present)
  * XFS_SCRUB_PHASE		-- run only this scrub phase
  * XFS_SCRUB_THREADS		-- start exactly this number of threads
+ *
+ * Available even in non-debug mode:
+ * SERVICE_MODE			-- compress all error codes to 1 for LSB
+ *				   service action compliance
  */
 
 /* Program name; needed for libfrog error reports. */
@@ -154,6 +158,12 @@ bool				want_fstrim = true;
 bool				stderr_isatty;
 bool				stdout_isatty;
 
+/*
+ * If we are running as a service, we need to be careful about what
+ * error codes we return to the calling process.
+ */
+static bool			is_service;
+
 #define SCRUB_RET_SUCCESS	(0)	/* no problems left behind */
 #define SCRUB_RET_CORRUPT	(1)	/* corruption remains on fs */
 #define SCRUB_RET_UNOPTIMIZED	(2)	/* fs could be optimized */
@@ -624,6 +634,9 @@ _("Only one of the options -n or -y may be specified.\n"));
 	if (stdout_isatty && !progress_fp)
 		progress_fp = fdopen(1, "w+");
 
+	if (getenv("SERVICE_MODE"))
+		is_service = true;
+
 	/* Find the mount record for the passed-in argument. */
 	if (stat(argv[optind], &ctx.mnt_sb) < 0) {
 		fprintf(stderr,
@@ -729,5 +742,24 @@ _("%s: %llu warnings found.\n"),
 	free(ctx.blkdev);
 	free(ctx.mntpoint);
 
+	/*
+	 * If we're being run as a service, the return code must fit the LSB
+	 * init script action error guidelines, which is to say that we
+	 * compress all errors to 1 ("generic or unspecified error", LSB 5.0
+	 * section 22.2) and hope the admin will scan the log for what
+	 * actually happened.
+	 *
+	 * We have to sleep 2 seconds here because journald uses the pid to
+	 * connect our log messages to the systemd service.  This is critical
+	 * for capturing all the log messages if the scrub fails, because the
+	 * fail service uses the service name to gather log messages for the
+	 * error report.
+	 */
+	if (is_service) {
+		sleep(2);
+		if (ret != SCRUB_RET_SUCCESS)
+			return 1;
+	}
+
 	return ret;
 }
scrub/[email protected] new file +20 -0
new file mode 100644
index 0000000..c14f813
@@ -0,0 +1,20 @@
+[Unit]
+Description=Online XFS Metadata Check for %I
+OnFailure=xfs_scrub_fail@%i.service
+Documentation=man:xfs_scrub(8)
+
+[Service]
+Type=oneshot
+WorkingDirectory=%I
+PrivateNetwork=true
+ProtectSystem=full
+ProtectHome=read-only
+PrivateTmp=yes
+AmbientCapabilities=CAP_SYS_ADMIN CAP_FOWNER CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_SYS_RAWIO
+NoNewPrivileges=yes
+User=nobody
+IOSchedulingClass=idle
+CPUSchedulingPolicy=idle
+Environment=SERVICE_MODE=1
+ExecStart=@sbindir@/xfs_scrub @scrub_args@ %I
+SyslogIdentifier=%N
scrub/xfs_scrub_all.cron.in new file +1 -0
new file mode 100644
index 0000000..3dea929
@@ -0,0 +1 @@
+10 3 * * 0 root test -e /run/systemd/system || @sbindir@/xfs_scrub_all
scrub/xfs_scrub_all.in +49 -0

83 lines not on this page · raw message

scrub/xfs_scrub_all.service.in new file +10 -0
new file mode 100644
index 0000000..66f82fc
@@ -0,0 +1,10 @@
+[Unit]
+Description=Online XFS Metadata Check for All Filesystems
+ConditionACPower=true
+Documentation=man:xfs_scrub_all(8)
+
+[Service]
+Type=oneshot
+Environment=SERVICE_MODE=1
+ExecStart=@sbindir@/xfs_scrub_all
+SyslogIdentifier=xfs_scrub_all
scrub/xfs_scrub_all.timer new file +11 -0
new file mode 100644
index 0000000..2e4a33b
@@ -0,0 +1,11 @@
+[Unit]
+Description=Periodic XFS Online Metadata Check for All Filesystems
+
+[Timer]
+# Run on Sunday at 3:10am, to avoid running afoul of DST changes
+OnCalendar=Sun *-*-* 03:10:00
+RandomizedDelaySec=60
+Persistent=true
+
+[Install]
+WantedBy=timers.target
scrub/xfs_scrub_fail new file +26 -0
new file mode 100755
index 0000000..36dd50e
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# Email logs of failed xfs_scrub unit runs
+
+mailer=/usr/sbin/sendmail
+recipient="$1"
+test -z "${recipient}" && exit 0
+mntpoint="$2"
+test -z "${mntpoint}" && exit 0
+hostname="$(hostname -f 2>/dev/null)"
+test -z "${hostname}" && hostname="${HOSTNAME}"
+if [ ! -x "${mailer}" ]; then
+	echo "${mailer}: Mailer program not found."
+	exit 1
+fi
+
+(cat << ENDL
+To: $1
+From: <xfs_scrub@${hostname}>
+Subject: xfs_scrub failure on ${mntpoint}
+
+So sorry, the automatic xfs_scrub of ${mntpoint} on ${hostname} failed.
+
+A log of what happened follows:
+ENDL
+systemctl status --full --lines 4294967295 "xfs_scrub@${mntpoint}") | "${mailer}" -t -i
scrub/[email protected] new file +10 -0
new file mode 100644
index 0000000..785f881
@@ -0,0 +1,10 @@
+[Unit]
+Description=Online XFS Metadata Check Failure Reporting for %I
+
+[Service]
+Type=oneshot
+Environment=EMAIL_ADDR=root
+ExecStart=@pkg_lib_dir@/@pkg_name@/xfs_scrub_fail "${EMAIL_ADDR}" %I
+User=mail
+Group=mail
+SupplementaryGroups=systemd-journal
#30 lore raw

Re: [PATCH v2 27/29] xfs_scrub: integrate services with systemd

Quoted 8 lines · Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Create a systemd service unit so that we can run the online scrubber under systemd with (somewhat) appropriate containment.

---
v2: fix some of the debian packaging weirdness, kudos to Nathan Scott!

Er, hang on:

checking for SYSTEMD... configure: error: Package requirements (systemd) were not met:

now systemd is a /build/ requirement for xfsprogs? nope nope. :)

This is only used for unit file install targets, right? If systemd is missing, surely those install targets should just be skipped.

Looks like the Makefile DTRT, but the stuff in m4/ should be non-fatal?

(I can't tell what makes this fatal ... I think its' fatal?

Quoted 7 lines

checking for SYSTEMD... configure: error: Package requirements (systemd) were not met:

No package 'systemd' found

Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix.

Quoted 6 lines

Alternatively, you may set the environment variables SYSTEMD_CFLAGS and SYSTEMD_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.

# echo $?
1

looks fatal.)

...

Quoted 10 lines
scrub/Makefile +2 -0
index ca6dab0..0632794 100644
@@ -15,6 +15,19 @@ LTCOMMAND = xfs_scrub
 INSTALL_SCRUB = install-scrub
 XFS_SCRUB_ALL_PROG = xfs_scrub_all
 XFS_SCRUB_ARGS = -b -n
+ifeq ($(HAVE_SYSTEMD),yes)
+INSTALL_SCRUB += install-systemd

scrub/Makefile LTCOMMAND = xfs_scrub · line 29

Quoted 10 lines
scrub/Makefile +10 -0
+SYSTEMD_SERVICES = [email protected] xfs_scrub_all.service xfs_scrub_all.timer [email protected]
+OPTIONAL_TARGETS += $(SYSTEMD_SERVICES)
+endif
+ifeq ($(HAVE_CROND),yes)
+INSTALL_SCRUB += install-crond
+CRONTABS = xfs_scrub_all.cron
+OPTIONAL_TARGETS += $(CRONTABS)
+# Don't enable the crontab by default for now
+CROND_DIR = $(PKG_LIB_DIR)/$(PKG_NAME)
+endif

Wouldn't an else if arrangement make more sense? Why would we install both? I'd have expected "Install systemd if available, else install crond if available, else don't install anything."
... and then the cron job can stop checking for systemd too:

scrub/xfs_scrub_all.in

Quoted 8 lines
scrub/xfs_scrub_all.cron.in new file +1 -0
new file mode 100644
index 0000000..3dea929
@@ -0,0 +1 @@
+10 3 * * 0 root test -e /run/systemd/system || @sbindir@/xfs_scrub_all
scrub/xfs_scrub_all.in +0 -0

unless I'm missing something?

Thanks,
-Eric

#31 lore raw

Re: [PATCH v2 27/29] xfs_scrub: integrate services with systemd

Quoted 14 lines · Eric Sandeen
Quoted 8 lines · Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Create a systemd service unit so that we can run the online scrubber under systemd with (somewhat) appropriate containment.

---
v2: fix some of the debian packaging weirdness, kudos to Nathan Scott!

Er, hang on:

checking for SYSTEMD... configure: error: Package requirements (systemd) were not met:

Quoted 8 lines

now systemd is a /build/ requirement for xfsprogs? nope nope. :)

This is only used for unit file install targets, right? If systemd is missing, surely those install targets should just be skipped.

Looks like the Makefile DTRT, but the stuff in m4/ should be non-fatal?

(I can't tell what makes this fatal ... I think its' fatal?

Yeah, I forgot to hoist the pkg-config bits into the if-true and neutralize the if-not parts of the PKG_CHECK_MODULES call.

--D

Quoted 65 lines
Quoted 8 lines

checking for SYSTEMD... configure: error: Package requirements (systemd) were not met:

No package 'systemd' found

Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix.

Quoted 6 lines

Alternatively, you may set the environment variables SYSTEMD_CFLAGS and SYSTEMD_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.

# echo $?
1

looks fatal.)

...

Quoted 10 lines
scrub/Makefile +2 -0
index ca6dab0..0632794 100644
@@ -15,6 +15,19 @@ LTCOMMAND = xfs_scrub
 INSTALL_SCRUB = install-scrub
 XFS_SCRUB_ALL_PROG = xfs_scrub_all
 XFS_SCRUB_ARGS = -b -n
+ifeq ($(HAVE_SYSTEMD),yes)
+INSTALL_SCRUB += install-systemd

scrub/Makefile LTCOMMAND = xfs_scrub · line 29

Quoted 10 lines
scrub/Makefile +10 -0
+SYSTEMD_SERVICES = [email protected] xfs_scrub_all.service xfs_scrub_all.timer [email protected]
+OPTIONAL_TARGETS += $(SYSTEMD_SERVICES)
+endif
+ifeq ($(HAVE_CROND),yes)
+INSTALL_SCRUB += install-crond
+CRONTABS = xfs_scrub_all.cron
+OPTIONAL_TARGETS += $(CRONTABS)
+# Don't enable the crontab by default for now
+CROND_DIR = $(PKG_LIB_DIR)/$(PKG_NAME)
+endif

Wouldn't an else if arrangement make more sense? Why would we install both? I'd have expected "Install systemd if available, else install crond if available, else don't install anything."
... and then the cron job can stop checking for systemd too:

scrub/xfs_scrub_all.in

Quoted 8 lines
scrub/xfs_scrub_all.cron.in new file +1 -0
new file mode 100644
index 0000000..3dea929
@@ -0,0 +1 @@
+10 3 * * 0 root test -e /run/systemd/system || @sbindir@/xfs_scrub_all
scrub/xfs_scrub_all.in +0 -0

unless I'm missing something?

Thanks,
-Eric
--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#32 lore raw

PATCH v3 27/29 xfs_scrub: integrate services with systemd

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Create a systemd service unit so that we can run the online scrubber under systemd with (somewhat) appropriate containment.

---
v3: fix pkgconfig autoconf thinko
v2: fix some of the debian packaging weirdness, kudos to Nathan Scott!

---
 .gitignore                       |    4 ++
 configure.ac                     |    2 +
 debian/postinst                  |    3 +
 include/builddefs.in             |    4 ++
 m4/Makefile                      |    1 
 m4/package_services.m4           |   77 ++++++++++++++++++++++++++++++++++++++
 scrub/Makefile                   |   36 +++++++++++++++++-
 scrub/xfs_scrub.c                |   32 ++++++++++++++++
 scrub/[email protected]      |   20 ++++++++++
 scrub/xfs_scrub_all.cron.in      |    1 
 scrub/xfs_scrub_all.in           |   49 ++++++++++++++++++++++++
 scrub/xfs_scrub_all.service.in   |   10 +++++
 scrub/xfs_scrub_all.timer        |   11 +++++
 scrub/xfs_scrub_fail             |   26 +++++++++++++
 scrub/[email protected] |   10 +++++
 15 files changed, 285 insertions(+), 1 deletion(-)
 create mode 100644 m4/package_services.m4
 create mode 100644 scrub/[email protected]
 create mode 100644 scrub/xfs_scrub_all.cron.in
 create mode 100644 scrub/xfs_scrub_all.service.in
 create mode 100644 scrub/xfs_scrub_all.timer
 create mode 100755 scrub/xfs_scrub_fail
 create mode 100644 scrub/[email protected]
.gitignore +4 -0
index a3db640..d887451 100644
@@ -69,6 +69,10 @@ cscope.*
 /rtcp/xfs_rtcp
 /spaceman/xfs_spaceman
 /scrub/xfs_scrub
+/scrub/[email protected]
+/scrub/xfs_scrub_all
+/scrub/xfs_scrub_all.service
+/scrub/[email protected]
 
 # generated crc files
 /libxfs/crc32selftest
configure.ac +2 -0
index bb032e5..b438165 100644
@@ -174,6 +174,8 @@ AC_HAVE_OPENAT
 AC_HAVE_FSTATAT
 AC_HAVE_SG_IO
 AC_HAVE_HDIO_GETGEO
+AC_CONFIG_SYSTEMD_SYSTEM_UNIT_DIR
+AC_CONFIG_CROND_DIR
 
 if test "$enable_blkid" = yes; then
 AC_HAVE_BLKID_TOPO
debian/postinst +3 -0
index d11c8d9..11693a6 100644
@@ -8,6 +8,9 @@ case "${1}" in
 		then
 			update-initramfs -u
 		fi
+		if [ -x /bin/systemctl ]; then
+			/bin/systemctl daemon-reload
+		fi
 		;;
 
 	abort-upgrade|abort-remove|abort-deconfigure)
include/builddefs.in +4 -0
index d44faf9..df76b2c 100644
@@ -127,6 +127,10 @@ HAVE_OPENAT = @have_openat@
 HAVE_FSTATAT = @have_fstatat@
 HAVE_SG_IO = @have_sg_io@
 HAVE_HDIO_GETGEO = @have_hdio_getgeo@
+HAVE_SYSTEMD = @have_systemd@
+SYSTEMD_SYSTEM_UNIT_DIR = @systemd_system_unit_dir@
+HAVE_CROND = @have_crond@
+CROND_DIR = @crond_dir@
 
 GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall
 #	   -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-decl
m4/Makefile +1 -0
index 61d617e..a6d11e9 100644
@@ -21,6 +21,7 @@ LSRCFILES = \
 	package_libcdev.m4 \
 	package_pthread.m4 \
 	package_sanitizer.m4 \
+	package_services.m4 \
 	package_types.m4 \
 	package_unistring.m4 \
 	package_utilies.m4 \
m4/package_services.m4 new file +77 -0

77 lines not on this page · raw message

scrub/Makefile +35 -1
index ca6dab0..0632794 100644
@@ -15,6 +15,19 @@ LTCOMMAND = xfs_scrub
 INSTALL_SCRUB = install-scrub
 XFS_SCRUB_ALL_PROG = xfs_scrub_all
 XFS_SCRUB_ARGS = -b -n
+ifeq ($(HAVE_SYSTEMD),yes)
+INSTALL_SCRUB += install-systemd
+SYSTEMD_SERVICES = [email protected] xfs_scrub_all.service xfs_scrub_all.timer [email protected]
+OPTIONAL_TARGETS += $(SYSTEMD_SERVICES)
+endif
+ifeq ($(HAVE_CROND),yes)
+INSTALL_SCRUB += install-crond
+CRONTABS = xfs_scrub_all.cron
+OPTIONAL_TARGETS += $(CRONTABS)
+# Don't enable the crontab by default for now
+CROND_DIR = $(PKG_LIB_DIR)/$(PKG_NAME)
+endif
+
 endif	# scrub_prereqs
 
 HFILES = \
@@ -84,7 +97,7 @@ ifeq ($(HAVE_HDIO_GETGEO),yes)
 LCFLAGS += -DHAVE_HDIO_GETGEO
 endif
 
-default: depend $(LTCOMMAND) $(XFS_SCRUB_ALL_PROG)
+default: depend $(LTCOMMAND) $(XFS_SCRUB_ALL_PROG) $(OPTIONAL_TARGETS)
 
 xfs_scrub_all: xfs_scrub_all.in
 	@echo "    [SED]    $@"
@@ -98,6 +111,27 @@ include $(BUILDRULES)
 
 install: $(INSTALL_SCRUB)
 
+%.service: %.service.in
+	@echo "    [SED]    $@"
+	$(Q)$(SED) -e "s|@sbindir@|$(PKG_ROOT_SBIN_DIR)|g" \
+		   -e "s|@scrub_args@|$(XFS_SCRUB_ARGS)|g" \
+		   -e "s|@pkg_lib_dir@|$(PKG_LIB_DIR)|g" \
+		   -e "s|@pkg_name@|$(PKG_NAME)|g" < $< > $@
+
+%.cron: %.cron.in
+	@echo "    [SED]    $@"
+	$(Q)$(SED) -e "s|@sbindir@|$(PKG_ROOT_SBIN_DIR)|g" < $< > $@
+
+install-systemd: default $(SYSTEMD_SERVICES)
+	$(INSTALL) -m 755 -d $(SYSTEMD_SYSTEM_UNIT_DIR)
+	$(INSTALL) -m 644 $(SYSTEMD_SERVICES) $(SYSTEMD_SYSTEM_UNIT_DIR)
+	$(INSTALL) -m 755 -d $(PKG_LIB_DIR)/$(PKG_NAME)
+	$(INSTALL) -m 755 xfs_scrub_fail $(PKG_LIB_DIR)/$(PKG_NAME)
+
+install-crond: default $(CRONTABS)
+	$(INSTALL) -m 755 -d $(CROND_DIR)
+	$(INSTALL) -m 644 $(CRONTABS) $(CROND_DIR)
+
 install-scrub: default
 	$(INSTALL) -m 755 -d $(PKG_ROOT_SBIN_DIR)
 	$(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_ROOT_SBIN_DIR)
scrub/xfs_scrub.c +32 -0
index 47e1381..5ab557d 100644
@@ -118,6 +118,10 @@
  * XFS_SCRUB_NO_SCSI_VERIFY	-- disable SCSI VERIFY (if present)
  * XFS_SCRUB_PHASE		-- run only this scrub phase
  * XFS_SCRUB_THREADS		-- start exactly this number of threads
+ *
+ * Available even in non-debug mode:
+ * SERVICE_MODE			-- compress all error codes to 1 for LSB
+ *				   service action compliance
  */
 
 /* Program name; needed for libfrog error reports. */
@@ -154,6 +158,12 @@ bool				want_fstrim = true;
 bool				stderr_isatty;
 bool				stdout_isatty;
 
+/*
+ * If we are running as a service, we need to be careful about what
+ * error codes we return to the calling process.
+ */
+static bool			is_service;
+
 #define SCRUB_RET_SUCCESS	(0)	/* no problems left behind */
 #define SCRUB_RET_CORRUPT	(1)	/* corruption remains on fs */
 #define SCRUB_RET_UNOPTIMIZED	(2)	/* fs could be optimized */
@@ -624,6 +634,9 @@ _("Only one of the options -n or -y may be specified.\n"));
 	if (stdout_isatty && !progress_fp)
 		progress_fp = fdopen(1, "w+");
 
+	if (getenv("SERVICE_MODE"))
+		is_service = true;
+
 	/* Find the mount record for the passed-in argument. */
 	if (stat(argv[optind], &ctx.mnt_sb) < 0) {
 		fprintf(stderr,
@@ -729,5 +742,24 @@ _("%s: %llu warnings found.\n"),
 	free(ctx.blkdev);
 	free(ctx.mntpoint);
 
+	/*
+	 * If we're being run as a service, the return code must fit the LSB
+	 * init script action error guidelines, which is to say that we
+	 * compress all errors to 1 ("generic or unspecified error", LSB 5.0
+	 * section 22.2) and hope the admin will scan the log for what
+	 * actually happened.
+	 *
+	 * We have to sleep 2 seconds here because journald uses the pid to
+	 * connect our log messages to the systemd service.  This is critical
+	 * for capturing all the log messages if the scrub fails, because the
+	 * fail service uses the service name to gather log messages for the
+	 * error report.
+	 */
+	if (is_service) {
+		sleep(2);
+		if (ret != SCRUB_RET_SUCCESS)
+			return 1;
+	}
+
 	return ret;
 }
scrub/[email protected] new file +20 -0
new file mode 100644
index 0000000..c14f813
@@ -0,0 +1,20 @@
+[Unit]
+Description=Online XFS Metadata Check for %I
+OnFailure=xfs_scrub_fail@%i.service
+Documentation=man:xfs_scrub(8)
+
+[Service]
+Type=oneshot
+WorkingDirectory=%I
+PrivateNetwork=true
+ProtectSystem=full
+ProtectHome=read-only
+PrivateTmp=yes
+AmbientCapabilities=CAP_SYS_ADMIN CAP_FOWNER CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_SYS_RAWIO
+NoNewPrivileges=yes
+User=nobody
+IOSchedulingClass=idle
+CPUSchedulingPolicy=idle
+Environment=SERVICE_MODE=1
+ExecStart=@sbindir@/xfs_scrub @scrub_args@ %I
+SyslogIdentifier=%N
scrub/xfs_scrub_all.cron.in new file +1 -0
new file mode 100644
index 0000000..3dea929
@@ -0,0 +1 @@
+10 3 * * 0 root test -e /run/systemd/system || @sbindir@/xfs_scrub_all
scrub/xfs_scrub_all.in +49 -0

83 lines not on this page · raw message

scrub/xfs_scrub_all.service.in new file +10 -0
new file mode 100644
index 0000000..66f82fc
@@ -0,0 +1,10 @@
+[Unit]
+Description=Online XFS Metadata Check for All Filesystems
+ConditionACPower=true
+Documentation=man:xfs_scrub_all(8)
+
+[Service]
+Type=oneshot
+Environment=SERVICE_MODE=1
+ExecStart=@sbindir@/xfs_scrub_all
+SyslogIdentifier=xfs_scrub_all
scrub/xfs_scrub_all.timer new file +11 -0
new file mode 100644
index 0000000..2e4a33b
@@ -0,0 +1,11 @@
+[Unit]
+Description=Periodic XFS Online Metadata Check for All Filesystems
+
+[Timer]
+# Run on Sunday at 3:10am, to avoid running afoul of DST changes
+OnCalendar=Sun *-*-* 03:10:00
+RandomizedDelaySec=60
+Persistent=true
+
+[Install]
+WantedBy=timers.target
scrub/xfs_scrub_fail new file +26 -0
new file mode 100755
index 0000000..36dd50e
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# Email logs of failed xfs_scrub unit runs
+
+mailer=/usr/sbin/sendmail
+recipient="$1"
+test -z "${recipient}" && exit 0
+mntpoint="$2"
+test -z "${mntpoint}" && exit 0
+hostname="$(hostname -f 2>/dev/null)"
+test -z "${hostname}" && hostname="${HOSTNAME}"
+if [ ! -x "${mailer}" ]; then
+	echo "${mailer}: Mailer program not found."
+	exit 1
+fi
+
+(cat << ENDL
+To: $1
+From: <xfs_scrub@${hostname}>
+Subject: xfs_scrub failure on ${mntpoint}
+
+So sorry, the automatic xfs_scrub of ${mntpoint} on ${hostname} failed.
+
+A log of what happened follows:
+ENDL
+systemctl status --full --lines 4294967295 "xfs_scrub@${mntpoint}") | "${mailer}" -t -i
scrub/[email protected] new file +10 -0
new file mode 100644
index 0000000..785f881
@@ -0,0 +1,10 @@
+[Unit]
+Description=Online XFS Metadata Check Failure Reporting for %I
+
+[Service]
+Type=oneshot
+Environment=EMAIL_ADDR=root
+ExecStart=@pkg_lib_dir@/@pkg_name@/xfs_scrub_fail "${EMAIL_ADDR}" %I
+User=mail
+Group=mail
+SupplementaryGroups=systemd-journal
#33 lore raw

PATCH 28/29 xfs_scrub: wire up repair ioctl

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Create the mechanism we need to actually call the kernel's online repair functionality. The interface will consume a repair description; the descriptor management will follow in the next patch.

---
 scrub/common.c    |   12 +++++
 scrub/common.h    |    6 ++
 scrub/phase1.c    |   11 ++++
 scrub/phase2.c    |    1 
 scrub/phase3.c    |    1 
 scrub/phase5.c    |    1 
 scrub/scrub.c     |  134 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/scrub.h     |   20 ++++++++
 scrub/xfs_scrub.h |    2 +
 9 files changed, 188 insertions(+)
scrub/common.c +12 -0
index 18171d1..17c3699 100644
@@ -59,7 +59,9 @@ xfs_scrub_excessive_errors(
 static const char *err_str[] = {
 	[S_ERROR]	= "Error",
 	[S_WARN]	= "Warning",
+	[S_REPAIR]	= "Repaired",
 	[S_INFO]	= "Info",
+	[S_PREEN]	= "Optimized",
 };
 
 /* If stream is a tty, clear to end of line to clean up progress bar. */
@@ -93,6 +95,11 @@ __str_out(
 		stream = stdout;
 
 	pthread_mutex_lock(&ctx->lock);
+
+	/* We only want to hear about optimizing when in debug/verbose mode. */
+	if (level == S_PREEN && !debug && !verbose)
+		goto out_record;
+
 	fprintf(stream, "%s%s: %s: ", stream_start(stream), _(err_str[level]),
 			descr);
 	if (error) {
@@ -109,12 +116,17 @@ __str_out(
 	if (stream == stdout)
 		fflush(stream);
 
+out_record:
 	if (error)      /* A syscall failed */
 		ctx->runtime_errors++;
 	else if (level == S_ERROR)
 		ctx->errors_found++;
 	else if (level == S_WARN)
 		ctx->warnings_found++;
+	else if (level == S_REPAIR)
+		ctx->repairs++;
+	else if (level == S_PREEN)
+		ctx->preens++;
 
 	pthread_mutex_unlock(&ctx->lock);
 }
scrub/common.h +6 -0
index 29b4332..287bd4d 100644
@@ -32,7 +32,9 @@ bool xfs_scrub_excessive_errors(struct scrub_ctx *ctx);
 enum error_level {
 	S_ERROR	= 0,
 	S_WARN,
+	S_REPAIR,
 	S_INFO,
+	S_PREEN,
 };
 
 void __str_out(struct scrub_ctx *ctx, const char *descr, enum error_level level,
@@ -46,6 +48,10 @@ void __str_out(struct scrub_ctx *ctx, const char *descr, enum error_level level,
 	__str_out(ctx, str, S_WARN,	0,	__FILE__, __LINE__, __VA_ARGS__)
 #define str_info(ctx, str, ...) \
 	__str_out(ctx, str, S_INFO,	0,	__FILE__, __LINE__, __VA_ARGS__)
+#define record_repair(ctx, str, ...) \
+	__str_out(ctx, str, S_REPAIR,	0,	__FILE__, __LINE__, __VA_ARGS__)
+#define record_preen(ctx, str, ...) \
+	__str_out(ctx, str, S_PREEN,	0,	__FILE__, __LINE__, __VA_ARGS__)
 
 #define dbg_printf(fmt, ...) \
 	do {if (debug > 1) {printf(fmt, __VA_ARGS__);}} while (0)
scrub/phase1.c +11 -0
index 6b986dd..547767b 100644
@@ -179,6 +179,17 @@ _("Kernel metadata scrubbing facility is required."));
 		return false;
 	}
 
+	/* Do we need kernel-assisted metadata repair? */
+	if (ctx->mode != SCRUB_MODE_DRY_RUN && !xfs_can_repair(ctx)) {
+		if (ctx->mode == SCRUB_MODE_PREEN)
+			str_error(ctx, ctx->mntpoint,
+_("Kernel metadata optimization facility is required."));
+		else
+			str_error(ctx, ctx->mntpoint,
+_("Kernel metadata repair facility is required."));
+		return false;
+	}
+
 	/* Go find the XFS devices if we have a usable fsmap. */
 	fs_table_initialise(0, NULL, 0, NULL);
 	errno = 0;
scrub/phase2.c +1 -0
index e8eb1ca..32e2752 100644
@@ -24,6 +24,7 @@
 #include <sys/stat.h>
 #include <sys/statvfs.h>
 #include "xfs.h"
+#include "list.h"
 #include "path.h"
 #include "workqueue.h"
 #include "xfs_scrub.h"
scrub/phase3.c +1 -0
index 43697c6..f4117b0 100644
@@ -24,6 +24,7 @@
 #include <sys/stat.h>
 #include <sys/statvfs.h>
 #include "xfs.h"
+#include "list.h"
 #include "path.h"
 #include "workqueue.h"
 #include "xfs_scrub.h"
scrub/phase5.c +1 -0
index fc3308b..703b279 100644
@@ -29,6 +29,7 @@
 #endif
 #include "xfs.h"
 #include "handle.h"
+#include "list.h"
 #include "path.h"
 #include "workqueue.h"
 #include "xfs_scrub.h"
scrub/scrub.c +134 -0

153 lines not on this page · raw message

scrub/scrub.h +20 -0
index 0b454df..1c44fba 100644
@@ -41,6 +41,7 @@ bool xfs_can_scrub_dir(struct scrub_ctx *ctx);
 bool xfs_can_scrub_attr(struct scrub_ctx *ctx);
 bool xfs_can_scrub_symlink(struct scrub_ctx *ctx);
 bool xfs_can_scrub_parent(struct scrub_ctx *ctx);
+bool xfs_can_repair(struct scrub_ctx *ctx);
 
 bool xfs_scrub_inode_fields(struct scrub_ctx *ctx, uint64_t ino, uint32_t gen,
 		int fd);
@@ -59,4 +60,23 @@ bool xfs_scrub_symlink(struct scrub_ctx *ctx, uint64_t ino, uint32_t gen,
 bool xfs_scrub_parent(struct scrub_ctx *ctx, uint64_t ino, uint32_t gen,
 		int fd);
 
+/* Repair parameters are the scrub inputs and retry count. */
+struct repair_item {
+	struct list_head	list;
+	__u64			ino;
+	__u32			type;
+	__u32			flags;
+	__u32			gen;
+	__u32			agno;
+};
+
+/* Only perform repairs; leave optimization-only actions for later. */
+#define XRM_REPAIR_ONLY		(1U << 0)
+
+/* Complain if still broken even after fix. */
+#define XRM_NOFIX_COMPLAIN	(1U << 1)
+
+enum check_outcome xfs_repair_metadata(struct scrub_ctx *ctx, int fd,
+		struct repair_item *ri, unsigned int repair_flags);
+
 #endif /* XFS_SCRUB_SCRUB_H_ */
scrub/xfs_scrub.h +2 -0
index 16cd1aa..8407885 100644
@@ -95,6 +95,8 @@ struct scrub_ctx {
 	unsigned long long	inodes_checked;
 	unsigned long long	bytes_checked;
 	unsigned long long	naming_warnings;
+	unsigned long long	repairs;
+	unsigned long long	preens;
 	bool			need_repair;
 	bool			preen_triggers[XFS_SCRUB_TYPE_NR];
 };
#34 lore raw

PATCH 29/29 xfs_scrub: schedule and manage optimizations/repairs to the filesystem

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

Teach xfs_scrub to remember scrub requests that failed (or indicated that optimization is a possibility) as action items. Depending on the circumstances, certain items are acted upon immediately (e.g. metadata that needs to be healthy in order to finish the scan, or files that are already open) or deferred until later. Expand the repair phase to deal with the deferred actions.

---
 man/man8/xfs_scrub.8 |   27 ++++-
 scrub/Makefile       |    2 
 scrub/phase1.c       |    7 +
 scrub/phase2.c       |   59 +++++++++-
 scrub/phase3.c       |   42 +++++--
 scrub/phase4.c       |   76 ++++++++++++-
 scrub/repair.c       |  298 ++++++++++++++++++++++++++++++++++++++++++++++++++
 scrub/repair.h       |   55 +++++++++
 scrub/scrub.c        |  123 +++++++++++++++------
 scrub/scrub.h        |   36 ++++--
 scrub/xfs_scrub.c    |   22 ++++
 scrub/xfs_scrub.h    |    1 
 12 files changed, 676 insertions(+), 72 deletions(-)
 create mode 100644 scrub/repair.c
 create mode 100644 scrub/repair.h
man/man8/xfs_scrub.8 +21 -6
index 4c394a5..ce5d876 100644
@@ -114,9 +114,27 @@ Instructing the underlying storage to discard unused extents via the
 .B FITRIM
 ioctl.
 .SH REPAIRS
-This program currently does not support making any repairs.
-Corruptions can only be fixed by unmounting the filesystem and running
-.BR xfs_repair (8).
+Repairs are performed by calling into the kernel.
+This limits the scope of repair activities to rebuilding primary data
+structures from secondary data structures, or secondary structures from
+primary structures.
+The existence of secondary data structures may require features that can
+only be turned on from
+.BR mkfs.xfs (8).
+If errors cannot be repaired, the filesystem must be
+unmounted and
+.BR xfs_repair (8)
+run.
+Repairs supported by the kernel include, but are not limited to:
+.IP \[bu] 2
+Reconstructing extent allocation data from the reverse mapping data.
+.IP \[bu]
+Reconstructing reverse mapping data from primary extent allocation data.
+.IP \[bu]
+Scheduling a quotacheck for the next mount.
+.PP
+If corrupt metadata is successfully repaired, this program will log that
+a repair has succeeded instead of a corruption report.
 .SH EXIT CODE
 The exit code returned by
 .B xfs_scrub
@@ -140,8 +158,5 @@ This program takes advantage of in-kernel scrubbing to verify a given
 data structure with locks held and can keep the filesystem busy for a
 long time.
 The kernel must be new enough to support the SCRUB_METADATA ioctl.
-.PP
-If errors are found and cannot be repaired, the filesystem must be
-unmounted and repaired.
 .SH SEE ALSO
 .BR xfs_repair (8).
scrub/Makefile +2 -0
index 0632794..8075732 100644
@@ -40,6 +40,7 @@ fscounters.h \
 inodes.h \
 progress.h \
 read_verify.h \
+repair.h \
 scrub.h \
 spacemap.h \
 unicrash.h \
@@ -63,6 +64,7 @@ phase6.c \
 phase7.c \
 progress.c \
 read_verify.c \
+repair.c \
 scrub.c \
 spacemap.c \
 vfs.c \
scrub/phase1.c +7 -0
index 547767b..80931e3 100644
@@ -47,6 +47,7 @@
 #include "common.h"
 #include "disk.h"
 #include "scrub.h"
+#include "repair.h"
 
 /* Phase 1: Find filesystem geometry (and clean up after) */
 
@@ -68,6 +69,7 @@ bool
 xfs_cleanup_fs(
 	struct scrub_ctx	*ctx)
 {
+	xfs_action_lists_free(&ctx->action_lists);
 	if (ctx->fshandle)
 		free_handle(ctx->fshandle, ctx->fshandle_len);
 	if (ctx->rtdev)
@@ -157,6 +159,11 @@ _("Does not appear to be an XFS filesystem!"));
 		return false;
 	}
 
+	if (!xfs_action_lists_alloc(ctx->geo.agcount, &ctx->action_lists)) {
+		str_error(ctx, ctx->mntpoint, _("Not enough memory."));
+		return false;
+	}
+
 	ctx->agblklog = log2_roundup(ctx->geo.agblocks);
 	ctx->blocklog = highbit32(ctx->geo.blocksize);
 	ctx->inodelog = highbit32(ctx->geo.inodesize);
scrub/phase2.c +55 -4

109 lines not on this page · raw message

scrub/phase3.c +31 -11

103 lines not on this page · raw message

scrub/phase4.c +74 -2

98 lines not on this page · raw message

scrub/repair.c new file +298 -0

298 lines not on this page · raw message

scrub/repair.h new file +55 -0

55 lines not on this page · raw message

scrub/scrub.c +88 -35

269 lines not on this page · raw message

scrub/scrub.h +22 -14
index 1c44fba..a719571 100644
@@ -28,11 +28,19 @@ enum check_outcome {
 	CHECK_RETRY,	/* repair failed, try again later */
 };
 
+struct action_item;
+
 void xfs_scrub_report_preen_triggers(struct scrub_ctx *ctx);
-bool xfs_scrub_primary_super(struct scrub_ctx *ctx);
-bool xfs_scrub_ag_headers(struct scrub_ctx *ctx, xfs_agnumber_t agno);
-bool xfs_scrub_ag_metadata(struct scrub_ctx *ctx, xfs_agnumber_t agno);
-bool xfs_scrub_fs_metadata(struct scrub_ctx *ctx);
+bool xfs_scrub_primary_super(struct scrub_ctx *ctx,
+		struct xfs_action_list *alist);
+bool xfs_scrub_ag_headers(struct scrub_ctx *ctx, xfs_agnumber_t agno,
+		struct xfs_action_list *alist);
+bool xfs_scrub_ag_metadata(struct scrub_ctx *ctx, xfs_agnumber_t agno,
+		struct xfs_action_list *alist);
+bool xfs_scrub_fs_metadata(struct scrub_ctx *ctx,
+		struct xfs_action_list *alist);
+enum check_outcome xfs_repair_metadata(struct scrub_ctx *ctx, int fd,
+		struct action_item *aitem, unsigned int flags);
 
 bool xfs_can_scrub_fs_metadata(struct scrub_ctx *ctx);
 bool xfs_can_scrub_inode(struct scrub_ctx *ctx);
@@ -44,24 +52,24 @@ bool xfs_can_scrub_parent(struct scrub_ctx *ctx);
 bool xfs_can_repair(struct scrub_ctx *ctx);
 
 bool xfs_scrub_inode_fields(struct scrub_ctx *ctx, uint64_t ino, uint32_t gen,
-		int fd);
+		int fd, struct xfs_action_list *alist);
 bool xfs_scrub_data_fork(struct scrub_ctx *ctx, uint64_t ino, uint32_t gen,
-		int fd);
+		int fd, struct xfs_action_list *alist);
 bool xfs_scrub_attr_fork(struct scrub_ctx *ctx, uint64_t ino, uint32_t gen,
-		int fd);
+		int fd, struct xfs_action_list *alist);
 bool xfs_scrub_cow_fork(struct scrub_ctx *ctx, uint64_t ino, uint32_t gen,
-		int fd);
+		int fd, struct xfs_action_list *alist);
 bool xfs_scrub_dir(struct scrub_ctx *ctx, uint64_t ino, uint32_t gen,
-		int fd);
+		int fd, struct xfs_action_list *alist);
 bool xfs_scrub_attr(struct scrub_ctx *ctx, uint64_t ino, uint32_t gen,
-		int fd);
+		int fd, struct xfs_action_list *alist);
 bool xfs_scrub_symlink(struct scrub_ctx *ctx, uint64_t ino, uint32_t gen,
-		int fd);
+		int fd, struct xfs_action_list *alist);
 bool xfs_scrub_parent(struct scrub_ctx *ctx, uint64_t ino, uint32_t gen,
-		int fd);
+		int fd, struct xfs_action_list *alist);
 
 /* Repair parameters are the scrub inputs and retry count. */
-struct repair_item {
+struct action_item {
 	struct list_head	list;
 	__u64			ino;
 	__u32			type;
@@ -77,6 +85,6 @@ struct repair_item {
 #define XRM_NOFIX_COMPLAIN	(1U << 1)
 
 enum check_outcome xfs_repair_metadata(struct scrub_ctx *ctx, int fd,
-		struct repair_item *ri, unsigned int repair_flags);
+		struct action_item *aitem, unsigned int repair_flags);
 
 #endif /* XFS_SCRUB_SCRUB_H_ */
scrub/xfs_scrub.c +22 -0
index 5ab557d..c83f4a2 100644
@@ -88,6 +88,15 @@
  * the previous two phases are retried here; if there are uncorrectable
  * errors, xfs_scrub stops here.
  *
+ * To perform the actual repairs (or optimizations), we iterate all the
+ * items on the per-AG action item list and ask the kernel to repair
+ * them.  Items which are successfully repaired are removed from the
+ * list.  If an item is not acted upon successfully (or the kernel asks us
+ * to try again), we retry the actions until there is nothing left to
+ * fix or we fail to make forward progress.  In that event, the
+ * unfinished items are recorded as errors.  If there are no errors at
+ * this point, we call FSTRIM on the filesystem.
+ *
  * The next phase is the "check directory tree" phase.  In this phase,
  * every directory is opened (via file handle) to confirm that each
  * directory is connected to the root.  Directory entries are checked
@@ -711,6 +720,19 @@ _("%s: Not a XFS mount point or block device.\n"),
 		ctx.runtime_errors++;
 
 out:
+	if (ctx.repairs && ctx.preens)
+		fprintf(stdout,
+_("%s: %llu repairs and %llu optimizations made.\n"),
+			ctx.mntpoint, ctx.repairs, ctx.preens);
+	else if (ctx.repairs && ctx.preens == 0)
+		fprintf(stdout,
+_("%s: %llu repairs made.\n"),
+			ctx.mntpoint, ctx.repairs);
+	else if (ctx.repairs == 0 && ctx.preens)
+		fprintf(stdout,
+_("%s: %llu optimizations made.\n"),
+			ctx.mntpoint, ctx.preens);
+
 	total_errors = ctx.errors_found + ctx.runtime_errors;
 	if (ctx.need_repair)
 		repairstr = _("  Unmount and run xfs_repair.");
scrub/xfs_scrub.h +1 -0
index 8407885..8c75f69 100644
@@ -88,6 +88,7 @@ struct scrub_ctx {
 
 	/* Mutable scrub state; use lock. */
 	pthread_mutex_t		lock;
+	struct xfs_action_list	*action_lists;
 	unsigned long long	max_errors;
 	unsigned long long	runtime_errors;
 	unsigned long long	errors_found;
#35 lore raw

[PATCH 30/29] debian/control: remove nonexistent libreadline5-dev build dependency

In reply to Darrick J. Wong

From: Darrick J. Wong <[email protected]>

libreadline5-dev hasn't existed as a package for quite some time now; even Debian "oldoldstable" doesn't know what that is. Drop it in favor of libreadline-gplv2-dev.

---
 debian/control |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
debian/control +1 -1
index a833571..60fcc46 100644
@@ -3,7 +3,7 @@ Section: admin
 Priority: optional
 Maintainer: XFS Development Team <[email protected]>
 Uploaders: Nathan Scott <[email protected]>, Anibal Monsalve Salazar <[email protected]>
-Build-Depends: uuid-dev, dh-autoreconf, debhelper (>= 5), gettext, libtool, libreadline-gplv2-dev | libreadline5-dev, libblkid-dev (>= 2.17), linux-libc-dev, libdevmapper-dev, libattr1-dev, libunistring-dev, dh-python
+Build-Depends: uuid-dev, dh-autoreconf, debhelper (>= 5), gettext, libtool, libreadline-gplv2-dev, libblkid-dev (>= 2.17), linux-libc-dev, libdevmapper-dev, libattr1-dev, libunistring-dev, dh-python
 Standards-Version: 3.9.1
 Homepage: https://xfs.wiki.kernel.org/
 
#36 lore raw

[PATCH 31/29] xfs_scrub: handle scrub-only kernels more helpfully

If xfs_scrub is run today against a 4.15 kernel, it fails with

EXPERIMENTAL xfs_scrub program in use! Use at your own risk!
Error: /home: Kernel metadata optimization facility is required.
Info: /home: Scrub aborted after phase 1.
/home: 2 errors found.

Be a bit kinder to the user and suggest a path forward. By the time we fail for missing preen or repair functionality, we do know that scrub is available, so suggest it.

Further, rather than stating what is required, state what was not found ... we're failing, so state what was missing, vs. what is required - seems a bit more definitive.

---

scrub/phase1.c +3 -3
index 547767b..e78ac7d 100644
@@ -175,7 +175,7 @@ _("Does not appear to be an XFS filesystem!"));
 	    !xfs_can_scrub_attr(ctx) || !xfs_can_scrub_symlink(ctx) ||
 	    !xfs_can_scrub_parent(ctx)) {
 		str_error(ctx, ctx->mntpoint,
-_("Kernel metadata scrubbing facility is required."));
+_("Kernel metadata scrubbing facility not available."));
 		return false;
 	}
 
@@ -183,10 +183,10 @@ _("Kernel metadata scrubbing facility is required."));
 	if (ctx->mode != SCRUB_MODE_DRY_RUN && !xfs_can_repair(ctx)) {
 		if (ctx->mode == SCRUB_MODE_PREEN)
 			str_error(ctx, ctx->mntpoint,
-_("Kernel metadata optimization facility is required."));
+_("Kernel metadata optimization facility not available.  Please use -n."));
 		else
 			str_error(ctx, ctx->mntpoint,
-_("Kernel metadata repair facility is required."));
+_("Kernel metadata repair facility not not available. Please use -n."));
 		return false;
 	}
 
#37 lore raw

Re: [PATCH 31/29] xfs_scrub: handle scrub-only kernels more helpfully

Quoted 23 lines · Eric Sandeen

If xfs_scrub is run today against a 4.15 kernel, it fails with

EXPERIMENTAL xfs_scrub program in use! Use at your own risk!
Error: /home: Kernel metadata optimization facility is required.
Info: /home: Scrub aborted after phase 1.
/home: 2 errors found.

Be a bit kinder to the user and suggest a path forward. By the time we fail for missing preen or repair functionality, we do know that scrub is available, so suggest it.

Further, rather than stating what is required, state what was not found ... we're failing, so state what was missing, vs. what is required - seems a bit more definitive.

---

scrub/phase1.c +0 -0
index 547767b..e78ac7d 100644

scrub/phase1.c _("Does not appear to be an XFS filesystem!")); · line 178

Quoted 5 lines
scrub/phase1.c +1 -1
@@ -175,7 +175,7 @@ _("Does not appear to be an XFS filesystem!"));
 	    !xfs_can_scrub_attr(ctx) || !xfs_can_scrub_symlink(ctx) ||
 	    !xfs_can_scrub_parent(ctx)) {
 		str_error(ctx, ctx->mntpoint,
-_("Kernel metadata scrubbing facility is required."));
+_("Kernel metadata scrubbing facility not available."));

"is not available"?

scrub/phase1.c _("Kernel metadata scrubbing facility is required.")); · line 186

Quoted 9 lines
scrub/phase1.c +1 -1
 		return false;
 	}
 
@@ -183,10 +183,10 @@ _("Kernel metadata scrubbing facility is required."));
 	if (ctx->mode != SCRUB_MODE_DRY_RUN && !xfs_can_repair(ctx)) {
 		if (ctx->mode == SCRUB_MODE_PREEN)
 			str_error(ctx, ctx->mntpoint,
-_("Kernel metadata optimization facility is required."));
+_("Kernel metadata optimization facility not available.  Please use -n."));

I approve of s/is required/is not available/, but I have trouble with the bare suggestion of running with -n. We're telling users that the strategy they asked for (e.g. -y) is not available, so the only realistic option is to choose a different strategy (i.e. -n). I don't want them to get the impression that -n is some magic fixit for -y not working (but maybe sysadmins are smarter than that?)

"Kernel metadata repair faciility not available. You can request a metadata check with -n."

scrub/phase1.c _("Kernel metadata scrubbing facility is required.")); · line 189

Quoted 4 lines
scrub/phase1.c +1 -1
 		else
 			str_error(ctx, ctx->mntpoint,
-_("Kernel metadata repair facility is required."));
+_("Kernel metadata repair facility not not available. Please use -n."));

not not available? So it is? :)

--D

Quoted 9 lines
scrub/phase1.c +0 -1
 		return false;
 	}
 
 
 
--

To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#38 lore raw

[PATCH 31/29 v2] xfs_scrub: handle scrub-only kernels more helpfully

In reply to Eric Sandeen

If xfs_scrub is run today against a 4.15 kernel, it fails with

EXPERIMENTAL xfs_scrub program in use! Use at your own risk!
Error: /home: Kernel metadata optimization facility is required.
Info: /home: Scrub aborted after phase 1.
/home: 2 errors found.

Be a bit kinder to the user and suggest a path forward. By the time we fail for missing preen or repair functionality, we do know that scrub is available, so suggest it.

Further, rather than stating what is required, state what was not found ... we're failing, so state what was missing, vs. what is required - seems a bit more definitive.

---

V2: change verbiage to make it more better and not not not confusing.

scrub/phase1.c +3 -3
index 547767b..9128429 100644
@@ -175,7 +175,7 @@ _("Does not appear to be an XFS filesystem!"));
 	    !xfs_can_scrub_attr(ctx) || !xfs_can_scrub_symlink(ctx) ||
 	    !xfs_can_scrub_parent(ctx)) {
 		str_error(ctx, ctx->mntpoint,
-_("Kernel metadata scrubbing facility is required."));
+_("Kernel metadata scrubbing facility is not available."));
 		return false;
 	}
 
@@ -183,10 +183,10 @@ _("Kernel metadata scrubbing facility is required."));
 	if (ctx->mode != SCRUB_MODE_DRY_RUN && !xfs_can_repair(ctx)) {
 		if (ctx->mode == SCRUB_MODE_PREEN)
 			str_error(ctx, ctx->mntpoint,
-_("Kernel metadata optimization facility is required."));
+_("Kernel metadata optimization facility is not available.  Use -n to scrub."));
 		else
 			str_error(ctx, ctx->mntpoint,
-_("Kernel metadata repair facility is required."));
+_("Kernel metadata repair facility is not available.  Use -n to scrub."));
 		return false;
 	}
 
Reviewed-by
#39 lore raw

Re: [PATCH 31/29 v2] xfs_scrub: handle scrub-only kernels more helpfully

Quoted 13 lines · Eric Sandeen

If xfs_scrub is run today against a 4.15 kernel, it fails with

EXPERIMENTAL xfs_scrub program in use! Use at your own risk!
Error: /home: Kernel metadata optimization facility is required.
Info: /home: Scrub aborted after phase 1.
/home: 2 errors found.

Be a bit kinder to the user and suggest a path forward. By the time we fail for missing preen or repair functionality, we do know that scrub is available, so suggest it.

Quoted 5 lines

Further, rather than stating what is required, state what was not found ... we're failing, so state what was missing, vs. what is required - seems a bit more definitive.

looks good.

Quoted 36 lines

---

V2: change verbiage to make it more better and not not not confusing.

scrub/phase1.c +3 -4
index 547767b..9128429 100644
@@ -175,7 +175,7 @@ _("Does not appear to be an XFS filesystem!"));
 	    !xfs_can_scrub_attr(ctx) || !xfs_can_scrub_symlink(ctx) ||
 	    !xfs_can_scrub_parent(ctx)) {
 		str_error(ctx, ctx->mntpoint,
-_("Kernel metadata scrubbing facility is required."));
+_("Kernel metadata scrubbing facility is not available."));
 		return false;
 	}
 
@@ -183,10 +183,10 @@ _("Kernel metadata scrubbing facility is required."));
 	if (ctx->mode != SCRUB_MODE_DRY_RUN && !xfs_can_repair(ctx)) {
 		if (ctx->mode == SCRUB_MODE_PREEN)
 			str_error(ctx, ctx->mntpoint,
-_("Kernel metadata optimization facility is required."));
+_("Kernel metadata optimization facility is not available.  Use -n to scrub."));
 		else
 			str_error(ctx, ctx->mntpoint,
-_("Kernel metadata repair facility is required."));
+_("Kernel metadata repair facility is not available.  Use -n to scrub."));
 		return false;
 	}
 
 
 
--

To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

author Reviewed-by
#40 lore raw

Re: [PATCH 31/29 v2] xfs_scrub: handle scrub-only kernels more helpfully

In reply to Eric Sandeen
Quoted 13 lines · Eric Sandeen

If xfs_scrub is run today against a 4.15 kernel, it fails with

EXPERIMENTAL xfs_scrub program in use! Use at your own risk!
Error: /home: Kernel metadata optimization facility is required.
Info: /home: Scrub aborted after phase 1.
/home: 2 errors found.

Be a bit kinder to the user and suggest a path forward. By the time we fail for missing preen or repair functionality, we do know that scrub is available, so suggest it.

Quoted 5 lines

Further, rather than stating what is required, state what was not found ... we're failing, so state what was missing, vs. what is required - seems a bit more definitive.

Looks ok,

Quoted 36 lines

---

V2: change verbiage to make it more better and not not not confusing.

scrub/phase1.c +3 -4
index 547767b..9128429 100644
@@ -175,7 +175,7 @@ _("Does not appear to be an XFS filesystem!"));
 	    !xfs_can_scrub_attr(ctx) || !xfs_can_scrub_symlink(ctx) ||
 	    !xfs_can_scrub_parent(ctx)) {
 		str_error(ctx, ctx->mntpoint,
-_("Kernel metadata scrubbing facility is required."));
+_("Kernel metadata scrubbing facility is not available."));
 		return false;
 	}
 
@@ -183,10 +183,10 @@ _("Kernel metadata scrubbing facility is required."));
 	if (ctx->mode != SCRUB_MODE_DRY_RUN && !xfs_can_repair(ctx)) {
 		if (ctx->mode == SCRUB_MODE_PREEN)
 			str_error(ctx, ctx->mntpoint,
-_("Kernel metadata optimization facility is required."));
+_("Kernel metadata optimization facility is not available.  Use -n to scrub."));
 		else
 			str_error(ctx, ctx->mntpoint,
-_("Kernel metadata repair facility is required."));
+_("Kernel metadata repair facility is not available.  Use -n to scrub."));
 		return false;
 	}
 
 
 
--

To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html