From patchwork Sat Jan 6 01:54:14 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 10147513 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id C21F960134 for ; Sat, 6 Jan 2018 01:54:23 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4722928998 for ; Sat, 6 Jan 2018 01:54:23 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3BFD0289BA; Sat, 6 Jan 2018 01:54:23 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1A0B428998 for ; Sat, 6 Jan 2018 01:54:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753706AbeAFByV (ORCPT ); Fri, 5 Jan 2018 20:54:21 -0500 Received: from aserp2130.oracle.com ([141.146.126.79]:43506 "EHLO aserp2130.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753711AbeAFByT (ORCPT ); Fri, 5 Jan 2018 20:54:19 -0500 Received: from pps.filterd (aserp2130.oracle.com [127.0.0.1]) by aserp2130.oracle.com (8.16.0.21/8.16.0.21) with SMTP id w061qcfW016196; Sat, 6 Jan 2018 01:54:16 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=subject : from : to : cc : date : message-id : in-reply-to : references : mime-version : content-type : content-transfer-encoding; s=corp-2017-10-26; bh=/IisghErjP4cCPPeesrUX8KHBUVVn297TAElMfSrFns=; b=rXvmn8vCI5YNCHuAsXwfWoAv0ADzMcruzetf4cnZreErL4RewTq5mWcfga+bwHHgFAbV jsZIBsYfycSmZzxTR6EQxQfQLBB7qSKp0hHBe3sHd0TUiYzU7/jcSEKXVKi2D/xHMm4e ihLJe3yoELvHlvA1a1QwcExpOAd30BwCuMFFjgDW/Fy33UPSPjcI9CcJVSfOXVuT8EvV lAbj558WobLDuxFQ+3QoypbOYFsuI8NJ77NFBZJmL1V2UXFUmzpJPBGsbWrRc7qhxECH kvxF7madOt3Sj4QjY4le7Zm0YeSLYLSks/mKSWtxBUuYxjTY83LnJbecYd8R6L6IVyYI +A== Received: from userv0022.oracle.com (userv0022.oracle.com [156.151.31.74]) by aserp2130.oracle.com with ESMTP id 2fam6ar2yx-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 06 Jan 2018 01:54:16 +0000 Received: from userv0121.oracle.com (userv0121.oracle.com [156.151.31.72]) by userv0022.oracle.com (8.14.4/8.14.4) with ESMTP id w061sF4M012035 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Sat, 6 Jan 2018 01:54:15 GMT Received: from abhmp0003.oracle.com (abhmp0003.oracle.com [141.146.116.9]) by userv0121.oracle.com (8.14.4/8.13.8) with ESMTP id w061sFIY013320; Sat, 6 Jan 2018 01:54:15 GMT Received: from localhost (/65.154.186.210) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Fri, 05 Jan 2018 17:54:15 -0800 Subject: [PATCH 26/27] xfs_scrub: create a script to scrub all xfs filesystems From: "Darrick J. Wong" To: sandeen@redhat.com, darrick.wong@oracle.com Cc: linux-xfs@vger.kernel.org Date: Fri, 05 Jan 2018 17:54:14 -0800 Message-ID: <151520365436.2027.16511464158136478480.stgit@magnolia> In-Reply-To: <151520348769.2027.9860697266310422360.stgit@magnolia> References: <151520348769.2027.9860697266310422360.stgit@magnolia> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=nai engine=5900 definitions=8765 signatures=668651 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 suspectscore=8 malwarescore=0 phishscore=0 bulkscore=0 spamscore=0 mlxscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1711220000 definitions=main-1801060020 Sender: linux-xfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Darrick J. Wong Create an xfs_scrub_all command to find all XFS filesystems and run an online scrub against them all. Signed-off-by: Darrick J. Wong --- 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 -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/debian/control b/debian/control index 36d1bd8..801744b 100644 --- a/debian/control +++ b/debian/control @@ -3,12 +3,13 @@ Section: admin Priority: optional Maintainer: XFS Development Team Uploaders: Nathan Scott , Anibal Monsalve Salazar -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) diff --git a/debian/rules b/debian/rules index baefdba..abb794e 100755 --- a/debian/rules +++ b/debian/rules @@ -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 diff --git a/man/man8/xfs_scrub_all.8 b/man/man8/xfs_scrub_all.8 new file mode 100644 index 0000000..5e1420b --- /dev/null +++ b/man/man8/xfs_scrub_all.8 @@ -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). diff --git a/scrub/Makefile b/scrub/Makefile index 7a80ff6..f709606 100644 --- a/scrub/Makefile +++ b/scrub/Makefile @@ -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: diff --git a/scrub/xfs_scrub_all.in b/scrub/xfs_scrub_all.in new file mode 100644 index 0000000..7738644 --- /dev/null +++ b/scrub/xfs_scrub_all.in @@ -0,0 +1,154 @@ +#!/usr/bin/env python3 + +# Run online scrubbers in parallel, but avoid thrashing. +# +# Copyright (C) 2018 Oracle. All rights reserved. +# +# Author: Darrick J. Wong +# +# 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. + +import subprocess +import json +import threading +import time +import sys + +retcode = 0 +terminate = False + +def find_mounts(): + '''Map mountpoints to physical disks.''' + + fs = {} + cmd=['lsblk', '-o', 'KNAME,TYPE,FSTYPE,MOUNTPOINT', '-J'] + result = subprocess.Popen(cmd, stdout=subprocess.PIPE) + result.wait() + if result.returncode != 0: + return fs + sarray = [x.decode('utf-8') for x in result.stdout.readlines()] + output = ' '.join(sarray) + bdevdata = json.loads(output) + # The lsblk output had better be in disks-then-partitions order + for bdev in bdevdata['blockdevices']: + if bdev['type'] in ('disk', 'loop'): + lastdisk = bdev['kname'] + if bdev['fstype'] == 'xfs': + mnt = bdev['mountpoint'] + if mnt is None: + continue + if mnt in fs: + fs[mnt].add(lastdisk) + else: + fs[mnt] = set([lastdisk]) + return fs + +def run_killable(cmd, stdout, killfuncs, kill_fn): + '''Run a killable program. Returns program retcode or -1 if we can't start it.''' + try: + proc = subprocess.Popen(cmd, stdout = stdout) + real_kill_fn = lambda: kill_fn(proc) + killfuncs.add(real_kill_fn) + proc.wait() + try: + killfuncs.remove(real_kill_fn) + except: + pass + return proc.returncode + except: + return -1 + +def run_scrub(mnt, cond, running_devs, mntdevs, killfuncs): + '''Run a scrub process.''' + global retcode, terminate + + print("Scrubbing %s..." % mnt) + sys.stdout.flush() + + try: + if terminate: + return + + # Invoke xfs_scrub manually + cmd=['@sbindir@/xfs_scrub', '@scrub_args@', mnt] + ret = run_killable(cmd, None, killfuncs, \ + lambda proc: proc.terminate()) + if ret >= 0: + print("Scrubbing %s done, (err=%d)" % (mnt, ret)) + sys.stdout.flush() + retcode |= ret + return + + if terminate: + return + + print("Unable to start scrub tool.") + sys.stdout.flush() + finally: + running_devs -= mntdevs + cond.acquire() + cond.notify() + cond.release() + +def main(): + '''Find mounts, schedule scrub runs.''' + def thr(mnt, devs): + a = (mnt, cond, running_devs, devs, killfuncs) + thr = threading.Thread(target = run_scrub, args = a) + thr.start() + global retcode, terminate + + fs = find_mounts() + + # Schedule scrub jobs... + running_devs = set() + killfuncs = set() + cond = threading.Condition() + while len(fs) > 0: + if len(running_devs) == 0: + mnt, devs = fs.popitem() + running_devs.update(devs) + thr(mnt, devs) + poppers = set() + for mnt in fs: + devs = fs[mnt] + can_run = True + for dev in devs: + if dev in running_devs: + can_run = False + break + if can_run: + running_devs.update(devs) + poppers.add(mnt) + thr(mnt, devs) + for p in poppers: + fs.pop(p) + cond.acquire() + try: + cond.wait() + except KeyboardInterrupt: + terminate = True + print("Terminating...") + sys.stdout.flush() + while len(killfuncs) > 0: + fn = killfuncs.pop() + fn() + fs = [] + cond.release() + + sys.exit(retcode) + +if __name__ == '__main__': + main()