From patchwork Fri Dec 30 22:18:38 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13085182 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DEDFDC4332F for ; Sat, 31 Dec 2022 00:37:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235807AbiLaAh3 (ORCPT ); Fri, 30 Dec 2022 19:37:29 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34678 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235750AbiLaAh2 (ORCPT ); Fri, 30 Dec 2022 19:37:28 -0500 Received: from sin.source.kernel.org (sin.source.kernel.org [145.40.73.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 026091EAC0 for ; Fri, 30 Dec 2022 16:37:27 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sin.source.kernel.org (Postfix) with ESMTPS id 71701CE1ABD for ; Sat, 31 Dec 2022 00:37:25 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7D3E2C433EF; Sat, 31 Dec 2022 00:37:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1672447043; bh=r29if4Ljae8OPUh65xNYDgnCQ04CQ46UN1Goty8J5Cg=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=eypipV32RQf7jsg9okKxDrmA7CfLsg1Mskm/ZYCce6etT1+LavZiXJkFYLKg9z3mw HLgUpOKXiSCe7qBbznMr4vbQOGdM9aLLb9ff7nk7CL/H1MXSApJmzcXuwOW0A+GRK1 npra2va9BnWdswXzjf7qZONO5rlLzNVEJg6p2MTbFeNcywM3g3PDnWqGzKQ4vdt4Yf 18sWCbGQGjMse+udBe3cS6FTLwVOvZOzUVxYf/ytgUOPOdttYsv+aNMyN/eai84XE+ seMwxxexmn7aLXFJPprc+d4V2gUSPqdjn6duf9TNV2MdDYWf21ZfBQ8ISXyOwMM15C lJMeB6Xk1QsIg== Subject: [PATCH 1/4] xfs_scrub_all: support metadata+media scans of all filesystems From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Date: Fri, 30 Dec 2022 14:18:38 -0800 Message-ID: <167243871808.718563.8496649193632369381.stgit@magnolia> In-Reply-To: <167243871794.718563.17643569431631339696.stgit@magnolia> References: <167243871794.718563.17643569431631339696.stgit@magnolia> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Darrick J. Wong Add the necessary systemd services and control bits so that xfs_scrub_all can kick off a metadata+media scan of a filesystem. Signed-off-by: Darrick J. Wong --- man/man8/xfs_scrub_all.8 | 5 +- scrub/Makefile | 2 + scrub/xfs_scrub_all.in | 27 ++++++++-- scrub/xfs_scrub_fail | 13 +++-- scrub/xfs_scrub_fail@.service.in | 2 - scrub/xfs_scrub_media@.service.in | 90 ++++++++++++++++++++++++++++++++ scrub/xfs_scrub_media_fail@.service.in | 76 +++++++++++++++++++++++++++ 7 files changed, 204 insertions(+), 11 deletions(-) create mode 100644 scrub/xfs_scrub_media@.service.in create mode 100644 scrub/xfs_scrub_media_fail@.service.in diff --git a/man/man8/xfs_scrub_all.8 b/man/man8/xfs_scrub_all.8 index 74548802eda..86a9b3eced2 100644 --- a/man/man8/xfs_scrub_all.8 +++ b/man/man8/xfs_scrub_all.8 @@ -4,7 +4,7 @@ xfs_scrub_all \- scrub all mounted XFS filesystems .SH SYNOPSIS .B xfs_scrub_all [ -.B \-hV +.B \-hxV ] .SH DESCRIPTION .B xfs_scrub_all @@ -21,6 +21,9 @@ the same device simultaneously. .B \-h Display help. .TP +.B \-x +Read all file data extents to look for disk errors. +.TP .B \-V Prints the version number and exits. .SH EXIT CODE diff --git a/scrub/Makefile b/scrub/Makefile index 1c36621b400..f65148e5469 100644 --- a/scrub/Makefile +++ b/scrub/Makefile @@ -18,6 +18,8 @@ INSTALL_SCRUB += install-systemd SYSTEMD_SERVICES=\ xfs_scrub@.service \ xfs_scrub_fail@.service \ + xfs_scrub_media@.service \ + xfs_scrub_media_fail@.service \ xfs_scrub_all.service \ xfs_scrub_all.timer \ system-xfs_scrub.slice diff --git a/scrub/xfs_scrub_all.in b/scrub/xfs_scrub_all.in index 3e0c48acb39..eeb52b651b5 100644 --- a/scrub/xfs_scrub_all.in +++ b/scrub/xfs_scrub_all.in @@ -18,6 +18,7 @@ from io import TextIOWrapper retcode = 0 terminate = False +scrub_media = False def DEVNULL(): '''Return /dev/null in subprocess writable format.''' @@ -111,6 +112,17 @@ def systemd_escape(path): except: return path +def scrub_unitname(mnt): + '''Return the systemd service name.''' + global scrub_media + + if mnt != '*': + mnt = systemd_escape(mnt) + + if scrub_media: + return 'xfs_scrub_media@%s' % mnt + return 'xfs_scrub@%s' % mnt + def systemctl_stop(unitname): '''Stop a systemd unit.''' cmd = ['systemctl', 'stop', unitname] @@ -163,7 +175,7 @@ def systemctl_start(unitname, killfuncs): def run_scrub(mnt, cond, running_devs, mntdevs, killfuncs): '''Run a scrub process.''' - global retcode, terminate + global retcode, terminate, scrub_media print("Scrubbing %s..." % mnt) sys.stdout.flush() @@ -173,7 +185,7 @@ def run_scrub(mnt, cond, running_devs, mntdevs, killfuncs): return # Try it the systemd way - unitname = 'xfs_scrub@%s' % systemd_escape(mnt) + unitname = scrub_unitname(mnt) ret = systemctl_start(unitname, killfuncs) if ret == 0 or ret == 1: print("Scrubbing %s done, (err=%d)" % (mnt, ret)) @@ -187,6 +199,8 @@ def run_scrub(mnt, cond, running_devs, mntdevs, killfuncs): # Invoke xfs_scrub manually cmd = ['@sbindir@/xfs_scrub'] cmd += '@scrub_args@'.split() + if scrub_media: + cmd += '-x' cmd += [mnt] ret = run_killable(cmd, None, killfuncs, \ lambda proc: proc.terminate()) @@ -213,26 +227,31 @@ def main(): a = (mnt, cond, running_devs, devs, killfuncs) thr = threading.Thread(target = run_scrub, args = a) thr.start() - global retcode, terminate + global retcode, terminate, scrub_media parser = argparse.ArgumentParser( \ description = "Scrub all mounted XFS filesystems.") parser.add_argument("-V", help = "Report version and exit.", \ action = "store_true") + parser.add_argument("-x", help = "Scrub file data after filesystem metadata.", \ + action = "store_true") args = parser.parse_args() if args.V: print("xfs_scrub_all version @pkg_version@") sys.exit(0) + scrub_media = args.x + fs = find_mounts() # Tail the journal if we ourselves aren't a service... journalthread = None if 'SERVICE_MODE' not in os.environ: try: + unitname = scrub_unitname('*') cmd=['journalctl', '--no-pager', '-q', '-S', 'now', \ - '-f', '-u', 'xfs_scrub@*', '-o', \ + '-f', '-u', unitname, '-o', \ 'cat'] journalthread = subprocess.Popen(cmd) except: diff --git a/scrub/xfs_scrub_fail b/scrub/xfs_scrub_fail index fbe30cbc4c6..58c50abe963 100755 --- a/scrub/xfs_scrub_fail +++ b/scrub/xfs_scrub_fail @@ -9,8 +9,11 @@ recipient="$1" test -z "${recipient}" && exit 0 -mntpoint="$2" +service="$2" +test -z "${service}" && exit 0 +mntpoint="$3" test -z "${mntpoint}" && exit 0 + hostname="$(hostname -f 2>/dev/null)" test -z "${hostname}" && hostname="${HOSTNAME}" @@ -48,12 +51,12 @@ mntpoint_esc="$(escape_path "${mntpoint}")" (cat << ENDL To: $1 -From: -Subject: xfs_scrub failure on ${mntpoint} +From: <${service}@${hostname}> +Subject: ${service} failure on ${mntpoint} -So sorry, the automatic xfs_scrub of ${mntpoint} on ${hostname} failed. +So sorry, the automatic ${service} of ${mntpoint} on ${hostname} failed. A log of what happened follows: ENDL -systemctl status --full --lines 4294967295 "xfs_scrub@${mntpoint_esc}") | "${mailer}" -t -i +systemctl status --full --lines 4294967295 "${service}@${mntpoint_esc}") | "${mailer}" -t -i exit "${PIPESTATUS[1]}" diff --git a/scrub/xfs_scrub_fail@.service.in b/scrub/xfs_scrub_fail@.service.in index 2c36c47ab02..cba194bad2d 100644 --- a/scrub/xfs_scrub_fail@.service.in +++ b/scrub/xfs_scrub_fail@.service.in @@ -10,7 +10,7 @@ Documentation=man:xfs_scrub(8) [Service] Type=oneshot Environment=EMAIL_ADDR=root -ExecStart=@pkg_lib_dir@/@pkg_name@/xfs_scrub_fail "${EMAIL_ADDR}" %I +ExecStart=@pkg_lib_dir@/@pkg_name@/xfs_scrub_fail "${EMAIL_ADDR}" xfs_scrub %I User=mail Group=mail SupplementaryGroups=systemd-journal diff --git a/scrub/xfs_scrub_media@.service.in b/scrub/xfs_scrub_media@.service.in new file mode 100644 index 00000000000..d2b991856df --- /dev/null +++ b/scrub/xfs_scrub_media@.service.in @@ -0,0 +1,90 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2022 Oracle. All Rights Reserved. +# Author: Darrick J. Wong + +[Unit] +Description=Online XFS Metadata and Media Check for %I +OnFailure=xfs_scrub_media_fail@%i.service +Documentation=man:xfs_scrub(8) + +[Service] +Type=oneshot +Environment=SERVICE_MODE=1 +Environment=SERVICE_MOUNTPOINT=/tmp/scrub +ExecStart=@sbindir@/xfs_scrub @scrub_args@ -x %I +SyslogIdentifier=%N + +# Run scrub with minimal CPU and IO priority so that nothing else will starve. +IOSchedulingClass=idle +CPUSchedulingPolicy=idle +CPUAccounting=true +Nice=19 + +# Create the service underneath the scrub background service slice so that we +# can control resource usage. +Slice=system-xfs_scrub.slice + +# No realtime CPU scheduling +RestrictRealtime=true + +# Dynamically create a user that isn't root +DynamicUser=true + +# Make the entire filesystem readonly and /home inaccessible, then bind mount +# the filesystem we're supposed to be checking into our private /tmp dir. +# 'norbind' means that we don't bind anything under that original mount. +ProtectSystem=strict +ProtectHome=yes +PrivateTmp=true +BindPaths=/%I:/tmp/scrub:norbind + +# Don't let scrub complain about paths in /etc/projects that have been hidden +# by our sandboxing. scrub doesn't care about project ids anyway. +InaccessiblePaths=-/etc/projects + +# No network access +PrivateNetwork=true +ProtectHostname=true +RestrictAddressFamilies=none +IPAddressDeny=any + +# Don't let the program mess with the kernel configuration at all +ProtectKernelLogs=true +ProtectKernelModules=true +ProtectKernelTunables=true +ProtectControlGroups=true +ProtectProc=invisible +RestrictNamespaces=true + +# Hide everything in /proc, even /proc/mounts +ProcSubset=pid + +# Only allow the default personality Linux +LockPersonality=true + +# No writable memory pages +MemoryDenyWriteExecute=true + +# Don't let our mounts leak out to the host +PrivateMounts=true + +# Restrict system calls to the native arch and only enough to get things going +SystemCallArchitectures=native +SystemCallFilter=@system-service +SystemCallFilter=~@privileged +SystemCallFilter=~@resources +SystemCallFilter=~@mount + +# xfs_scrub needs these privileges to run, and no others +CapabilityBoundingSet=CAP_SYS_ADMIN CAP_FOWNER CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_SYS_RAWIO +AmbientCapabilities=CAP_SYS_ADMIN CAP_FOWNER CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_SYS_RAWIO +NoNewPrivileges=true + +# xfs_scrub doesn't create files +UMask=7777 + +# No access to hardware /dev files except for block devices +ProtectClock=true +DevicePolicy=closed +DeviceAllow=block-* diff --git a/scrub/xfs_scrub_media_fail@.service.in b/scrub/xfs_scrub_media_fail@.service.in new file mode 100644 index 00000000000..e6c45e72f20 --- /dev/null +++ b/scrub/xfs_scrub_media_fail@.service.in @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2022 Oracle. All Rights Reserved. +# Author: Darrick J. Wong + +[Unit] +Description=Online XFS Metadata and Media Check Failure Reporting for %I +Documentation=man:xfs_scrub(8) + +[Service] +Type=oneshot +Environment=EMAIL_ADDR=root +ExecStart=@pkg_lib_dir@/@pkg_name@/xfs_scrub_fail "${EMAIL_ADDR}" xfs_scrub_media %I +User=mail +Group=mail +SupplementaryGroups=systemd-journal + +# Create the service underneath the scrub background service slice so that we +# can control resource usage. +Slice=system-xfs_scrub.slice + +# No realtime scheduling +RestrictRealtime=true + +# Make the entire filesystem readonly and /home inaccessible, then bind mount +# the filesystem we're supposed to be checking into our private /tmp dir. +ProtectSystem=full +ProtectHome=yes +PrivateTmp=true +RestrictSUIDSGID=true + +# Emailing reports requires network access, but not the ability to change the +# hostname. +ProtectHostname=true + +# Don't let the program mess with the kernel configuration at all +ProtectKernelLogs=true +ProtectKernelModules=true +ProtectKernelTunables=true +ProtectControlGroups=true +ProtectProc=invisible +RestrictNamespaces=true + +# Can't hide /proc because journalctl needs it to find various pieces of log +# information +#ProcSubset=pid + +# Only allow the default personality Linux +LockPersonality=true + +# No writable memory pages +MemoryDenyWriteExecute=true + +# Don't let our mounts leak out to the host +PrivateMounts=true + +# Restrict system calls to the native arch and only enough to get things going +SystemCallArchitectures=native +SystemCallFilter=@system-service +SystemCallFilter=~@privileged +SystemCallFilter=~@resources +SystemCallFilter=~@mount + +# xfs_scrub needs these privileges to run, and no others +CapabilityBoundingSet= +NoNewPrivileges=true + +# Failure reporting shouldn't create world-readable files +UMask=0077 + +# Clean up any IPC objects when this unit stops +RemoveIPC=true + +# No access to hardware device files +PrivateDevices=true +ProtectClock=true From patchwork Fri Dec 30 22:18:38 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13085183 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7D2C7C4332F for ; Sat, 31 Dec 2022 00:37:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235813AbiLaAhl (ORCPT ); Fri, 30 Dec 2022 19:37:41 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34686 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235750AbiLaAhl (ORCPT ); Fri, 30 Dec 2022 19:37:41 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2EF241E3EE for ; Fri, 30 Dec 2022 16:37:40 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id AA25F61CDB for ; Sat, 31 Dec 2022 00:37:39 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 10C25C433D2; Sat, 31 Dec 2022 00:37:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1672447059; bh=4nZtJ11DLX5lc564XkimLUgmbiYzY0OZB272KCDex0c=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=rVA2f348snv3MagUkzQIns38ypDhRQnJghBBj78YqirjQL99j1lGgp1RMQ5viJ69I RZA2fU11CJDxtPfjVCV1YH3KKUJDfC2rQq0VKPcG0G6m7bEGKbhyeGUzHE2R6YIOh3 AObn+ygNH8m+lucOqh6wxw6hK4gcK2X8YyNUTKGRgoolENKorsNmORl4tQY9V7EHoR Mi5AHEZGDweHeOFXLS8MZFH/DHzP4R+59tb28CRcjfQD+L4mJO1h3S+/CV+U1PF7tL h6JT2n0N0ZpD/mNk0HpQqSsYt2tKAeyEv3sEhrJwScZDLR3+WfXhtFuPHqUaurCuzM QoX9ms+PYoJOw== Subject: [PATCH 2/4] xfs_scrub_all: enable periodic file data scrubs automatically From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Date: Fri, 30 Dec 2022 14:18:38 -0800 Message-ID: <167243871819.718563.17339870560556373949.stgit@magnolia> In-Reply-To: <167243871794.718563.17643569431631339696.stgit@magnolia> References: <167243871794.718563.17643569431631339696.stgit@magnolia> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Darrick J. Wong Enhance xfs_scrub_all with the ability to initiate a file data scrub periodically. The user must specify the period, and they may optionally specify the path to a file that will record the last time the file data was scrubbed. Signed-off-by: Darrick J. Wong --- debian/rules | 3 +- include/builddefs.in | 3 ++ man/man8/Makefile | 7 +++- man/man8/xfs_scrub_all.8.in | 15 ++++++++ scrub/Makefile | 3 ++ scrub/xfs_scrub_all.in | 74 +++++++++++++++++++++++++++++++++++++++- scrub/xfs_scrub_all.service.in | 6 ++- 7 files changed, 106 insertions(+), 5 deletions(-) rename man/man8/{xfs_scrub_all.8 => xfs_scrub_all.8.in} (63%) diff --git a/debian/rules b/debian/rules index 57baad625c5..97fbbbfa1ab 100755 --- a/debian/rules +++ b/debian/rules @@ -34,7 +34,8 @@ configure_options = \ --disable-ubsan \ --disable-addrsan \ --disable-threadsan \ - --enable-lto + --enable-lto \ + --localstatedir=/var options = export DEBUG=-DNDEBUG DISTRIBUTION=debian \ INSTALL_USER=root INSTALL_GROUP=root \ diff --git a/include/builddefs.in b/include/builddefs.in index c0de6000c2a..50ebb9f75d8 100644 --- a/include/builddefs.in +++ b/include/builddefs.in @@ -59,6 +59,9 @@ PKG_DOC_DIR = @datadir@/doc/@pkg_name@ PKG_LOCALE_DIR = @datadir@/locale PKG_DATA_DIR = @datadir@/@pkg_name@ MKFS_CFG_DIR = @datadir@/@pkg_name@/mkfs +PKG_STATE_DIR = @localstatedir@/lib/@pkg_name@ + +XFS_SCRUB_ALL_AUTO_MEDIA_SCAN_STAMP=$(PKG_STATE_DIR)/xfs_scrub_all_media.stamp CC = @cc@ BUILD_CC = @BUILD_CC@ diff --git a/man/man8/Makefile b/man/man8/Makefile index 272e45aebc2..5be76ab727a 100644 --- a/man/man8/Makefile +++ b/man/man8/Makefile @@ -11,11 +11,12 @@ ifneq ("$(ENABLE_SCRUB)","yes") MAN_PAGES = $(filter-out xfs_scrub%,$(shell echo *.$(MAN_SECTION))) else MAN_PAGES = $(shell echo *.$(MAN_SECTION)) + MAN_PAGES += xfs_scrub_all.8 endif MAN_PAGES += mkfs.xfs.8 MAN_DEST = $(PKG_MAN_DIR)/man$(MAN_SECTION) LSRCFILES = $(MAN_PAGES) -DIRT = mkfs.xfs.8 +DIRT = mkfs.xfs.8 xfs_scrub_all.8 default : $(MAN_PAGES) @@ -29,4 +30,8 @@ mkfs.xfs.8: mkfs.xfs.8.in @echo " [SED] $@" $(Q)$(SED) -e 's|@mkfs_cfg_dir@|$(MKFS_CFG_DIR)|g' < $^ > $@ +xfs_scrub_all.8: xfs_scrub_all.8.in + @echo " [SED] $@" + $(Q)$(SED) -e 's|@stampfile@|$(XFS_SCRUB_ALL_AUTO_MEDIA_SCAN_STAMP)|g' < $^ > $@ + install-dev : diff --git a/man/man8/xfs_scrub_all.8 b/man/man8/xfs_scrub_all.8.in similarity index 63% rename from man/man8/xfs_scrub_all.8 rename to man/man8/xfs_scrub_all.8.in index 86a9b3eced2..0aa87e23716 100644 --- a/man/man8/xfs_scrub_all.8 +++ b/man/man8/xfs_scrub_all.8.in @@ -18,6 +18,21 @@ operations can be run in parallel so long as no two scrubbers access the same device simultaneously. .SH OPTIONS .TP +.B \--auto-media-scan-interval +Automatically enable the file data scan (i.e. the +.B -x +flag) if it has not been run in the specified interval. +The interval must be a floating point number with an optional unit suffix. +Supported unit suffixes are +.IR y ", " q ", " mo ", " w ", " d ", " h ", " m ", and " s +for years, 90-day quarters, 30-day months, weeks, days, hours, minutes, and +seconds, respectively. +If no units are specified, the default is seconds. +.TP +.B \--auto-media-scan-stamp +Path to a file that will record the last time the media scan was run. +Defaults to @stampfile@. +.TP .B \-h Display help. .TP diff --git a/scrub/Makefile b/scrub/Makefile index f65148e5469..f773995dcd7 100644 --- a/scrub/Makefile +++ b/scrub/Makefile @@ -118,6 +118,7 @@ xfs_scrub_all: xfs_scrub_all.in $(builddefs) @echo " [SED] $@" $(Q)$(SED) -e "s|@sbindir@|$(PKG_SBIN_DIR)|g" \ -e "s|@pkg_version@|$(PKG_VERSION)|g" \ + -e "s|@stampfile@|$(XFS_SCRUB_ALL_AUTO_MEDIA_SCAN_STAMP)|g" \ -e "s|@scrub_args@|$(XFS_SCRUB_ARGS)|g" < $< > $@ $(Q)chmod a+x $@ @@ -132,6 +133,7 @@ install: $(INSTALL_SCRUB) $(Q)$(SED) -e "s|@sbindir@|$(PKG_SBIN_DIR)|g" \ -e "s|@scrub_args@|$(XFS_SCRUB_ARGS)|g" \ -e "s|@pkg_lib_dir@|$(PKG_LIB_SCRIPT_DIR)|g" \ + -e "s|@pkg_state_dir@|$(PKG_STATE_DIR)|g" \ -e "s|@pkg_name@|$(PKG_NAME)|g" \ < $< > $@ @@ -153,6 +155,7 @@ install-scrub: default $(INSTALL) -m 755 -d $(PKG_SBIN_DIR) $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_SBIN_DIR) $(INSTALL) -m 755 $(XFS_SCRUB_ALL_PROG) $(PKG_SBIN_DIR) + $(INSTALL) -m 755 -d $(PKG_STATE_DIR) install-dev: diff --git a/scrub/xfs_scrub_all.in b/scrub/xfs_scrub_all.in index eeb52b651b5..db307f78ebb 100644 --- a/scrub/xfs_scrub_all.in +++ b/scrub/xfs_scrub_all.in @@ -15,6 +15,10 @@ import sys import os import argparse from io import TextIOWrapper +from pathlib import Path +from datetime import timedelta +from datetime import datetime +from datetime import timezone retcode = 0 terminate = False @@ -221,6 +225,63 @@ def run_scrub(mnt, cond, running_devs, mntdevs, killfuncs): cond.notify() cond.release() +def scan_interval(string): + '''Convert a textual scan interval argument into a time delta.''' + + if string.endswith('y'): + year = timedelta(seconds = 31556952) + return year * float(string[:-1]) + if string.endswith('q'): + return timedelta(days = 90 * float(string[:-1])) + if string.endswith('mo'): + return timedelta(days = 30 * float(string[:-2])) + if string.endswith('w'): + return timedelta(weeks = float(string[:-1])) + if string.endswith('d'): + return timedelta(days = float(string[:-1])) + if string.endswith('h'): + return timedelta(hours = float(string[:-1])) + if string.endswith('m'): + return timedelta(minutes = float(string[:-1])) + if string.endswith('s'): + return timedelta(seconds = float(string[:-1])) + return timedelta(seconds = int(string)) + +def utcnow(): + '''Create a representation of the time right now, in UTC.''' + + dt = datetime.utcnow() + return dt.replace(tzinfo = timezone.utc) + +def enable_automatic_media_scan(args): + '''Decide if we enable media scanning automatically.''' + already_enabled = args.x + + try: + interval = scan_interval(args.auto_media_scan_interval) + except Exception as e: + raise Exception(f"{args.auto_media_scan_interval}: Invalid media scan interval.") + + p = Path(args.auto_media_scan_stamp) + if already_enabled: + res = True + else: + try: + last_run = p.stat().st_mtime + now = utcnow().timestamp() + res = last_run + interval.total_seconds() < now + except FileNotFoundError: + res = True + + if res: + # Truncate the stamp file to update its mtime + with p.open('w') as f: + pass + if not already_enabled: + print('Automatically enabling file data scrub.') + + return res + def main(): '''Find mounts, schedule scrub runs.''' def thr(mnt, devs): @@ -235,13 +296,24 @@ def main(): action = "store_true") parser.add_argument("-x", help = "Scrub file data after filesystem metadata.", \ action = "store_true") + parser.add_argument("--auto-media-scan-interval", help = "Automatically scrub file data at this interval.", \ + default = None) + parser.add_argument("--auto-media-scan-stamp", help = "Stamp file for automatic file data scrub.", \ + default = '@stampfile@') args = parser.parse_args() if args.V: print("xfs_scrub_all version @pkg_version@") sys.exit(0) - scrub_media = args.x + if args.auto_media_scan_interval is not None: + try: + scrub_media = enable_automatic_media_scan(args) + except Exception as e: + print(e) + sys.exit(16) + else: + scrub_media = args.x fs = find_mounts() diff --git a/scrub/xfs_scrub_all.service.in b/scrub/xfs_scrub_all.service.in index c1c6012b47d..4938404ee95 100644 --- a/scrub/xfs_scrub_all.service.in +++ b/scrub/xfs_scrub_all.service.in @@ -34,11 +34,13 @@ CapabilityBoundingSet= NoNewPrivileges=true RestrictSUIDSGID=true -# Make the entire filesystem readonly. We don't want to hide anything because -# we need to find all mounted XFS filesystems in the host. +# Make the entire filesystem readonly except for the media scan stamp file +# directory. We don't want to hide anything because we need to find all +# mounted XFS filesystems in the host. ProtectSystem=strict ProtectHome=read-only PrivateTmp=false +BindPaths=@pkg_state_dir@ # No network access except to the systemd control socket PrivateNetwork=true From patchwork Fri Dec 30 22:18:38 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13085184 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 59470C4332F for ; Sat, 31 Dec 2022 00:38:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235817AbiLaAh7 (ORCPT ); Fri, 30 Dec 2022 19:37:59 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34712 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235750AbiLaAh6 (ORCPT ); Fri, 30 Dec 2022 19:37:58 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 385281E3EE for ; Fri, 30 Dec 2022 16:37:57 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id DFE8FB81E07 for ; Sat, 31 Dec 2022 00:37:55 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id A4349C433EF; Sat, 31 Dec 2022 00:37:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1672447074; bh=OYF411aDwhrerbL/KzsHSyKtmRfHsiezEiuWUEIq9Uw=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=Cr3ORys/t3AE0r/+6wxCauYI/V+PVuqMubClgJ25MrXqmp2lzXyMPDl7D9hWpAm1L dDsEwHLEnrtv1GxftlsfIhVbnaWWPcuANaXQC67B0sNrwG/7OdmxdGZjOP7uOi1PKQ UOX6z4BK2Ji2fJKaE7iD39Fpz7aBIAxIp5K6ugVelqz3dys0kMyKX+ZseHV+MfKjrn gY5erF7JHD9k57R3OjszrtB4q7ZwaiS9sQBWU3xnYKm5o76IHqF4BQYzmAWtAdcseh ixwSebIERttQy5TZ2tHfMkOI4/7DmLoyIyspBG9FtAXo9obsJqmOjXSx6dp2jQVURs ClwMG2G0xFr+Q== Subject: [PATCH 3/4] xfs_scrub_all: trigger automatic media scans once per month From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Date: Fri, 30 Dec 2022 14:18:38 -0800 Message-ID: <167243871831.718563.8824972404105654601.stgit@magnolia> In-Reply-To: <167243871794.718563.17643569431631339696.stgit@magnolia> References: <167243871794.718563.17643569431631339696.stgit@magnolia> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Darrick J. Wong Teach the xfs_scrub_all background service to trigger an automatic scan of all file data once per month. Signed-off-by: Darrick J. Wong --- scrub/Makefile | 8 +++++++- scrub/xfs_scrub_all.cron.in | 2 +- scrub/xfs_scrub_all.service.in | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/scrub/Makefile b/scrub/Makefile index f773995dcd7..7434ac0ce4e 100644 --- a/scrub/Makefile +++ b/scrub/Makefile @@ -110,6 +110,9 @@ ifeq ($(HAVE_HDIO_GETGEO),yes) LCFLAGS += -DHAVE_HDIO_GETGEO endif +# Automatically trigger a media scan once per month +XFS_SCRUB_ALL_AUTO_MEDIA_SCAN_INTERVAL=1mo + LDIRT = $(XFS_SCRUB_ALL_PROG) *.service *.cron default: depend $(LTCOMMAND) $(XFS_SCRUB_ALL_PROG) $(OPTIONAL_TARGETS) @@ -135,11 +138,14 @@ install: $(INSTALL_SCRUB) -e "s|@pkg_lib_dir@|$(PKG_LIB_SCRIPT_DIR)|g" \ -e "s|@pkg_state_dir@|$(PKG_STATE_DIR)|g" \ -e "s|@pkg_name@|$(PKG_NAME)|g" \ + -e "s|@media_scan_interval@|$(XFS_SCRUB_ALL_AUTO_MEDIA_SCAN_INTERVAL)|g" \ < $< > $@ %.cron: %.cron.in $(builddefs) @echo " [SED] $@" - $(Q)$(SED) -e "s|@sbindir@|$(PKG_SBIN_DIR)|g" < $< > $@ + $(Q)$(SED) -e "s|@sbindir@|$(PKG_SBIN_DIR)|g" \ + -e "s|@media_scan_interval@|$(XFS_SCRUB_ALL_AUTO_MEDIA_SCAN_INTERVAL)|g" \ + < $< > $@ install-systemd: default $(SYSTEMD_SERVICES) $(INSTALL) -m 755 -d $(SYSTEMD_SYSTEM_UNIT_DIR) diff --git a/scrub/xfs_scrub_all.cron.in b/scrub/xfs_scrub_all.cron.in index 0ef97cc0ca8..d55d2ad2d89 100644 --- a/scrub/xfs_scrub_all.cron.in +++ b/scrub/xfs_scrub_all.cron.in @@ -3,4 +3,4 @@ # Copyright (C) 2018 Oracle. All Rights Reserved. # Author: Darrick J. Wong # -10 3 * * 0 root test -e /run/systemd/system || @sbindir@/xfs_scrub_all +10 3 * * 0 root test -e /run/systemd/system || @sbindir@/xfs_scrub_all --auto-media-scan-interval @media_scan_interval@ diff --git a/scrub/xfs_scrub_all.service.in b/scrub/xfs_scrub_all.service.in index 4938404ee95..e831ad58eb8 100644 --- a/scrub/xfs_scrub_all.service.in +++ b/scrub/xfs_scrub_all.service.in @@ -12,7 +12,7 @@ After=paths.target multi-user.target network.target network-online.target system [Service] Type=oneshot Environment=SERVICE_MODE=1 -ExecStart=@sbindir@/xfs_scrub_all +ExecStart=@sbindir@/xfs_scrub_all --auto-media-scan-interval @media_scan_interval@ SyslogIdentifier=xfs_scrub_all # Create the service underneath the scrub background service slice so that we From patchwork Fri Dec 30 22:18:38 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13085185 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0027BC4332F for ; Sat, 31 Dec 2022 00:38:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235831AbiLaAiQ (ORCPT ); Fri, 30 Dec 2022 19:38:16 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34738 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235822AbiLaAiP (ORCPT ); Fri, 30 Dec 2022 19:38:15 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DD2B81E3FE for ; Fri, 30 Dec 2022 16:38:12 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 78A58B81E08 for ; Sat, 31 Dec 2022 00:38:11 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3AD06C433EF; Sat, 31 Dec 2022 00:38:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1672447090; bh=y+KQKroufgYQjwLEgOY3uqll077LBKS3Bmuz4IdOyuQ=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=LRp5V/mGd/pLr1WUm8wkSvFoc8oiMGg+NyHfMeWT0pssY6kpJmm2Xg3h+h+mzuDu+ uO2BvtAzX5Rzua1oSueTG3c1X0WeV5+uUyOJDEv5xxiZi+tm7sdHYp1Npu/Wfg3CEq oa6XxeWoG5oWTLY3Io6/CN5WV5CTk/Bki6tN1d23A3NYAcKPMZVnyMsl8d6KI3Q01D m4MEJp6wFJ2Csgef1r8XgC3KgoB9Ios8uwW56N37r9vp0OAwaUUG8vcRYejpVS+KcI MaKOFCVI5X1fIvLcr4YWCg3bES247JV3mjL8M3R49OgPApvct1j6scAf3nMIhOixLm lsDX+Za/Uf3ww== Subject: [PATCH 4/4] xfs_scrub_all: failure reporting for the xfs_scrub_all job From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Date: Fri, 30 Dec 2022 14:18:38 -0800 Message-ID: <167243871844.718563.13357729046234850218.stgit@magnolia> In-Reply-To: <167243871794.718563.17643569431631339696.stgit@magnolia> References: <167243871794.718563.17643569431631339696.stgit@magnolia> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Darrick J. Wong Create a failure reporting service for when xfs_scrub_all fails. This shouldn't happen often, but let's report anyways. Signed-off-by: Darrick J. Wong --- scrub/Makefile | 1 + scrub/xfs_scrub_all.service.in | 1 + scrub/xfs_scrub_all_fail.service.in | 67 +++++++++++++++++++++++++++++++++++ scrub/xfs_scrub_fail | 33 ++++++++++++++--- 4 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 scrub/xfs_scrub_all_fail.service.in diff --git a/scrub/Makefile b/scrub/Makefile index 7434ac0ce4e..f2d0c1aa0bf 100644 --- a/scrub/Makefile +++ b/scrub/Makefile @@ -21,6 +21,7 @@ SYSTEMD_SERVICES=\ xfs_scrub_media@.service \ xfs_scrub_media_fail@.service \ xfs_scrub_all.service \ + xfs_scrub_all_fail.service \ xfs_scrub_all.timer \ system-xfs_scrub.slice OPTIONAL_TARGETS += $(SYSTEMD_SERVICES) diff --git a/scrub/xfs_scrub_all.service.in b/scrub/xfs_scrub_all.service.in index e831ad58eb8..c11d6a96037 100644 --- a/scrub/xfs_scrub_all.service.in +++ b/scrub/xfs_scrub_all.service.in @@ -5,6 +5,7 @@ [Unit] Description=Online XFS Metadata Check for All Filesystems +OnFailure=xfs_scrub_all_fail.service ConditionACPower=true Documentation=man:xfs_scrub_all(8) After=paths.target multi-user.target network.target network-online.target systemd-networkd.service NetworkManager.service connman.service diff --git a/scrub/xfs_scrub_all_fail.service.in b/scrub/xfs_scrub_all_fail.service.in new file mode 100644 index 00000000000..002d05b67de --- /dev/null +++ b/scrub/xfs_scrub_all_fail.service.in @@ -0,0 +1,67 @@ +[Unit] +Description=Online XFS Metadata Check for All Filesystems Failure Reporting +Documentation=man:xfs_scrub_all(8) + +[Service] +Type=oneshot +Environment=EMAIL_ADDR=root +ExecStart=@pkg_lib_dir@/@pkg_name@/xfs_scrub_fail "${EMAIL_ADDR}" xfs_scrub_all +User=mail +Group=mail +SupplementaryGroups=systemd-journal + +# No realtime scheduling +RestrictRealtime=true + +# Make the entire filesystem readonly and /home inaccessible, then bind mount +# the filesystem we're supposed to be checking into our private /tmp dir. +ProtectSystem=full +ProtectHome=yes +PrivateTmp=true +RestrictSUIDSGID=true + +# Emailing reports requires network access, but not the ability to change the +# hostname. +ProtectHostname=true + +# Don't let the program mess with the kernel configuration at all +ProtectKernelLogs=true +ProtectKernelModules=true +ProtectKernelTunables=true +ProtectControlGroups=true +ProtectProc=invisible +RestrictNamespaces=true + +# Can't hide /proc because journalctl needs it to find various pieces of log +# information +#ProcSubset=pid + +# Only allow the default personality Linux +LockPersonality=true + +# No writable memory pages +MemoryDenyWriteExecute=true + +# Don't let our mounts leak out to the host +PrivateMounts=true + +# Restrict system calls to the native arch and only enough to get things going +SystemCallArchitectures=native +SystemCallFilter=@system-service +SystemCallFilter=~@privileged +SystemCallFilter=~@resources +SystemCallFilter=~@mount + +# xfs_scrub needs these privileges to run, and no others +CapabilityBoundingSet= +NoNewPrivileges=true + +# Failure reporting shouldn't create world-readable files +UMask=0077 + +# Clean up any IPC objects when this unit stops +RemoveIPC=true + +# No access to hardware device files +PrivateDevices=true +ProtectClock=true diff --git a/scrub/xfs_scrub_fail b/scrub/xfs_scrub_fail index 58c50abe963..0739a00dec9 100755 --- a/scrub/xfs_scrub_fail +++ b/scrub/xfs_scrub_fail @@ -5,14 +5,13 @@ # Copyright (C) 2018 Oracle. All Rights Reserved. # Author: Darrick J. Wong -# Email logs of failed xfs_scrub unit runs +# Email logs of failed xfs_scrub and xfs_scrub_all unit runs recipient="$1" test -z "${recipient}" && exit 0 service="$2" test -z "${service}" && exit 0 mntpoint="$3" -test -z "${mntpoint}" && exit 0 hostname="$(hostname -f 2>/dev/null)" test -z "${hostname}" && hostname="${HOSTNAME}" @@ -47,10 +46,12 @@ escape_path() { echo "-$(systemd-escape --path "${mntpoint}")" } -mntpoint_esc="$(escape_path "${mntpoint}")" +fail_mail_mntpoint() { + local mntpoint_esc -(cat << ENDL -To: $1 + mntpoint_esc="$(escape_path "${mntpoint}")" + cat << ENDL +To: ${recipient} From: <${service}@${hostname}> Subject: ${service} failure on ${mntpoint} @@ -58,5 +59,25 @@ So sorry, the automatic ${service} of ${mntpoint} on ${hostname} failed. A log of what happened follows: ENDL -systemctl status --full --lines 4294967295 "${service}@${mntpoint_esc}") | "${mailer}" -t -i + systemctl status --full --lines 4294967295 "${service}@${mntpoint_esc}" +} + +fail_mail() { + cat << ENDL +To: ${recipient} +From: <${service}@${hostname}> +Subject: ${service} failure + +So sorry, the automatic ${service} on ${hostname} failed. + +A log of what happened follows: +ENDL + systemctl status --full --lines 4294967295 "${service}" +} + +if [ -n "${mntpoint}" ]; then + fail_mail_mntpoint | "${mailer}" -t -i +else + fail_mail | "${mailer}" -t -i +fi exit "${PIPESTATUS[1]}"