From patchwork Fri Dec 30 22:20:40 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: 13085940 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 E2B5DC4167B for ; Sat, 31 Dec 2022 03:25:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236381AbiLaDZ1 (ORCPT ); Fri, 30 Dec 2022 22:25:27 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38486 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236382AbiLaDZE (ORCPT ); Fri, 30 Dec 2022 22:25:04 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6027C12A80 for ; Fri, 30 Dec 2022 19:25:03 -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 EC65461CC1 for ; Sat, 31 Dec 2022 03:25:02 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4FF44C433EF; Sat, 31 Dec 2022 03:25:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1672457102; bh=1aDgw+OdoEVEfb9KilMz+gbALKo2DQwY2tHIzjcNDJk=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=HYWb3kHpgi0gDXGdUq3DHuYs++JN1tKg71sNrAA8+Oig02GLpcuiPZI6YKyhqfe4d FCZIixz+i7NDtIAFy1BhRRwUAwNatKSHgNdNJ59dV1aZJ4gs4jd7MOsMThkAMVa4cr tV1l2WGaC27tv8V9FQjf8RNDeqSXaItNv2x7Zo5gVDwoSUMjJLOqxa15VmbAjYn3AA A8G/WUcIabyDvIUCgVEmwX+3xC3di34+775V0b3anAflAYWsZ9tyn/NlrRn9Ji1/Rp TDBO/dClpQqarFhjwgCULqg9GCrtZ4EVQMWNLTOlJl16ridI6gPkRo16zZuQHZN9rf sBcMuVL6IgaUw== Subject: [PATCH 01/11] xfs: track deferred ops statistics From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Date: Fri, 30 Dec 2022 14:20:40 -0800 Message-ID: <167243884045.739244.9856060374468246701.stgit@magnolia> In-Reply-To: <167243884029.739244.16777239536975047510.stgit@magnolia> References: <167243884029.739244.16777239536975047510.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 Track some basic statistics on how hard we're pushing the defer ops. Signed-off-by: Darrick J. Wong --- include/xfs_trans.h | 4 ++++ libxfs/xfs_defer.c | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/include/xfs_trans.h b/include/xfs_trans.h index 0ecf0a95560..9b12791ff4e 100644 --- a/include/xfs_trans.h +++ b/include/xfs_trans.h @@ -75,6 +75,10 @@ typedef struct xfs_trans { long t_frextents_delta;/* superblock freextents chg*/ struct list_head t_items; /* log item descriptors */ struct list_head t_dfops; /* deferred operations */ + + unsigned int t_dfops_nr; + unsigned int t_dfops_nr_max; + unsigned int t_dfops_finished; } xfs_trans_t; void xfs_trans_init(struct xfs_mount *); diff --git a/libxfs/xfs_defer.c b/libxfs/xfs_defer.c index 1d8bf2f6f65..2ca03674e2d 100644 --- a/libxfs/xfs_defer.c +++ b/libxfs/xfs_defer.c @@ -504,6 +504,8 @@ xfs_defer_finish_one( /* Done with the dfp, free it. */ list_del(&dfp->dfp_list); kmem_cache_free(xfs_defer_pending_cache, dfp); + tp->t_dfops_nr--; + tp->t_dfops_finished++; out: if (ops->finish_cleanup) ops->finish_cleanup(tp, state, error); @@ -545,6 +547,9 @@ xfs_defer_finish_noroll( list_splice_init(&(*tp)->t_dfops, &dop_pending); + (*tp)->t_dfops_nr_max = max((*tp)->t_dfops_nr, + (*tp)->t_dfops_nr_max); + if (has_intents < 0) { error = has_intents; goto out_shutdown; @@ -575,6 +580,7 @@ xfs_defer_finish_noroll( xfs_force_shutdown((*tp)->t_mountp, SHUTDOWN_CORRUPT_INCORE); trace_xfs_defer_finish_error(*tp, error); xfs_defer_cancel_list((*tp)->t_mountp, &dop_pending); + (*tp)->t_dfops_nr = 0; xfs_defer_cancel(*tp); return error; } @@ -615,6 +621,7 @@ xfs_defer_cancel( trace_xfs_defer_cancel(tp, _RET_IP_); xfs_defer_cancel_list(mp, &tp->t_dfops); + tp->t_dfops_nr = 0; } /* Add an item for later deferred processing. */ @@ -651,6 +658,7 @@ xfs_defer_add( dfp->dfp_count = 0; INIT_LIST_HEAD(&dfp->dfp_work); list_add_tail(&dfp->dfp_list, &tp->t_dfops); + tp->t_dfops_nr++; } list_add_tail(li, &dfp->dfp_work); @@ -669,6 +677,12 @@ xfs_defer_move( struct xfs_trans *stp) { list_splice_init(&stp->t_dfops, &dtp->t_dfops); + dtp->t_dfops_nr += stp->t_dfops_nr; + dtp->t_dfops_nr_max = stp->t_dfops_nr_max; + dtp->t_dfops_finished = stp->t_dfops_finished; + stp->t_dfops_nr = 0; + stp->t_dfops_nr_max = 0; + stp->t_dfops_finished = 0; /* * Low free space mode was historically controlled by a dfops field. From patchwork Fri Dec 30 22:20:40 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: 13085939 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 1B1FBC4332F for ; Sat, 31 Dec 2022 03:25:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236383AbiLaDZ2 (ORCPT ); Fri, 30 Dec 2022 22:25:28 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38492 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236361AbiLaDZV (ORCPT ); Fri, 30 Dec 2022 22:25:21 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 61F8612A80 for ; Fri, 30 Dec 2022 19:25:20 -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 1EA5CB81E73 for ; Sat, 31 Dec 2022 03:25:19 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id D6377C433EF; Sat, 31 Dec 2022 03:25:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1672457117; bh=XbOYt1quCT5N6pjlEpWpbq50eoDCaFVreZdvSgEY/g0=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=Y8IS2IG2pjtulM2YIISK6ATMMil0lqXRugu91N8HLb3sZ2xcifq0iCTvAxN1mPFku EKZzGx3KJWynKObQwda8C7YKhflSZaMmCiyZwGv7mz/URk+rMU88B6hQr+As+V+lfk pqrCXsZkd89NbdQDLjrwvESPqV6K/bnP1OmIHa0sSVcoeNx8Rx+W3xExvsOfG9k2ya t6uZLlmbEWinDimdmY3tPbeqQOFITiqojLg2LKESVfwEMSN14udWRo/tyMvkg2G9cS Fu+nbdoKTBy9u7glffvsexn0XUicgAwdfiN+81C3VKVF/m7MShT+DvmLf2v1P3biz1 FfxIEEvJkoVvA== Subject: [PATCH 02/11] xfs: introduce vectored scrub mode From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Date: Fri, 30 Dec 2022 14:20:40 -0800 Message-ID: <167243884059.739244.8952934219433779096.stgit@magnolia> In-Reply-To: <167243884029.739244.16777239536975047510.stgit@magnolia> References: <167243884029.739244.16777239536975047510.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 Introduce a variant on XFS_SCRUB_METADATA that allows for vectored mode. Signed-off-by: Darrick J. Wong --- libxfs/xfs_fs.h | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h index 453b0861225..067dd0b1315 100644 --- a/libxfs/xfs_fs.h +++ b/libxfs/xfs_fs.h @@ -751,6 +751,15 @@ struct xfs_scrub_metadata { /* Number of scrub subcommands. */ #define XFS_SCRUB_TYPE_NR 32 +/* + * This special type code only applies to the vectored scrub implementation. + * + * If any of the previous scrub vectors recorded runtime errors or have + * sv_flags bits set that match the OFLAG bits in the barrier vector's + * sv_flags, set the barrier's sv_ret to -ECANCELED and return to userspace. + */ +#define XFS_SCRUB_TYPE_BARRIER (-1U) + /* i: Repair this metadata. */ #define XFS_SCRUB_IFLAG_REPAIR (1u << 0) @@ -795,6 +804,33 @@ struct xfs_scrub_metadata { XFS_SCRUB_OFLAG_NO_REPAIR_NEEDED) #define XFS_SCRUB_FLAGS_ALL (XFS_SCRUB_FLAGS_IN | XFS_SCRUB_FLAGS_OUT) +struct xfs_scrub_vec { + __u32 sv_type; /* XFS_SCRUB_TYPE_* */ + __u32 sv_flags; /* XFS_SCRUB_FLAGS_* */ + __s32 sv_ret; /* 0 or a negative error code */ + __u32 sv_reserved; /* must be zero */ +}; + +/* Vectored metadata scrub control structure. */ +struct xfs_scrub_vec_head { + __u64 svh_ino; /* inode number. */ + __u32 svh_gen; /* inode generation. */ + __u32 svh_agno; /* ag number. */ + __u32 svh_flags; /* XFS_SCRUB_VEC_FLAGS_* */ + __u16 svh_rest_us; /* wait this much time between vector items */ + __u16 svh_nr; /* number of svh_vecs */ + + struct xfs_scrub_vec svh_vecs[0]; +}; + +#define XFS_SCRUB_VEC_FLAGS_ALL (0) + +static inline size_t sizeof_xfs_scrub_vec(unsigned int nr) +{ + return sizeof(struct xfs_scrub_vec_head) + + nr * sizeof(struct xfs_scrub_vec); +} + /* * ioctl limits */ @@ -839,6 +875,7 @@ struct xfs_scrub_metadata { #define XFS_IOC_FREE_EOFBLOCKS _IOR ('X', 58, struct xfs_fs_eofblocks) /* XFS_IOC_GETFSMAP ------ hoisted 59 */ #define XFS_IOC_SCRUB_METADATA _IOWR('X', 60, struct xfs_scrub_metadata) +#define XFS_IOC_SCRUBV_METADATA _IOWR('X', 60, struct xfs_scrub_vec_head) #define XFS_IOC_AG_GEOMETRY _IOWR('X', 61, struct xfs_ag_geometry) #define XFS_IOC_RTGROUP_GEOMETRY _IOWR('X', 62, struct xfs_rtgroup_geometry) From patchwork Fri Dec 30 22:20:40 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: 13085941 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 D182CC3DA7C for ; Sat, 31 Dec 2022 03:25:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236390AbiLaDZq (ORCPT ); Fri, 30 Dec 2022 22:25:46 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38522 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236357AbiLaDZf (ORCPT ); Fri, 30 Dec 2022 22:25:35 -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 61AF712A80 for ; Fri, 30 Dec 2022 19:25:34 -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 0142B61C7A for ; Sat, 31 Dec 2022 03:25:34 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5F7AFC433EF; Sat, 31 Dec 2022 03:25:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1672457133; bh=RedcZtUlhM9LzsQTYpybCqt2h/vSHAx1cngBcOQQlF0=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=Nhlfkw58wV5YTejfcAFXRtg/XoRG5J86HaidwJpGhj+77aXWKzvs2wLJZUDXxs0qe aJa5bSTC4uuKKfHe0K1R4Q2K6aXioplmJh+m4mdL9iN6feNDenv3yxIJfQQefuKA9H 0dQzBnTJgjhlS7xglL/FCkq+yEQxMIhgTr3S8iXD/lzTw8pV2tCdD2v4DUXTFTDLYm CRaM3muqvHvH3tKFaI6dPQzgMdxZwZ42raYCGDNpippcYaKjUkT/4rMWObQSF28SBp jtc8Re2WC+5FM3Iv+HGDP0YuYgytAyJVJTawrzqIX/FJNONkaa0mid5ELPvem5zKVV 5bjapW8d/QgZg== Subject: [PATCH 03/11] libfrog: support vectored scrub From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Date: Fri, 30 Dec 2022 14:20:40 -0800 Message-ID: <167243884072.739244.9544942319521737422.stgit@magnolia> In-Reply-To: <167243884029.739244.16777239536975047510.stgit@magnolia> References: <167243884029.739244.16777239536975047510.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 libfrog to support performing vectored metadata scrub. Signed-off-by: Darrick J. Wong --- libfrog/fsgeom.h | 6 +++ libfrog/scrub.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ libfrog/scrub.h | 1 3 files changed, 131 insertions(+) diff --git a/libfrog/fsgeom.h b/libfrog/fsgeom.h index 6c6d6bb815a..0265a7c1684 100644 --- a/libfrog/fsgeom.h +++ b/libfrog/fsgeom.h @@ -58,6 +58,12 @@ struct xfs_fd { /* Only use FIEXCHANGE_RANGE for file data exchanges. */ #define XFROG_FLAG_FORCE_FIEXCHANGE (1 << 3) +/* Only use the older one-at-a-time scrub ioctl. */ +#define XFROG_FLAG_SCRUB_FORCE_SINGLE (1 << 4) + +/* Only use the vectored scrub ioctl. */ +#define XFROG_FLAG_SCRUB_FORCE_VECTOR (1 << 5) + /* Static initializers */ #define XFS_FD_INIT(_fd) { .fd = (_fd), } #define XFS_FD_INIT_EMPTY XFS_FD_INIT(-1) diff --git a/libfrog/scrub.c b/libfrog/scrub.c index c3cf5312f80..02b659ea2bd 100644 --- a/libfrog/scrub.c +++ b/libfrog/scrub.c @@ -186,3 +186,127 @@ xfrog_scrub_metadata( return 0; } + +/* Decide if there have been any scrub failures up to this point. */ +static inline int +xfrog_scrubv_previous_failures( + struct xfs_scrub_vec_head *vhead, + struct xfs_scrub_vec *barrier_vec) +{ + struct xfs_scrub_vec *v; + __u32 failmask; + + failmask = barrier_vec->sv_flags & XFS_SCRUB_FLAGS_OUT; + for (v = vhead->svh_vecs; v < barrier_vec; v++) { + if (v->sv_type == XFS_SCRUB_TYPE_BARRIER) + continue; + + /* + * Runtime errors count as a previous failure, except the ones + * used to ask userspace to retry. + */ + if (v->sv_ret && v->sv_ret != -EBUSY && v->sv_ret != -ENOENT && + v->sv_ret != -EUSERS) + return -ECANCELED; + + /* + * If any of the out-flags on the scrub vector match the mask + * that was set on the barrier vector, that's a previous fail. + */ + if (v->sv_flags & failmask) + return -ECANCELED; + } + + return 0; +} + +static int +xfrog_scrubv_fallback( + struct xfs_fd *xfd, + struct xfs_scrub_vec_head *vhead) +{ + struct xfs_scrub_vec *v; + unsigned int i; + + if (vhead->svh_flags & ~XFS_SCRUB_VEC_FLAGS_ALL) + return -EINVAL; + for (i = 0, v = vhead->svh_vecs; i < vhead->svh_nr; i++, v++) { + if (v->sv_reserved) + return -EINVAL; + if (v->sv_type == XFS_SCRUB_TYPE_BARRIER && + (v->sv_flags & ~XFS_SCRUB_FLAGS_OUT)) + return -EINVAL; + } + + /* Run all the scrubbers. */ + for (i = 0, v = vhead->svh_vecs; i < vhead->svh_nr; i++, v++) { + struct xfs_scrub_metadata sm = { + .sm_type = v->sv_type, + .sm_flags = v->sv_flags, + .sm_ino = vhead->svh_ino, + .sm_gen = vhead->svh_gen, + .sm_agno = vhead->svh_agno, + }; + struct timespec tv; + + if (v->sv_type == XFS_SCRUB_TYPE_BARRIER) { + v->sv_ret = xfrog_scrubv_previous_failures(vhead, v); + if (v->sv_ret) + break; + continue; + } + + v->sv_ret = xfrog_scrub_metadata(xfd, &sm); + v->sv_flags = sm.sm_flags; + + if (vhead->svh_rest_us) { + tv.tv_sec = 0; + tv.tv_nsec = vhead->svh_rest_us * 1000; + nanosleep(&tv, NULL); + } + } + + return 0; +} + +/* Invoke the vectored scrub ioctl. */ +static int +xfrog_scrubv_call( + struct xfs_fd *xfd, + struct xfs_scrub_vec_head *vhead) +{ + int ret; + + ret = ioctl(xfd->fd, XFS_IOC_SCRUBV_METADATA, vhead); + if (ret) + return -errno; + + return 0; +} + +/* Invoke the vectored scrub ioctl. Returns zero or negative error code. */ +int +xfrog_scrubv_metadata( + struct xfs_fd *xfd, + struct xfs_scrub_vec_head *vhead) +{ + int error = 0; + + if (xfd->flags & XFROG_FLAG_SCRUB_FORCE_SINGLE) + goto try_single; + + error = xfrog_scrubv_call(xfd, vhead); + if (error == 0 || (xfd->flags & XFROG_FLAG_SCRUB_FORCE_VECTOR)) + return error; + + /* If the vectored scrub ioctl wasn't found, force single mode. */ + switch (error) { + case -EOPNOTSUPP: + case -ENOTTY: + xfd->flags |= XFROG_FLAG_SCRUB_FORCE_SINGLE; + break; + } + +try_single: + return xfrog_scrubv_fallback(xfd, vhead); +} diff --git a/libfrog/scrub.h b/libfrog/scrub.h index 7155e6a9b0e..2f5ca2b1317 100644 --- a/libfrog/scrub.h +++ b/libfrog/scrub.h @@ -28,5 +28,6 @@ struct xfrog_scrub_descr { extern const struct xfrog_scrub_descr xfrog_scrubbers[XFS_SCRUB_TYPE_NR]; int xfrog_scrub_metadata(struct xfs_fd *xfd, struct xfs_scrub_metadata *meta); +int xfrog_scrubv_metadata(struct xfs_fd *xfd, struct xfs_scrub_vec_head *vhead); #endif /* __LIBFROG_SCRUB_H__ */ From patchwork Fri Dec 30 22:20:40 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: 13085942 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 6A411C4332F for ; Sat, 31 Dec 2022 03:25:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236360AbiLaDZy (ORCPT ); Fri, 30 Dec 2022 22:25:54 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38778 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236230AbiLaDZx (ORCPT ); Fri, 30 Dec 2022 22:25:53 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CDE2F2BFB for ; Fri, 30 Dec 2022 19:25:51 -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 5B360B81E74 for ; Sat, 31 Dec 2022 03:25:50 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 06F84C433D2; Sat, 31 Dec 2022 03:25:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1672457149; bh=Wp++0LyVbyEC2+8RIZXT3ZwSvga8CKJBwKsq+Hq7knQ=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=s5B9tnL0Yu+BvLDKTbgZX2yqyQIFUwznW3RsK2Ofaxdb8Sokic5+cRGhKbqoxMOvb pNPtteMjfSApY6E/q1tS0qG9ZAMEsqWqTBos1o8OiMl62kvsP3B9Eh6YewGto5v9Ne d3v/PRtZIRT4T0UU1aWrRRTWTT2lwcSrq8wD2LMBcQIBjHU1P571FUqMYnyp8gs4Zz RX5kzORdMx4+JIW8j+tkxHBA+9cgYBZVbrDr11SuXSET+B/BLtJG/Fx2vaEFwjgEK0 M5lzgI3U2vnyupD/GNaBV/0PVfQm08AfYIwjkjOEkrH80MjWIBVHG1P+kPNyNaOM12 ztHVjowKffoaQ== Subject: [PATCH 04/11] xfs_io: support vectored scrub From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Date: Fri, 30 Dec 2022 14:20:40 -0800 Message-ID: <167243884086.739244.15774628633142018640.stgit@magnolia> In-Reply-To: <167243884029.739244.16777239536975047510.stgit@magnolia> References: <167243884029.739244.16777239536975047510.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 new scrubv command to xfs_io to support the vectored scrub ioctl. Signed-off-by: Darrick J. Wong --- io/scrub.c | 485 ++++++++++++++++++++++++++++++++++++++++++++--------- man/man8/xfs_io.8 | 47 +++++ 2 files changed, 451 insertions(+), 81 deletions(-) diff --git a/io/scrub.c b/io/scrub.c index d764a5a997b..117855f8c7a 100644 --- a/io/scrub.c +++ b/io/scrub.c @@ -12,10 +12,13 @@ #include "libfrog/paths.h" #include "libfrog/fsgeom.h" #include "libfrog/scrub.h" +#include "libfrog/logging.h" #include "io.h" +#include "list.h" static struct cmdinfo scrub_cmd; static struct cmdinfo repair_cmd; +static const struct cmdinfo scrubv_cmd; static void scrub_help(void) @@ -42,54 +45,61 @@ scrub_help(void) } static void -scrub_ioctl( - int fd, - int type, - uint64_t control, - uint32_t control2, - uint32_t flags) +report_scrub_outcome( + uint32_t flags) { - struct xfs_scrub_metadata meta; - const struct xfrog_scrub_descr *sc; - int error; - - sc = &xfrog_scrubbers[type]; - memset(&meta, 0, sizeof(meta)); - meta.sm_type = type; - switch (sc->group) { - case XFROG_SCRUB_GROUP_AGHEADER: - case XFROG_SCRUB_GROUP_PERAG: - case XFROG_SCRUB_GROUP_RTGROUP: - meta.sm_agno = control; - break; - case XFROG_SCRUB_GROUP_INODE: - meta.sm_ino = control; - meta.sm_gen = control2; - break; - case XFROG_SCRUB_GROUP_NONE: - case XFROG_SCRUB_GROUP_METAFILES: - case XFROG_SCRUB_GROUP_SUMMARY: - case XFROG_SCRUB_GROUP_ISCAN: - /* no control parameters */ - break; - } - meta.sm_flags = flags; - - error = ioctl(fd, XFS_IOC_SCRUB_METADATA, &meta); - if (error) - perror("scrub"); - if (meta.sm_flags & XFS_SCRUB_OFLAG_CORRUPT) + if (flags & XFS_SCRUB_OFLAG_CORRUPT) printf(_("Corruption detected.\n")); - if (meta.sm_flags & XFS_SCRUB_OFLAG_PREEN) + if (flags & XFS_SCRUB_OFLAG_PREEN) printf(_("Optimization possible.\n")); - if (meta.sm_flags & XFS_SCRUB_OFLAG_XFAIL) + if (flags & XFS_SCRUB_OFLAG_XFAIL) printf(_("Cross-referencing failed.\n")); - if (meta.sm_flags & XFS_SCRUB_OFLAG_XCORRUPT) + if (flags & XFS_SCRUB_OFLAG_XCORRUPT) printf(_("Corruption detected during cross-referencing.\n")); - if (meta.sm_flags & XFS_SCRUB_OFLAG_INCOMPLETE) + if (flags & XFS_SCRUB_OFLAG_INCOMPLETE) printf(_("Scan was not complete.\n")); } +static void +scrub_ioctl( + int fd, + int type, + uint64_t control, + uint32_t control2, + uint32_t flags) +{ + struct xfs_scrub_metadata meta; + const struct xfrog_scrub_descr *sc; + int error; + + sc = &xfrog_scrubbers[type]; + memset(&meta, 0, sizeof(meta)); + meta.sm_type = type; + switch (sc->group) { + case XFROG_SCRUB_GROUP_AGHEADER: + case XFROG_SCRUB_GROUP_PERAG: + case XFROG_SCRUB_GROUP_RTGROUP: + meta.sm_agno = control; + break; + case XFROG_SCRUB_GROUP_INODE: + meta.sm_ino = control; + meta.sm_gen = control2; + break; + case XFROG_SCRUB_GROUP_NONE: + case XFROG_SCRUB_GROUP_METAFILES: + case XFROG_SCRUB_GROUP_SUMMARY: + case XFROG_SCRUB_GROUP_ISCAN: + /* no control parameters */ + break; + } + meta.sm_flags = flags; + + error = ioctl(fd, XFS_IOC_SCRUB_METADATA, &meta); + if (error) + perror("scrub"); + report_scrub_outcome(meta.sm_flags); +} + static int parse_args( int argc, @@ -223,6 +233,7 @@ scrub_init(void) scrub_cmd.help = scrub_help; add_command(&scrub_cmd); + add_command(&scrubv_cmd); } static void @@ -252,56 +263,63 @@ repair_help(void) } static void -repair_ioctl( - int fd, - int type, - uint64_t control, - uint32_t control2, - uint32_t flags) +report_repair_outcome( + uint32_t flags) { - struct xfs_scrub_metadata meta; - const struct xfrog_scrub_descr *sc; - int error; - - sc = &xfrog_scrubbers[type]; - memset(&meta, 0, sizeof(meta)); - meta.sm_type = type; - switch (sc->group) { - case XFROG_SCRUB_GROUP_AGHEADER: - case XFROG_SCRUB_GROUP_PERAG: - case XFROG_SCRUB_GROUP_RTGROUP: - meta.sm_agno = control; - break; - case XFROG_SCRUB_GROUP_INODE: - meta.sm_ino = control; - meta.sm_gen = control2; - break; - case XFROG_SCRUB_GROUP_NONE: - case XFROG_SCRUB_GROUP_METAFILES: - case XFROG_SCRUB_GROUP_SUMMARY: - case XFROG_SCRUB_GROUP_ISCAN: - /* no control parameters */ - break; - } - meta.sm_flags = flags | XFS_SCRUB_IFLAG_REPAIR; - - error = ioctl(fd, XFS_IOC_SCRUB_METADATA, &meta); - if (error) - perror("repair"); - if (meta.sm_flags & XFS_SCRUB_OFLAG_CORRUPT) + if (flags & XFS_SCRUB_OFLAG_CORRUPT) printf(_("Corruption remains.\n")); - if (meta.sm_flags & XFS_SCRUB_OFLAG_PREEN) + if (flags & XFS_SCRUB_OFLAG_PREEN) printf(_("Optimization possible.\n")); - if (meta.sm_flags & XFS_SCRUB_OFLAG_XFAIL) + if (flags & XFS_SCRUB_OFLAG_XFAIL) printf(_("Cross-referencing failed.\n")); - if (meta.sm_flags & XFS_SCRUB_OFLAG_XCORRUPT) + if (flags & XFS_SCRUB_OFLAG_XCORRUPT) printf(_("Corruption still detected during cross-referencing.\n")); - if (meta.sm_flags & XFS_SCRUB_OFLAG_INCOMPLETE) + if (flags & XFS_SCRUB_OFLAG_INCOMPLETE) printf(_("Repair was not complete.\n")); - if (meta.sm_flags & XFS_SCRUB_OFLAG_NO_REPAIR_NEEDED) + if (flags & XFS_SCRUB_OFLAG_NO_REPAIR_NEEDED) printf(_("Metadata did not need repair or optimization.\n")); } +static void +repair_ioctl( + int fd, + int type, + uint64_t control, + uint32_t control2, + uint32_t flags) +{ + struct xfs_scrub_metadata meta; + const struct xfrog_scrub_descr *sc; + int error; + + sc = &xfrog_scrubbers[type]; + memset(&meta, 0, sizeof(meta)); + meta.sm_type = type; + switch (sc->group) { + case XFROG_SCRUB_GROUP_AGHEADER: + case XFROG_SCRUB_GROUP_PERAG: + case XFROG_SCRUB_GROUP_RTGROUP: + meta.sm_agno = control; + break; + case XFROG_SCRUB_GROUP_INODE: + meta.sm_ino = control; + meta.sm_gen = control2; + break; + case XFROG_SCRUB_GROUP_NONE: + case XFROG_SCRUB_GROUP_METAFILES: + case XFROG_SCRUB_GROUP_SUMMARY: + case XFROG_SCRUB_GROUP_ISCAN: + /* no control parameters */ + break; + } + meta.sm_flags = flags | XFS_SCRUB_IFLAG_REPAIR; + + error = ioctl(fd, XFS_IOC_SCRUB_METADATA, &meta); + if (error) + perror("repair"); + report_repair_outcome(meta.sm_flags); +} + static int repair_f( int argc, @@ -327,3 +345,308 @@ repair_init(void) add_command(&repair_cmd); } + +static void +scrubv_help(void) +{ + printf(_( +"\n" +" Scrubs pieces of XFS filesystem metadata. The first argument is the group\n" +" of metadata to examine. If the group is 'ag', the second parameter should\n" +" be the AG number. If the group is 'inode', the second and third parameters\n" +" should be the inode number and generation number to act upon; if these are\n" +" omitted, the scrub is performed on the open file. If the group is 'fs',\n" +" 'summary', or 'probe', there are no other parameters.\n" +"\n" +" Flags are -d for debug, and -r to allow repairs.\n" +" -b NN will insert a scrub barrier after every NN scrubs, and -m sets the\n" +" desired corruption mask in all barriers. -w pauses for some microseconds\n" +" after each scrub call.\n" +"\n" +" Example:\n" +" 'scrubv ag 3' - scrub all metadata in AG 3.\n" +" 'scrubv ag 3 -b 2 -m 0x4' - scrub all metadata in AG 3, and use barriers\n" +" every third scrub to exit early if there are optimizations.\n" +" 'scrubv fs' - scrub all non-AG non-file metadata.\n" +" 'scrubv inode' - scrub all metadata for the open file.\n" +" 'scrubv inode 128 13525' - scrub all metadata for inode 128 gen 13525.\n" +" 'scrubv probe' - check for presence of online scrub.\n" +" 'scrubv summary' - scrub all summary metadata.\n")); +} + +/* Fill out the scrub vectors for a group of scrubber (ag, ino, fs, summary) */ +static void +scrubv_fill_group( + struct xfs_scrub_vec_head *vhead, + int barrier_interval, + __u32 barrier_mask, + enum xfrog_scrub_group group) +{ + const struct xfrog_scrub_descr *d; + unsigned int i; + + for (i = 0, d = xfrog_scrubbers; i < XFS_SCRUB_TYPE_NR; i++, d++) { + if (d->group != group) + continue; + vhead->svh_vecs[vhead->svh_nr++].sv_type = i; + + if (barrier_interval && + vhead->svh_nr % (barrier_interval + 1) == 0) { + struct xfs_scrub_vec *v; + + v = &vhead->svh_vecs[vhead->svh_nr++]; + v->sv_flags = barrier_mask; + v->sv_type = XFS_SCRUB_TYPE_BARRIER; + } + } +} + +/* Declare a structure big enough to handle all scrub types + barriers */ +struct scrubv_head { + struct xfs_scrub_vec_head head; + struct xfs_scrub_vec __vecs[XFS_SCRUB_TYPE_NR * 2]; +}; + + +static int +scrubv_f( + int argc, + char **argv) +{ + struct scrubv_head bighead = { }; + struct xfs_fd xfd = XFS_FD_INIT(file->fd); + struct xfs_scrub_vec_head *vhead = &bighead.head; + struct xfs_scrub_vec *v; + char *p; + uint32_t flags = 0; + __u32 barrier_mask = XFS_SCRUB_OFLAG_CORRUPT; + enum xfrog_scrub_group group; + bool debug = false; + int version = -1; + int barrier_interval = 0; + int rest_us = 0; + int c; + int error; + + while ((c = getopt(argc, argv, "b:dm:rv:w:")) != EOF) { + switch (c) { + case 'b': + barrier_interval = atoi(optarg); + if (barrier_interval < 0) { + printf( + _("Negative barrier interval makes no sense.\n")); + return 0; + } + break; + case 'd': + debug = true; + break; + case 'm': + barrier_mask = strtoul(optarg, NULL, 0); + break; + case 'r': + flags |= XFS_SCRUB_IFLAG_REPAIR; + break; + case 'v': + version = atoi(optarg); + if (version != 0 && version != 1) { + printf(_("API version must be 0 or 1.\n")); + return 0; + } + break; + case 'w': + rest_us = atoi(optarg); + if (rest_us < 0) { + printf(_("Rest time must be positive.\n")); + return 0; + } + break; + default: + scrubv_help(); + return 0; + } + } + if (optind > argc - 1) { + scrubv_help(); + return 0; + } + + if ((flags & XFS_SCRUB_IFLAG_REPAIR) && !expert) { + printf(_("Repair flag requires expert mode.\n")); + return 1; + } + + vhead->svh_rest_us = rest_us; + for (c = 0, v = vhead->svh_vecs; c < vhead->svh_nr; c++, v++) + v->sv_flags = flags; + + /* Extract group and domain information from cmdline. */ + if (!strcmp(argv[optind], "probe")) + group = XFROG_SCRUB_GROUP_NONE; + else if (!strcmp(argv[optind], "agheader")) + group = XFROG_SCRUB_GROUP_AGHEADER; + else if (!strcmp(argv[optind], "ag")) + group = XFROG_SCRUB_GROUP_PERAG; + else if (!strcmp(argv[optind], "metafiles")) + group = XFROG_SCRUB_GROUP_METAFILES; + else if (!strcmp(argv[optind], "inode")) + group = XFROG_SCRUB_GROUP_INODE; + else if (!strcmp(argv[optind], "iscan")) + group = XFROG_SCRUB_GROUP_ISCAN; + else if (!strcmp(argv[optind], "summary")) + group = XFROG_SCRUB_GROUP_SUMMARY; + else if (!strcmp(argv[optind], "rtgroup")) + group = XFROG_SCRUB_GROUP_RTGROUP; + else { + printf(_("Unknown group '%s'.\n"), argv[optind]); + scrubv_help(); + return 0; + } + optind++; + + switch (group) { + case XFROG_SCRUB_GROUP_INODE: + if (optind == argc) { + vhead->svh_ino = 0; + vhead->svh_gen = 0; + } else if (optind == argc - 2) { + vhead->svh_ino = strtoull(argv[optind], &p, 0); + if (*p != '\0') { + fprintf(stderr, + _("Bad inode number '%s'.\n"), + argv[optind]); + return 0; + } + vhead->svh_gen = strtoul(argv[optind + 1], &p, 0); + if (*p != '\0') { + fprintf(stderr, + _("Bad generation number '%s'.\n"), + argv[optind + 1]); + return 0; + } + } else { + fprintf(stderr, + _("Must specify inode number and generation.\n")); + return 0; + } + break; + case XFROG_SCRUB_GROUP_AGHEADER: + case XFROG_SCRUB_GROUP_PERAG: + if (optind != argc - 1) { + fprintf(stderr, + _("Must specify one AG number.\n")); + return 0; + } + vhead->svh_agno = strtoul(argv[optind], &p, 0); + if (*p != '\0') { + fprintf(stderr, + _("Bad AG number '%s'.\n"), argv[optind]); + return 0; + } + break; + case XFROG_SCRUB_GROUP_METAFILES: + case XFROG_SCRUB_GROUP_SUMMARY: + case XFROG_SCRUB_GROUP_ISCAN: + case XFROG_SCRUB_GROUP_NONE: + if (optind != argc) { + fprintf(stderr, + _("No parameters allowed.\n")); + return 0; + } + break; + case XFROG_SCRUB_GROUP_RTGROUP: + if (optind != argc - 1) { + fprintf(stderr, + _("Must specify one rtgroup number.\n")); + return 0; + } + vhead->svh_agno = strtoul(argv[optind], &p, 0); + if (*p != '\0') { + fprintf(stderr, + _("Bad rtgroup number '%s'.\n"), argv[optind]); + return 0; + } + break; + default: + ASSERT(0); + break; + } + scrubv_fill_group(vhead, barrier_interval, barrier_mask, group); + assert(vhead->svh_nr < ARRAY_SIZE(bighead.__vecs)); + + error = -xfd_prepare_geometry(&xfd); + if (error) { + xfrog_perror(error, "xfd_prepare_geometry"); + exitcode = 1; + return 0; + } + + switch (version) { + case 0: + xfd.flags |= XFROG_FLAG_SCRUB_FORCE_SINGLE; + break; + case 1: + xfd.flags |= XFROG_FLAG_SCRUB_FORCE_VECTOR; + break; + default: + break; + } + + error = -xfrog_scrubv_metadata(&xfd, vhead); + if (error) { + xfrog_perror(error, "xfrog_scrub_many"); + exitcode = 1; + return 0; + } + + /* Figure out what happened. */ + for (c = 0, v = vhead->svh_vecs; debug && c < vhead->svh_nr; c++, v++) { + const char *type; + + if (v->sv_type == XFS_SCRUB_TYPE_BARRIER) + type = _("barrier"); + else + type = _(xfrog_scrubbers[v->sv_type].descr); + printf(_("[%02u] %-25s: flags 0x%x ret %d\n"), c, type, + v->sv_flags, v->sv_ret); + } + + /* Figure out what happened. */ + for (c = 0, v = vhead->svh_vecs; c < vhead->svh_nr; c++, v++) { + /* Report barrier failures. */ + if (v->sv_type == XFS_SCRUB_TYPE_BARRIER) { + if (v->sv_ret) { + printf(_("barrier: FAILED\n")); + break; + } + continue; + } + + printf("%s: ", _(xfrog_scrubbers[v->sv_type].descr)); + switch (v->sv_ret) { + case 0: + break; + default: + printf("%s\n", strerror(-v->sv_ret)); + continue; + } + if (!(v->sv_flags & XFS_SCRUB_FLAGS_OUT)) + printf(_("OK.\n")); + else if (v->sv_flags & XFS_SCRUB_IFLAG_REPAIR) + report_repair_outcome(v->sv_flags); + else + report_scrub_outcome(v->sv_flags); + } + + return 0; +} + +static const struct cmdinfo scrubv_cmd = { + .name = "scrubv", + .cfunc = scrubv_f, + .argmin = 1, + .argmax = -1, + .flags = CMD_NOMAP_OK, + .oneline = N_("vectored metadata scrub"), + .help = scrubv_help, +}; diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8 index 16768275b5c..92458e8a787 100644 --- a/man/man8/xfs_io.8 +++ b/man/man8/xfs_io.8 @@ -1420,6 +1420,53 @@ inode number and generation number are specified. .RE .PD .TP +.BI "scrubv [ \-b NN ] [ \-d ] [ \-f ] [ \-r ] [ \-v NN ] [ \-w ms ] " group " [ " agnumber " | " "ino" " " "gen" " ]" +Scrub a bunch of internal XFS filesystem metadata. +The +.BI group +parameter specifies which group of metadata to scrub. +Valid groups are +.IR ag ", " agheader ", " inode ", " iscan ", " metafiles ", " probe ", " rtgroup ", or " summary . + +For +.BR ag " and " agheader +metadata, one AG number must be specified. +For +.B inode +metadata, the scrub is applied to the open file unless the +inode number and generation number are specified. +For +.B rtgroup +metadata, one rt group number must be specified. + +.RS 1.0i +.PD 0 +.TP +.BI "\-b " NN +Inject scrub barriers into the vector stream at the given interval. +Barriers abort vector processing if any previous scrub function found +corruption. +.TP +.BI \-d +Enables debug mode. +.TP +.BI \-f +Permit the kernel to freeze the filesystem in order to scrub or repair. +.TP +.BI \-r +Repair metadata if corruptions are found. +This option requires expert mode. +.TP +.BI "\-v " NN +Force a particular API version. +0 selects XFS_SCRUB_METADATA (one-by-one). +1 selects XFS_SCRUBV_METADATA (vectored). +.TP +.BI "\-w " us +Wait the given number of microseconds between each scrub function. +.RE +.PD +.TP .BI "repair " type " [ " agnumber " | " "ino" " " "gen" " ]" Repair internal XFS filesystem metadata. The .BI type From patchwork Fri Dec 30 22:20:41 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: 13085947 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 B8538C4332F for ; Sat, 31 Dec 2022 03:26:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236357AbiLaD0H (ORCPT ); Fri, 30 Dec 2022 22:26:07 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38836 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236230AbiLaD0G (ORCPT ); Fri, 30 Dec 2022 22:26:06 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A6346112C for ; Fri, 30 Dec 2022 19:26:05 -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 2FFF961C7A for ; Sat, 31 Dec 2022 03:26:05 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8C0C6C433EF; Sat, 31 Dec 2022 03:26:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1672457164; bh=W/kKXhrJ7IGToBylBD4kRjqto5d63izvnyW9Pq6yoBQ=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=s82BHKW2Qa3DHtMxEnRdsDSdUC5ls8hAnaL1Ygqd7bI/Ekw9OH6Tob0L3d8XFhHuS EUM/e9FxBheqaIsARdywlN1C54KZc+o7SH7aHlCOVXxUxbIoJ362o6xG/0WYo/yrMU /tvoZXj16PPH6nyX/SP/EnngpvDxrWurSF4OaRVgdrXGpK4qtXuaajQUM6z8zF3Jsm hRSGQngDOzCQZpMSFJOR/1uUstZIgeppg5Wdfby1DpnS3QH3q0u4S7UVxMBJJW2ZQr EH9wvlV//Zkkcff4LcgGb9JLBR7c989vGZ4tVHlrdWbiQcGRS2mleMWkkNWPbHizmy QzeChRAfrPVEg== Subject: [PATCH 05/11] xfs_scrub: split the scrub epilogue code into a separate function From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Date: Fri, 30 Dec 2022 14:20:41 -0800 Message-ID: <167243884099.739244.5199836162131265706.stgit@magnolia> In-Reply-To: <167243884029.739244.16777239536975047510.stgit@magnolia> References: <167243884029.739244.16777239536975047510.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 Move all the code that updates the internal state in response to a scrub ioctl() call completion into a separate function. This will help with vectorizing scrub calls later on. Signed-off-by: Darrick J. Wong --- scrub/scrub.c | 52 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/scrub/scrub.c b/scrub/scrub.c index a6d5ec056c8..b102a457cc2 100644 --- a/scrub/scrub.c +++ b/scrub/scrub.c @@ -22,6 +22,10 @@ #include "descr.h" #include "scrub_private.h" +static int scrub_epilogue(struct scrub_ctx *ctx, struct descr *dsc, + struct scrub_item *sri, struct xfs_scrub_metadata *meta, + int error); + /* Online scrub and repair wrappers. */ /* Format a scrub description. */ @@ -121,12 +125,32 @@ xfs_check_metadata( dbg_printf("check %s flags %xh\n", descr_render(&dsc), meta.sm_flags); error = -xfrog_scrub_metadata(xfdp, &meta); + return scrub_epilogue(ctx, &dsc, sri, &meta, error); +} + +/* + * Update all internal state after a scrub ioctl call. + * Returns 0 for success, or ECANCELED to abort the program. + */ +static int +scrub_epilogue( + struct scrub_ctx *ctx, + struct descr *dsc, + struct scrub_item *sri, + struct xfs_scrub_metadata *meta, + int error) +{ + unsigned int scrub_type = meta->sm_type; + enum xfrog_scrub_group group; + + group = xfrog_scrubbers[scrub_type].group; + switch (error) { case 0: /* No operational errors encountered. */ if (!sri->sri_revalidate && debug_tweak_on("XFS_SCRUB_FORCE_REPAIR")) - meta.sm_flags |= XFS_SCRUB_OFLAG_CORRUPT; + meta->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT; break; case ENOENT: /* Metadata not present, just skip it. */ @@ -134,13 +158,13 @@ xfs_check_metadata( return 0; case ESHUTDOWN: /* FS already crashed, give up. */ - str_error(ctx, descr_render(&dsc), + str_error(ctx, descr_render(dsc), _("Filesystem is shut down, aborting.")); return ECANCELED; case EIO: case ENOMEM: /* Abort on I/O errors or insufficient memory. */ - str_liberror(ctx, error, descr_render(&dsc)); + str_liberror(ctx, error, descr_render(dsc)); return ECANCELED; case EDEADLOCK: case EBUSY: @@ -156,7 +180,7 @@ _("Filesystem is shut down, aborting.")); return 0; default: /* Operational error. Log it and move on. */ - str_liberror(ctx, error, descr_render(&dsc)); + str_liberror(ctx, error, descr_render(dsc)); scrub_item_clean_state(sri, scrub_type); return 0; } @@ -167,27 +191,27 @@ _("Filesystem is shut down, aborting.")); * we'll try the scan again, just in case the fs was busy. * Only retry so many times. */ - if (want_retry(&meta) && scrub_item_schedule_retry(sri, scrub_type)) + if (want_retry(meta) && scrub_item_schedule_retry(sri, scrub_type)) return 0; /* Complain about incomplete or suspicious metadata. */ - scrub_warn_incomplete_scrub(ctx, &dsc, &meta); + scrub_warn_incomplete_scrub(ctx, dsc, meta); /* * If we need repairs or there were discrepancies, schedule a * repair if desired, otherwise complain. */ - if (is_corrupt(&meta) || xref_disagrees(&meta)) { + if (is_corrupt(meta) || xref_disagrees(meta)) { if (ctx->mode != SCRUB_MODE_REPAIR) { /* Dry-run mode, so log an error and forget it. */ - str_corrupt(ctx, descr_render(&dsc), + str_corrupt(ctx, descr_render(dsc), _("Repairs are required.")); scrub_item_clean_state(sri, scrub_type); return 0; } /* Schedule repairs. */ - scrub_item_save_state(sri, scrub_type, meta.sm_flags); + scrub_item_save_state(sri, scrub_type, meta->sm_flags); return 0; } @@ -195,12 +219,12 @@ _("Repairs are required.")); * If we could optimize, schedule a repair if desired, * otherwise complain. */ - if (is_unoptimized(&meta)) { + if (is_unoptimized(meta)) { if (ctx->mode == SCRUB_MODE_DRY_RUN) { /* Dry-run mode, so log an error and forget it. */ if (group != XFROG_SCRUB_GROUP_INODE) { /* AG or FS metadata, always warn. */ - str_info(ctx, descr_render(&dsc), + str_info(ctx, descr_render(dsc), _("Optimization is possible.")); } else if (!ctx->preen_triggers[scrub_type]) { /* File metadata, only warn once per type. */ @@ -214,7 +238,7 @@ _("Optimization is possible.")); } /* Schedule optimizations. */ - scrub_item_save_state(sri, scrub_type, meta.sm_flags); + scrub_item_save_state(sri, scrub_type, meta->sm_flags); return 0; } @@ -225,8 +249,8 @@ _("Optimization is possible.")); * re-examine the object as repairs progress to see if the kernel will * deem it completely consistent at some point. */ - if (xref_failed(&meta) && ctx->mode == SCRUB_MODE_REPAIR) { - scrub_item_save_state(sri, scrub_type, meta.sm_flags); + if (xref_failed(meta) && ctx->mode == SCRUB_MODE_REPAIR) { + scrub_item_save_state(sri, scrub_type, meta->sm_flags); return 0; } From patchwork Fri Dec 30 22:20:41 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: 13085948 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 1FCD1C4332F for ; Sat, 31 Dec 2022 03:26:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236363AbiLaD0X (ORCPT ); Fri, 30 Dec 2022 22:26:23 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38876 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236230AbiLaD0V (ORCPT ); Fri, 30 Dec 2022 22:26:21 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1D3B1112C for ; Fri, 30 Dec 2022 19:26:21 -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 ACEC561C7A for ; Sat, 31 Dec 2022 03:26:20 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 196B6C433EF; Sat, 31 Dec 2022 03:26:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1672457180; bh=4IVIFHBL/bI1p9WCFI+DozXklhDsSRsVYDN5VPF9AYE=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=bt/KFgrJKb8GB69YclFInR98Xe8FtMnm0QFXJroAJAkYwdq0+lSZ+37XxgePFx18b d2+wlay5qB00zKomgMypjFVYC6ebEHcWqdQP7M4YySkiyxkPT2eiBq7pN4OY2UQIxA luTe2q/g1MMsQ+VTeENZYLWjt0Cx9cyg/EfxkNtYBEjiRvfCB4Y8Qdkkhx2fdj3JzU lTlqpvBvz88eGtXCGTgFBwBw0hQ2zAuQBD6L9I275aex9G2n6XycB8jl/2DpxgnoLS NIeOo3WU2zUbGjW+QJxbYtPo/WyAwVs/8CTa7I9Z1yqHG+4XinOL4ThysfmSiGIc1u nnzvFrAe1GOVA== Subject: [PATCH 06/11] xfs_scrub: split the repair epilogue code into a separate function From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Date: Fri, 30 Dec 2022 14:20:41 -0800 Message-ID: <167243884112.739244.14416993847913051461.stgit@magnolia> In-Reply-To: <167243884029.739244.16777239536975047510.stgit@magnolia> References: <167243884029.739244.16777239536975047510.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 Move all the code that updates the internal state in response to a repair ioctl() call completion into a separate function. This will help with vectorizing repair calls later on. Signed-off-by: Darrick J. Wong --- scrub/repair.c | 61 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/scrub/repair.c b/scrub/repair.c index cd652dc85a1..4d8552cf9d0 100644 --- a/scrub/repair.c +++ b/scrub/repair.c @@ -20,6 +20,11 @@ #include "descr.h" #include "scrub_private.h" +static int repair_epilogue(struct scrub_ctx *ctx, struct descr *dsc, + struct scrub_item *sri, unsigned int repair_flags, + struct xfs_scrub_metadata *oldm, + struct xfs_scrub_metadata *meta, int error); + /* General repair routines. */ /* @@ -142,6 +147,22 @@ xfs_repair_metadata( _("Attempting optimization.")); error = -xfrog_scrub_metadata(xfdp, &meta); + return repair_epilogue(ctx, &dsc, sri, repair_flags, &oldm, &meta, + error); +} + +static int +repair_epilogue( + struct scrub_ctx *ctx, + struct descr *dsc, + struct scrub_item *sri, + unsigned int repair_flags, + struct xfs_scrub_metadata *oldm, + struct xfs_scrub_metadata *meta, + int error) +{ + unsigned int scrub_type = meta->sm_type; + switch (error) { case 0: /* No operational errors encountered. */ @@ -150,12 +171,12 @@ xfs_repair_metadata( case EBUSY: /* Filesystem is busy, try again later. */ if (debug || verbose) - str_info(ctx, descr_render(&dsc), + str_info(ctx, descr_render(dsc), _("Filesystem is busy, deferring repair.")); return 0; case ESHUTDOWN: /* Filesystem is already shut down, abort. */ - str_error(ctx, descr_render(&dsc), + str_error(ctx, descr_render(dsc), _("Filesystem is shut down, aborting.")); return ECANCELED; case ENOTTY: @@ -174,7 +195,7 @@ _("Filesystem is shut down, aborting.")); * If we forced repairs or this is a preen, don't * error out if the kernel doesn't know how to fix. */ - if (is_unoptimized(&oldm) || + if (is_unoptimized(oldm) || debug_tweak_on("XFS_SCRUB_FORCE_REPAIR")) { scrub_item_clean_state(sri, scrub_type); return 0; @@ -182,14 +203,14 @@ _("Filesystem is shut down, aborting.")); fallthrough; case EINVAL: /* Kernel doesn't know how to repair this? */ - str_corrupt(ctx, descr_render(&dsc), + str_corrupt(ctx, descr_render(dsc), _("Don't know how to fix; offline repair required.")); scrub_item_clean_state(sri, scrub_type); return 0; case EROFS: /* Read-only filesystem, can't fix. */ - if (verbose || debug || needs_repair(&oldm)) - str_error(ctx, descr_render(&dsc), + if (verbose || debug || needs_repair(oldm)) + str_error(ctx, descr_render(dsc), _("Read-only filesystem; cannot make changes.")); return ECANCELED; case ENOENT: @@ -199,7 +220,7 @@ _("Read-only filesystem; cannot make changes.")); case ENOMEM: case ENOSPC: /* Don't care if preen fails due to low resources. */ - if (is_unoptimized(&oldm) && !needs_repair(&oldm)) { + if (is_unoptimized(oldm) && !needs_repair(oldm)) { scrub_item_clean_state(sri, scrub_type); return 0; } @@ -214,7 +235,7 @@ _("Read-only filesystem; cannot make changes.")); */ if (!(repair_flags & XRM_FINAL_WARNING)) return 0; - str_liberror(ctx, error, descr_render(&dsc)); + str_liberror(ctx, error, descr_render(dsc)); scrub_item_clean_state(sri, scrub_type); return 0; } @@ -225,12 +246,12 @@ _("Read-only filesystem; cannot make changes.")); * the repair again, just in case the fs was busy. Only retry so many * times. */ - if (want_retry(&meta) && scrub_item_schedule_retry(sri, scrub_type)) + if (want_retry(meta) && scrub_item_schedule_retry(sri, scrub_type)) return 0; if (repair_flags & XRM_FINAL_WARNING) - scrub_warn_incomplete_scrub(ctx, &dsc, &meta); - if (needs_repair(&meta) || is_incomplete(&meta)) { + scrub_warn_incomplete_scrub(ctx, dsc, meta); + if (needs_repair(meta) || is_incomplete(meta)) { /* * Still broken; if we've been told not to complain then we * just requeue this and try again later. Otherwise we @@ -238,9 +259,9 @@ _("Read-only filesystem; cannot make changes.")); */ if (!(repair_flags & XRM_FINAL_WARNING)) return 0; - str_corrupt(ctx, descr_render(&dsc), + str_corrupt(ctx, descr_render(dsc), _("Repair unsuccessful; offline repair required.")); - } else if (xref_failed(&meta)) { + } else if (xref_failed(meta)) { /* * This metadata object itself looks ok, but we still noticed * inconsistencies when comparing it with the other filesystem @@ -249,25 +270,25 @@ _("Read-only filesystem; cannot make changes.")); * reverify the cross-referencing as repairs progress. */ if (repair_flags & XRM_FINAL_WARNING) { - str_info(ctx, descr_render(&dsc), + str_info(ctx, descr_render(dsc), _("Seems correct but cross-referencing failed; offline repair recommended.")); } else { if (verbose) - str_info(ctx, descr_render(&dsc), + str_info(ctx, descr_render(dsc), _("Seems correct but cross-referencing failed; will keep checking.")); return 0; } - } else if (meta.sm_flags & XFS_SCRUB_OFLAG_NO_REPAIR_NEEDED) { + } else if (meta->sm_flags & XFS_SCRUB_OFLAG_NO_REPAIR_NEEDED) { if (verbose) - str_info(ctx, descr_render(&dsc), + str_info(ctx, descr_render(dsc), _("No modification needed.")); } else { /* Clean operation, no corruption detected. */ - if (needs_repair(&oldm)) - record_repair(ctx, descr_render(&dsc), + if (needs_repair(oldm)) + record_repair(ctx, descr_render(dsc), _("Repairs successful.")); else - record_preen(ctx, descr_render(&dsc), + record_preen(ctx, descr_render(dsc), _("Optimization successful.")); } From patchwork Fri Dec 30 22:20:41 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: 13085949 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 45BC4C4332F for ; Sat, 31 Dec 2022 03:26:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236361AbiLaD0k (ORCPT ); Fri, 30 Dec 2022 22:26:40 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38890 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236230AbiLaD0j (ORCPT ); Fri, 30 Dec 2022 22:26:39 -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 C3CA32DCA for ; Fri, 30 Dec 2022 19:26:36 -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 4937C612E3 for ; Sat, 31 Dec 2022 03:26:36 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id A0C06C433EF; Sat, 31 Dec 2022 03:26:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1672457195; bh=FLPg68dFqVZsYvxVTJo5uuABz38w9exOZkak41dK7zs=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=qy09x6PfvD4Dvz9fY++YJaRRAe4V9gVJv2lCN7GQU/YJ2hTTtLarYbr8oEXNq2axW 9pOa3V8ZDtAHLG4tU4rByWrA0CwCFJzqh/BED1MFbjykPwobSUyS3xalBJwNDGSUCr L+Q4Zu/PZKujI2Qbpzsko2Z0jf4DEJTFrn8TXFXJOvk6osxO46LE0dv2VfEgedXZ8o 5NWue2csXLn7KtTN8dssswHdPRSRyyxw8W8Gt1nRGGU/V5lT2qdlKuDtVZYPP0dxAQ RuRyfnUlvOPVdlAQ4FvhegZCThVq7dF579yKCkMKNFpBRZ4HmpzY8oeML01aNWaJQe 2ogkYOw13H5Fw== Subject: [PATCH 07/11] xfs_scrub: convert scrub and repair epilogues to use xfs_scrub_vec From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Date: Fri, 30 Dec 2022 14:20:41 -0800 Message-ID: <167243884126.739244.10663679183976658897.stgit@magnolia> In-Reply-To: <167243884029.739244.16777239536975047510.stgit@magnolia> References: <167243884029.739244.16777239536975047510.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 Convert the scrub and repair epilogue code to pass around xfs_scrub_vecs as we prepare for vectorized operation. Signed-off-by: Darrick J. Wong --- scrub/repair.c | 35 ++++++++++++++++++----------------- scrub/scrub.c | 27 ++++++++++++++------------- scrub/scrub_private.h | 34 +++++++++++++++++----------------- 3 files changed, 49 insertions(+), 47 deletions(-) diff --git a/scrub/repair.c b/scrub/repair.c index 4d8552cf9d0..7c4fc6143f0 100644 --- a/scrub/repair.c +++ b/scrub/repair.c @@ -22,8 +22,8 @@ static int repair_epilogue(struct scrub_ctx *ctx, struct descr *dsc, struct scrub_item *sri, unsigned int repair_flags, - struct xfs_scrub_metadata *oldm, - struct xfs_scrub_metadata *meta, int error); + const struct xfs_scrub_vec *oldm, + const struct xfs_scrub_vec *meta); /* General repair routines. */ @@ -101,10 +101,9 @@ xfs_repair_metadata( unsigned int repair_flags) { struct xfs_scrub_metadata meta = { 0 }; - struct xfs_scrub_metadata oldm; + struct xfs_scrub_vec oldm, vec; DEFINE_DESCR(dsc, ctx, format_scrub_descr); bool repair_only; - int error; /* * If the caller boosted the priority of this scrub type on behalf of a @@ -133,22 +132,24 @@ xfs_repair_metadata( break; } - if (!is_corrupt(&meta) && repair_only) + vec.sv_type = scrub_type; + vec.sv_flags = sri->sri_state[scrub_type] & SCRUB_ITEM_REPAIR_ANY; + memcpy(&oldm, &vec, sizeof(struct xfs_scrub_vec)); + if (!is_corrupt(&vec) && repair_only) return 0; - memcpy(&oldm, &meta, sizeof(oldm)); - oldm.sm_flags = sri->sri_state[scrub_type] & SCRUB_ITEM_REPAIR_ANY; - descr_set(&dsc, &oldm); + descr_set(&dsc, &meta); - if (needs_repair(&oldm)) + if (needs_repair(&vec)) str_info(ctx, descr_render(&dsc), _("Attempting repair.")); else if (debug || verbose) str_info(ctx, descr_render(&dsc), _("Attempting optimization.")); - error = -xfrog_scrub_metadata(xfdp, &meta); - return repair_epilogue(ctx, &dsc, sri, repair_flags, &oldm, &meta, - error); + vec.sv_ret = xfrog_scrub_metadata(xfdp, &meta); + vec.sv_flags = meta.sm_flags; + + return repair_epilogue(ctx, &dsc, sri, repair_flags, &oldm, &vec); } static int @@ -157,11 +158,11 @@ repair_epilogue( struct descr *dsc, struct scrub_item *sri, unsigned int repair_flags, - struct xfs_scrub_metadata *oldm, - struct xfs_scrub_metadata *meta, - int error) + const struct xfs_scrub_vec *oldm, + const struct xfs_scrub_vec *meta) { - unsigned int scrub_type = meta->sm_type; + unsigned int scrub_type = meta->sv_type; + int error = -meta->sv_ret; switch (error) { case 0: @@ -278,7 +279,7 @@ _("Read-only filesystem; cannot make changes.")); _("Seems correct but cross-referencing failed; will keep checking.")); return 0; } - } else if (meta->sm_flags & XFS_SCRUB_OFLAG_NO_REPAIR_NEEDED) { + } else if (meta->sv_flags & XFS_SCRUB_OFLAG_NO_REPAIR_NEEDED) { if (verbose) str_info(ctx, descr_render(dsc), _("No modification needed.")); diff --git a/scrub/scrub.c b/scrub/scrub.c index b102a457cc2..37cc97cdfda 100644 --- a/scrub/scrub.c +++ b/scrub/scrub.c @@ -23,8 +23,7 @@ #include "scrub_private.h" static int scrub_epilogue(struct scrub_ctx *ctx, struct descr *dsc, - struct scrub_item *sri, struct xfs_scrub_metadata *meta, - int error); + struct scrub_item *sri, struct xfs_scrub_vec *vec); /* Online scrub and repair wrappers. */ @@ -65,7 +64,7 @@ void scrub_warn_incomplete_scrub( struct scrub_ctx *ctx, struct descr *dsc, - struct xfs_scrub_metadata *meta) + const struct xfs_scrub_vec *meta) { if (is_incomplete(meta)) str_info(ctx, descr_render(dsc), _("Check incomplete.")); @@ -94,8 +93,8 @@ xfs_check_metadata( { DEFINE_DESCR(dsc, ctx, format_scrub_descr); struct xfs_scrub_metadata meta = { }; + struct xfs_scrub_vec vec; enum xfrog_scrub_group group; - int error; background_sleep(); @@ -124,8 +123,10 @@ xfs_check_metadata( dbg_printf("check %s flags %xh\n", descr_render(&dsc), meta.sm_flags); - error = -xfrog_scrub_metadata(xfdp, &meta); - return scrub_epilogue(ctx, &dsc, sri, &meta, error); + vec.sv_ret = xfrog_scrub_metadata(xfdp, &meta); + vec.sv_type = scrub_type; + vec.sv_flags = meta.sm_flags; + return scrub_epilogue(ctx, &dsc, sri, &vec); } /* @@ -137,11 +138,11 @@ scrub_epilogue( struct scrub_ctx *ctx, struct descr *dsc, struct scrub_item *sri, - struct xfs_scrub_metadata *meta, - int error) + struct xfs_scrub_vec *meta) { - unsigned int scrub_type = meta->sm_type; + unsigned int scrub_type = meta->sv_type; enum xfrog_scrub_group group; + int error = -meta->sv_ret; group = xfrog_scrubbers[scrub_type].group; @@ -150,7 +151,7 @@ scrub_epilogue( /* No operational errors encountered. */ if (!sri->sri_revalidate && debug_tweak_on("XFS_SCRUB_FORCE_REPAIR")) - meta->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT; + meta->sv_flags |= XFS_SCRUB_OFLAG_CORRUPT; break; case ENOENT: /* Metadata not present, just skip it. */ @@ -211,7 +212,7 @@ _("Repairs are required.")); } /* Schedule repairs. */ - scrub_item_save_state(sri, scrub_type, meta->sm_flags); + scrub_item_save_state(sri, scrub_type, meta->sv_flags); return 0; } @@ -238,7 +239,7 @@ _("Optimization is possible.")); } /* Schedule optimizations. */ - scrub_item_save_state(sri, scrub_type, meta->sm_flags); + scrub_item_save_state(sri, scrub_type, meta->sv_flags); return 0; } @@ -250,7 +251,7 @@ _("Optimization is possible.")); * deem it completely consistent at some point. */ if (xref_failed(meta) && ctx->mode == SCRUB_MODE_REPAIR) { - scrub_item_save_state(sri, scrub_type, meta->sm_flags); + scrub_item_save_state(sri, scrub_type, meta->sv_flags); return 0; } diff --git a/scrub/scrub_private.h b/scrub/scrub_private.h index c60ea555885..383bc17a567 100644 --- a/scrub/scrub_private.h +++ b/scrub/scrub_private.h @@ -13,40 +13,40 @@ int format_scrub_descr(struct scrub_ctx *ctx, char *buf, size_t buflen, /* Predicates for scrub flag state. */ -static inline bool is_corrupt(struct xfs_scrub_metadata *sm) +static inline bool is_corrupt(const struct xfs_scrub_vec *sv) { - return sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT; + return sv->sv_flags & XFS_SCRUB_OFLAG_CORRUPT; } -static inline bool is_unoptimized(struct xfs_scrub_metadata *sm) +static inline bool is_unoptimized(const struct xfs_scrub_vec *sv) { - return sm->sm_flags & XFS_SCRUB_OFLAG_PREEN; + return sv->sv_flags & XFS_SCRUB_OFLAG_PREEN; } -static inline bool xref_failed(struct xfs_scrub_metadata *sm) +static inline bool xref_failed(const struct xfs_scrub_vec *sv) { - return sm->sm_flags & XFS_SCRUB_OFLAG_XFAIL; + return sv->sv_flags & XFS_SCRUB_OFLAG_XFAIL; } -static inline bool xref_disagrees(struct xfs_scrub_metadata *sm) +static inline bool xref_disagrees(const struct xfs_scrub_vec *sv) { - return sm->sm_flags & XFS_SCRUB_OFLAG_XCORRUPT; + return sv->sv_flags & XFS_SCRUB_OFLAG_XCORRUPT; } -static inline bool is_incomplete(struct xfs_scrub_metadata *sm) +static inline bool is_incomplete(const struct xfs_scrub_vec *sv) { - return sm->sm_flags & XFS_SCRUB_OFLAG_INCOMPLETE; + return sv->sv_flags & XFS_SCRUB_OFLAG_INCOMPLETE; } -static inline bool is_suspicious(struct xfs_scrub_metadata *sm) +static inline bool is_suspicious(const struct xfs_scrub_vec *sv) { - return sm->sm_flags & XFS_SCRUB_OFLAG_WARNING; + return sv->sv_flags & XFS_SCRUB_OFLAG_WARNING; } /* Should we fix it? */ -static inline bool needs_repair(struct xfs_scrub_metadata *sm) +static inline bool needs_repair(const struct xfs_scrub_vec *sv) { - return is_corrupt(sm) || xref_disagrees(sm); + return is_corrupt(sv) || xref_disagrees(sv); } /* @@ -54,13 +54,13 @@ static inline bool needs_repair(struct xfs_scrub_metadata *sm) * scan/repair; or if there were cross-referencing problems but the object was * not obviously corrupt. */ -static inline bool want_retry(struct xfs_scrub_metadata *sm) +static inline bool want_retry(const struct xfs_scrub_vec *sv) { - return is_incomplete(sm) || (xref_disagrees(sm) && !is_corrupt(sm)); + return is_incomplete(sv) || (xref_disagrees(sv) && !is_corrupt(sv)); } void scrub_warn_incomplete_scrub(struct scrub_ctx *ctx, struct descr *dsc, - struct xfs_scrub_metadata *meta); + const struct xfs_scrub_vec *meta); /* Scrub item functions */ From patchwork Fri Dec 30 22:20:41 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: 13085950 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 B3CDCC4332F for ; Sat, 31 Dec 2022 03:26:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236364AbiLaD0y (ORCPT ); Fri, 30 Dec 2022 22:26:54 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38928 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236399AbiLaD0x (ORCPT ); Fri, 30 Dec 2022 22:26:53 -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 4B443164AE for ; Fri, 30 Dec 2022 19:26:52 -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 CDA5D61CC1 for ; Sat, 31 Dec 2022 03:26:51 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3EB1AC433EF; Sat, 31 Dec 2022 03:26:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1672457211; bh=2h7c6V/m7Hf9iTR7/Nc4+OX9MuSsanFyKVMQWytxfZI=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=JPzEuMhougt+vFXe73SnfAy2h9DOLL5WZxdfVEWBgxxHGKXSIh/5pPDK70RRUFfdf Ehr8k0Z3EROZX0Tk26PtIESXotSPhr0qKuiYiqB0uGSAonQfyjRxgomMXv4e0k6uEJ DuNPSYO9ywPZCXM/b/kbxt5RJEr34QT4bMCJpetJmCNnb4czQHUTQiTxj/pMzndm2A ENdZr9bjkBuGx4snxGZF4bCrea/NvPVWFE67vS9pZvQ5NtqDclgYcToxD7raxW+5Y5 lOwQVxHpa1aVfc1fu8PQUdNvbaGspkH8HDn9plAoVlf1+ZhMawlrG+XxQbAEfVsIQF lJxvz6PnlU+3Q== Subject: [PATCH 08/11] xfs_scrub: vectorize scrub calls From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Date: Fri, 30 Dec 2022 14:20:41 -0800 Message-ID: <167243884139.739244.5801642526934140867.stgit@magnolia> In-Reply-To: <167243884029.739244.16777239536975047510.stgit@magnolia> References: <167243884029.739244.16777239536975047510.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 Use the new vectorized kernel scrub calls to reduce the overhead of checking metadata. Signed-off-by: Darrick J. Wong --- scrub/phase1.c | 2 scrub/scrub.c | 265 +++++++++++++++++++++++++++++++++++-------------- scrub/scrub.h | 2 scrub/scrub_private.h | 21 ++++ 4 files changed, 216 insertions(+), 74 deletions(-) diff --git a/scrub/phase1.c b/scrub/phase1.c index 7b9caa4258c..85da1b7a7d1 100644 --- a/scrub/phase1.c +++ b/scrub/phase1.c @@ -216,6 +216,8 @@ _("Kernel metadata scrubbing facility is not available.")); return ECANCELED; } + check_scrubv(ctx); + /* * Normally, callers are required to pass -n if the provided path is a * readonly filesystem or the kernel wasn't built with online repair diff --git a/scrub/scrub.c b/scrub/scrub.c index 37cc97cdfda..95c798acd0a 100644 --- a/scrub/scrub.c +++ b/scrub/scrub.c @@ -22,11 +22,42 @@ #include "descr.h" #include "scrub_private.h" -static int scrub_epilogue(struct scrub_ctx *ctx, struct descr *dsc, - struct scrub_item *sri, struct xfs_scrub_vec *vec); - /* Online scrub and repair wrappers. */ +/* Describe the current state of a vectored scrub. */ +static int +format_scrubv_descr( + struct scrub_ctx *ctx, + char *buf, + size_t buflen, + void *where) +{ + struct scrubv_head *bh = where; + struct xfs_scrub_vec_head *vhead = &bh->head; + struct xfs_scrub_vec *v = bh->head.svh_vecs + bh->i; + const struct xfrog_scrub_descr *sc = &xfrog_scrubbers[v->sv_type]; + + switch (sc->group) { + case XFROG_SCRUB_GROUP_AGHEADER: + case XFROG_SCRUB_GROUP_PERAG: + return snprintf(buf, buflen, _("AG %u %s"), vhead->svh_agno, + _(sc->descr)); + case XFROG_SCRUB_GROUP_INODE: + return scrub_render_ino_descr(ctx, buf, buflen, + vhead->svh_ino, vhead->svh_gen, "%s", + _(sc->descr)); + case XFROG_SCRUB_GROUP_METAFILES: + case XFROG_SCRUB_GROUP_SUMMARY: + case XFROG_SCRUB_GROUP_ISCAN: + case XFROG_SCRUB_GROUP_NONE: + return snprintf(buf, buflen, _("%s"), _(sc->descr)); + case XFROG_SCRUB_GROUP_RTGROUP: + return snprintf(buf, buflen, _("rtgroup %u %s"), + vhead->svh_agno, _(sc->descr)); + } + return -1; +} + /* Format a scrub description. */ int format_scrub_descr( @@ -83,52 +114,6 @@ scrub_warn_incomplete_scrub( _("Cross-referencing failed.")); } -/* Do a read-only check of some metadata. */ -static int -xfs_check_metadata( - struct scrub_ctx *ctx, - struct xfs_fd *xfdp, - unsigned int scrub_type, - struct scrub_item *sri) -{ - DEFINE_DESCR(dsc, ctx, format_scrub_descr); - struct xfs_scrub_metadata meta = { }; - struct xfs_scrub_vec vec; - enum xfrog_scrub_group group; - - background_sleep(); - - group = xfrog_scrubbers[scrub_type].group; - meta.sm_type = scrub_type; - switch (group) { - case XFROG_SCRUB_GROUP_AGHEADER: - case XFROG_SCRUB_GROUP_PERAG: - case XFROG_SCRUB_GROUP_RTGROUP: - meta.sm_agno = sri->sri_agno; - break; - case XFROG_SCRUB_GROUP_METAFILES: - case XFROG_SCRUB_GROUP_SUMMARY: - case XFROG_SCRUB_GROUP_ISCAN: - case XFROG_SCRUB_GROUP_NONE: - break; - case XFROG_SCRUB_GROUP_INODE: - meta.sm_ino = sri->sri_ino; - meta.sm_gen = sri->sri_gen; - break; - } - - assert(!debug_tweak_on("XFS_SCRUB_NO_KERNEL")); - assert(scrub_type < XFS_SCRUB_TYPE_NR); - descr_set(&dsc, &meta); - - dbg_printf("check %s flags %xh\n", descr_render(&dsc), meta.sm_flags); - - vec.sv_ret = xfrog_scrub_metadata(xfdp, &meta); - vec.sv_type = scrub_type; - vec.sv_flags = meta.sm_flags; - return scrub_epilogue(ctx, &dsc, sri, &vec); -} - /* * Update all internal state after a scrub ioctl call. * Returns 0 for success, or ECANCELED to abort the program. @@ -260,6 +245,88 @@ _("Optimization is possible.")); return 0; } +/* Fill out the scrub vector header. */ +void +scrub_item_to_vhead( + struct scrubv_head *bighead, + const struct scrub_item *sri) +{ + struct xfs_scrub_vec_head *vhead = &bighead->head; + + if (bg_mode > 1) + vhead->svh_rest_us = bg_mode - 1; + if (sri->sri_agno != -1) + vhead->svh_agno = sri->sri_agno; + if (sri->sri_ino != -1ULL) { + vhead->svh_ino = sri->sri_ino; + vhead->svh_gen = sri->sri_gen; + } +} + +/* Add a scrubber to the scrub vector. */ +void +scrub_vhead_add( + struct scrubv_head *bighead, + const struct scrub_item *sri, + unsigned int scrub_type) +{ + struct xfs_scrub_vec_head *vhead = &bighead->head; + struct xfs_scrub_vec *v; + + v = &vhead->svh_vecs[vhead->svh_nr++]; + v->sv_type = scrub_type; + bighead->i = v - vhead->svh_vecs; +} + +/* Do a read-only check of some metadata. */ +static int +scrub_call_kernel( + struct scrub_ctx *ctx, + struct xfs_fd *xfdp, + struct scrub_item *sri) +{ + DEFINE_DESCR(dsc, ctx, format_scrubv_descr); + struct scrubv_head bh = { }; + struct xfs_scrub_vec *v; + unsigned int scrub_type; + int error; + + assert(!debug_tweak_on("XFS_SCRUB_NO_KERNEL")); + + scrub_item_to_vhead(&bh, sri); + descr_set(&dsc, &bh); + + foreach_scrub_type(scrub_type) { + if (!(sri->sri_state[scrub_type] & SCRUB_ITEM_NEEDSCHECK)) + continue; + scrub_vhead_add(&bh, sri, scrub_type); + + dbg_printf("check %s flags %xh tries %u\n", descr_render(&dsc), + sri->sri_state[scrub_type], + sri->sri_tries[scrub_type]); + } + + error = -xfrog_scrubv_metadata(xfdp, &bh.head); + if (error) + return error; + + foreach_bighead_vec(&bh, v) { + error = scrub_epilogue(ctx, &dsc, sri, v); + if (error) + return error; + + /* + * Progress is counted by the inode for inode metadata; for + * everything else, it's counted for each scrub call. + */ + if (!(sri->sri_state[v->sv_type] & SCRUB_ITEM_NEEDSCHECK) && + sri->sri_ino == -1ULL) + progress_add(1); + } + + return 0; +} + /* Bulk-notify user about things that could be optimized. */ void scrub_report_preen_triggers( @@ -295,6 +362,37 @@ scrub_item_schedule_group( } } +/* Decide if we call the kernel again to finish scrub/repair activity. */ +static inline bool +scrub_item_call_kernel_again_future( + struct scrub_item *sri, + uint8_t work_mask, + const struct scrub_item *old) +{ + unsigned int scrub_type; + unsigned int nr = 0; + + /* If there's nothing to do, we're done. */ + foreach_scrub_type(scrub_type) { + if (sri->sri_state[scrub_type] & work_mask) + nr++; + } + if (!nr) + return false; + + foreach_scrub_type(scrub_type) { + uint8_t statex = sri->sri_state[scrub_type] ^ + old->sri_state[scrub_type]; + + if (statex & work_mask) + return true; + if (sri->sri_tries[scrub_type] != old->sri_tries[scrub_type]) + return true; + } + + return false; +} + /* Decide if we call the kernel again to finish scrub/repair activity. */ bool scrub_item_call_kernel_again( @@ -323,6 +421,29 @@ scrub_item_call_kernel_again( return false; } +/* + * For each scrub item whose state matches the state_flags, set up the item + * state for a kernel call. Returns true if any work was scheduled. + */ +bool +scrub_item_schedule_work( + struct scrub_item *sri, + uint8_t state_flags) +{ + unsigned int scrub_type; + unsigned int nr = 0; + + foreach_scrub_type(scrub_type) { + if (!(sri->sri_state[scrub_type] & state_flags)) + continue; + + sri->sri_tries[scrub_type] = SCRUB_ITEM_MAX_RETRIES; + nr++; + } + + return nr > 0; +} + /* Run all the incomplete scans on this scrub principal. */ int scrub_item_check_file( @@ -333,8 +454,10 @@ scrub_item_check_file( struct xfs_fd xfd; struct scrub_item old_sri; struct xfs_fd *xfdp = &ctx->mnt; - unsigned int scrub_type; - int error; + int error = 0; + + if (!scrub_item_schedule_work(sri, SCRUB_ITEM_NEEDSCHECK)) + return 0; /* * If the caller passed us a file descriptor for a scrub, use it @@ -347,31 +470,15 @@ scrub_item_check_file( xfdp = &xfd; } - foreach_scrub_type(scrub_type) { - if (!(sri->sri_state[scrub_type] & SCRUB_ITEM_NEEDSCHECK)) - continue; - - sri->sri_tries[scrub_type] = SCRUB_ITEM_MAX_RETRIES; - do { - memcpy(&old_sri, sri, sizeof(old_sri)); - error = xfs_check_metadata(ctx, xfdp, scrub_type, sri); - if (error) - return error; - } while (scrub_item_call_kernel_again(sri, scrub_type, - SCRUB_ITEM_NEEDSCHECK, &old_sri)); - - /* - * Progress is counted by the inode for inode metadata; for - * everything else, it's counted for each scrub call. - */ - if (sri->sri_ino == -1ULL) - progress_add(1); - + do { + memcpy(&old_sri, sri, sizeof(old_sri)); + error = scrub_call_kernel(ctx, xfdp, sri); if (error) - break; - } + return error; + } while (scrub_item_call_kernel_again_future(sri, SCRUB_ITEM_NEEDSCHECK, + &old_sri)); - return error; + return 0; } /* How many items do we have to check? */ @@ -566,3 +673,13 @@ can_force_rebuild( return __scrub_test(ctx, XFS_SCRUB_TYPE_PROBE, XFS_SCRUB_IFLAG_REPAIR | XFS_SCRUB_IFLAG_FORCE_REBUILD); } + +void +check_scrubv( + struct scrub_ctx *ctx) +{ + struct xfs_scrub_vec_head head = { }; + + /* We set the fallback flag if this doesn't work. */ + xfrog_scrubv_metadata(&ctx->mnt, &head); +} diff --git a/scrub/scrub.h b/scrub/scrub.h index b7e6173f8fa..0db94da5281 100644 --- a/scrub/scrub.h +++ b/scrub/scrub.h @@ -147,6 +147,8 @@ bool can_scrub_parent(struct scrub_ctx *ctx); bool can_repair(struct scrub_ctx *ctx); bool can_force_rebuild(struct scrub_ctx *ctx); +void check_scrubv(struct scrub_ctx *ctx); + int scrub_file(struct scrub_ctx *ctx, int fd, const struct xfs_bulkstat *bstat, unsigned int type, struct scrub_item *sri); diff --git a/scrub/scrub_private.h b/scrub/scrub_private.h index 383bc17a567..1059c197fa2 100644 --- a/scrub/scrub_private.h +++ b/scrub/scrub_private.h @@ -8,6 +8,26 @@ /* Shared code between scrub.c and repair.c. */ +/* + * Declare a structure big enough to handle all scrub types + barriers, and + * an iteration pointer. So far we only need two barriers. + */ +struct scrubv_head { + struct xfs_scrub_vec_head head; + struct xfs_scrub_vec __vecs[XFS_SCRUB_TYPE_NR + 2]; + unsigned int i; +}; + +#define foreach_bighead_vec(bh, v) \ + for ((bh)->i = 0, (v) = (bh)->head.svh_vecs; \ + (bh)->i < (bh)->head.svh_nr; \ + (bh)->i++, (v)++) + +void scrub_item_to_vhead(struct scrubv_head *bighead, + const struct scrub_item *sri); +void scrub_vhead_add(struct scrubv_head *bighead, const struct scrub_item *sri, + unsigned int scrub_type); + int format_scrub_descr(struct scrub_ctx *ctx, char *buf, size_t buflen, void *where); @@ -104,5 +124,6 @@ scrub_item_schedule_retry(struct scrub_item *sri, unsigned int scrub_type) bool scrub_item_call_kernel_again(struct scrub_item *sri, unsigned int scrub_type, uint8_t work_mask, const struct scrub_item *old); +bool scrub_item_schedule_work(struct scrub_item *sri, uint8_t state_flags); #endif /* XFS_SCRUB_SCRUB_PRIVATE_H_ */ From patchwork Fri Dec 30 22:20:41 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: 13085951 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 E8860C4332F for ; Sat, 31 Dec 2022 03:27:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236365AbiLaD1M (ORCPT ); Fri, 30 Dec 2022 22:27:12 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38944 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236230AbiLaD1L (ORCPT ); Fri, 30 Dec 2022 22:27:11 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A42A613D49 for ; Fri, 30 Dec 2022 19:27:09 -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 2C674B81E5A for ; Sat, 31 Dec 2022 03:27:08 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id C6F74C433EF; Sat, 31 Dec 2022 03:27:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1672457226; bh=1Tp0Ns/PD7wQcKbSQ6WGbWuAMHzk0HzMEeW+vIJOluU=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=rahj+9lcd0PJMnvMfAh4ZOFH4aFGhxnl5oNX0J3yuZrxNAPhRshxB/2yGVP+IiCj3 UqFsHpuvfB6hf8DZ6fVPwQ06yNBRaAEjJlSEQVg+CCxHObvPOcrGjNVLBoClf1RyfR zq8LQppIljs4xC0v+W3OI5NeFDOUcwDGywo9Mp+FYrkBs7SPF0G9rzEKTcq8gAeBKN uR0uJ79mULBzfMhgNuz++3hwDOOrk/3kkHtokfTPxMRWwAmxEQMLHYVQOnlOzZ+4yw L4oNuwU4tMbJs+SYR7lDsiiu4tDT2tose6F6sDLFnjWI0RMlHWs/C20zKnKT2uRnGU aJv5SAeehpbwA== Subject: [PATCH 09/11] xfs_scrub: vectorize repair calls From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Date: Fri, 30 Dec 2022 14:20:41 -0800 Message-ID: <167243884152.739244.14288193484547963107.stgit@magnolia> In-Reply-To: <167243884029.739244.16777239536975047510.stgit@magnolia> References: <167243884029.739244.16777239536975047510.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 Use the new vectorized scrub kernel calls to reduce the overhead of performing repairs. Signed-off-by: Darrick J. Wong --- scrub/repair.c | 268 +++++++++++++++++++++++++++---------------------- scrub/scrub.c | 82 +++------------ scrub/scrub_private.h | 7 + 3 files changed, 166 insertions(+), 191 deletions(-) diff --git a/scrub/repair.c b/scrub/repair.c index 7c4fc6143f0..8a6263c675e 100644 --- a/scrub/repair.c +++ b/scrub/repair.c @@ -20,11 +20,6 @@ #include "descr.h" #include "scrub_private.h" -static int repair_epilogue(struct scrub_ctx *ctx, struct descr *dsc, - struct scrub_item *sri, unsigned int repair_flags, - const struct xfs_scrub_vec *oldm, - const struct xfs_scrub_vec *meta); - /* General repair routines. */ /* @@ -91,65 +86,14 @@ repair_want_service_downgrade( return false; } -/* Repair some metadata. */ -static int -xfs_repair_metadata( - struct scrub_ctx *ctx, - struct xfs_fd *xfdp, - unsigned int scrub_type, - struct scrub_item *sri, - unsigned int repair_flags) +static inline void +restore_oldvec( + struct xfs_scrub_vec *oldvec, + const struct scrub_item *sri, + unsigned int scrub_type) { - struct xfs_scrub_metadata meta = { 0 }; - struct xfs_scrub_vec oldm, vec; - DEFINE_DESCR(dsc, ctx, format_scrub_descr); - bool repair_only; - - /* - * If the caller boosted the priority of this scrub type on behalf of a - * higher level repair by setting IFLAG_REPAIR, turn off REPAIR_ONLY. - */ - repair_only = (repair_flags & XRM_REPAIR_ONLY) && - scrub_item_type_boosted(sri, scrub_type); - - assert(scrub_type < XFS_SCRUB_TYPE_NR); - assert(!debug_tweak_on("XFS_SCRUB_NO_KERNEL")); - meta.sm_type = scrub_type; - meta.sm_flags = XFS_SCRUB_IFLAG_REPAIR; - if (use_force_rebuild) - meta.sm_flags |= XFS_SCRUB_IFLAG_FORCE_REBUILD; - switch (xfrog_scrubbers[scrub_type].group) { - case XFROG_SCRUB_GROUP_AGHEADER: - case XFROG_SCRUB_GROUP_PERAG: - case XFROG_SCRUB_GROUP_RTGROUP: - meta.sm_agno = sri->sri_agno; - break; - case XFROG_SCRUB_GROUP_INODE: - meta.sm_ino = sri->sri_ino; - meta.sm_gen = sri->sri_gen; - break; - default: - break; - } - - vec.sv_type = scrub_type; - vec.sv_flags = sri->sri_state[scrub_type] & SCRUB_ITEM_REPAIR_ANY; - memcpy(&oldm, &vec, sizeof(struct xfs_scrub_vec)); - if (!is_corrupt(&vec) && repair_only) - return 0; - - descr_set(&dsc, &meta); - - if (needs_repair(&vec)) - str_info(ctx, descr_render(&dsc), _("Attempting repair.")); - else if (debug || verbose) - str_info(ctx, descr_render(&dsc), - _("Attempting optimization.")); - - vec.sv_ret = xfrog_scrub_metadata(xfdp, &meta); - vec.sv_flags = meta.sm_flags; - - return repair_epilogue(ctx, &dsc, sri, repair_flags, &oldm, &vec); + oldvec->sv_type = scrub_type; + oldvec->sv_flags = sri->sri_state[scrub_type] & SCRUB_ITEM_REPAIR_ANY; } static int @@ -158,12 +102,15 @@ repair_epilogue( struct descr *dsc, struct scrub_item *sri, unsigned int repair_flags, - const struct xfs_scrub_vec *oldm, const struct xfs_scrub_vec *meta) { + struct xfs_scrub_vec oldv; + struct xfs_scrub_vec *oldm = &oldv; unsigned int scrub_type = meta->sv_type; int error = -meta->sv_ret; + restore_oldvec(oldm, sri, meta->sv_type); + switch (error) { case 0: /* No operational errors encountered. */ @@ -297,6 +244,132 @@ _("Read-only filesystem; cannot make changes.")); return 0; } +/* Decide if the dependent scrub types of the given scrub type are ok. */ +static bool +repair_item_dependencies_ok( + const struct scrub_item *sri, + unsigned int scrub_type) +{ + unsigned int dep_mask = repair_deps[scrub_type]; + unsigned int b; + + for (b = 0; dep_mask && b < XFS_SCRUB_TYPE_NR; b++, dep_mask >>= 1) { + if (!(dep_mask & 1)) + continue; + /* + * If this lower level object also needs repair, we can't fix + * the higher level item. + */ + if (sri->sri_state[b] & SCRUB_ITEM_NEEDSREPAIR) + return false; + } + + return true; +} + +/* Decide if we want to repair a particular type of metadata. */ +static bool +can_repair_now( + const struct scrub_item *sri, + unsigned int scrub_type, + __u32 repair_mask, + unsigned int repair_flags) +{ + struct xfs_scrub_vec oldvec; + bool repair_only; + + /* Do we even need to repair this thing? */ + if (!(sri->sri_state[scrub_type] & repair_mask)) + return false; + + restore_oldvec(&oldvec, sri, scrub_type); + + /* + * If the caller boosted the priority of this scrub type on behalf of a + * higher level repair by setting IFLAG_REPAIR, ignore REPAIR_ONLY. + */ + repair_only = (repair_flags & XRM_REPAIR_ONLY) && + !(sri->sri_state[scrub_type] & SCRUB_ITEM_BOOST_REPAIR); + if (!is_corrupt(&oldvec) && repair_only) + return false; + + /* + * Don't try to repair higher level items if their lower-level + * dependencies haven't been verified, unless this is our last chance + * to fix things without complaint. + */ + if (!(repair_flags & XRM_FINAL_WARNING) && + !repair_item_dependencies_ok(sri, scrub_type)) + return false; + + return true; +} + +/* + * Repair some metadata. + * + * Returns 0 for success (or repair item deferral), or ECANCELED to abort the + * program. + */ +static int +repair_call_kernel( + struct scrub_ctx *ctx, + struct xfs_fd *xfdp, + struct scrub_item *sri, + __u32 repair_mask, + unsigned int repair_flags) +{ + DEFINE_DESCR(dsc, ctx, format_scrubv_descr); + struct scrubv_head bh = { }; + struct xfs_scrub_vec *v; + unsigned int scrub_type; + int error; + + assert(!debug_tweak_on("XFS_SCRUB_NO_KERNEL")); + + scrub_item_to_vhead(&bh, sri); + descr_set(&dsc, &bh); + + foreach_scrub_type(scrub_type) { + if (scrub_excessive_errors(ctx)) + return ECANCELED; + + if (!can_repair_now(sri, scrub_type, repair_mask, + repair_flags)) + continue; + + scrub_vhead_add(&bh, sri, scrub_type, true); + + if (sri->sri_state[scrub_type] & SCRUB_ITEM_NEEDSREPAIR) + str_info(ctx, descr_render(&dsc), + _("Attempting repair.")); + else if (debug || verbose) + str_info(ctx, descr_render(&dsc), + _("Attempting optimization.")); + + dbg_printf("repair %s flags %xh tries %u\n", descr_render(&dsc), + sri->sri_state[scrub_type], + sri->sri_tries[scrub_type]); + } + + error = -xfrog_scrubv_metadata(xfdp, &bh.head); + if (error) + return error; + + foreach_bighead_vec(&bh, v) { + error = repair_epilogue(ctx, &dsc, sri, repair_flags, v); + if (error) + return error; + + /* Maybe update progress if we fixed the problem. */ + if (!(repair_flags & XRM_NOPROGRESS) && + !(sri->sri_state[v->sv_type] & SCRUB_ITEM_REPAIR_ANY)) + progress_add(1); + } + + return 0; +} + /* * Prioritize action items in order of how long we can wait. * @@ -636,29 +709,6 @@ action_list_process( return ret; } -/* Decide if the dependent scrub types of the given scrub type are ok. */ -static bool -repair_item_dependencies_ok( - const struct scrub_item *sri, - unsigned int scrub_type) -{ - unsigned int dep_mask = repair_deps[scrub_type]; - unsigned int b; - - for (b = 0; dep_mask && b < XFS_SCRUB_TYPE_NR; b++, dep_mask >>= 1) { - if (!(dep_mask & 1)) - continue; - /* - * If this lower level object also needs repair, we can't fix - * the higher level item. - */ - if (sri->sri_state[b] & SCRUB_ITEM_NEEDSREPAIR) - return false; - } - - return true; -} - /* * For a given filesystem object, perform all repairs of a given class * (corrupt, xcorrupt, xfail, preen) if the repair item says it's needed. @@ -674,13 +724,14 @@ repair_item_class( struct xfs_fd xfd; struct scrub_item old_sri; struct xfs_fd *xfdp = &ctx->mnt; - unsigned int scrub_type; int error = 0; if (ctx->mode == SCRUB_MODE_DRY_RUN) return 0; if (ctx->mode == SCRUB_MODE_PREEN && !(repair_mask & SCRUB_ITEM_PREEN)) return 0; + if (!scrub_item_schedule_work(sri, repair_mask)) + return 0; /* * If the caller passed us a file descriptor for a scrub, use it @@ -693,39 +744,14 @@ repair_item_class( xfdp = &xfd; } - foreach_scrub_type(scrub_type) { - if (scrub_excessive_errors(ctx)) - return ECANCELED; - - if (!(sri->sri_state[scrub_type] & repair_mask)) - continue; - - /* - * Don't try to repair higher level items if their lower-level - * dependencies haven't been verified, unless this is our last - * chance to fix things without complaint. - */ - if (!(flags & XRM_FINAL_WARNING) && - !repair_item_dependencies_ok(sri, scrub_type)) - continue; - - sri->sri_tries[scrub_type] = SCRUB_ITEM_MAX_RETRIES; - do { - memcpy(&old_sri, sri, sizeof(old_sri)); - error = xfs_repair_metadata(ctx, xfdp, scrub_type, sri, - flags); - if (error) - return error; - } while (scrub_item_call_kernel_again(sri, scrub_type, - repair_mask, &old_sri)); - - /* Maybe update progress if we fixed the problem. */ - if (!(flags & XRM_NOPROGRESS) && - !(sri->sri_state[scrub_type] & SCRUB_ITEM_REPAIR_ANY)) - progress_add(1); - } - - return error; + do { + memcpy(&old_sri, sri, sizeof(struct scrub_item)); + error = repair_call_kernel(ctx, xfdp, sri, repair_mask, flags); + if (error) + return error; + } while (scrub_item_call_kernel_again(sri, repair_mask, &old_sri)); + + return 0; } /* diff --git a/scrub/scrub.c b/scrub/scrub.c index 95c798acd0a..76d4fa87931 100644 --- a/scrub/scrub.c +++ b/scrub/scrub.c @@ -25,7 +25,7 @@ /* Online scrub and repair wrappers. */ /* Describe the current state of a vectored scrub. */ -static int +int format_scrubv_descr( struct scrub_ctx *ctx, char *buf, @@ -58,38 +58,6 @@ format_scrubv_descr( return -1; } -/* Format a scrub description. */ -int -format_scrub_descr( - struct scrub_ctx *ctx, - char *buf, - size_t buflen, - void *where) -{ - struct xfs_scrub_metadata *meta = where; - const struct xfrog_scrub_descr *sc = &xfrog_scrubbers[meta->sm_type]; - - switch (sc->group) { - case XFROG_SCRUB_GROUP_AGHEADER: - case XFROG_SCRUB_GROUP_PERAG: - return snprintf(buf, buflen, _("AG %u %s"), meta->sm_agno, - _(sc->descr)); - case XFROG_SCRUB_GROUP_INODE: - return scrub_render_ino_descr(ctx, buf, buflen, - meta->sm_ino, meta->sm_gen, "%s", - _(sc->descr)); - case XFROG_SCRUB_GROUP_METAFILES: - case XFROG_SCRUB_GROUP_SUMMARY: - case XFROG_SCRUB_GROUP_ISCAN: - case XFROG_SCRUB_GROUP_NONE: - return snprintf(buf, buflen, _("%s"), _(sc->descr)); - case XFROG_SCRUB_GROUP_RTGROUP: - return snprintf(buf, buflen, _("rtgroup %u %s"), meta->sm_agno, - _(sc->descr)); - } - return -1; -} - /* Warn about strange circumstances after scrub. */ void scrub_warn_incomplete_scrub( @@ -268,13 +236,18 @@ void scrub_vhead_add( struct scrubv_head *bighead, const struct scrub_item *sri, - unsigned int scrub_type) + unsigned int scrub_type, + bool repair) { struct xfs_scrub_vec_head *vhead = &bighead->head; struct xfs_scrub_vec *v; v = &vhead->svh_vecs[vhead->svh_nr++]; v->sv_type = scrub_type; + if (repair) + v->sv_flags |= XFS_SCRUB_IFLAG_REPAIR; + if (repair && use_force_rebuild) + v->sv_flags |= XFS_SCRUB_IFLAG_FORCE_REBUILD; bighead->i = v - vhead->svh_vecs; } @@ -299,7 +272,7 @@ scrub_call_kernel( foreach_scrub_type(scrub_type) { if (!(sri->sri_state[scrub_type] & SCRUB_ITEM_NEEDSCHECK)) continue; - scrub_vhead_add(&bh, sri, scrub_type); + scrub_vhead_add(&bh, sri, scrub_type, false); dbg_printf("check %s flags %xh tries %u\n", descr_render(&dsc), sri->sri_state[scrub_type], @@ -363,8 +336,8 @@ scrub_item_schedule_group( } /* Decide if we call the kernel again to finish scrub/repair activity. */ -static inline bool -scrub_item_call_kernel_again_future( +bool +scrub_item_call_kernel_again( struct scrub_item *sri, uint8_t work_mask, const struct scrub_item *old) @@ -380,6 +353,11 @@ scrub_item_call_kernel_again_future( if (!nr) return false; + /* + * We are willing to go again if the last call had any effect on the + * state of the scrub item that the caller cares about or if the kernel + * asked us to try again. + */ foreach_scrub_type(scrub_type) { uint8_t statex = sri->sri_state[scrub_type] ^ old->sri_state[scrub_type]; @@ -393,34 +371,6 @@ scrub_item_call_kernel_again_future( return false; } -/* Decide if we call the kernel again to finish scrub/repair activity. */ -bool -scrub_item_call_kernel_again( - struct scrub_item *sri, - unsigned int scrub_type, - uint8_t work_mask, - const struct scrub_item *old) -{ - uint8_t statex; - - /* If there's nothing to do, we're done. */ - if (!(sri->sri_state[scrub_type] & work_mask)) - return false; - - /* - * We are willing to go again if the last call had any effect on the - * state of the scrub item that the caller cares about, if the freeze - * flag got set, or if the kernel asked us to try again... - */ - statex = sri->sri_state[scrub_type] ^ old->sri_state[scrub_type]; - if (statex & work_mask) - return true; - if (sri->sri_tries[scrub_type] != old->sri_tries[scrub_type]) - return true; - - return false; -} - /* * For each scrub item whose state matches the state_flags, set up the item * state for a kernel call. Returns true if any work was scheduled. @@ -475,7 +425,7 @@ scrub_item_check_file( error = scrub_call_kernel(ctx, xfdp, sri); if (error) return error; - } while (scrub_item_call_kernel_again_future(sri, SCRUB_ITEM_NEEDSCHECK, + } while (scrub_item_call_kernel_again(sri, SCRUB_ITEM_NEEDSCHECK, &old_sri)); return 0; diff --git a/scrub/scrub_private.h b/scrub/scrub_private.h index 1059c197fa2..8daf28c26ee 100644 --- a/scrub/scrub_private.h +++ b/scrub/scrub_private.h @@ -26,9 +26,9 @@ struct scrubv_head { void scrub_item_to_vhead(struct scrubv_head *bighead, const struct scrub_item *sri); void scrub_vhead_add(struct scrubv_head *bighead, const struct scrub_item *sri, - unsigned int scrub_type); + unsigned int scrub_type, bool repair); -int format_scrub_descr(struct scrub_ctx *ctx, char *buf, size_t buflen, +int format_scrubv_descr(struct scrub_ctx *ctx, char *buf, size_t buflen, void *where); /* Predicates for scrub flag state. */ @@ -121,8 +121,7 @@ scrub_item_schedule_retry(struct scrub_item *sri, unsigned int scrub_type) return true; } -bool scrub_item_call_kernel_again(struct scrub_item *sri, - unsigned int scrub_type, uint8_t work_mask, +bool scrub_item_call_kernel_again(struct scrub_item *sri, uint8_t work_mask, const struct scrub_item *old); bool scrub_item_schedule_work(struct scrub_item *sri, uint8_t state_flags); From patchwork Fri Dec 30 22:20:41 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: 13085952 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 D4B28C4332F for ; Sat, 31 Dec 2022 03:27:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236377AbiLaD10 (ORCPT ); Fri, 30 Dec 2022 22:27:26 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38952 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236230AbiLaD10 (ORCPT ); Fri, 30 Dec 2022 22:27:26 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DFBC813D49 for ; Fri, 30 Dec 2022 19:27:24 -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 9B413B81E73 for ; Sat, 31 Dec 2022 03:27:23 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4A777C433D2; Sat, 31 Dec 2022 03:27:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1672457242; bh=LizPYZZtsSVM78x3/9roLeaJuTP4n6sGE9xlFfWwa6Q=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=r7qtfLgSXQnA+UM78DCZFVWazp3LYOH+c3GY/zUQHC0BoBQRfnN9zkI6UqeAgnBG/ quY3HCst3L0Ty3lYzN6UgeqvrrplNbfUgm2plDJLln65gdAbjmT8OrxXGynmjvZGR9 y8BM6uAWgN2K5DP92WXe9UlAPuQcrCgDwLpPo/UMd6Qvn3/puphNYX45kQLMTrg5M1 +w5Yc19x1jktVaoReMJkFqwP4arLGierOcokWHTL4htxXizPldOiE0TOneGhOHB6f0 48D+XFflfRTmVD36dLz6Wy5G2kJKTLP9PwcixPNrwGhhrQMIpLdnlF7wSF7SV3HROm Ewy3R15FB9nVA== Subject: [PATCH 10/11] xfs_scrub: use scrub barriers to reduce kernel calls From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Date: Fri, 30 Dec 2022 14:20:41 -0800 Message-ID: <167243884166.739244.11995511541336261812.stgit@magnolia> In-Reply-To: <167243884029.739244.16777239536975047510.stgit@magnolia> References: <167243884029.739244.16777239536975047510.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 Use scrub barriers so that we can submit a single scrub request for a bunch of things, and have the kernel stop midway through if it finds anything broken. Signed-off-by: Darrick J. Wong --- scrub/phase2.c | 15 ++------- scrub/phase3.c | 17 +--------- scrub/repair.c | 32 ++++++++++++++++++- scrub/scrub.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++- scrub/scrub.h | 17 ++++++++++ scrub/scrub_private.h | 4 ++ 6 files changed, 134 insertions(+), 32 deletions(-) diff --git a/scrub/phase2.c b/scrub/phase2.c index a224af11ed4..e4c7d32d75e 100644 --- a/scrub/phase2.c +++ b/scrub/phase2.c @@ -99,21 +99,12 @@ scan_ag_metadata( snprintf(descr, DESCR_BUFSZ, _("AG %u"), agno); /* - * First we scrub and fix the AG headers, because we need - * them to work well enough to check the AG btrees. + * First we scrub and fix the AG headers, because we need them to work + * well enough to check the AG btrees. Then scrub the AG btrees. */ scrub_item_schedule_group(&sri, XFROG_SCRUB_GROUP_AGHEADER); - ret = scrub_item_check(ctx, &sri); - if (ret) - goto err; - - /* Repair header damage. */ - ret = repair_item_corruption(ctx, &sri); - if (ret) - goto err; - - /* Now scrub the AG btrees. */ scrub_item_schedule_group(&sri, XFROG_SCRUB_GROUP_PERAG); + ret = scrub_item_check(ctx, &sri); if (ret) goto err; diff --git a/scrub/phase3.c b/scrub/phase3.c index 56a4385a408..14fff96ff77 100644 --- a/scrub/phase3.c +++ b/scrub/phase3.c @@ -145,25 +145,11 @@ scrub_inode( /* Scrub the inode. */ scrub_item_schedule(&sri, XFS_SCRUB_TYPE_INODE); - error = scrub_item_check_file(ctx, &sri, fd); - if (error) - goto out; - - error = try_inode_repair(ictx, &sri, fd); - if (error) - goto out; /* Scrub all block mappings. */ scrub_item_schedule(&sri, XFS_SCRUB_TYPE_BMBTD); scrub_item_schedule(&sri, XFS_SCRUB_TYPE_BMBTA); scrub_item_schedule(&sri, XFS_SCRUB_TYPE_BMBTC); - error = scrub_item_check_file(ctx, &sri, fd); - if (error) - goto out; - - error = try_inode_repair(ictx, &sri, fd); - if (error) - goto out; /* Check everything accessible via file mapping. */ if (S_ISLNK(bstat->bs_mode)) @@ -173,11 +159,12 @@ scrub_inode( scrub_item_schedule(&sri, XFS_SCRUB_TYPE_XATTR); scrub_item_schedule(&sri, XFS_SCRUB_TYPE_PARENT); + + /* Try to check and repair the file while it's open. */ error = scrub_item_check_file(ctx, &sri, fd); if (error) goto out; - /* Try to repair the file while it's open. */ error = try_inode_repair(ictx, &sri, fd); if (error) goto out; diff --git a/scrub/repair.c b/scrub/repair.c index 8a6263c675e..91259feb758 100644 --- a/scrub/repair.c +++ b/scrub/repair.c @@ -323,6 +323,7 @@ repair_call_kernel( struct scrubv_head bh = { }; struct xfs_scrub_vec *v; unsigned int scrub_type; + bool need_barrier = false; int error; assert(!debug_tweak_on("XFS_SCRUB_NO_KERNEL")); @@ -338,6 +339,11 @@ repair_call_kernel( repair_flags)) continue; + if (need_barrier) { + scrub_vhead_add_barrier(&bh); + need_barrier = false; + } + scrub_vhead_add(&bh, sri, scrub_type, true); if (sri->sri_state[scrub_type] & SCRUB_ITEM_NEEDSREPAIR) @@ -350,6 +356,17 @@ repair_call_kernel( dbg_printf("repair %s flags %xh tries %u\n", descr_render(&dsc), sri->sri_state[scrub_type], sri->sri_tries[scrub_type]); + + /* + * One of the other scrub types depends on this one. Set us up + * to add a repair barrier if we decide to schedule a repair + * after this one. If the UNFIXED flag is set, that means this + * is our last chance to fix things, so we skip the barriers + * just let everything run. + */ + if (!(repair_flags & XRM_FINAL_WARNING) && + (sri->sri_state[scrub_type] & SCRUB_ITEM_BARRIER)) + need_barrier = true; } error = -xfrog_scrubv_metadata(xfdp, &bh.head); @@ -357,6 +374,16 @@ repair_call_kernel( return error; foreach_bighead_vec(&bh, v) { + /* Deal with barriers separately. */ + if (v->sv_type == XFS_SCRUB_TYPE_BARRIER) { + /* -ECANCELED means the kernel stopped here. */ + if (v->sv_ret == -ECANCELED) + return 0; + if (v->sv_ret) + return -v->sv_ret; + continue; + } + error = repair_epilogue(ctx, &dsc, sri, repair_flags, v); if (error) return error; @@ -445,7 +472,8 @@ repair_item_boost_priorities( * bits are left untouched to force a rescan in phase 4. */ #define MUSTFIX_STATES (SCRUB_ITEM_CORRUPT | \ - SCRUB_ITEM_BOOST_REPAIR) + SCRUB_ITEM_BOOST_REPAIR | \ + SCRUB_ITEM_BARRIER) /* * Figure out which AG metadata must be fixed before we can move on * to the inode scan. @@ -730,7 +758,7 @@ repair_item_class( return 0; if (ctx->mode == SCRUB_MODE_PREEN && !(repair_mask & SCRUB_ITEM_PREEN)) return 0; - if (!scrub_item_schedule_work(sri, repair_mask)) + if (!scrub_item_schedule_work(sri, repair_mask, repair_deps)) return 0; /* diff --git a/scrub/scrub.c b/scrub/scrub.c index 76d4fa87931..6031e2b1991 100644 --- a/scrub/scrub.c +++ b/scrub/scrub.c @@ -24,6 +24,35 @@ /* Online scrub and repair wrappers. */ +/* + * Bitmap showing the correctness dependencies between scrub types for scrubs. + * Dependencies cannot cross scrub groups. + */ +#define DEP(x) (1U << (x)) +static const unsigned int scrub_deps[XFS_SCRUB_TYPE_NR] = { + [XFS_SCRUB_TYPE_AGF] = DEP(XFS_SCRUB_TYPE_SB), + [XFS_SCRUB_TYPE_AGFL] = DEP(XFS_SCRUB_TYPE_SB) | + DEP(XFS_SCRUB_TYPE_AGF), + [XFS_SCRUB_TYPE_AGI] = DEP(XFS_SCRUB_TYPE_SB), + [XFS_SCRUB_TYPE_BNOBT] = DEP(XFS_SCRUB_TYPE_AGF), + [XFS_SCRUB_TYPE_CNTBT] = DEP(XFS_SCRUB_TYPE_AGF), + [XFS_SCRUB_TYPE_INOBT] = DEP(XFS_SCRUB_TYPE_AGI), + [XFS_SCRUB_TYPE_FINOBT] = DEP(XFS_SCRUB_TYPE_AGI), + [XFS_SCRUB_TYPE_RMAPBT] = DEP(XFS_SCRUB_TYPE_AGF), + [XFS_SCRUB_TYPE_REFCNTBT] = DEP(XFS_SCRUB_TYPE_AGF), + [XFS_SCRUB_TYPE_BMBTD] = DEP(XFS_SCRUB_TYPE_INODE), + [XFS_SCRUB_TYPE_BMBTA] = DEP(XFS_SCRUB_TYPE_INODE), + [XFS_SCRUB_TYPE_BMBTC] = DEP(XFS_SCRUB_TYPE_INODE), + [XFS_SCRUB_TYPE_DIR] = DEP(XFS_SCRUB_TYPE_BMBTD), + [XFS_SCRUB_TYPE_XATTR] = DEP(XFS_SCRUB_TYPE_BMBTA), + [XFS_SCRUB_TYPE_SYMLINK] = DEP(XFS_SCRUB_TYPE_BMBTD), + [XFS_SCRUB_TYPE_PARENT] = DEP(XFS_SCRUB_TYPE_BMBTD), + [XFS_SCRUB_TYPE_QUOTACHECK] = DEP(XFS_SCRUB_TYPE_UQUOTA) | + DEP(XFS_SCRUB_TYPE_GQUOTA) | + DEP(XFS_SCRUB_TYPE_PQUOTA), +}; +#undef DEP + /* Describe the current state of a vectored scrub. */ int format_scrubv_descr( @@ -251,6 +280,21 @@ scrub_vhead_add( bighead->i = v - vhead->svh_vecs; } +/* Add a barrier to the scrub vector. */ +void +scrub_vhead_add_barrier( + struct scrubv_head *bighead) +{ + struct xfs_scrub_vec_head *vhead = &bighead->head; + struct xfs_scrub_vec *v; + + v = &vhead->svh_vecs[vhead->svh_nr++]; + v->sv_type = XFS_SCRUB_TYPE_BARRIER; + v->sv_flags = XFS_SCRUB_OFLAG_CORRUPT | XFS_SCRUB_OFLAG_XFAIL | + XFS_SCRUB_OFLAG_XCORRUPT | XFS_SCRUB_OFLAG_INCOMPLETE; + bighead->i = v - vhead->svh_vecs; +} + /* Do a read-only check of some metadata. */ static int scrub_call_kernel( @@ -262,6 +306,7 @@ scrub_call_kernel( struct scrubv_head bh = { }; struct xfs_scrub_vec *v; unsigned int scrub_type; + bool need_barrier = false; int error; assert(!debug_tweak_on("XFS_SCRUB_NO_KERNEL")); @@ -272,8 +317,17 @@ scrub_call_kernel( foreach_scrub_type(scrub_type) { if (!(sri->sri_state[scrub_type] & SCRUB_ITEM_NEEDSCHECK)) continue; + + if (need_barrier) { + scrub_vhead_add_barrier(&bh); + need_barrier = false; + } + scrub_vhead_add(&bh, sri, scrub_type, false); + if (sri->sri_state[scrub_type] & SCRUB_ITEM_BARRIER) + need_barrier = true; + dbg_printf("check %s flags %xh tries %u\n", descr_render(&dsc), sri->sri_state[scrub_type], sri->sri_tries[scrub_type]); @@ -284,6 +338,16 @@ scrub_call_kernel( return error; foreach_bighead_vec(&bh, v) { + /* Deal with barriers separately. */ + if (v->sv_type == XFS_SCRUB_TYPE_BARRIER) { + /* -ECANCELED means the kernel stopped here. */ + if (v->sv_ret == -ECANCELED) + return 0; + if (v->sv_ret) + return -v->sv_ret; + continue; + } + error = scrub_epilogue(ctx, &dsc, sri, v); if (error) return error; @@ -378,15 +442,25 @@ scrub_item_call_kernel_again( bool scrub_item_schedule_work( struct scrub_item *sri, - uint8_t state_flags) + uint8_t state_flags, + const unsigned int *schedule_deps) { unsigned int scrub_type; unsigned int nr = 0; foreach_scrub_type(scrub_type) { + unsigned int j; + + sri->sri_state[scrub_type] &= ~SCRUB_ITEM_BARRIER; + if (!(sri->sri_state[scrub_type] & state_flags)) continue; + foreach_scrub_type(j) { + if (schedule_deps[scrub_type] & (1U << j)) + sri->sri_state[j] |= SCRUB_ITEM_BARRIER; + } + sri->sri_tries[scrub_type] = SCRUB_ITEM_MAX_RETRIES; nr++; } @@ -406,7 +480,7 @@ scrub_item_check_file( struct xfs_fd *xfdp = &ctx->mnt; int error = 0; - if (!scrub_item_schedule_work(sri, SCRUB_ITEM_NEEDSCHECK)) + if (!scrub_item_schedule_work(sri, SCRUB_ITEM_NEEDSCHECK, scrub_deps)) return 0; /* @@ -630,6 +704,9 @@ check_scrubv( { struct xfs_scrub_vec_head head = { }; + if (debug_tweak_on("XFS_SCRUB_FORCE_SINGLE")) + ctx->mnt.flags |= XFROG_FLAG_SCRUB_FORCE_SINGLE; + /* We set the fallback flag if this doesn't work. */ xfrog_scrubv_metadata(&ctx->mnt, &head); } diff --git a/scrub/scrub.h b/scrub/scrub.h index 0db94da5281..69a37ad7bfa 100644 --- a/scrub/scrub.h +++ b/scrub/scrub.h @@ -30,6 +30,9 @@ enum xfrog_scrub_group; /* This scrub type needs to be checked. */ #define SCRUB_ITEM_NEEDSCHECK (1 << 5) +/* Scrub barrier. */ +#define SCRUB_ITEM_BARRIER (1 << 6) + /* All of the state flags that we need to prioritize repair work. */ #define SCRUB_ITEM_REPAIR_ANY (SCRUB_ITEM_CORRUPT | \ SCRUB_ITEM_PREEN | \ @@ -135,6 +138,20 @@ scrub_item_check(struct scrub_ctx *ctx, struct scrub_item *sri) return scrub_item_check_file(ctx, sri, -1); } +/* Count the number of metadata objects still needing a scrub. */ +static inline unsigned int +scrub_item_count_needscheck( + const struct scrub_item *sri) +{ + unsigned int ret = 0; + unsigned int i; + + foreach_scrub_type(i) + if (sri->sri_state[i] & SCRUB_ITEM_NEEDSCHECK) + ret++; + return ret; +} + void scrub_report_preen_triggers(struct scrub_ctx *ctx); bool can_scrub_fs_metadata(struct scrub_ctx *ctx); diff --git a/scrub/scrub_private.h b/scrub/scrub_private.h index 8daf28c26ee..b21a6ca62ba 100644 --- a/scrub/scrub_private.h +++ b/scrub/scrub_private.h @@ -27,6 +27,7 @@ void scrub_item_to_vhead(struct scrubv_head *bighead, const struct scrub_item *sri); void scrub_vhead_add(struct scrubv_head *bighead, const struct scrub_item *sri, unsigned int scrub_type, bool repair); +void scrub_vhead_add_barrier(struct scrubv_head *bighead); int format_scrubv_descr(struct scrub_ctx *ctx, char *buf, size_t buflen, void *where); @@ -123,6 +124,7 @@ scrub_item_schedule_retry(struct scrub_item *sri, unsigned int scrub_type) bool scrub_item_call_kernel_again(struct scrub_item *sri, uint8_t work_mask, const struct scrub_item *old); -bool scrub_item_schedule_work(struct scrub_item *sri, uint8_t state_flags); +bool scrub_item_schedule_work(struct scrub_item *sri, uint8_t state_flags, + const unsigned int *schedule_deps); #endif /* XFS_SCRUB_SCRUB_PRIVATE_H_ */ From patchwork Fri Dec 30 22:20:41 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: 13085953 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 3E84FC4332F for ; Sat, 31 Dec 2022 03:27:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236382AbiLaD1m (ORCPT ); Fri, 30 Dec 2022 22:27:42 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38980 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236230AbiLaD1l (ORCPT ); Fri, 30 Dec 2022 22:27:41 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 75D4E13D49 for ; Fri, 30 Dec 2022 19:27: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 ams.source.kernel.org (Postfix) with ESMTPS id 21CABB81E5A for ; Sat, 31 Dec 2022 03:27:39 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id CECEAC433EF; Sat, 31 Dec 2022 03:27:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1672457257; bh=ObR+DQwouU/7/H8MVzgsFr3kpjWcTLoWBClV6Ut4laY=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=MBzt7aC8rzdSWOqwKrEu9Xow20tTka6bv5ZRyLVCqAw+zmDMBUVy5PsyRNcnyqm8G 3rjeqAEWo6Qv3mqJ4y2J/676f0hWCQ7FCKTq6IiSN1Z3kOfXU7+UrU7aIQm6kNs249 d66C0Z/Ututifb89Iiqh7MIdEsoaiprqVTmwWP1mVqrbAhMw5puSE9KZsz0sHUgZUw ffYMjGYShW3OKf7KmIuMWsItYmfQwzXq0HxrO0DNj2WfYQLjBTpzkMAk2nc423xx90 doKjssX/XpUNMNdBqHQYor7ykzMyI0jEC92Ue6ifBl1Nx0sGYeYUVjFBsklqu+O0/T Jm4y125gk9n8Q== Subject: [PATCH 11/11] xfs_scrub: try spot repairs of metadata items to make scrub progress From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Date: Fri, 30 Dec 2022 14:20:41 -0800 Message-ID: <167243884179.739244.14046030541432078868.stgit@magnolia> In-Reply-To: <167243884029.739244.16777239536975047510.stgit@magnolia> References: <167243884029.739244.16777239536975047510.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 Now that we've enabled scrub dependency barriers, it's possible that a scrub_item_check call will return with some of the scrub items still in NEEDSCHECK state. If, for example, scrub type B depends on scrub type A being clean and A is not clean, B will still be in NEEDSCHECK state. In order to make as much scanning progress as possible during phase 2 and phase 3, allow ourselves to try some spot repairs in the hopes that it will enable us to make progress towards at least scanning the whole metadata item. If we can't make any forward progress, we'll queue the scrub item for repair in phase 4, which means that anything still in in NEEDSCHECK state becomes CORRUPT state. (At worst, the NEEDSCHECK item will actually be clean by phase 4, and xfs_scrub will report that it didn't need any work after all.) Signed-off-by: Darrick J. Wong --- scrub/phase2.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ scrub/phase3.c | 71 +++++++++++++++++++++++++++++++++++++++++++- scrub/repair.c | 15 +++++++++ 3 files changed, 176 insertions(+), 1 deletion(-) diff --git a/scrub/phase2.c b/scrub/phase2.c index e4c7d32d75e..e2d46cba640 100644 --- a/scrub/phase2.c +++ b/scrub/phase2.c @@ -77,6 +77,53 @@ defer_fs_repair( return 0; } +/* + * If we couldn't check all the scheduled metadata items, try performing spot + * repairs until we check everything or stop making forward progress. + */ +static int +repair_and_scrub_loop( + struct scrub_ctx *ctx, + struct scrub_item *sri, + const char *descr, + bool *defer) +{ + unsigned int to_check; + int ret; + + *defer = false; + if (ctx->mode != SCRUB_MODE_REPAIR) + return 0; + + to_check = scrub_item_count_needscheck(sri); + while (to_check > 0) { + unsigned int nr; + + ret = repair_item_corruption(ctx, sri); + if (ret) + return ret; + + ret = scrub_item_check(ctx, sri); + if (ret) + return ret; + + nr = scrub_item_count_needscheck(sri); + if (nr == to_check) { + /* + * We cannot make forward scanning progress with this + * metadata, so defer the rest until phase 4. + */ + str_info(ctx, descr, + _("Unable to make forward checking progress; will try again in phase 4.")); + *defer = true; + return 0; + } + to_check = nr; + } + + return 0; +} + /* Scrub each AG's metadata btrees. */ static void scan_ag_metadata( @@ -90,6 +137,7 @@ scan_ag_metadata( struct scan_ctl *sctl = arg; char descr[DESCR_BUFSZ]; unsigned int difficulty; + bool defer_repairs; int ret; if (sctl->aborted) @@ -105,10 +153,22 @@ scan_ag_metadata( scrub_item_schedule_group(&sri, XFROG_SCRUB_GROUP_AGHEADER); scrub_item_schedule_group(&sri, XFROG_SCRUB_GROUP_PERAG); + /* + * Try to check all of the AG metadata items that we just scheduled. + * If we return with some types still needing a check, try repairing + * any damaged metadata that we've found so far, and try again. Abort + * if we stop making forward progress. + */ ret = scrub_item_check(ctx, &sri); if (ret) goto err; + ret = repair_and_scrub_loop(ctx, &sri, descr, &defer_repairs); + if (ret) + goto err; + if (defer_repairs) + goto defer; + /* * Figure out if we need to perform early fixing. The only * reason we need to do this is if the inobt is broken, which @@ -125,6 +185,7 @@ scan_ag_metadata( if (ret) goto err; +defer: /* Everything else gets fixed during phase 4. */ ret = defer_fs_repair(ctx, &sri); if (ret) @@ -145,11 +206,18 @@ scan_metafile( struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx; struct scan_ctl *sctl = arg; unsigned int difficulty; + bool defer_repairs; int ret; if (sctl->aborted) goto out; + /* + * Try to check all of the metadata files that we just scheduled. If + * we return with some types still needing a check, try repairing any + * damaged metadata that we've found so far, and try again. Abort if + * we stop making forward progress. + */ scrub_item_init_fs(&sri); scrub_item_schedule(&sri, type); ret = scrub_item_check(ctx, &sri); @@ -158,10 +226,20 @@ scan_metafile( goto out; } + ret = repair_and_scrub_loop(ctx, &sri, xfrog_scrubbers[type].descr, + &defer_repairs); + if (ret) { + sctl->aborted = true; + goto out; + } + if (defer_repairs) + goto defer; + /* Complain about metadata corruptions that might not be fixable. */ difficulty = repair_item_difficulty(&sri); warn_repair_difficulties(ctx, difficulty, xfrog_scrubbers[type].descr); +defer: ret = defer_fs_repair(ctx, &sri); if (ret) { sctl->aborted = true; @@ -188,6 +266,7 @@ scan_rtgroup_metadata( struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx; struct scan_ctl *sctl = arg; char descr[DESCR_BUFSZ]; + bool defer_repairs; int ret; if (sctl->aborted) @@ -196,6 +275,12 @@ scan_rtgroup_metadata( scrub_item_init_rtgroup(&sri, rgno); snprintf(descr, DESCR_BUFSZ, _("rtgroup %u"), rgno); + /* + * Try to check all of the rtgroup metadata items that we just + * scheduled. If we return with some types still needing a check, try + * repairing any damaged metadata that we've found so far, and try + * again. Abort if we stop making forward progress. + */ scrub_item_schedule_group(&sri, XFROG_SCRUB_GROUP_RTGROUP); ret = scrub_item_check(ctx, &sri); if (ret) { @@ -203,6 +288,12 @@ scan_rtgroup_metadata( goto out; } + ret = repair_and_scrub_loop(ctx, &sri, descr, &defer_repairs); + if (ret) { + sctl->aborted = true; + goto out; + } + /* Everything else gets fixed during phase 4. */ ret = defer_fs_repair(ctx, &sri); if (ret) { diff --git a/scrub/phase3.c b/scrub/phase3.c index 14fff96ff77..43495b3b746 100644 --- a/scrub/phase3.c +++ b/scrub/phase3.c @@ -99,6 +99,58 @@ try_inode_repair( return repair_file_corruption(ictx->ctx, sri, fd); } +/* + * If we couldn't check all the scheduled file metadata items, try performing + * spot repairs until we check everything or stop making forward progress. + */ +static int +repair_and_scrub_inode_loop( + struct scrub_ctx *ctx, + struct xfs_bulkstat *bstat, + int fd, + struct scrub_item *sri, + bool *defer) +{ + unsigned int to_check; + int error; + + *defer = false; + if (ctx->mode != SCRUB_MODE_REPAIR) + return 0; + + to_check = scrub_item_count_needscheck(sri); + while (to_check > 0) { + unsigned int nr; + + error = repair_file_corruption(ctx, sri, fd); + if (error) + return error; + + error = scrub_item_check_file(ctx, sri, fd); + if (error) + return error; + + nr = scrub_item_count_needscheck(sri); + if (nr == to_check) { + char descr[DESCR_BUFSZ]; + + /* + * We cannot make forward scanning progress with this + * inode, so defer the rest until phase 4. + */ + scrub_render_ino_descr(ctx, descr, DESCR_BUFSZ, + bstat->bs_ino, bstat->bs_gen, NULL); + str_info(ctx, descr, + _("Unable to make forward checking progress; will try again in phase 4.")); + *defer = true; + return 0; + } + to_check = nr; + } + + return 0; +} + /* Verify the contents, xattrs, and extent maps of an inode. */ static int scrub_inode( @@ -160,11 +212,28 @@ scrub_inode( scrub_item_schedule(&sri, XFS_SCRUB_TYPE_XATTR); scrub_item_schedule(&sri, XFS_SCRUB_TYPE_PARENT); - /* Try to check and repair the file while it's open. */ + /* + * Try to check all of the metadata items that we just scheduled. If + * we return with some types still needing a check and the space + * metadata isn't also in need of repairs, try repairing any damaged + * file metadata that we've found so far, and try checking the file + * again. Worst case, defer the repairs and the checks to phase 4 if + * we can't make any progress on anything. + */ error = scrub_item_check_file(ctx, &sri, fd); if (error) goto out; + if (!ictx->always_defer_repairs) { + bool defer_repairs; + + error = repair_and_scrub_inode_loop(ctx, bstat, fd, &sri, + &defer_repairs); + if (error || defer_repairs) + goto out; + } + + /* Try to repair the file while it's open. */ error = try_inode_repair(ictx, &sri, fd); if (error) goto out; diff --git a/scrub/repair.c b/scrub/repair.c index 91259feb758..bf843522993 100644 --- a/scrub/repair.c +++ b/scrub/repair.c @@ -849,6 +849,7 @@ repair_item_to_action_item( struct action_item **aitemp) { struct action_item *aitem; + unsigned int scrub_type; if (repair_item_count_needsrepair(sri) == 0) return 0; @@ -864,6 +865,20 @@ repair_item_to_action_item( INIT_LIST_HEAD(&aitem->list); memcpy(&aitem->sri, sri, sizeof(struct scrub_item)); + /* + * If the scrub item indicates that there is unchecked metadata, assume + * that the scrub type checker depends on something that couldn't be + * fixed. Mark that type as corrupt so that phase 4 will try it again. + */ + foreach_scrub_type(scrub_type) { + __u8 *state = aitem->sri.sri_state; + + if (state[scrub_type] & SCRUB_ITEM_NEEDSCHECK) { + state[scrub_type] &= ~SCRUB_ITEM_NEEDSCHECK; + state[scrub_type] |= SCRUB_ITEM_CORRUPT; + } + } + *aitemp = aitem; return 0; }