From patchwork Wed Jan 17 22:04:50 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: 10172085 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 515B3603B5 for ; Wed, 17 Jan 2018 22:05:12 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3EE0C1FFFF for ; Wed, 17 Jan 2018 22:05:12 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 30D952237D; Wed, 17 Jan 2018 22:05:12 +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 3419C1FFFF for ; Wed, 17 Jan 2018 22:05:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753762AbeAQWFI (ORCPT ); Wed, 17 Jan 2018 17:05:08 -0500 Received: from aserp2130.oracle.com ([141.146.126.79]:33090 "EHLO aserp2130.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753769AbeAQWFC (ORCPT ); Wed, 17 Jan 2018 17:05:02 -0500 Received: from pps.filterd (aserp2130.oracle.com [127.0.0.1]) by aserp2130.oracle.com (8.16.0.22/8.16.0.22) with SMTP id w0HM1shX100485; Wed, 17 Jan 2018 22:04:52 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=HXHXWCPolrT6Gcfv55YuKJ631/kr5u6KukyG5/9J56s=; b=X3cAmELwh+bCZmu5MtFLqIUmBIgTWpgXAYrUjdDlIrSzC8yjLdaCFS182KwMNGpORzKy wANOcH8Eu6Ma4wlnpySjBxBRJYbdkrAAmBoiCXbIP+9JilRB+zFykUjKhkg+ckV2xYdT lGnS1TrQyo8lD1EJdUixZgWdfGKabiAXR/YDPhk/Z6EIcY8oZ04HjLi+8BwzESqYkNWX cuKarkdbY/8PjtUW2cRMppFwb1Gh1plD6V9Y28qUUv1mU/LuOgIGIDlkhk/me5SZ0nvx P8DS1BuJr2BvHNGP21KvC/Ubsu7iOhtzkOz3i/Ev+S/mzldbyYTu0qh5Im3+GSe1c/oW tQ== Received: from userv0022.oracle.com (userv0022.oracle.com [156.151.31.74]) by aserp2130.oracle.com with ESMTP id 2fjewf00gm-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 17 Jan 2018 22:04:52 +0000 Received: from aserv0121.oracle.com (aserv0121.oracle.com [141.146.126.235]) by userv0022.oracle.com (8.14.4/8.14.4) with ESMTP id w0HM4pop020305 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 17 Jan 2018 22:04:51 GMT Received: from abhmp0019.oracle.com (abhmp0019.oracle.com [141.146.116.25]) by aserv0121.oracle.com (8.14.4/8.13.8) with ESMTP id w0HM4pvV001796; Wed, 17 Jan 2018 22:04:51 GMT Received: from localhost (/67.169.218.210) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Wed, 17 Jan 2018 14:04:51 -0800 Subject: [PATCH 28/29] xfs_scrub: wire up repair ioctl From: "Darrick J. Wong" To: sandeen@redhat.com, darrick.wong@oracle.com Cc: linux-xfs@vger.kernel.org Date: Wed, 17 Jan 2018 14:04:50 -0800 Message-ID: <151622669005.31925.1032846942610114371.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=0 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 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. Signed-off-by: Darrick J. Wong --- scrub/common.c | 12 +++++ scrub/common.h | 6 ++ scrub/phase1.c | 15 ++++++ 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, 192 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.c b/scrub/common.c index 18171d1..17c3699 100644 --- a/scrub/common.c +++ b/scrub/common.c @@ -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); } diff --git a/scrub/common.h b/scrub/common.h index 29b4332..287bd4d 100644 --- a/scrub/common.h +++ b/scrub/common.h @@ -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) diff --git a/scrub/phase1.c b/scrub/phase1.c index d7a321f..3a2fbd7 100644 --- a/scrub/phase1.c +++ b/scrub/phase1.c @@ -176,6 +176,21 @@ _("Does not appear to be an XFS filesystem!")); !xfs_can_scrub_parent(ctx)) return false; + /* Do we have kernel-assisted metadata repair? */ + if (ctx->mode != SCRUB_MODE_DRY_RUN && !xfs_can_repair(ctx)) { + if (ctx->mode == SCRUB_MODE_PREEN) { + /* w/o repair, demote preen to dry run. */ + if (debug || verbose) + str_info(ctx, ctx->mntpoint, +_("Metadata repairing not supported; demoting to scan mode.") + ); + ctx->mode = SCRUB_MODE_DRY_RUN; + } else { + /* Repair mode w/o repair; abort. */ + return false; + } + } + /* Go find the XFS devices if we have a usable fsmap. */ fs_table_initialise(0, NULL, 0, NULL); errno = 0; diff --git a/scrub/phase2.c b/scrub/phase2.c index e8eb1ca..32e2752 100644 --- a/scrub/phase2.c +++ b/scrub/phase2.c @@ -24,6 +24,7 @@ #include #include #include "xfs.h" +#include "list.h" #include "path.h" #include "workqueue.h" #include "xfs_scrub.h" diff --git a/scrub/phase3.c b/scrub/phase3.c index 43697c6..f4117b0 100644 --- a/scrub/phase3.c +++ b/scrub/phase3.c @@ -24,6 +24,7 @@ #include #include #include "xfs.h" +#include "list.h" #include "path.h" #include "workqueue.h" #include "xfs_scrub.h" diff --git a/scrub/phase5.c b/scrub/phase5.c index fc3308b..703b279 100644 --- a/scrub/phase5.c +++ b/scrub/phase5.c @@ -29,6 +29,7 @@ #endif #include "xfs.h" #include "handle.h" +#include "list.h" #include "path.h" #include "workqueue.h" #include "xfs_scrub.h" diff --git a/scrub/scrub.c b/scrub/scrub.c index bc4eab4..171b9b7 100644 --- a/scrub/scrub.c +++ b/scrub/scrub.c @@ -28,6 +28,7 @@ #include #include "xfs.h" #include "xfs_fs.h" +#include "list.h" #include "path.h" #include "xfs_scrub.h" #include "common.h" @@ -561,10 +562,15 @@ __xfs_scrub_test( bool repair) { struct xfs_scrub_metadata meta = {0}; + static bool injected; int error; if (debug_tweak_on("XFS_SCRUB_NO_KERNEL")) return false; + if (debug_tweak_on("XFS_SCRUB_FORCE_REPAIR") && !injected) { + str_error(ctx, "XFS_SCRUB_FORCE_REPAIR", "Not supported."); + return false; + } meta.sm_type = type; if (repair) @@ -646,3 +652,131 @@ xfs_can_scrub_parent( { return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_PARENT, false); } + +bool +xfs_can_repair( + struct scrub_ctx *ctx) +{ + return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_PROBE, true); +} + +/* General repair routines. */ + +/* Repair some metadata. */ +enum check_outcome +xfs_repair_metadata( + struct scrub_ctx *ctx, + int fd, + struct repair_item *ri, + unsigned int repair_flags) +{ + char buf[DESCR_BUFSZ]; + struct xfs_scrub_metadata meta = { 0 }; + struct xfs_scrub_metadata oldm; + int error; + + assert(ri->type < XFS_SCRUB_TYPE_NR); + assert(!debug_tweak_on("XFS_SCRUB_NO_KERNEL")); + meta.sm_type = ri->type; + meta.sm_flags = ri->flags | XFS_SCRUB_IFLAG_REPAIR; + switch (scrubbers[ri->type].type) { + case ST_AGHEADER: + case ST_PERAG: + meta.sm_agno = ri->agno; + break; + case ST_INODE: + meta.sm_ino = ri->ino; + meta.sm_gen = ri->gen; + break; + default: + break; + } + + /* + * If this is a preen operation but we're only repairing + * critical items, defer the preening until later. + */ + if (!needs_repair(&meta) && (repair_flags & XRM_REPAIR_ONLY)) + return CHECK_RETRY; + + memcpy(&oldm, &meta, sizeof(oldm)); + format_scrub_descr(buf, DESCR_BUFSZ, &meta, &scrubbers[meta.sm_type]); + + if (needs_repair(&meta)) + str_info(ctx, buf, _("Attempting repair.")); + else if (debug || verbose) + str_info(ctx, buf, _("Attempting optimization.")); + + error = ioctl(fd, XFS_IOC_SCRUB_METADATA, &meta); + /* + * If the caller doesn't want us to complain, tell the caller to + * requeue the repair for later and don't say a thing. + */ + if (!(repair_flags & XRM_NOFIX_COMPLAIN) && + (error || needs_repair(&meta))) + return CHECK_RETRY; + if (error) { + switch (errno) { + case EDEADLOCK: + case EBUSY: + /* Filesystem is busy, try again later. */ + if (debug || verbose) + str_info(ctx, buf, +_("Filesystem is busy, deferring repair.")); + return CHECK_RETRY; + case ESHUTDOWN: + /* Filesystem is already shut down, abort. */ + str_error(ctx, buf, +_("Filesystem is shut down, aborting.")); + return CHECK_ABORT; + case ENOTTY: + case EOPNOTSUPP: + /* + * If we forced repairs, don't complain if kernel + * doesn't know how to fix. + */ + if (debug_tweak_on("XFS_SCRUB_FORCE_REPAIR")) + return CHECK_DONE; + /* fall through */ + case EINVAL: + /* Kernel doesn't know how to repair this? */ + str_error(ctx, buf, +_("Don't know how to fix; offline repair required.")); + return CHECK_DONE; + case EROFS: + /* Read-only filesystem, can't fix. */ + if (verbose || debug || needs_repair(&oldm)) + str_info(ctx, buf, +_("Read-only filesystem; cannot make changes.")); + return CHECK_DONE; + case ENOENT: + /* Metadata not present, just skip it. */ + return CHECK_DONE; + case ENOMEM: + case ENOSPC: + /* Don't care if preen fails due to low resources. */ + if (is_unoptimized(&oldm) && !needs_repair(&oldm)) + return CHECK_DONE; + /* fall through */ + default: + /* Operational error. */ + str_errno(ctx, buf); + return CHECK_DONE; + } + } + if (repair_flags & XRM_NOFIX_COMPLAIN) + xfs_scrub_warn_incomplete_scrub(ctx, buf, &meta); + if (needs_repair(&meta)) { + /* Still broken, try again or fix offline. */ + if (repair_flags & XRM_NOFIX_COMPLAIN) + str_error(ctx, buf, +_("Repair unsuccessful; offline repair required.")); + } else { + /* Clean operation, no corruption detected. */ + if (needs_repair(&oldm)) + record_repair(ctx, buf, _("Repairs successful.")); + else + record_preen(ctx, buf, _("Optimization successful.")); + } + return CHECK_DONE; +} diff --git a/scrub/scrub.h b/scrub/scrub.h index 0b454df..1c44fba 100644 --- a/scrub/scrub.h +++ b/scrub/scrub.h @@ -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_ */ diff --git a/scrub/xfs_scrub.h b/scrub/xfs_scrub.h index 16cd1aa..8407885 100644 --- a/scrub/xfs_scrub.h +++ b/scrub/xfs_scrub.h @@ -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]; };