From patchwork Wed Jan 17 22:02:10 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: 10172059 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 2B7516055D for ; Wed, 17 Jan 2018 22:04:41 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 194B01FE82 for ; Wed, 17 Jan 2018 22:04:41 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0CE8327165; Wed, 17 Jan 2018 22:04:41 +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 5D7DF27FAE for ; Wed, 17 Jan 2018 22:02:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753301AbeAQWC2 (ORCPT ); Wed, 17 Jan 2018 17:02:28 -0500 Received: from aserp2120.oracle.com ([141.146.126.78]:56000 "EHLO aserp2120.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750931AbeAQWC1 (ORCPT ); Wed, 17 Jan 2018 17:02:27 -0500 Received: from pps.filterd (aserp2120.oracle.com [127.0.0.1]) by aserp2120.oracle.com (8.16.0.22/8.16.0.22) with SMTP id w0HM23bc080044; Wed, 17 Jan 2018 22:02:13 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=2C6cxoKzPlMpCsW3wkhv0JBV236hak7MIVPlghMzpMg=; b=XntZmHC8zpKMiN7EHHXkBLLptqVSfvd1QHZBZj/HAKOhdW83Q6G+8ixJ6NrcqhAjRARK kz+hytcuEWDsIPiCapLWJIwCZv6fXfqUo++atc0OCngdRY6+9BoampseqkdW4Y6eSnSP qBXmsdHAZd9cOs5NamgSIgxG/FnIXb96vxr29tRxeAIOe7+23LjJzca3CCTUAoaIdsZ8 lPNfuXuPM8d77OaRb5hNRlRR8jDl2zs3Do/PciGjUlCpS1JjdJ1r/GtXRo7kBszOdLBV NgYuhdl7kas7z0DT+Y4jAP52rA0wRQTSh7KVg0RawPJz1psbWIiiZ435m6kjZGOtuvft ZA== Received: from userv0022.oracle.com (userv0022.oracle.com [156.151.31.74]) by aserp2120.oracle.com with ESMTP id 2fjcscgr5t-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 17 Jan 2018 22:02:13 +0000 Received: from aserv0122.oracle.com (aserv0122.oracle.com [141.146.126.236]) by userv0022.oracle.com (8.14.4/8.14.4) with ESMTP id w0HM2CdS011891 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 17 Jan 2018 22:02:12 GMT Received: from abhmp0009.oracle.com (abhmp0009.oracle.com [141.146.116.15]) by aserv0122.oracle.com (8.14.4/8.14.4) with ESMTP id w0HM2B5v032463; Wed, 17 Jan 2018 22:02:11 GMT Received: from localhost (/67.169.218.210) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Wed, 17 Jan 2018 14:02:11 -0800 Subject: [PATCH 03/29] xfs_scrub: set up command line argument parsing From: "Darrick J. Wong" To: sandeen@redhat.com, darrick.wong@oracle.com Cc: linux-xfs@vger.kernel.org Date: Wed, 17 Jan 2018 14:02:10 -0800 Message-ID: <151622653031.31925.2370829301086526738.stgit@magnolia> In-Reply-To: <151622651142.31925.4179778330985746435.stgit@magnolia> References: <151622651142.31925.4179778330985746435.stgit@magnolia> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=nai engine=5900 definitions=8777 signatures=668653 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 suspectscore=2 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-1801170299 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 Parse command line options in order to set up the context in which we will scrub the filesystem. Signed-off-by: Darrick J. Wong --- scrub/common.h | 8 ++ scrub/xfs_scrub.c | 219 +++++++++++++++++++++++++++++++++++++++++++++++++++++ scrub/xfs_scrub.h | 32 ++++++++ 3 files changed, 259 insertions(+) -- 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/scrub/common.h b/scrub/common.h index b383767..7a7e362 100644 --- a/scrub/common.h +++ b/scrub/common.h @@ -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_ */ diff --git a/scrub/xfs_scrub.c b/scrub/xfs_scrub.c index 6ed7bf6..3ae1a08 100644 --- a/scrub/xfs_scrub.c +++ b/scrub/xfs_scrub.c @@ -20,7 +20,12 @@ #include #include #include +#include +#include "platform_defs.h" +#include "xfs.h" +#include "input.h" #include "xfs_scrub.h" +#include "common.h" /* * XFS Online Metadata Scrub (and Repair) @@ -98,17 +103,231 @@ * thorough the scrub was. */ +/* + * Known debug tweaks (pass -d and set the environment variable): + * XFS_SCRUB_FORCE_ERROR -- pretend all metadata is corrupt + * XFS_SCRUB_FORCE_REPAIR -- repair all metadata even if it's ok + * XFS_SCRUB_NO_KERNEL -- pretend there is no kernel ioctl + * 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 + */ + /* Program name; needed for libfrog error reports. */ char *progname = "xfs_scrub"; /* Debug level; higher values mean more verbosity. */ unsigned int debug; +/* Display resource usage at the end of each phase? */ +static bool display_rusage; + +/* Background mode; higher values insert more pauses between scrub calls. */ +unsigned int bg_mode; + +/* Maximum number of processors available to us. */ +int nproc; + +/* Number of threads we're allowed to use. */ +unsigned int nr_threads; + +/* Verbosity; higher values print more information. */ +bool verbose; + +/* Should we scrub the data blocks? */ +static bool scrub_data; + +/* Size of a memory page. */ +long page_size; + +static void __attribute__((noreturn)) +usage(void) +{ + fprintf(stderr, _("Usage: %s [OPTIONS] mountpoint | device\n"), progname); + fprintf(stderr, "\n"); + fprintf(stderr, _("Options:\n")); + 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, _(" -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")); + fprintf(stderr, _(" -v Verbose output.\n")); + fprintf(stderr, _(" -V Print version.\n")); + fprintf(stderr, _(" -x Scrub file data too.\n")); + fprintf(stderr, _(" -y Repair all errors.\n")); + + exit(16); +} + int main( int argc, char **argv) { + int c; + char *mtab = NULL; + char *repairstr = ""; + struct scrub_ctx ctx = {0}; + unsigned long long total_errors; + bool moveon = true; + int ret = 0; + fprintf(stdout, "EXPERIMENTAL xfs_scrub program in use! Use at your own risk!\n"); return 4; + + progname = basename(argv[0]); + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + 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) { + switch (c) { + case 'a': + ctx.max_errors = cvt_u64(optarg, 10); + if (errno) { + perror(optarg); + usage(); + } + break; + case 'b': + nr_threads = 1; + bg_mode++; + break; + case 'd': + debug++; + break; + case 'e': + if (!strcmp("continue", optarg)) + ctx.error_action = ERRORS_CONTINUE; + else if (!strcmp("shutdown", optarg)) + ctx.error_action = ERRORS_SHUTDOWN; + else { + fprintf(stderr, + _("Unknown error behavior \"%s\".\n"), + optarg); + usage(); + } + break; + case 'm': + mtab = optarg; + break; + case 'n': + if (ctx.mode != SCRUB_MODE_DEFAULT) { + fprintf(stderr, +_("Only one of the options -n or -y may be specified.\n")); + return 1; + } + ctx.mode = SCRUB_MODE_DRY_RUN; + break; + case 'T': + display_rusage = true; + break; + case 'v': + verbose = true; + break; + case 'V': + fprintf(stdout, _("%s version %s\n"), progname, + VERSION); + fflush(stdout); + exit(0); + case 'x': + scrub_data = true; + break; + case 'y': + if (ctx.mode != SCRUB_MODE_DEFAULT) { + fprintf(stderr, +_("Only one of the options -n or -y may be specified.\n")); + return 1; + } + ctx.mode = SCRUB_MODE_REPAIR; + break; + case '?': + /* fall through */ + default: + usage(); + } + } + + /* Override thread count if debugger */ + if (debug_tweak_on("XFS_SCRUB_THREADS")) { + unsigned int x; + + x = cvt_u32(getenv("XFS_SCRUB_THREADS"), 10); + if (errno) { + perror("nr_threads"); + usage(); + } + nr_threads = x; + } + + if (optind != argc - 1) + usage(); + + ctx.mntpoint = strdup(argv[optind]); + + /* + * If the user did not specify an explicit mount table, try to use + * /proc/mounts if it is available, else /etc/mtab. We prefer + * /proc/mounts because it is kernel controlled, while /etc/mtab + * may contain garbage that userspace tools like pam_mounts wrote + * into it. + */ + if (!mtab) { + if (access(_PATH_PROC_MOUNTS, R_OK) == 0) + mtab = _PATH_PROC_MOUNTS; + else + mtab = _PATH_MOUNTED; + } + + /* How many CPUs? */ + nproc = sysconf(_SC_NPROCESSORS_ONLN); + if (nproc < 1) + nproc = 1; + + /* Set up a page-aligned buffer for read verification. */ + page_size = sysconf(_SC_PAGESIZE); + if (page_size < 0) { + str_errno(&ctx, ctx.mntpoint); + goto out; + } + + if (debug_tweak_on("XFS_SCRUB_FORCE_REPAIR")) + ctx.mode = SCRUB_MODE_REPAIR; + + if (xfs_scrub_excessive_errors(&ctx)) + str_info(&ctx, ctx.mntpoint, _("Too many errors; aborting.")); + + if (debug_tweak_on("XFS_SCRUB_FORCE_ERROR")) + str_error(&ctx, ctx.mntpoint, _("Injecting error.")); + +out: + total_errors = ctx.errors_found + ctx.runtime_errors; + if (ctx.need_repair) + repairstr = _(" Unmount and run xfs_repair."); + if (total_errors && ctx.warnings_found) + fprintf(stderr, +_("%s: %llu errors and %llu warnings found.%s\n"), + ctx.mntpoint, total_errors, ctx.warnings_found, + repairstr); + else if (total_errors && ctx.warnings_found == 0) + fprintf(stderr, +_("%s: %llu errors found.%s\n"), + ctx.mntpoint, total_errors, repairstr); + else if (total_errors == 0 && ctx.warnings_found) + fprintf(stderr, +_("%s: %llu warnings found.\n"), + ctx.mntpoint, ctx.warnings_found); + if (ctx.errors_found) + ret |= 1; + if (ctx.warnings_found) + ret |= 2; + if (ctx.runtime_errors) + ret |= 4; + free(ctx.mntpoint); + + return ret; } diff --git a/scrub/xfs_scrub.h b/scrub/xfs_scrub.h index 811bc2d..51b8b7a 100644 --- a/scrub/xfs_scrub.h +++ b/scrub/xfs_scrub.h @@ -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_ */