From patchwork Sun Dec 31 20:19:33 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13507378 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 53BDFBA2E for ; Sun, 31 Dec 2023 20:19:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Rzx0HgfT" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2756CC433C8; Sun, 31 Dec 2023 20:19:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704053974; bh=XeRK9kRCmvDkHWdtcjLwZ2/OI/aLheehQrMAnDVz28A=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Rzx0HgfTWRTyOHUaD8R9ISxqqhlEOMZQKAwjbsTASxleVdI7avSj1+VPwsf7juGHa +KxQP+yJse3LxV0xS1HglBkUZiKU9FfprWsxrKPCxQDRi/F6KfTuTqWUt1npXV7iIT y0crjpbw6/uueYJG21r1jFr8l6MswX4Y/k74tW0pyDJ0UBZQ8E4i5Yxfu58s52epr7 y+aoQigRGnB2OPqAvrxMQk3kQETNGYAuhBbQv7VyA2MpxEWmWmzuATNnq4gMDf7RID m0qd+CrCjoPD8A5DdaFvfMYrhkDAxUwFOJk6Nu2W+IAat2NoZwQIWYkuPTDzUVBFc0 7CV77XXJX32QQ== Date: Sun, 31 Dec 2023 12:19:33 -0800 Subject: [PATCH 1/4] xfs: move lru refs to the btree ops structure From: "Darrick J. Wong" To: djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170404831021.1749557.2760974108166727419.stgit@frogsfrogsfrogs> In-Reply-To: <170404830995.1749557.6135790697605021363.stgit@frogsfrogsfrogs> References: <170404830995.1749557.6135790697605021363.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Move the btree buffer LRU refcount to the btree ops structure so that we can eliminate the last bc_btnum switch in the generic btree code. We're about to create repair-specific btree types, and we don't want that stuff cluttering up libxfs. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_alloc_btree.c | 2 ++ fs/xfs/libxfs/xfs_bmap_btree.c | 1 + fs/xfs/libxfs/xfs_btree.c | 24 ++---------------------- fs/xfs/libxfs/xfs_btree.h | 3 +++ fs/xfs/libxfs/xfs_ialloc_btree.c | 2 ++ fs/xfs/libxfs/xfs_refcount_btree.c | 1 + fs/xfs/libxfs/xfs_rmap_btree.c | 2 ++ 7 files changed, 13 insertions(+), 22 deletions(-) diff --git a/fs/xfs/libxfs/xfs_alloc_btree.c b/fs/xfs/libxfs/xfs_alloc_btree.c index 08aa92f574334..fd769e62cc35b 100644 --- a/fs/xfs/libxfs/xfs_alloc_btree.c +++ b/fs/xfs/libxfs/xfs_alloc_btree.c @@ -457,6 +457,7 @@ xfs_allocbt_keys_contiguous( const struct xfs_btree_ops xfs_bnobt_ops = { .rec_len = sizeof(xfs_alloc_rec_t), .key_len = sizeof(xfs_alloc_key_t), + .lru_refs = XFS_ALLOC_BTREE_REF, .dup_cursor = xfs_allocbt_dup_cursor, .set_root = xfs_allocbt_set_root, @@ -480,6 +481,7 @@ const struct xfs_btree_ops xfs_bnobt_ops = { const struct xfs_btree_ops xfs_cntbt_ops = { .rec_len = sizeof(xfs_alloc_rec_t), .key_len = sizeof(xfs_alloc_key_t), + .lru_refs = XFS_ALLOC_BTREE_REF, .geom_flags = XFS_BTREE_LASTREC_UPDATE, .dup_cursor = xfs_allocbt_dup_cursor, diff --git a/fs/xfs/libxfs/xfs_bmap_btree.c b/fs/xfs/libxfs/xfs_bmap_btree.c index 54e0a47169487..fd5fb8abf4448 100644 --- a/fs/xfs/libxfs/xfs_bmap_btree.c +++ b/fs/xfs/libxfs/xfs_bmap_btree.c @@ -516,6 +516,7 @@ xfs_bmbt_keys_contiguous( const struct xfs_btree_ops xfs_bmbt_ops = { .rec_len = sizeof(xfs_bmbt_rec_t), .key_len = sizeof(xfs_bmbt_key_t), + .lru_refs = XFS_BMAP_BTREE_REF, .geom_flags = XFS_BTREE_LONG_PTRS | XFS_BTREE_ROOT_IN_INODE, .dup_cursor = xfs_bmbt_dup_cursor, diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c index 5af19610d8919..4c8e9dd25b739 100644 --- a/fs/xfs/libxfs/xfs_btree.c +++ b/fs/xfs/libxfs/xfs_btree.c @@ -1350,32 +1350,12 @@ xfs_btree_buf_to_ptr( } } -STATIC void +static inline void xfs_btree_set_refs( struct xfs_btree_cur *cur, struct xfs_buf *bp) { - switch (cur->bc_btnum) { - case XFS_BTNUM_BNO: - case XFS_BTNUM_CNT: - xfs_buf_set_ref(bp, XFS_ALLOC_BTREE_REF); - break; - case XFS_BTNUM_INO: - case XFS_BTNUM_FINO: - xfs_buf_set_ref(bp, XFS_INO_BTREE_REF); - break; - case XFS_BTNUM_BMAP: - xfs_buf_set_ref(bp, XFS_BMAP_BTREE_REF); - break; - case XFS_BTNUM_RMAP: - xfs_buf_set_ref(bp, XFS_RMAP_BTREE_REF); - break; - case XFS_BTNUM_REFC: - xfs_buf_set_ref(bp, XFS_REFC_BTREE_REF); - break; - default: - ASSERT(0); - } + xfs_buf_set_ref(bp, cur->bc_ops->lru_refs); } int diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h index 41000bd6cccf7..edbcd4f0e9888 100644 --- a/fs/xfs/libxfs/xfs_btree.h +++ b/fs/xfs/libxfs/xfs_btree.h @@ -120,6 +120,9 @@ struct xfs_btree_ops { /* XFS_BTREE_* flags that determine the geometry of the btree */ unsigned int geom_flags; + /* LRU refcount to set on each btree buffer created */ + int lru_refs; + /* cursor operations */ struct xfs_btree_cur *(*dup_cursor)(struct xfs_btree_cur *); void (*update_cursor)(struct xfs_btree_cur *src, diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c index 69086fdc3be6f..cdb1f99970724 100644 --- a/fs/xfs/libxfs/xfs_ialloc_btree.c +++ b/fs/xfs/libxfs/xfs_ialloc_btree.c @@ -401,6 +401,7 @@ xfs_inobt_keys_contiguous( const struct xfs_btree_ops xfs_inobt_ops = { .rec_len = sizeof(xfs_inobt_rec_t), .key_len = sizeof(xfs_inobt_key_t), + .lru_refs = XFS_INO_BTREE_REF, .dup_cursor = xfs_inobt_dup_cursor, .set_root = xfs_inobt_set_root, @@ -423,6 +424,7 @@ const struct xfs_btree_ops xfs_inobt_ops = { const struct xfs_btree_ops xfs_finobt_ops = { .rec_len = sizeof(xfs_inobt_rec_t), .key_len = sizeof(xfs_inobt_key_t), + .lru_refs = XFS_INO_BTREE_REF, .dup_cursor = xfs_inobt_dup_cursor, .set_root = xfs_finobt_set_root, diff --git a/fs/xfs/libxfs/xfs_refcount_btree.c b/fs/xfs/libxfs/xfs_refcount_btree.c index 36e7b26d5e3b2..06a2f062b58cb 100644 --- a/fs/xfs/libxfs/xfs_refcount_btree.c +++ b/fs/xfs/libxfs/xfs_refcount_btree.c @@ -320,6 +320,7 @@ xfs_refcountbt_keys_contiguous( const struct xfs_btree_ops xfs_refcountbt_ops = { .rec_len = sizeof(struct xfs_refcount_rec), .key_len = sizeof(struct xfs_refcount_key), + .lru_refs = XFS_REFC_BTREE_REF, .dup_cursor = xfs_refcountbt_dup_cursor, .set_root = xfs_refcountbt_set_root, diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c index b4a8b4b62456b..23841ee6e2ff6 100644 --- a/fs/xfs/libxfs/xfs_rmap_btree.c +++ b/fs/xfs/libxfs/xfs_rmap_btree.c @@ -489,6 +489,7 @@ xfs_rmapbt_keys_contiguous( const struct xfs_btree_ops xfs_rmapbt_ops = { .rec_len = sizeof(struct xfs_rmap_rec), .key_len = 2 * sizeof(struct xfs_rmap_key), + .lru_refs = XFS_RMAP_BTREE_REF, .geom_flags = XFS_BTREE_CRC_BLOCKS | XFS_BTREE_OVERLAPPING, .dup_cursor = xfs_rmapbt_dup_cursor, @@ -613,6 +614,7 @@ static const struct xfs_buf_ops xfs_rmapbt_mem_buf_ops = { static const struct xfs_btree_ops xfs_rmapbt_mem_ops = { .rec_len = sizeof(struct xfs_rmap_rec), .key_len = 2 * sizeof(struct xfs_rmap_key), + .lru_refs = XFS_RMAP_BTREE_REF, .geom_flags = XFS_BTREE_CRC_BLOCKS | XFS_BTREE_OVERLAPPING | XFS_BTREE_IN_XFILE, From patchwork Sun Dec 31 20:19:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13507379 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F14F9BA22 for ; Sun, 31 Dec 2023 20:19:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="pTDsyBmW" Received: by smtp.kernel.org (Postfix) with ESMTPSA id BC842C433C8; Sun, 31 Dec 2023 20:19:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704053989; bh=/2seqoWlMXyKPa4VCX/sc3MyMBGX1ln8i/NwcNtDpJI=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=pTDsyBmWofIb3wUr7XboHvHNQmpwNluUMVgQMCBM+w6JGSRjk4BCEnSiyZIXotBFT k/fvRx51SYe5dlFVNurxSJgpnA/0M/TfL8WpJVbhDuuoMocEZKZ9f5ZqK6hJH8O9qJ AJ0pJafGBo/6EuhQbdlHB/Spq+RAJ0EOFwNFdH4Cua/pnwCaZ5mMtU6tmRjHeb/9t1 4S57FijgGKw0hq7TbaKqRibIlUEqeqrSNFCwlBEKbyYWUfs6UoIxoP6KfDrYom6Is2 8ScWdLoPbSTfPoIyKbv6PZxq+ZM2WeZttMwaujQF8ns675teENQcAGx6uX0XrfV9IY IAcqqnr/LtQ0A== Date: Sun, 31 Dec 2023 12:19:49 -0800 Subject: [PATCH 2/4] xfs: define an in-memory btree for storing refcount bag info during repairs From: "Darrick J. Wong" To: djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170404831037.1749557.13971406924347839328.stgit@frogsfrogsfrogs> In-Reply-To: <170404830995.1749557.6135790697605021363.stgit@frogsfrogsfrogs> References: <170404830995.1749557.6135790697605021363.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Create a new in-memory btree type so that we can store refcount bag info in a much more memory-efficient format. Signed-off-by: Darrick J. Wong --- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_btree.h | 1 fs/xfs/libxfs/xfs_types.h | 6 + fs/xfs/scrub/rcbag_btree.c | 314 ++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/rcbag_btree.h | 76 +++++++++++ fs/xfs/scrub/trace.h | 1 fs/xfs/xfs_trace.h | 1 7 files changed, 398 insertions(+), 2 deletions(-) create mode 100644 fs/xfs/scrub/rcbag_btree.c create mode 100644 fs/xfs/scrub/rcbag_btree.h diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index dfa142eb16f46..f927a43cc16a5 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile @@ -198,6 +198,7 @@ xfs-y += $(addprefix scrub/, \ inode_repair.o \ newbt.o \ nlinks_repair.o \ + rcbag_btree.o \ reap.o \ refcount_repair.o \ repair.o \ diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h index edbcd4f0e9888..339b5561e5b04 100644 --- a/fs/xfs/libxfs/xfs_btree.h +++ b/fs/xfs/libxfs/xfs_btree.h @@ -62,6 +62,7 @@ union xfs_btree_rec { #define XFS_BTNUM_FINO ((xfs_btnum_t)XFS_BTNUM_FINOi) #define XFS_BTNUM_RMAP ((xfs_btnum_t)XFS_BTNUM_RMAPi) #define XFS_BTNUM_REFC ((xfs_btnum_t)XFS_BTNUM_REFCi) +#define XFS_BTNUM_RCBAG ((xfs_btnum_t)XFS_BTNUM_RCBAGi) struct xfs_btree_ops; uint32_t xfs_btree_magic(struct xfs_mount *mp, const struct xfs_btree_ops *ops); diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h index 035bf703d719a..5556615a2ff9c 100644 --- a/fs/xfs/libxfs/xfs_types.h +++ b/fs/xfs/libxfs/xfs_types.h @@ -121,7 +121,8 @@ typedef enum { */ typedef enum { XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_RMAPi, XFS_BTNUM_BMAPi, - XFS_BTNUM_INOi, XFS_BTNUM_FINOi, XFS_BTNUM_REFCi, XFS_BTNUM_MAX + XFS_BTNUM_INOi, XFS_BTNUM_FINOi, XFS_BTNUM_REFCi, XFS_BTNUM_RCBAGi, + XFS_BTNUM_MAX } xfs_btnum_t; #define XFS_BTNUM_STRINGS \ @@ -131,7 +132,8 @@ typedef enum { { XFS_BTNUM_BMAPi, "bmbt" }, \ { XFS_BTNUM_INOi, "inobt" }, \ { XFS_BTNUM_FINOi, "finobt" }, \ - { XFS_BTNUM_REFCi, "refcbt" } + { XFS_BTNUM_REFCi, "refcbt" }, \ + { XFS_BTNUM_RCBAGi, "rcbagbt" } struct xfs_name { const unsigned char *name; diff --git a/fs/xfs/scrub/rcbag_btree.c b/fs/xfs/scrub/rcbag_btree.c new file mode 100644 index 0000000000000..4b0c849321b25 --- /dev/null +++ b/fs/xfs/scrub/rcbag_btree.c @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022-2024 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_defer.h" +#include "xfs_btree.h" +#include "xfs_btree_mem.h" +#include "xfs_error.h" +#include "scrub/xfile.h" +#include "scrub/xfbtree.h" +#include "scrub/rcbag_btree.h" +#include "scrub/trace.h" + +static struct kmem_cache *rcbagbt_cur_cache; + +STATIC void +rcbagbt_init_key_from_rec( + union xfs_btree_key *key, + const union xfs_btree_rec *rec) +{ + struct rcbag_key *bag_key = (struct rcbag_key *)key; + const struct rcbag_rec *bag_rec = (const struct rcbag_rec *)rec; + + BUILD_BUG_ON(sizeof(struct rcbag_key) > sizeof(union xfs_btree_key)); + BUILD_BUG_ON(sizeof(struct rcbag_rec) > sizeof(union xfs_btree_rec)); + + bag_key->rbg_startblock = bag_rec->rbg_startblock; + bag_key->rbg_blockcount = bag_rec->rbg_blockcount; +} + +STATIC void +rcbagbt_init_rec_from_cur( + struct xfs_btree_cur *cur, + union xfs_btree_rec *rec) +{ + struct rcbag_rec *bag_rec = (struct rcbag_rec *)rec; + struct rcbag_rec *bag_irec = (struct rcbag_rec *)&cur->bc_rec; + + bag_rec->rbg_startblock = bag_irec->rbg_startblock; + bag_rec->rbg_blockcount = bag_irec->rbg_blockcount; + bag_rec->rbg_refcount = bag_irec->rbg_refcount; +} + +STATIC int64_t +rcbagbt_key_diff( + struct xfs_btree_cur *cur, + const union xfs_btree_key *key) +{ + struct rcbag_rec *rec = (struct rcbag_rec *)&cur->bc_rec; + const struct rcbag_key *kp = (const struct rcbag_key *)key; + + if (kp->rbg_startblock > rec->rbg_startblock) + return 1; + if (kp->rbg_startblock < rec->rbg_startblock) + return -1; + + if (kp->rbg_blockcount > rec->rbg_blockcount) + return 1; + if (kp->rbg_blockcount < rec->rbg_blockcount) + return -1; + + return 0; +} + +STATIC int64_t +rcbagbt_diff_two_keys( + struct xfs_btree_cur *cur, + const union xfs_btree_key *k1, + const union xfs_btree_key *k2, + const union xfs_btree_key *mask) +{ + const struct rcbag_key *kp1 = (const struct rcbag_key *)k1; + const struct rcbag_key *kp2 = (const struct rcbag_key *)k2; + + ASSERT(mask == NULL); + + if (kp1->rbg_startblock > kp2->rbg_startblock) + return 1; + if (kp1->rbg_startblock < kp2->rbg_startblock) + return -1; + + if (kp1->rbg_blockcount > kp2->rbg_blockcount) + return 1; + if (kp1->rbg_blockcount < kp2->rbg_blockcount) + return -1; + + return 0; +} + +STATIC int +rcbagbt_keys_inorder( + struct xfs_btree_cur *cur, + const union xfs_btree_key *k1, + const union xfs_btree_key *k2) +{ + const struct rcbag_key *kp1 = (const struct rcbag_key *)k1; + const struct rcbag_key *kp2 = (const struct rcbag_key *)k2; + + if (kp1->rbg_startblock > kp2->rbg_startblock) + return 0; + if (kp1->rbg_startblock < kp2->rbg_startblock) + return 1; + + if (kp1->rbg_blockcount > kp2->rbg_blockcount) + return 0; + if (kp1->rbg_blockcount < kp2->rbg_blockcount) + return 1; + + return 0; +} + +STATIC int +rcbagbt_recs_inorder( + struct xfs_btree_cur *cur, + const union xfs_btree_rec *r1, + const union xfs_btree_rec *r2) +{ + const struct rcbag_rec *rp1 = (const struct rcbag_rec *)r1; + const struct rcbag_rec *rp2 = (const struct rcbag_rec *)r2; + + if (rp1->rbg_startblock > rp2->rbg_startblock) + return 0; + if (rp1->rbg_startblock < rp2->rbg_startblock) + return 1; + + if (rp1->rbg_blockcount > rp2->rbg_blockcount) + return 0; + if (rp1->rbg_blockcount < rp2->rbg_blockcount) + return 1; + + return 0; +} + +static xfs_failaddr_t +rcbagbt_verify( + struct xfs_buf *bp) +{ + struct xfs_mount *mp = bp->b_mount; + struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); + xfs_failaddr_t fa; + unsigned int level; + + if (!xfs_verify_magic(bp, block->bb_magic)) + return __this_address; + + fa = xfs_btree_lblock_v5hdr_verify(bp, XFS_RMAP_OWN_UNKNOWN); + if (fa) + return fa; + + level = be16_to_cpu(block->bb_level); + if (level >= rcbagbt_maxlevels_possible()) + return __this_address; + + return xfbtree_lblock_verify(bp, + rcbagbt_maxrecs(mp, xfo_to_b(1), level == 0)); +} + +static void +rcbagbt_rw_verify( + struct xfs_buf *bp) +{ + xfs_failaddr_t fa = rcbagbt_verify(bp); + + if (fa) + xfs_verifier_error(bp, -EFSCORRUPTED, fa); +} + +/* skip crc checks on in-memory btrees to save time */ +static const struct xfs_buf_ops rcbagbt_mem_buf_ops = { + .name = "rcbagbt_mem", + .magic = { 0, cpu_to_be32(RCBAG_MAGIC) }, + .verify_read = rcbagbt_rw_verify, + .verify_write = rcbagbt_rw_verify, + .verify_struct = rcbagbt_verify, +}; + +static const struct xfs_btree_ops rcbagbt_mem_ops = { + .rec_len = sizeof(struct rcbag_rec), + .key_len = sizeof(struct rcbag_key), + .lru_refs = 1, + .geom_flags = XFS_BTREE_CRC_BLOCKS | XFS_BTREE_LONG_PTRS | + XFS_BTREE_IN_XFILE, + + .dup_cursor = xfbtree_dup_cursor, + .set_root = xfbtree_set_root, + .alloc_block = xfbtree_alloc_block, + .free_block = xfbtree_free_block, + .get_minrecs = xfbtree_get_minrecs, + .get_maxrecs = xfbtree_get_maxrecs, + .init_key_from_rec = rcbagbt_init_key_from_rec, + .init_rec_from_cur = rcbagbt_init_rec_from_cur, + .init_ptr_from_cur = xfbtree_init_ptr_from_cur, + .key_diff = rcbagbt_key_diff, + .buf_ops = &rcbagbt_mem_buf_ops, + .diff_two_keys = rcbagbt_diff_two_keys, + .keys_inorder = rcbagbt_keys_inorder, + .recs_inorder = rcbagbt_recs_inorder, +}; + +/* Create a cursor for an in-memory btree. */ +struct xfs_btree_cur * +rcbagbt_mem_cursor( + struct xfs_mount *mp, + struct xfs_trans *tp, + struct xfs_buf *head_bp, + struct xfbtree *xfbtree) +{ + struct xfs_btree_cur *cur; + + cur = xfs_btree_alloc_cursor(mp, tp, XFS_BTNUM_RCBAG, &rcbagbt_mem_ops, + rcbagbt_maxlevels_possible(), rcbagbt_cur_cache); + + cur->bc_mem.xfbtree = xfbtree; + cur->bc_mem.head_bp = head_bp; + cur->bc_nlevels = xfs_btree_mem_head_nlevels(head_bp); + return cur; +} + +/* Create an in-memory refcount bag btree. */ +int +rcbagbt_mem_create( + struct xfs_mount *mp, + struct xfs_buftarg *target, + struct xfbtree **xfbtreep) +{ + struct xfbtree_config cfg = { + .btree_ops = &rcbagbt_mem_ops, + .target = target, + }; + + return xfbtree_create(mp, &cfg, xfbtreep); +} + +/* Calculate number of records in a refcount bag btree block. */ +static inline unsigned int +rcbagbt_block_maxrecs( + unsigned int blocklen, + bool leaf) +{ + if (leaf) + return blocklen / sizeof(struct rcbag_rec); + return blocklen / + (sizeof(struct rcbag_key) + sizeof(rcbag_ptr_t)); +} + +/* + * Calculate number of records in an refcount bag btree block. + */ +unsigned int +rcbagbt_maxrecs( + struct xfs_mount *mp, + unsigned int blocklen, + bool leaf) +{ + blocklen -= RCBAG_BLOCK_LEN; + return rcbagbt_block_maxrecs(blocklen, leaf); +} + +#define RCBAGBT_INIT_MINRECS(minrecs) \ + do { \ + unsigned int blocklen; \ +\ + blocklen = PAGE_SIZE - XFS_BTREE_LBLOCK_CRC_LEN; \ +\ + minrecs[0] = rcbagbt_block_maxrecs(blocklen, true) / 2; \ + minrecs[1] = rcbagbt_block_maxrecs(blocklen, false) / 2; \ + } while (0) + +/* Compute the max possible height for refcount bag btrees. */ +unsigned int +rcbagbt_maxlevels_possible(void) +{ + unsigned int minrecs[2]; + + RCBAGBT_INIT_MINRECS(minrecs); + return xfs_btree_space_to_height(minrecs, ULLONG_MAX); +} + +/* Calculate the refcount bag btree size for some records. */ +unsigned long long +rcbagbt_calc_size( + unsigned long long nr_records) +{ + unsigned int minrecs[2]; + + RCBAGBT_INIT_MINRECS(minrecs); + return xfs_btree_calc_size(minrecs, nr_records); +} + +int __init +rcbagbt_init_cur_cache(void) +{ + rcbagbt_cur_cache = kmem_cache_create("xfs_rcbagbt_cur", + xfs_btree_cur_sizeof(rcbagbt_maxlevels_possible()), + 0, 0, NULL); + + if (!rcbagbt_cur_cache) + return -ENOMEM; + return 0; +} + +void +rcbagbt_destroy_cur_cache(void) +{ + kmem_cache_destroy(rcbagbt_cur_cache); + rcbagbt_cur_cache = NULL; +} diff --git a/fs/xfs/scrub/rcbag_btree.h b/fs/xfs/scrub/rcbag_btree.h new file mode 100644 index 0000000000000..dfe276cfd96c1 --- /dev/null +++ b/fs/xfs/scrub/rcbag_btree.h @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022-2024 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#ifndef __XFS_SCRUB_RCBAG_BTREE_H__ +#define __XFS_SCRUB_RCBAG_BTREE_H__ + +#ifdef CONFIG_XFS_BTREE_IN_XFILE + +struct xfs_buf; +struct xfs_btree_cur; +struct xfs_mount; + +#define RCBAG_MAGIC 0x74826671 /* 'JRBG' */ + +struct rcbag_key { + uint32_t rbg_startblock; + uint32_t rbg_blockcount; +}; + +struct rcbag_rec { + uint32_t rbg_startblock; + uint32_t rbg_blockcount; + uint64_t rbg_refcount; +}; + +typedef __be64 rcbag_ptr_t; + +/* reflinks only exist on crc enabled filesystems */ +#define RCBAG_BLOCK_LEN XFS_BTREE_LBLOCK_CRC_LEN + +/* + * Record, key, and pointer address macros for btree blocks. + * + * (note that some of these may appear unused, but they are used in userspace) + */ +#define RCBAG_REC_ADDR(block, index) \ + ((struct rcbag_rec *) \ + ((char *)(block) + RCBAG_BLOCK_LEN + \ + (((index) - 1) * sizeof(struct rcbag_rec)))) + +#define RCBAG_KEY_ADDR(block, index) \ + ((struct rcbag_key *) \ + ((char *)(block) + RCBAG_BLOCK_LEN + \ + ((index) - 1) * sizeof(struct rcbag_key))) + +#define RCBAG_PTR_ADDR(block, index, maxrecs) \ + ((rcbag_ptr_t *) \ + ((char *)(block) + RCBAG_BLOCK_LEN + \ + (maxrecs) * sizeof(struct rcbag_key) + \ + ((index) - 1) * sizeof(rcbag_ptr_t))) + +unsigned int rcbagbt_maxrecs(struct xfs_mount *mp, unsigned int blocklen, + bool leaf); + +unsigned long long rcbagbt_calc_size(unsigned long long nr_records); + +unsigned int rcbagbt_maxlevels_possible(void); + +int __init rcbagbt_init_cur_cache(void); +void rcbagbt_destroy_cur_cache(void); + +struct xfbtree; +struct xfs_btree_cur *rcbagbt_mem_cursor(struct xfs_mount *mp, + struct xfs_trans *tp, struct xfs_buf *head_bp, + struct xfbtree *xfbtree); +int rcbagbt_mem_create(struct xfs_mount *mp, struct xfs_buftarg *target, + struct xfbtree **xfbtreep); + +#else +# define rcbagbt_init_cur_cache() 0 +# define rcbagbt_destroy_cur_cache() ((void)0) +#endif /* CONFIG_XFS_BTREE_IN_XFILE */ + +#endif /* __XFS_SCRUB_RCBAG_BTREE_H__ */ diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h index 14bbefdd7ab81..e8f71179e1eab 100644 --- a/fs/xfs/scrub/trace.h +++ b/fs/xfs/scrub/trace.h @@ -42,6 +42,7 @@ TRACE_DEFINE_ENUM(XFS_BTNUM_INOi); TRACE_DEFINE_ENUM(XFS_BTNUM_FINOi); TRACE_DEFINE_ENUM(XFS_BTNUM_RMAPi); TRACE_DEFINE_ENUM(XFS_BTNUM_REFCi); +TRACE_DEFINE_ENUM(XFS_BTNUM_RCBAGi); TRACE_DEFINE_ENUM(XFS_REFC_DOMAIN_SHARED); TRACE_DEFINE_ENUM(XFS_REFC_DOMAIN_COW); diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index ba3eed23533f0..1690f518ae74b 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -2458,6 +2458,7 @@ TRACE_DEFINE_ENUM(XFS_BTNUM_INOi); TRACE_DEFINE_ENUM(XFS_BTNUM_FINOi); TRACE_DEFINE_ENUM(XFS_BTNUM_RMAPi); TRACE_DEFINE_ENUM(XFS_BTNUM_REFCi); +TRACE_DEFINE_ENUM(XFS_BTNUM_RCBAGi); DECLARE_EVENT_CLASS(xfs_btree_cur_class, TP_PROTO(struct xfs_btree_cur *cur, int level, struct xfs_buf *bp), From patchwork Sun Dec 31 20:20:04 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13507380 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DDAADBA2E for ; Sun, 31 Dec 2023 20:20:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="tPZnlHiZ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 630CAC433C8; Sun, 31 Dec 2023 20:20:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704054005; bh=h9Oyg5OxQV3OjVMKS6em1FdoRqkA/Z5namZPXuDPqK4=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=tPZnlHiZ8MR+cBELi9pY8ZI30ExOl2cPTyMnNVxyru+v8qYFzz65aVl2ls7IELOoo JDZc+LQ5EkmXLSh2MaB9Y2BeFFPbwiZcwykFWjbI5C8BoC2Ty9IWFiy78iRVEOGPnJ 8TJt9vG4IovZUQBCPgK8Taf07liUnJ94VWLf08WtcLor8dCeKDnpbQjb/jdvFDU8Zl xJMlsC/RQRrSOGK9hYBfUrBP8P43SlvUVJ5oKZtxWZemmvOrKJkf4m2MzDkIFhScy1 svlzqQqDB1va9WU/Mwo9/QXDwA+HFVzAYQPmtxrN+13cMHX6sFCGZC5IpuWA1ekA/4 a/QrBgEhUG1Eg== Date: Sun, 31 Dec 2023 12:20:04 -0800 Subject: [PATCH 3/4] xfs: create refcount bag structure for btree repairs From: "Darrick J. Wong" To: djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170404831054.1749557.2525900741908980674.stgit@frogsfrogsfrogs> In-Reply-To: <170404830995.1749557.6135790697605021363.stgit@frogsfrogsfrogs> References: <170404830995.1749557.6135790697605021363.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Create a bag structure for refcount information that uses the refcount bag btree defined in the previous patch. Signed-off-by: Darrick J. Wong --- fs/xfs/Makefile | 1 fs/xfs/scrub/rcbag.c | 331 ++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/rcbag.h | 28 ++++ fs/xfs/scrub/rcbag_btree.c | 58 ++++++++ fs/xfs/scrub/rcbag_btree.h | 7 + 5 files changed, 425 insertions(+) create mode 100644 fs/xfs/scrub/rcbag.c create mode 100644 fs/xfs/scrub/rcbag.h diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index f927a43cc16a5..a76e98e94b64a 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile @@ -199,6 +199,7 @@ xfs-y += $(addprefix scrub/, \ newbt.o \ nlinks_repair.o \ rcbag_btree.o \ + rcbag.o \ reap.o \ refcount_repair.o \ repair.o \ diff --git a/fs/xfs/scrub/rcbag.c b/fs/xfs/scrub/rcbag.c new file mode 100644 index 0000000000000..63f1b6e6488e1 --- /dev/null +++ b/fs/xfs/scrub/rcbag.c @@ -0,0 +1,331 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022-2024 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_log_format.h" +#include "xfs_trans.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_defer.h" +#include "xfs_btree.h" +#include "xfs_btree_mem.h" +#include "xfs_error.h" +#include "scrub/scrub.h" +#include "scrub/xfile.h" +#include "scrub/xfbtree.h" +#include "scrub/rcbag_btree.h" +#include "scrub/rcbag.h" +#include "scrub/trace.h" + +struct rcbag { + struct xfs_mount *mp; + struct xfbtree *xfbtree; + uint64_t nr_items; +}; + +int +rcbag_init( + struct xfs_mount *mp, + struct xfs_buftarg *target, + struct rcbag **bagp) +{ + struct rcbag *bag; + int error; + + bag = kmalloc(sizeof(struct rcbag), XCHK_GFP_FLAGS); + if (!bag) + return -ENOMEM; + + bag->nr_items = 0; + bag->mp = mp; + + error = rcbagbt_mem_create(mp, target, &bag->xfbtree); + if (error) + goto out_bag; + + *bagp = bag; + return 0; + +out_bag: + kfree(bag); + return error; +} + +void +rcbag_free( + struct rcbag **bagp) +{ + struct rcbag *bag = *bagp; + + xfbtree_destroy(bag->xfbtree); + kfree(bag); + *bagp = NULL; +} + +/* Track an rmap in the refcount bag. */ +int +rcbag_add( + struct rcbag *bag, + struct xfs_trans *tp, + const struct xfs_rmap_irec *rmap) +{ + struct rcbag_rec bagrec; + struct xfs_mount *mp = bag->mp; + struct xfs_buf *head_bp; + struct xfs_btree_cur *cur; + int has; + int error; + + error = xfbtree_head_read_buf(bag->xfbtree, tp, &head_bp); + if (error) + return error; + + cur = rcbagbt_mem_cursor(mp, tp, head_bp, bag->xfbtree); + error = rcbagbt_lookup_eq(cur, rmap, &has); + if (error) + goto out_cur; + + if (has) { + error = rcbagbt_get_rec(cur, &bagrec, &has); + if (error) + goto out_cur; + if (!has) { + error = -EFSCORRUPTED; + goto out_cur; + } + + bagrec.rbg_refcount++; + error = rcbagbt_update(cur, &bagrec); + if (error) + goto out_cur; + } else { + bagrec.rbg_startblock = rmap->rm_startblock; + bagrec.rbg_blockcount = rmap->rm_blockcount; + bagrec.rbg_refcount = 1; + + error = rcbagbt_insert(cur, &bagrec, &has); + if (error) + goto out_cur; + if (!has) { + error = -EFSCORRUPTED; + goto out_cur; + } + } + + xfs_btree_del_cursor(cur, 0); + xfs_trans_brelse(tp, head_bp); + + error = xfbtree_trans_commit(bag->xfbtree, tp); + if (error) + return error; + + bag->nr_items++; + return 0; + +out_cur: + xfs_btree_del_cursor(cur, error); + xfs_trans_brelse(tp, head_bp); + xfbtree_trans_cancel(bag->xfbtree, tp); + return error; +} + +uint64_t +rcbag_count( + const struct rcbag *rcbag) +{ + return rcbag->nr_items; +} + +#define BAGREC_NEXT(r) ((r)->rbg_startblock + (r)->rbg_blockcount) + +/* + * Find the next block where the refcount changes, given the next rmap we + * looked at and the ones we're already tracking. + */ +int +rcbag_next_edge( + struct rcbag *bag, + struct xfs_trans *tp, + const struct xfs_rmap_irec *next_rmap, + bool next_valid, + uint32_t *next_bnop) +{ + struct rcbag_rec bagrec; + struct xfs_mount *mp = bag->mp; + struct xfs_buf *head_bp; + struct xfs_btree_cur *cur; + uint32_t next_bno = NULLAGBLOCK; + int has; + int error; + + if (next_valid) + next_bno = next_rmap->rm_startblock; + + error = xfbtree_head_read_buf(bag->xfbtree, tp, &head_bp); + if (error) + return error; + + cur = rcbagbt_mem_cursor(mp, tp, head_bp, bag->xfbtree); + error = xfs_btree_goto_left_edge(cur); + if (error) + goto out_cur; + + while (true) { + error = xfs_btree_increment(cur, 0, &has); + if (error) + goto out_cur; + if (!has) + break; + + error = rcbagbt_get_rec(cur, &bagrec, &has); + if (error) + goto out_cur; + if (!has) { + error = -EFSCORRUPTED; + goto out_cur; + } + + next_bno = min(next_bno, BAGREC_NEXT(&bagrec)); + } + + /* + * We should have found /something/ because either next_rrm is the next + * interesting rmap to look at after emitting this refcount extent, or + * there are other rmaps in rmap_bag contributing to the current + * sharing count. But if something is seriously wrong, bail out. + */ + if (next_bno == NULLAGBLOCK) { + error = -EFSCORRUPTED; + goto out_cur; + } + + xfs_btree_del_cursor(cur, 0); + xfs_trans_brelse(tp, head_bp); + + *next_bnop = next_bno; + return 0; + +out_cur: + xfs_btree_del_cursor(cur, error); + xfs_trans_brelse(tp, head_bp); + return error; +} + +/* Pop all refcount bag records that end at next_bno */ +int +rcbag_remove_ending_at( + struct rcbag *bag, + struct xfs_trans *tp, + uint32_t next_bno) +{ + struct rcbag_rec bagrec; + struct xfs_mount *mp = bag->mp; + struct xfs_buf *head_bp; + struct xfs_btree_cur *cur; + int has; + int error; + + error = xfbtree_head_read_buf(bag->xfbtree, tp, &head_bp); + if (error) + return error; + + /* go to the right edge of the tree */ + cur = rcbagbt_mem_cursor(mp, tp, head_bp, bag->xfbtree); + memset(&cur->bc_rec, 0xFF, sizeof(cur->bc_rec)); + error = xfs_btree_lookup(cur, XFS_LOOKUP_GE, &has); + if (error) + goto out_cur; + + while (true) { + error = xfs_btree_decrement(cur, 0, &has); + if (error) + goto out_cur; + if (!has) + break; + + error = rcbagbt_get_rec(cur, &bagrec, &has); + if (error) + goto out_cur; + if (!has) { + error = -EFSCORRUPTED; + goto out_cur; + } + + if (BAGREC_NEXT(&bagrec) != next_bno) + continue; + + error = xfs_btree_delete(cur, &has); + if (error) + goto out_cur; + if (!has) { + error = -EFSCORRUPTED; + goto out_cur; + } + + bag->nr_items -= bagrec.rbg_refcount; + } + + xfs_btree_del_cursor(cur, 0); + xfs_trans_brelse(tp, head_bp); + return xfbtree_trans_commit(bag->xfbtree, tp); +out_cur: + xfs_btree_del_cursor(cur, error); + xfs_trans_brelse(tp, head_bp); + xfbtree_trans_cancel(bag->xfbtree, tp); + return error; +} + +/* Dump the rcbag. */ +void +rcbag_dump( + struct rcbag *bag, + struct xfs_trans *tp) +{ + struct rcbag_rec bagrec; + struct xfs_mount *mp = bag->mp; + struct xfs_buf *head_bp; + struct xfs_btree_cur *cur; + unsigned long long nr = 0; + int has; + int error; + + error = xfbtree_head_read_buf(bag->xfbtree, tp, &head_bp); + if (error) + return; + + cur = rcbagbt_mem_cursor(mp, tp, head_bp, bag->xfbtree); + error = xfs_btree_goto_left_edge(cur); + if (error) + goto out_cur; + + while (true) { + error = xfs_btree_increment(cur, 0, &has); + if (error) + goto out_cur; + if (!has) + break; + + error = rcbagbt_get_rec(cur, &bagrec, &has); + if (error) + goto out_cur; + if (!has) { + error = -EFSCORRUPTED; + goto out_cur; + } + + xfs_err(bag->mp, "[%llu]: bno 0x%x fsbcount 0x%x refcount 0x%llx\n", + nr++, + (unsigned int)bagrec.rbg_startblock, + (unsigned int)bagrec.rbg_blockcount, + (unsigned long long)bagrec.rbg_refcount); + } + +out_cur: + xfs_btree_del_cursor(cur, error); + xfs_trans_brelse(tp, head_bp); +} diff --git a/fs/xfs/scrub/rcbag.h b/fs/xfs/scrub/rcbag.h new file mode 100644 index 0000000000000..08b6b85c09d6b --- /dev/null +++ b/fs/xfs/scrub/rcbag.h @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022-2024 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#ifndef __XFS_SCRUB_RCBAG_H__ +#define __XFS_SCRUB_RCBAG_H__ + +struct xfs_mount; +struct rcbag; +struct xfs_buftarg; + +int rcbag_init(struct xfs_mount *mp, struct xfs_buftarg *target, + struct rcbag **bagp); +void rcbag_free(struct rcbag **bagp); +int rcbag_add(struct rcbag *bag, struct xfs_trans *tp, + const struct xfs_rmap_irec *rmap); +uint64_t rcbag_count(const struct rcbag *bag); + +int rcbag_next_edge(struct rcbag *bag, struct xfs_trans *tp, + const struct xfs_rmap_irec *next_rmap, bool next_valid, + uint32_t *next_bnop); +int rcbag_remove_ending_at(struct rcbag *bag, struct xfs_trans *tp, + uint32_t next_bno); + +void rcbag_dump(struct rcbag *bag, struct xfs_trans *tp); + +#endif /* __XFS_SCRUB_RCBAG_H__ */ diff --git a/fs/xfs/scrub/rcbag_btree.c b/fs/xfs/scrub/rcbag_btree.c index 4b0c849321b25..3d66e80b7bc25 100644 --- a/fs/xfs/scrub/rcbag_btree.c +++ b/fs/xfs/scrub/rcbag_btree.c @@ -312,3 +312,61 @@ rcbagbt_destroy_cur_cache(void) kmem_cache_destroy(rcbagbt_cur_cache); rcbagbt_cur_cache = NULL; } + +/* Look up the refcount bag record corresponding to this reverse mapping. */ +int +rcbagbt_lookup_eq( + struct xfs_btree_cur *cur, + const struct xfs_rmap_irec *rmap, + int *success) +{ + struct rcbag_rec *rec = (struct rcbag_rec *)&cur->bc_rec; + + rec->rbg_startblock = rmap->rm_startblock; + rec->rbg_blockcount = rmap->rm_blockcount; + + return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, success); +} + +/* Get the data from the pointed-to record. */ +int +rcbagbt_get_rec( + struct xfs_btree_cur *cur, + struct rcbag_rec *rec, + int *has) +{ + union xfs_btree_rec *btrec; + int error; + + error = xfs_btree_get_rec(cur, &btrec, has); + if (error || !(*has)) + return error; + + memcpy(rec, btrec, sizeof(struct rcbag_rec)); + return 0; +} + +/* Update the record referred to by cur to the value given. */ +int +rcbagbt_update( + struct xfs_btree_cur *cur, + const struct rcbag_rec *rec) +{ + union xfs_btree_rec btrec; + + memcpy(&btrec, rec, sizeof(struct rcbag_rec)); + return xfs_btree_update(cur, &btrec); +} + +/* Update the record referred to by cur to the value given. */ +int +rcbagbt_insert( + struct xfs_btree_cur *cur, + const struct rcbag_rec *rec, + int *success) +{ + struct rcbag_rec *btrec = (struct rcbag_rec *)&cur->bc_rec; + + memcpy(btrec, rec, sizeof(struct rcbag_rec)); + return xfs_btree_insert(cur, success); +} diff --git a/fs/xfs/scrub/rcbag_btree.h b/fs/xfs/scrub/rcbag_btree.h index dfe276cfd96c1..6486b6ae53409 100644 --- a/fs/xfs/scrub/rcbag_btree.h +++ b/fs/xfs/scrub/rcbag_btree.h @@ -68,6 +68,13 @@ struct xfs_btree_cur *rcbagbt_mem_cursor(struct xfs_mount *mp, int rcbagbt_mem_create(struct xfs_mount *mp, struct xfs_buftarg *target, struct xfbtree **xfbtreep); +int rcbagbt_lookup_eq(struct xfs_btree_cur *cur, + const struct xfs_rmap_irec *rmap, int *success); +int rcbagbt_get_rec(struct xfs_btree_cur *cur, struct rcbag_rec *rec, int *has); +int rcbagbt_update(struct xfs_btree_cur *cur, const struct rcbag_rec *rec); +int rcbagbt_insert(struct xfs_btree_cur *cur, const struct rcbag_rec *rec, + int *success); + #else # define rcbagbt_init_cur_cache() 0 # define rcbagbt_destroy_cur_cache() ((void)0) From patchwork Sun Dec 31 20:20:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13507381 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 65859BA2B for ; Sun, 31 Dec 2023 20:20:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="to4XwTX5" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EDE06C433C7; Sun, 31 Dec 2023 20:20:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704054021; bh=JJqb0Q7ljrNrBA0BkC4GXSRx0N9JIBuozCEwjJgMC6E=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=to4XwTX5w4wDT0Yr9BnndSBE0hwSgPSLVRw5z0zRkkFLMrw7s9ro0748Xi9UQ3/Ge 1HsS3bKL1qoAjCzFNKXuVrI9D4AOaZIK8E0UfZw71gRjkGWOESdiHjrGv4/s/wWaHU YEpob74G9qJLcDaCeOC3z9RVlzgcWLX39BA8+L9mQcrPvh7Kwv3AP374AVWAK68kO9 GirSrswTSDwPrxEcLN10Jv/4fXpiX4gSlHD9lD7ggcK6m9N6k4D4DMU9FiuclcQR2e 4sAgrXligFykmLMaCWzJFNkHsz17ackEQy1Xn6iJs4opjj0rLBa/z0EgsvLK6UmIUX +p5DNnV3Z+DvQ== Date: Sun, 31 Dec 2023 12:20:20 -0800 Subject: [PATCH 4/4] xfs: port refcount repair to the new refcount bag structure From: "Darrick J. Wong" To: djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170404831070.1749557.18013766870623858132.stgit@frogsfrogsfrogs> In-Reply-To: <170404830995.1749557.6135790697605021363.stgit@frogsfrogsfrogs> References: <170404830995.1749557.6135790697605021363.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Port the refcount record generating code to use the new refcount bag data structure. Signed-off-by: Darrick J. Wong --- fs/xfs/scrub/refcount.c | 12 +++ fs/xfs/scrub/refcount_repair.c | 164 ++++++++++++++-------------------------- fs/xfs/scrub/repair.h | 2 fs/xfs/xfs_super.c | 10 ++ 4 files changed, 81 insertions(+), 107 deletions(-) diff --git a/fs/xfs/scrub/refcount.c b/fs/xfs/scrub/refcount.c index bf22f245bbfa8..d0c7d4a29c0fe 100644 --- a/fs/xfs/scrub/refcount.c +++ b/fs/xfs/scrub/refcount.c @@ -7,8 +7,10 @@ #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" +#include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" +#include "xfs_trans.h" #include "xfs_ag.h" #include "xfs_btree.h" #include "xfs_rmap.h" @@ -17,6 +19,7 @@ #include "scrub/common.h" #include "scrub/btree.h" #include "scrub/trace.h" +#include "scrub/repair.h" /* * Set us up to scrub reference count btrees. @@ -27,6 +30,15 @@ xchk_setup_ag_refcountbt( { if (xchk_need_intent_drain(sc)) xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN); + + if (xchk_could_repair(sc)) { + int error; + + error = xrep_setup_ag_refcountbt(sc); + if (error) + return error; + } + return xchk_setup_ag_btree(sc, false); } diff --git a/fs/xfs/scrub/refcount_repair.c b/fs/xfs/scrub/refcount_repair.c index 9c39af03ee1d8..b485c5cc9f290 100644 --- a/fs/xfs/scrub/refcount_repair.c +++ b/fs/xfs/scrub/refcount_repair.c @@ -38,6 +38,7 @@ #include "scrub/xfarray.h" #include "scrub/newbt.h" #include "scrub/reap.h" +#include "scrub/rcbag.h" /* * Rebuilding the Reference Count Btree @@ -98,12 +99,6 @@ * insert all the records. */ -/* The only parts of the rmap that we care about for computing refcounts. */ -struct xrep_refc_rmap { - xfs_agblock_t startblock; - xfs_extlen_t blockcount; -} __packed; - struct xrep_refc { /* refcount extents */ struct xfarray *refcount_records; @@ -123,6 +118,20 @@ struct xrep_refc { xfs_extlen_t btblocks; }; +/* Set us up to repair refcount btrees. */ +int +xrep_setup_ag_refcountbt( + struct xfs_scrub *sc) +{ + char *descr; + int error; + + descr = xchk_xfile_ag_descr(sc, "rmap record bag"); + error = xrep_setup_buftarg(sc, descr); + kfree(descr); + return error; +} + /* Check for any obvious conflicts with this shared/CoW staging extent. */ STATIC int xrep_refc_check_ext( @@ -224,10 +233,9 @@ xrep_refc_rmap_shareable( STATIC int xrep_refc_walk_rmaps( struct xrep_refc *rr, - struct xrep_refc_rmap *rrm, + struct xfs_rmap_irec *rmap, bool *have_rec) { - struct xfs_rmap_irec rmap; struct xfs_btree_cur *cur = rr->sc->sa.rmap_cur; struct xfs_mount *mp = cur->bc_mp; int have_gt; @@ -251,7 +259,7 @@ xrep_refc_walk_rmaps( if (!have_gt) return 0; - error = xfs_rmap_get_rec(cur, &rmap, &have_gt); + error = xfs_rmap_get_rec(cur, rmap, &have_gt); if (error) return error; if (XFS_IS_CORRUPT(mp, !have_gt)) { @@ -259,23 +267,22 @@ xrep_refc_walk_rmaps( return -EFSCORRUPTED; } - if (rmap.rm_owner == XFS_RMAP_OWN_COW) { - error = xrep_refc_stash_cow(rr, rmap.rm_startblock, - rmap.rm_blockcount); + if (rmap->rm_owner == XFS_RMAP_OWN_COW) { + error = xrep_refc_stash_cow(rr, rmap->rm_startblock, + rmap->rm_blockcount); if (error) return error; - } else if (rmap.rm_owner == XFS_RMAP_OWN_REFC) { + } else if (rmap->rm_owner == XFS_RMAP_OWN_REFC) { /* refcountbt block, dump it when we're done. */ - rr->btblocks += rmap.rm_blockcount; + rr->btblocks += rmap->rm_blockcount; error = xagb_bitmap_set(&rr->old_refcountbt_blocks, - rmap.rm_startblock, rmap.rm_blockcount); + rmap->rm_startblock, + rmap->rm_blockcount); if (error) return error; } - } while (!xrep_refc_rmap_shareable(mp, &rmap)); + } while (!xrep_refc_rmap_shareable(mp, rmap)); - rrm->startblock = rmap.rm_startblock; - rrm->blockcount = rmap.rm_blockcount; *have_rec = true; return 0; } @@ -357,45 +364,6 @@ xrep_refc_sort_records( return error; } -#define RRM_NEXT(r) ((r).startblock + (r).blockcount) -/* - * Find the next block where the refcount changes, given the next rmap we - * looked at and the ones we're already tracking. - */ -static inline int -xrep_refc_next_edge( - struct xfarray *rmap_bag, - struct xrep_refc_rmap *next_rrm, - bool next_valid, - xfs_agblock_t *nbnop) -{ - struct xrep_refc_rmap rrm; - xfarray_idx_t array_cur = XFARRAY_CURSOR_INIT; - xfs_agblock_t nbno = NULLAGBLOCK; - int error; - - if (next_valid) - nbno = next_rrm->startblock; - - while ((error = xfarray_iter(rmap_bag, &array_cur, &rrm)) == 1) - nbno = min_t(xfs_agblock_t, nbno, RRM_NEXT(rrm)); - - if (error) - return error; - - /* - * We should have found /something/ because either next_rrm is the next - * interesting rmap to look at after emitting this refcount extent, or - * there are other rmaps in rmap_bag contributing to the current - * sharing count. But if something is seriously wrong, bail out. - */ - if (nbno == NULLAGBLOCK) - return -EFSCORRUPTED; - - *nbnop = nbno; - return 0; -} - /* * Walk forward through the rmap btree to collect all rmaps starting at * @bno in @rmap_bag. These represent the file(s) that share ownership of @@ -405,22 +373,21 @@ xrep_refc_next_edge( static int xrep_refc_push_rmaps_at( struct xrep_refc *rr, - struct xfarray *rmap_bag, + struct rcbag *rcstack, xfs_agblock_t bno, - struct xrep_refc_rmap *rrm, - bool *have, - uint64_t *stack_sz) + struct xfs_rmap_irec *rmap, + bool *have) { struct xfs_scrub *sc = rr->sc; int have_gt; int error; - while (*have && rrm->startblock == bno) { - error = xfarray_store_anywhere(rmap_bag, rrm); + while (*have && rmap->rm_startblock == bno) { + error = rcbag_add(rcstack, rr->sc->tp, rmap); if (error) return error; - (*stack_sz)++; - error = xrep_refc_walk_rmaps(rr, rrm, have); + + error = xrep_refc_walk_rmaps(rr, rmap, have); if (error) return error; } @@ -441,12 +408,9 @@ STATIC int xrep_refc_find_refcounts( struct xrep_refc *rr) { - struct xrep_refc_rmap rrm; struct xfs_scrub *sc = rr->sc; - struct xfarray *rmap_bag; - char *descr; - uint64_t old_stack_sz; - uint64_t stack_sz = 0; + struct rcbag *rcstack; + uint64_t old_stack_height; xfs_agblock_t sbno; xfs_agblock_t cbno; xfs_agblock_t nbno; @@ -456,14 +420,11 @@ xrep_refc_find_refcounts( xrep_ag_btcur_init(sc, &sc->sa); /* - * Set up a sparse array to store all the rmap records that we're - * tracking to generate a reference count record. If this exceeds + * Set up a bag to store all the rmap records that we're tracking to + * generate a reference count record. If the size of the bag exceeds * MAXREFCOUNT, we clamp rc_refcount. */ - descr = xchk_xfile_ag_descr(sc, "rmap record bag"); - error = xfarray_create(descr, 0, sizeof(struct xrep_refc_rmap), - &rmap_bag); - kfree(descr); + error = rcbag_init(sc->mp, sc->xfile_buftarg, &rcstack); if (error) goto out_cur; @@ -474,62 +435,54 @@ xrep_refc_find_refcounts( /* Process reverse mappings into refcount data. */ while (xfs_btree_has_more_records(sc->sa.rmap_cur)) { + struct xfs_rmap_irec rmap; + /* Push all rmaps with pblk == sbno onto the stack */ - error = xrep_refc_walk_rmaps(rr, &rrm, &have); + error = xrep_refc_walk_rmaps(rr, &rmap, &have); if (error) goto out_bag; if (!have) break; - sbno = cbno = rrm.startblock; - error = xrep_refc_push_rmaps_at(rr, rmap_bag, sbno, - &rrm, &have, &stack_sz); + sbno = cbno = rmap.rm_startblock; + error = xrep_refc_push_rmaps_at(rr, rcstack, sbno, &rmap, + &have); if (error) goto out_bag; /* Set nbno to the bno of the next refcount change */ - error = xrep_refc_next_edge(rmap_bag, &rrm, have, &nbno); + error = rcbag_next_edge(rcstack, sc->tp, &rmap, have, &nbno); if (error) goto out_bag; ASSERT(nbno > sbno); - old_stack_sz = stack_sz; + old_stack_height = rcbag_count(rcstack); /* While stack isn't empty... */ - while (stack_sz) { - xfarray_idx_t array_cur = XFARRAY_CURSOR_INIT; - + while (rcbag_count(rcstack) > 0) { /* Pop all rmaps that end at nbno */ - while ((error = xfarray_iter(rmap_bag, &array_cur, - &rrm)) == 1) { - if (RRM_NEXT(rrm) != nbno) - continue; - error = xfarray_unset(rmap_bag, array_cur - 1); - if (error) - goto out_bag; - stack_sz--; - } + error = rcbag_remove_ending_at(rcstack, sc->tp, nbno); if (error) goto out_bag; /* Push array items that start at nbno */ - error = xrep_refc_walk_rmaps(rr, &rrm, &have); + error = xrep_refc_walk_rmaps(rr, &rmap, &have); if (error) goto out_bag; if (have) { - error = xrep_refc_push_rmaps_at(rr, rmap_bag, - nbno, &rrm, &have, &stack_sz); + error = xrep_refc_push_rmaps_at(rr, rcstack, + nbno, &rmap, &have); if (error) goto out_bag; } /* Emit refcount if necessary */ ASSERT(nbno > cbno); - if (stack_sz != old_stack_sz) { - if (old_stack_sz > 1) { + if (rcbag_count(rcstack) != old_stack_height) { + if (old_stack_height > 1) { error = xrep_refc_stash(rr, XFS_REFC_DOMAIN_SHARED, cbno, nbno - cbno, - old_stack_sz); + old_stack_height); if (error) goto out_bag; } @@ -537,13 +490,13 @@ xrep_refc_find_refcounts( } /* Stack empty, go find the next rmap */ - if (stack_sz == 0) + if (rcbag_count(rcstack) == 0) break; - old_stack_sz = stack_sz; + old_stack_height = rcbag_count(rcstack); sbno = nbno; /* Set nbno to the bno of the next refcount change */ - error = xrep_refc_next_edge(rmap_bag, &rrm, have, + error = rcbag_next_edge(rcstack, sc->tp, &rmap, have, &nbno); if (error) goto out_bag; @@ -552,14 +505,13 @@ xrep_refc_find_refcounts( } } - ASSERT(stack_sz == 0); + ASSERT(rcbag_count(rcstack) == 0); out_bag: - xfarray_destroy(rmap_bag); + rcbag_free(&rcstack); out_cur: xchk_ag_btcur_free(&sc->sa); return error; } -#undef RRM_NEXT /* Retrieve refcountbt data for bulk load. */ STATIC int diff --git a/fs/xfs/scrub/repair.h b/fs/xfs/scrub/repair.h index 0243481f770fe..38aa5c9649d71 100644 --- a/fs/xfs/scrub/repair.h +++ b/fs/xfs/scrub/repair.h @@ -89,6 +89,7 @@ int xrep_reset_perag_resv(struct xfs_scrub *sc); int xrep_bmap(struct xfs_scrub *sc, int whichfork, bool allow_unwritten); int xrep_metadata_inode_forks(struct xfs_scrub *sc); int xrep_setup_ag_rmapbt(struct xfs_scrub *sc); +int xrep_setup_ag_refcountbt(struct xfs_scrub *sc); /* Repair setup functions */ int xrep_setup_ag_allocbt(struct xfs_scrub *sc); @@ -186,6 +187,7 @@ xrep_setup_nothing( } #define xrep_setup_ag_allocbt xrep_setup_nothing #define xrep_setup_ag_rmapbt xrep_setup_nothing +#define xrep_setup_ag_refcountbt xrep_setup_nothing #define xrep_setup_inode(sc, imap) ((void)0) diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 8619f517b1bf3..d535445129752 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -44,6 +44,7 @@ #include "xfs_dahash_test.h" #include "xfs_rtbitmap.h" #include "scrub/stats.h" +#include "scrub/rcbag_btree.h" #include #include @@ -2069,10 +2070,14 @@ xfs_init_caches(void) if (error) goto out_destroy_log_ticket_cache; - error = xfs_defer_init_item_caches(); + error = rcbagbt_init_cur_cache(); if (error) goto out_destroy_btree_cur_cache; + error = xfs_defer_init_item_caches(); + if (error) + goto out_destroy_rcbagbt_cur_cache; + xfs_da_state_cache = kmem_cache_create("xfs_da_state", sizeof(struct xfs_da_state), 0, 0, NULL); @@ -2229,6 +2234,8 @@ xfs_init_caches(void) kmem_cache_destroy(xfs_da_state_cache); out_destroy_defer_item_cache: xfs_defer_destroy_item_caches(); + out_destroy_rcbagbt_cur_cache: + rcbagbt_destroy_cur_cache(); out_destroy_btree_cur_cache: xfs_btree_destroy_cur_caches(); out_destroy_log_ticket_cache: @@ -2266,6 +2273,7 @@ xfs_destroy_caches(void) kmem_cache_destroy(xfs_ifork_cache); kmem_cache_destroy(xfs_da_state_cache); xfs_defer_destroy_item_caches(); + rcbagbt_destroy_cur_cache(); xfs_btree_destroy_cur_caches(); kmem_cache_destroy(xfs_log_ticket_cache); kmem_cache_destroy(xfs_buf_cache);