From patchwork Wed May 22 03:21:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13670344 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 76C672C9D for ; Wed, 22 May 2024 03:21:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716348083; cv=none; b=Gbr5qVNKVQgBsc8xLveMJt8+/WTDdWW9bhMKLK26UYujpsCAqdJs8f0xx0nlBxp7CF5wlDtDQJJyWU5KBjDxM84QNrUtw///ahfVJdTAgDtWGY8FjvJ/sF1cLQ9Ln3hZcOKgdqKIIOcx1FgJUdKI1tk3GAO6lEeqNt3YBFkxP/Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716348083; c=relaxed/simple; bh=Ndj7NBRzsbssyfwEqS+KjV5iCt7PHuzMq0I9Zxfi338=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=KA2oIm51EMpiSZEcyddHUD4AN+3kksHc2g9M1nkBrrOXJddgYTkOcu1jRBW6VXYDPY6DcBgnoQjX0BOXAH8WSOlyx53Dnp7en0ujXYftOLmoYfUFPPZU5CJbwP1KxtAM8M8gI4MIZOanlQYLDLt6vEmU91r+P4NUoZafxdSSRgI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=f88ssMPN; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="f88ssMPN" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4E456C2BD11; Wed, 22 May 2024 03:21:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1716348083; bh=Ndj7NBRzsbssyfwEqS+KjV5iCt7PHuzMq0I9Zxfi338=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=f88ssMPNV0wPVrYzZN8mds+RrpRgjvMhYdR9IxvvmKWtuO1gYld7H9No1+M7jsCcq Z4kM7sGklFAu0p6rvF+ueHZoJovl04SJgSHoN3oXRPEVFhrrVUo44ap+t+rCt3h6RK V+gYTGhG5h3j5Pt8EPkuUj3Uj1KzU8MsheTHwKYH5/r7ZaQpueBdbQffjuqW5aZ9/X a4TYWkCrUvu/9Py+hnA9gsR97tVvgrvY73E/NwaoeVjqN9tBKoG5TZGat0O0J/HrhK +ipynOatT3CMWYTSXuhbV+rz3mxdBsR8jJ5AlIMmrbsiPuSunKtA19D5QrPGEq6bjj ITadwyeoUu7HQ== Date: Tue, 21 May 2024 20:21:22 -0700 Subject: [PATCH 1/6] libxfs: provide a kernel-compatible kasprintf From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Christoph Hellwig , linux-xfs@vger.kernel.org Message-ID: <171634535404.2483278.11403421783079513759.stgit@frogsfrogsfrogs> In-Reply-To: <171634535383.2483278.14868148193055852399.stgit@frogsfrogsfrogs> References: <171634535383.2483278.14868148193055852399.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: Christoph Hellwig The kernel-like kasprintf will be used by the new metadir code, as well as the rmap data structures in xfs_repair. Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong [djwong: tweak commit message] Signed-off-by: Darrick J. Wong --- include/kmem.h | 3 +++ libxfs/kmem.c | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/include/kmem.h b/include/kmem.h index 386b4a6be..8dfb2fb0b 100644 --- a/include/kmem.h +++ b/include/kmem.h @@ -65,4 +65,7 @@ static inline void kfree(const void *ptr) free((void *)ptr); } +__attribute__((format(printf,2,3))) +char *kasprintf(gfp_t gfp, const char *fmt, ...); + #endif diff --git a/libxfs/kmem.c b/libxfs/kmem.c index a2a3935d0..2e2935180 100644 --- a/libxfs/kmem.c +++ b/libxfs/kmem.c @@ -104,3 +104,16 @@ krealloc(void *ptr, size_t new_size, int flags) } return ptr; } + +char *kasprintf(gfp_t gfp, const char *fmt, ...) +{ + va_list ap; + char *p; + + va_start(ap, fmt); + if (vasprintf(&p, fmt, ap) < 0) + p = NULL; + va_end(ap); + + return p; +} From patchwork Wed May 22 03:21:38 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13670345 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 57AA61E498 for ; Wed, 22 May 2024 03:21:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716348099; cv=none; b=Oxp9hVhOgIsRxEfpeaFW2UARgMfw0PSsAtwNTU2xfNDiK5ZRgcxAMT0TZF1k7hDhzUIMSl+ls6/XW49i/y3vaAZzAjIUDWxhc2V553L9zhTZR5LTr25egJ4vzIdY0La3hXgV8vYG4C4l/gsHaUEYd66xRDQyWzhvB0ycsYKcCKQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716348099; c=relaxed/simple; bh=5rMSK7EcoDS5E7GfHCWBpgHw4XN0rcERWhlb6OarVsk=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=CgOueUD0VWYjJ4YgI1wTEXYZTdDEBGuypHt1FEqxy4gvRd900H961gX3G89bB08KoA54snCBDwhC0iY43EO48IEUtmPcQEKYqWqcsyqToNMoIIVnwZ2xkQLd4CBdeNgVErXOSpcTVv39SYvE5mFPWcxArtL9tqfuB1Rcq9jSOCQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=NLmHD/WD; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="NLmHD/WD" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0EE78C2BD11; Wed, 22 May 2024 03:21:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1716348099; bh=5rMSK7EcoDS5E7GfHCWBpgHw4XN0rcERWhlb6OarVsk=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=NLmHD/WDGh5GP4Dm028p/qSbX4qBiD0YkMZkd7wROhHIlkAZ057rvxMCEZOXKcVh8 xRzmU60RWRvxfiK9hmpL1+SmAWcGtGN+8L+Xk5iTmAU813OQw3xJf0gofn7Tu+Nlta A9CsvR3odDfVYVjyOPdzVM+2JnyT77a3gK1frPBxdY2L1w8m1/7k6secPQUy4w3Y/U BoS217i9wTFsD+VgW6ZW874zu+O/+72fuiLAklIUJDyi8/47tgAdR1UvnkJRllGHyk XACFyYHNd4gSWR/wxyOgrSL8f/wfuFha1gThNtAf+MkycCkhfluJXm/QkE9peGhWdB DUlv2YPOgselQ== Date: Tue, 21 May 2024 20:21:38 -0700 Subject: [PATCH 2/6] xfs_repair: convert regular rmap repair to use in-memory btrees From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Christoph Hellwig , linux-xfs@vger.kernel.org Message-ID: <171634535418.2483278.15599705413208919242.stgit@frogsfrogsfrogs> In-Reply-To: <171634535383.2483278.14868148193055852399.stgit@frogsfrogsfrogs> References: <171634535383.2483278.14868148193055852399.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 Convert the rmap btree repair code to use in-memory rmap btrees to store the observed reverse mapping records. This will eliminate the need for a separate record sorting step, as well as eliminate the need for all the code that turns multiple consecutive bmap records into a single rmap record. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- include/libxfs.h | 3 + libxfs/buf_mem.h | 5 + libxfs/libxfs_api_defs.h | 9 ++ repair/agbtree.c | 18 ++- repair/agbtree.h | 1 repair/phase5.c | 2 repair/rmap.c | 259 ++++++++++++++++++++++++++++++++++++++++++---- repair/rmap.h | 9 +- repair/xfs_repair.c | 6 + 9 files changed, 283 insertions(+), 29 deletions(-) diff --git a/include/libxfs.h b/include/libxfs.h index 79df8bc7c..fb8efb696 100644 --- a/include/libxfs.h +++ b/include/libxfs.h @@ -87,6 +87,9 @@ struct iomap; #include "xfs_btree_staging.h" #include "xfs_rtbitmap.h" #include "xfs_symlink_remote.h" +#include "libxfs/xfile.h" +#include "libxfs/buf_mem.h" +#include "xfs_btree_mem.h" #ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) diff --git a/libxfs/buf_mem.h b/libxfs/buf_mem.h index 3829dd00d..f19bc6fd7 100644 --- a/libxfs/buf_mem.h +++ b/libxfs/buf_mem.h @@ -27,4 +27,9 @@ bool xmbuf_verify_daddr(struct xfs_buftarg *btp, xfs_daddr_t daddr); void xmbuf_trans_bdetach(struct xfs_trans *tp, struct xfs_buf *bp); int xmbuf_finalize(struct xfs_buf *bp); +static inline unsigned long long xmbuf_bytes(struct xfs_buftarg *btp) +{ + return xfile_bytes(btp->bt_xfile); +} + #endif /* __XFS_BUF_MEM_H__ */ diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index de37d3050..74bf15172 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -64,10 +64,15 @@ #define xfs_btree_bload libxfs_btree_bload #define xfs_btree_bload_compute_geometry libxfs_btree_bload_compute_geometry #define xfs_btree_del_cursor libxfs_btree_del_cursor +#define xfs_btree_get_block libxfs_btree_get_block +#define xfs_btree_goto_left_edge libxfs_btree_goto_left_edge +#define xfs_btree_increment libxfs_btree_increment #define xfs_btree_init_block libxfs_btree_init_block +#define xfs_btree_mem_head_read_buf libxfs_btree_mem_head_read_buf #define xfs_btree_rec_addr libxfs_btree_rec_addr #define xfs_btree_stage_afakeroot libxfs_btree_stage_afakeroot #define xfs_btree_stage_ifakeroot libxfs_btree_stage_ifakeroot +#define xfs_btree_visit_blocks libxfs_btree_visit_blocks #define xfs_buf_delwri_submit libxfs_buf_delwri_submit #define xfs_buf_get libxfs_buf_get #define xfs_buf_get_uncached libxfs_buf_get_uncached @@ -191,6 +196,8 @@ #define xfs_rmapbt_init_cursor libxfs_rmapbt_init_cursor #define xfs_rmapbt_maxlevels_ondisk libxfs_rmapbt_maxlevels_ondisk #define xfs_rmapbt_maxrecs libxfs_rmapbt_maxrecs +#define xfs_rmapbt_mem_init libxfs_rmapbt_mem_init +#define xfs_rmapbt_mem_cursor libxfs_rmapbt_mem_cursor #define xfs_rmapbt_stage_cursor libxfs_rmapbt_stage_cursor #define xfs_rmap_compare libxfs_rmap_compare #define xfs_rmap_get_rec libxfs_rmap_get_rec @@ -199,6 +206,7 @@ #define xfs_rmap_irec_offset_unpack libxfs_rmap_irec_offset_unpack #define xfs_rmap_lookup_le libxfs_rmap_lookup_le #define xfs_rmap_lookup_le_range libxfs_rmap_lookup_le_range +#define xfs_rmap_map_raw libxfs_rmap_map_raw #define xfs_rmap_query_all libxfs_rmap_query_all #define xfs_rmap_query_range libxfs_rmap_query_range @@ -256,6 +264,7 @@ #define xfs_validate_stripe_geometry libxfs_validate_stripe_geometry #define xfs_verify_agbno libxfs_verify_agbno +#define xfs_verify_agbext libxfs_verify_agbext #define xfs_verify_agino libxfs_verify_agino #define xfs_verify_cksum libxfs_verify_cksum #define xfs_verify_dir_ino libxfs_verify_dir_ino diff --git a/repair/agbtree.c b/repair/agbtree.c index 1a3e40cca..c8f75f49e 100644 --- a/repair/agbtree.c +++ b/repair/agbtree.c @@ -104,7 +104,8 @@ reserve_agblocks( do_error(_("could not set up btree reservation: %s\n"), strerror(-error)); - error = rmap_add_ag_rec(mp, agno, ext_ptr->ex_startblock, len, + error = rmap_add_agbtree_mapping(mp, agno, + ext_ptr->ex_startblock, len, btr->newbt.oinfo.oi_owner); if (error) do_error(_("could not set up btree rmaps: %s\n"), @@ -602,14 +603,19 @@ get_rmapbt_records( unsigned int nr_wanted, void *priv) { - struct xfs_rmap_irec *rec; struct bt_rebuild *btr = priv; union xfs_btree_rec *block_rec; unsigned int loaded; + int ret; for (loaded = 0; loaded < nr_wanted; loaded++, idx++) { - rec = pop_slab_cursor(btr->slab_cursor); - memcpy(&cur->bc_rec.r, rec, sizeof(struct xfs_rmap_irec)); + ret = rmap_get_mem_rec(btr->rmapbt_cursor, &cur->bc_rec.r); + if (ret < 0) + return ret; + if (ret == 0) + do_error( + _("ran out of records while rebuilding AG %u rmap btree\n"), + cur->bc_ag.pag->pag_agno); block_rec = libxfs_btree_rec_addr(cur, idx, block); cur->bc_ops->init_rec_from_cur(cur, block_rec); @@ -658,7 +664,7 @@ build_rmap_tree( { int error; - error = rmap_init_cursor(agno, &btr->slab_cursor); + error = rmap_init_mem_cursor(sc->mp, NULL, agno, &btr->rmapbt_cursor); if (error) do_error( _("Insufficient memory to construct rmap cursor.\n")); @@ -671,7 +677,7 @@ _("Error %d while creating rmap btree for AG %u.\n"), error, agno); /* Since we're not writing the AGF yet, no need to commit the cursor */ libxfs_btree_del_cursor(btr->cur, 0); - free_slab_cursor(&btr->slab_cursor); + libxfs_btree_del_cursor(btr->rmapbt_cursor, 0); } /* rebuild the refcount tree */ diff --git a/repair/agbtree.h b/repair/agbtree.h index 714d8e687..6d2c401a6 100644 --- a/repair/agbtree.h +++ b/repair/agbtree.h @@ -20,6 +20,7 @@ struct bt_rebuild { /* Tree-specific data. */ union { struct xfs_slab_cursor *slab_cursor; + struct xfs_btree_cur *rmapbt_cursor; struct { struct extent_tree_node *bno_rec; unsigned int freeblks; diff --git a/repair/phase5.c b/repair/phase5.c index b689a4234..52666ad88 100644 --- a/repair/phase5.c +++ b/repair/phase5.c @@ -712,7 +712,7 @@ phase5(xfs_mount_t *mp) * the superblock counters. */ for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { - error = rmap_store_ag_btree_rec(mp, agno); + error = rmap_commit_agbtree_mappings(mp, agno); if (error) do_error( _("unable to add AG %u reverse-mapping data to btree.\n"), agno); diff --git a/repair/rmap.c b/repair/rmap.c index 032bf4942..c1ae7da1e 100644 --- a/repair/rmap.c +++ b/repair/rmap.c @@ -13,6 +13,7 @@ #include "slab.h" #include "rmap.h" #include "libfrog/bitmap.h" +#include "libfrog/platform.h" #undef RMAP_DEBUG @@ -24,12 +25,25 @@ /* per-AG rmap object anchor */ struct xfs_ag_rmap { - struct xfs_slab *ar_rmaps; /* rmap observations, p4 */ - struct xfs_slab *ar_raw_rmaps; /* unmerged rmaps */ - int ar_flcount; /* agfl entries from leftover */ - /* agbt allocations */ - struct xfs_rmap_irec ar_last_rmap; /* last rmap seen */ - struct xfs_slab *ar_refcount_items; /* refcount items, p4-5 */ + /* root of rmap observations btree */ + struct xfbtree ar_xfbtree; + /* rmap buffer target for btree */ + struct xfs_buftarg *ar_xmbtp; + + /* rmap observations, p4 */ + struct xfs_slab *ar_rmaps; + + /* unmerged rmaps */ + struct xfs_slab *ar_raw_rmaps; + + /* agfl entries from leftover agbt allocations */ + int ar_flcount; + + /* last rmap seen */ + struct xfs_rmap_irec ar_last_rmap; + + /* refcount items, p4-5 */ + struct xfs_slab *ar_refcount_items; }; static struct xfs_ag_rmap *ag_rmaps; @@ -53,6 +67,61 @@ rmap_needs_work( xfs_has_rmapbt(mp); } +static inline bool rmaps_has_observations(const struct xfs_ag_rmap *ag_rmap) +{ + return ag_rmap->ar_xfbtree.target; +} + +/* Destroy an in-memory rmap btree. */ +STATIC void +rmaps_destroy( + struct xfs_mount *mp, + struct xfs_ag_rmap *ag_rmap) +{ + free_slab(&ag_rmap->ar_refcount_items); + + if (!rmaps_has_observations(ag_rmap)) + return; + + xfbtree_destroy(&ag_rmap->ar_xfbtree); + xmbuf_free(ag_rmap->ar_xmbtp); +} + +/* Initialize the in-memory rmap btree for collecting per-AG rmap records. */ +STATIC void +rmaps_init_ag( + struct xfs_mount *mp, + xfs_agnumber_t agno, + struct xfs_ag_rmap *ag_rmap) +{ + char *descr; + unsigned long long maxbytes; + int error; + + maxbytes = XFS_FSB_TO_B(mp, mp->m_sb.sb_agblocks); + descr = kasprintf(GFP_KERNEL, "xfs_repair (%s): AG %u rmap records", + mp->m_fsname, agno); + error = -xmbuf_alloc(mp, descr, maxbytes, &ag_rmap->ar_xmbtp); + kfree(descr); + if (error) + goto nomem; + + error = -libxfs_rmapbt_mem_init(mp, &ag_rmap->ar_xfbtree, + ag_rmap->ar_xmbtp, agno); + if (error) + goto nomem; + + error = init_slab(&ag_rmap->ar_refcount_items, + sizeof(struct xfs_refcount_irec)); + if (error) + goto nomem; + + return; +nomem: + do_error( +_("Insufficient memory while allocating realtime reverse mapping btree.")); +} + /* * Initialize per-AG reverse map data. */ @@ -71,6 +140,8 @@ rmaps_init( do_error(_("couldn't allocate per-AG reverse map roots\n")); for (i = 0; i < mp->m_sb.sb_agcount; i++) { + rmaps_init_ag(mp, i, &ag_rmaps[i]); + error = init_slab(&ag_rmaps[i].ar_rmaps, sizeof(struct xfs_rmap_irec)); if (error) @@ -82,11 +153,6 @@ _("Insufficient memory while allocating reverse mapping slabs.")); do_error( _("Insufficient memory while allocating raw metadata reverse mapping slabs.")); ag_rmaps[i].ar_last_rmap.rm_owner = XFS_RMAP_OWN_UNKNOWN; - error = init_slab(&ag_rmaps[i].ar_refcount_items, - sizeof(struct xfs_refcount_irec)); - if (error) - do_error( -_("Insufficient memory while allocating refcount item slabs.")); } } @@ -105,7 +171,7 @@ rmaps_free( for (i = 0; i < mp->m_sb.sb_agcount; i++) { free_slab(&ag_rmaps[i].ar_rmaps); free_slab(&ag_rmaps[i].ar_raw_rmaps); - free_slab(&ag_rmaps[i].ar_refcount_items); + rmaps_destroy(mp, &ag_rmaps[i]); } free(ag_rmaps); ag_rmaps = NULL; @@ -136,6 +202,87 @@ rmaps_are_mergeable( return r1->rm_offset + r1->rm_blockcount == r2->rm_offset; } +int +rmap_init_mem_cursor( + struct xfs_mount *mp, + struct xfs_trans *tp, + xfs_agnumber_t agno, + struct xfs_btree_cur **rmcurp) +{ + struct xfbtree *xfbt; + struct xfs_perag *pag; + int error; + + xfbt = &ag_rmaps[agno].ar_xfbtree; + pag = libxfs_perag_get(mp, agno); + *rmcurp = libxfs_rmapbt_mem_cursor(pag, tp, xfbt); + + error = -libxfs_btree_goto_left_edge(*rmcurp); + if (error) + libxfs_btree_del_cursor(*rmcurp, error); + + libxfs_perag_put(pag); + return error; +} + +/* + * Retrieve the next record from the in-memory rmap btree. Returns 1 if irec + * has been filled out, 0 if there aren't any more records, or a negative errno + * value if an error happened. + */ +int +rmap_get_mem_rec( + struct xfs_btree_cur *rmcur, + struct xfs_rmap_irec *irec) +{ + int stat = 0; + int error; + + error = -libxfs_btree_increment(rmcur, 0, &stat); + if (error) + return -error; + if (!stat) + return 0; + + error = -libxfs_rmap_get_rec(rmcur, irec, &stat); + if (error) + return -error; + + return stat; +} + +static void +rmap_add_mem_rec( + struct xfs_mount *mp, + xfs_agnumber_t agno, + struct xfs_rmap_irec *rmap) +{ + struct xfs_btree_cur *rmcur; + struct xfbtree *xfbt; + struct xfs_trans *tp; + int error; + + xfbt = &ag_rmaps[agno].ar_xfbtree; + error = -libxfs_trans_alloc_empty(mp, &tp); + if (error) + do_error(_("allocating tx for in-memory rmap update\n")); + + error = rmap_init_mem_cursor(mp, tp, agno, &rmcur); + if (error) + do_error(_("reading in-memory rmap btree head\n")); + + error = -libxfs_rmap_map_raw(rmcur, rmap); + if (error) + do_error(_("adding rmap to in-memory btree, err %d\n"), error); + libxfs_btree_del_cursor(rmcur, 0); + + error = xfbtree_trans_commit(xfbt, tp); + if (error) + do_error(_("committing in-memory rmap record\n")); + + libxfs_trans_cancel(tp); +} + /* * Add an observation about a block mapping in an inode's data or attribute * fork for later btree reconstruction. @@ -173,6 +320,9 @@ rmap_add_rec( rmap.rm_blockcount = irec->br_blockcount; if (irec->br_state == XFS_EXT_UNWRITTEN) rmap.rm_flags |= XFS_RMAP_UNWRITTEN; + + rmap_add_mem_rec(mp, agno, &rmap); + last_rmap = &ag_rmaps[agno].ar_last_rmap; if (last_rmap->rm_owner == XFS_RMAP_OWN_UNKNOWN) *last_rmap = rmap; @@ -223,6 +373,8 @@ __rmap_add_raw_rec( rmap.rm_flags |= XFS_RMAP_BMBT_BLOCK; rmap.rm_startblock = agbno; rmap.rm_blockcount = len; + + rmap_add_mem_rec(mp, agno, &rmap); return slab_add(ag_rmaps[agno].ar_raw_rmaps, &rmap); } @@ -273,6 +425,36 @@ rmap_add_ag_rec( return __rmap_add_raw_rec(mp, agno, agbno, len, owner, false, false); } +/* + * Add a reverse mapping for a per-AG btree extent. These are /not/ tracked + * in the in-memory rmap btree because they can only be added to the rmap + * data after the in-memory btrees have been written to disk. + */ +int +rmap_add_agbtree_mapping( + struct xfs_mount *mp, + xfs_agnumber_t agno, + xfs_agblock_t agbno, + xfs_extlen_t len, + uint64_t owner) +{ + struct xfs_rmap_irec rmap = { + .rm_owner = owner, + .rm_startblock = agbno, + .rm_blockcount = len, + }; + struct xfs_perag *pag; + + if (!rmap_needs_work(mp)) + return 0; + + pag = libxfs_perag_get(mp, agno); + assert(libxfs_verify_agbext(pag, agbno, len)); + libxfs_perag_put(pag); + + return slab_add(ag_rmaps[agno].ar_raw_rmaps, &rmap); +} + /* * Merge adjacent raw rmaps and add them to the main rmap list. */ @@ -441,7 +623,7 @@ rmap_add_fixed_ag_rec( * the rmapbt, after which it is fully regenerated. */ int -rmap_store_ag_btree_rec( +rmap_commit_agbtree_mappings( struct xfs_mount *mp, xfs_agnumber_t agno) { @@ -536,7 +718,7 @@ rmap_store_ag_btree_rec( if (error) goto err; - /* Create cursors to refcount structures */ + /* Create cursors to rmap structures */ error = init_slab_cursor(ag_rmap->ar_rmaps, rmap_compare, &rm_cur); if (error) goto err; @@ -869,6 +1051,21 @@ compute_refcounts( } #undef RMAP_END +static int +count_btree_records( + struct xfs_btree_cur *cur, + int level, + void *data) +{ + uint64_t *nr = data; + struct xfs_btree_block *block; + struct xfs_buf *bp; + + block = libxfs_btree_get_block(cur, level, &bp); + *nr += be16_to_cpu(block->bb_numrecs); + return 0; +} + /* * Return the number of rmap objects for an AG. */ @@ -877,7 +1074,26 @@ rmap_record_count( struct xfs_mount *mp, xfs_agnumber_t agno) { - return slab_count(ag_rmaps[agno].ar_rmaps); + struct xfs_btree_cur *rmcur; + uint64_t nr = 0; + int error; + + if (!rmaps_has_observations(&ag_rmaps[agno])) + return 0; + + error = rmap_init_mem_cursor(mp, NULL, agno, &rmcur); + if (error) + do_error(_("%s while reading in-memory rmap btree\n"), + strerror(error)); + + error = -libxfs_btree_visit_blocks(rmcur, count_btree_records, + XFS_BTREE_VISIT_RECORDS, &nr); + if (error) + do_error(_("%s while counting in-memory rmap records\n"), + strerror(error)); + + libxfs_btree_del_cursor(rmcur, 0); + return nr; } /* @@ -1545,15 +1761,16 @@ estimate_rmapbt_blocks( /* * Overestimate the amount of space needed by pretending that every - * record in the incore slab will become rmapbt records. + * byte in the incore tree is used to store rmapbt records. This + * means we can use SEEK_DATA/HOLE on the xfile, which is faster than + * walking the entire btree to count records. */ x = &ag_rmaps[pag->pag_agno]; - if (x->ar_rmaps) - nr_recs += slab_count(x->ar_rmaps); - if (x->ar_raw_rmaps) - nr_recs += slab_count(x->ar_raw_rmaps); + if (!rmaps_has_observations(x)) + return 0; - return libxfs_rmapbt_calc_size(mp, nr_recs); + nr_recs = xmbuf_bytes(x->ar_xmbtp) / sizeof(struct xfs_rmap_rec); + return libxfs_rmapbt_calc_size(pag->pag_mount, nr_recs); } /* Estimate the size of the ondisk refcountbt from the incore data. */ diff --git a/repair/rmap.h b/repair/rmap.h index 1bc8c127d..2de3ec56f 100644 --- a/repair/rmap.h +++ b/repair/rmap.h @@ -24,7 +24,10 @@ extern int rmap_fold_raw_recs(struct xfs_mount *mp, xfs_agnumber_t agno); extern bool rmaps_are_mergeable(struct xfs_rmap_irec *r1, struct xfs_rmap_irec *r2); extern int rmap_add_fixed_ag_rec(struct xfs_mount *, xfs_agnumber_t); -extern int rmap_store_ag_btree_rec(struct xfs_mount *, xfs_agnumber_t); + +int rmap_add_agbtree_mapping(struct xfs_mount *mp, xfs_agnumber_t agno, + xfs_agblock_t agbno, xfs_extlen_t len, uint64_t owner); +int rmap_commit_agbtree_mappings(struct xfs_mount *mp, xfs_agnumber_t agno); uint64_t rmap_record_count(struct xfs_mount *mp, xfs_agnumber_t agno); extern int rmap_init_cursor(xfs_agnumber_t, struct xfs_slab_cursor **); @@ -52,4 +55,8 @@ extern void rmap_store_agflcount(struct xfs_mount *, xfs_agnumber_t, int); xfs_extlen_t estimate_rmapbt_blocks(struct xfs_perag *pag); xfs_extlen_t estimate_refcountbt_blocks(struct xfs_perag *pag); +int rmap_init_mem_cursor(struct xfs_mount *mp, struct xfs_trans *tp, + xfs_agnumber_t agno, struct xfs_btree_cur **rmcurp); +int rmap_get_mem_rec(struct xfs_btree_cur *rmcur, struct xfs_rmap_irec *irec); + #endif /* RMAP_H_ */ diff --git a/repair/xfs_repair.c b/repair/xfs_repair.c index bf56daa93..f8c37c632 100644 --- a/repair/xfs_repair.c +++ b/repair/xfs_repair.c @@ -949,6 +949,12 @@ repair_capture_writeback( struct xfs_mount *mp = bp->b_mount; static pthread_mutex_t wb_mutex = PTHREAD_MUTEX_INITIALIZER; + /* We only care about ondisk metadata. */ + if (bp->b_target != mp->m_ddev_targp && + bp->b_target != mp->m_logdev_targp && + bp->b_target != mp->m_rtdev_targp) + return; + /* * This write hook ignores any buffer that looks like a superblock to * avoid hook recursion when setting NEEDSREPAIR. Higher level code From patchwork Wed May 22 03:21:54 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13670346 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 2F9E6282E5 for ; Wed, 22 May 2024 03:21:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716348115; cv=none; b=AsrvU+HWTFBMKstEz9bX52U3neIUIhf+l2LG2sceV4oMrmMRljyi1r9l5HDkD+MdT2eFn/taF+utcwpgFxn9yIfXwik/kWIcXBfHWwNX++SMWiiPdKm71WZZnWP1TCVugmAMl9R6fKgkQ9K0mOv/8zTzIO7EOnZE/PIc8UW1CQs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716348115; c=relaxed/simple; bh=XhBPMVZ7P+Qiupt1HUMuzugCf8OfWlCaAwy0ex3gBaM=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=QkFOeWURGAuDtiI06u3gIjOPtrBMvCboWhs6oA79ffxCAZK+whZKj9Svw4NaD+y/WIiiKL86cUZOtQDE5x3LJRZ5D/Gs1IiGKQjEUesk/kb+WnLeE3yFY0ec71YFQVW1yG7BZbSS2Uzv95QpdBKGeR5Hz3/Ynf5SatGTZaOODgo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=UcfYEEf4; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="UcfYEEf4" Received: by smtp.kernel.org (Postfix) with ESMTPSA id BA7F9C2BD11; Wed, 22 May 2024 03:21:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1716348114; bh=XhBPMVZ7P+Qiupt1HUMuzugCf8OfWlCaAwy0ex3gBaM=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=UcfYEEf4QT1XFjIXMkyoVmZFyHrWqGnADRJnhuuw75rJ6ul5VnbsAQMKHj4Ma6Gou ELy1r4FeLz8kQbV7PVTu02nKARc9lBPra6be7lJ2t1kzcHTT+BBQndSZijxKqpHXOt 8A/ajcD5E5CigZVXHrHTgYpvmLLFxCTRkmhqg5yr/9lz/vzmrjf4U1H7pcA+e2aeHj cU9rdUZA5cdYocdzjcIGFt1POqyYly450x/UzoJmeAaNQPNrnHmDbkY+1qAoFVBEnI fWK3+sGSSlIh4saswXIYoi5o+pc4LaQhw1IejtctTgHHbii/OvR97pIeXdUjoEZeKA RQ1yTAC/6GIsQ== Date: Tue, 21 May 2024 20:21:54 -0700 Subject: [PATCH 3/6] xfs_repair: verify on-disk rmap btrees with in-memory btree data From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Christoph Hellwig , linux-xfs@vger.kernel.org Message-ID: <171634535433.2483278.6294467241938212956.stgit@frogsfrogsfrogs> In-Reply-To: <171634535383.2483278.14868148193055852399.stgit@frogsfrogsfrogs> References: <171634535383.2483278.14868148193055852399.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 Check the on-disk reverse mappings with the observations we've recorded in the in-memory btree during the filesystem walk. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- repair/rmap.c | 58 +++++++++++++++++++++++++++------------------------------ 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/repair/rmap.c b/repair/rmap.c index c1ae7da1e..69f134ed0 100644 --- a/repair/rmap.c +++ b/repair/rmap.c @@ -1190,11 +1190,11 @@ rmaps_verify_btree( struct xfs_mount *mp, xfs_agnumber_t agno) { + struct xfs_btree_cur *rm_cur; + struct xfs_rmap_irec rm_rec; struct xfs_rmap_irec tmp; - struct xfs_slab_cursor *rm_cur; struct xfs_btree_cur *bt_cur = NULL; struct xfs_buf *agbp = NULL; - struct xfs_rmap_irec *rm_rec; struct xfs_perag *pag = NULL; int have; int error; @@ -1207,8 +1207,8 @@ rmaps_verify_btree( return; } - /* Create cursors to refcount structures */ - error = rmap_init_cursor(agno, &rm_cur); + /* Create cursors to rmap structures */ + error = rmap_init_mem_cursor(mp, NULL, agno, &rm_cur); if (error) { do_warn(_("Not enough memory to check reverse mappings.\n")); return; @@ -1231,13 +1231,12 @@ rmaps_verify_btree( goto err_agf; } - rm_rec = pop_slab_cursor(rm_cur); - while (rm_rec) { - error = rmap_lookup(bt_cur, rm_rec, &tmp, &have); + while ((error = rmap_get_mem_rec(rm_cur, &rm_rec)) == 1) { + error = rmap_lookup(bt_cur, &rm_rec, &tmp, &have); if (error) { do_warn( _("Could not read reverse-mapping record for (%u/%u).\n"), - agno, rm_rec->rm_startblock); + agno, rm_rec.rm_startblock); goto err_cur; } @@ -1247,13 +1246,13 @@ _("Could not read reverse-mapping record for (%u/%u).\n"), * match the observed rmap. */ if (xfs_has_reflink(bt_cur->bc_mp) && - (!have || !rmap_is_good(rm_rec, &tmp))) { - error = rmap_lookup_overlapped(bt_cur, rm_rec, + (!have || !rmap_is_good(&rm_rec, &tmp))) { + error = rmap_lookup_overlapped(bt_cur, &rm_rec, &tmp, &have); if (error) { do_warn( _("Could not read reverse-mapping record for (%u/%u).\n"), - agno, rm_rec->rm_startblock); + agno, rm_rec.rm_startblock); goto err_cur; } } @@ -1261,21 +1260,21 @@ _("Could not read reverse-mapping record for (%u/%u).\n"), do_warn( _("Missing reverse-mapping record for (%u/%u) %slen %u owner %"PRId64" \ %s%soff %"PRIu64"\n"), - agno, rm_rec->rm_startblock, - (rm_rec->rm_flags & XFS_RMAP_UNWRITTEN) ? + agno, rm_rec.rm_startblock, + (rm_rec.rm_flags & XFS_RMAP_UNWRITTEN) ? _("unwritten ") : "", - rm_rec->rm_blockcount, - rm_rec->rm_owner, - (rm_rec->rm_flags & XFS_RMAP_ATTR_FORK) ? + rm_rec.rm_blockcount, + rm_rec.rm_owner, + (rm_rec.rm_flags & XFS_RMAP_ATTR_FORK) ? _("attr ") : "", - (rm_rec->rm_flags & XFS_RMAP_BMBT_BLOCK) ? + (rm_rec.rm_flags & XFS_RMAP_BMBT_BLOCK) ? _("bmbt ") : "", - rm_rec->rm_offset); - goto next_loop; + rm_rec.rm_offset); + continue; } /* Compare each refcount observation against the btree's */ - if (!rmap_is_good(rm_rec, &tmp)) { + if (!rmap_is_good(&rm_rec, &tmp)) { do_warn( _("Incorrect reverse-mapping: saw (%u/%u) %slen %u owner %"PRId64" %s%soff \ %"PRIu64"; should be (%u/%u) %slen %u owner %"PRId64" %s%soff %"PRIu64"\n"), @@ -1289,20 +1288,17 @@ _("Incorrect reverse-mapping: saw (%u/%u) %slen %u owner %"PRId64" %s%soff \ (tmp.rm_flags & XFS_RMAP_BMBT_BLOCK) ? _("bmbt ") : "", tmp.rm_offset, - agno, rm_rec->rm_startblock, - (rm_rec->rm_flags & XFS_RMAP_UNWRITTEN) ? + agno, rm_rec.rm_startblock, + (rm_rec.rm_flags & XFS_RMAP_UNWRITTEN) ? _("unwritten ") : "", - rm_rec->rm_blockcount, - rm_rec->rm_owner, - (rm_rec->rm_flags & XFS_RMAP_ATTR_FORK) ? + rm_rec.rm_blockcount, + rm_rec.rm_owner, + (rm_rec.rm_flags & XFS_RMAP_ATTR_FORK) ? _("attr ") : "", - (rm_rec->rm_flags & XFS_RMAP_BMBT_BLOCK) ? + (rm_rec.rm_flags & XFS_RMAP_BMBT_BLOCK) ? _("bmbt ") : "", - rm_rec->rm_offset); - goto next_loop; + rm_rec.rm_offset); } -next_loop: - rm_rec = pop_slab_cursor(rm_cur); } err_cur: @@ -1311,7 +1307,7 @@ _("Incorrect reverse-mapping: saw (%u/%u) %slen %u owner %"PRId64" %s%soff \ libxfs_buf_relse(agbp); err_pag: libxfs_perag_put(pag); - free_slab_cursor(&rm_cur); + libxfs_btree_del_cursor(rm_cur, error); } /* From patchwork Wed May 22 03:22:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13670347 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 93CF52C9D for ; Wed, 22 May 2024 03:22:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716348130; cv=none; b=jSkMMZRI8sOESS5egUkO9Dl41WCLEKY6g75ZmXCmgZIsafDQUBuQFxunKUxL0ayTuzqMuVISptRnxosOBhwaxNAXnumNWbClVRGRttjWaz6dclRV7VQK780BmYTKa4MoCgRCaUl0QZGp9HA3i+pijd9ll5ZvBQQComj4pcOFIpE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716348130; c=relaxed/simple; bh=/f1Nr8Lai8jVrnfQXS6vAQZfCjXioTl3s26zomBIs3k=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=lBO5prFmjEOBVbdiRp0QgvNvQwANkHZ47JnG1qAUwDSYVhPeMBi6wTtktc/UOwvSf4YjEzfOd6ggQJ3AXhR9oc0aQ9rqM33zuFdbHaHTO8TQYEvVipSIBXFLQY2Oi1zHL2GUqFiWa5Olljs53WRo0TQ0FrQuAoAv3zB7FSEvayU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Ci4In/uS; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Ci4In/uS" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6D4A5C2BD11; Wed, 22 May 2024 03:22:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1716348130; bh=/f1Nr8Lai8jVrnfQXS6vAQZfCjXioTl3s26zomBIs3k=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Ci4In/uSP6ezSDaT5+WjbD7AsnCFR6pSdxvrLVCJYlAo3H1IlGrRsDx45HcnhX4E6 Ra/094imJp4c4IRqk2dvGK64umRn1qf3e0pCDfzILHiclxwkQ6ltbg28wcnR8LK9Sl oyk5XTFgH9EkmBgcfq4hw0JkitMTRNXLWDnaX/ueFRctvlOapbE3kuTRM+6z8/2FBT SHT+UjebMMBKWQvfIMtXW8RR8W03hyhIhW8jsm8naduATxHxVVQcWL/Zbx5pTaQ4Qe V1xx/8iCXyX2c/R8EU5DO+JQUL7DcM1wqauK5PJyuLrCMqLF9nAwsZPm5nW+mc03fw ExPsVG1OGXBnw== Date: Tue, 21 May 2024 20:22:09 -0700 Subject: [PATCH 4/6] xfs_repair: compute refcount data from in-memory rmap btrees From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Christoph Hellwig , linux-xfs@vger.kernel.org Message-ID: <171634535448.2483278.13687034405467910446.stgit@frogsfrogsfrogs> In-Reply-To: <171634535383.2483278.14868148193055852399.stgit@frogsfrogsfrogs> References: <171634535383.2483278.14868148193055852399.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 Use the in-memory rmap btrees to compute the reference count information. Convert the bag implementation to hold actual records instead of pointers to slab objects. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- libxfs/libxfs_api_defs.h | 4 + repair/phase4.c | 2 repair/rmap.c | 232 ++++++++++++++++++++++++++++++++++++---------- repair/slab.c | 49 ++++++---- repair/slab.h | 2 5 files changed, 217 insertions(+), 72 deletions(-) diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index 74bf15172..209c7a189 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -63,9 +63,11 @@ #define xfs_btree_bload libxfs_btree_bload #define xfs_btree_bload_compute_geometry libxfs_btree_bload_compute_geometry +#define xfs_btree_decrement libxfs_btree_decrement #define xfs_btree_del_cursor libxfs_btree_del_cursor #define xfs_btree_get_block libxfs_btree_get_block #define xfs_btree_goto_left_edge libxfs_btree_goto_left_edge +#define xfs_btree_has_more_records libxfs_btree_has_more_records #define xfs_btree_increment libxfs_btree_increment #define xfs_btree_init_block libxfs_btree_init_block #define xfs_btree_mem_head_read_buf libxfs_btree_mem_head_read_buf @@ -167,6 +169,8 @@ #define xfs_inode_validate_cowextsize libxfs_inode_validate_cowextsize #define xfs_inode_validate_extsize libxfs_inode_validate_extsize +#define xfs_internal_inum libxfs_internal_inum + #define xfs_iread_extents libxfs_iread_extents #define xfs_irele libxfs_irele #define xfs_log_calc_minimum_size libxfs_log_calc_minimum_size diff --git a/repair/phase4.c b/repair/phase4.c index e4c0e616f..f267149ab 100644 --- a/repair/phase4.c +++ b/repair/phase4.c @@ -188,7 +188,7 @@ compute_ag_refcounts( if (error) do_error( _("%s while computing reference count records.\n"), - strerror(-error)); + strerror(error)); } static void diff --git a/repair/rmap.c b/repair/rmap.c index 69f134ed0..f58773cb3 100644 --- a/repair/rmap.c +++ b/repair/rmap.c @@ -924,66 +924,196 @@ refcount_emit( _("Insufficient memory while recreating refcount tree.")); } +#define RMAP_NEXT(r) ((r)->rm_startblock + (r)->rm_blockcount) + +/* Decide if an rmap could describe a shared extent. */ +static inline bool +rmap_shareable( + struct xfs_mount *mp, + const struct xfs_rmap_irec *rmap) +{ + /* AG metadata are never sharable */ + if (XFS_RMAP_NON_INODE_OWNER(rmap->rm_owner)) + return false; + + /* Metadata in files are never shareable */ + if (libxfs_internal_inum(mp, rmap->rm_owner)) + return false; + + /* Metadata and unwritten file blocks are not shareable. */ + if (rmap->rm_flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK | + XFS_RMAP_UNWRITTEN)) + return false; + + return true; +} + +/* Grab the rmap for the next possible shared extent. */ +STATIC int +refcount_walk_rmaps( + struct xfs_btree_cur *cur, + struct xfs_rmap_irec *rmap, + bool *have_rec) +{ + struct xfs_mount *mp = cur->bc_mp; + int have_gt; + int error = 0; + + *have_rec = false; + + /* + * Loop through the remaining rmaps. Remember CoW staging + * extents and the refcountbt blocks from the old tree for later + * disposal. We can only share written data fork extents, so + * keep looping until we find an rmap for one. + */ + do { + error = -libxfs_btree_increment(cur, 0, &have_gt); + if (error) + return error; + if (!have_gt) + return 0; + + error = -libxfs_rmap_get_rec(cur, rmap, &have_gt); + if (error) + return error; + if (!have_gt) + return EFSCORRUPTED; + } while (!rmap_shareable(mp, rmap)); + + *have_rec = true; + return 0; +} + +/* + * 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 +next_refcount_edge( + struct xfs_bag *stack_top, + struct xfs_rmap_irec *next_rmap, + bool next_valid, + xfs_agblock_t *nbnop) +{ + struct xfs_rmap_irec *rmap; + uint64_t idx; + xfs_agblock_t nbno = NULLAGBLOCK; + + if (next_valid) + nbno = next_rmap->rm_startblock; + + foreach_bag_ptr(stack_top, idx, rmap) + nbno = min(nbno, RMAP_NEXT(rmap)); + + /* + * 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 + * the current block. Upon return, the rmap cursor points to the last record + * satisfying the startblock constraint. + */ +static int +refcount_push_rmaps_at( + struct xfs_btree_cur *rmcur, + xfs_agnumber_t agno, + struct xfs_bag *stack_top, + xfs_agblock_t bno, + struct xfs_rmap_irec *irec, + bool *have, + const char *tag) +{ + int have_gt; + int error; + + while (*have && irec->rm_startblock == bno) { + rmap_dump(tag, agno, irec); + error = bag_add(stack_top, irec); + if (error) + return error; + error = refcount_walk_rmaps(rmcur, irec, have); + if (error) + return error; + } + + error = -libxfs_btree_decrement(rmcur, 0, &have_gt); + if (error) + return error; + if (!have_gt) + return EFSCORRUPTED; + + return 0; +} + /* * Transform a pile of physical block mapping observations into refcount data * for eventual rebuilding of the btrees. */ -#define RMAP_END(r) ((r)->rm_startblock + (r)->rm_blockcount) int compute_refcounts( - struct xfs_mount *mp, + struct xfs_mount *mp, xfs_agnumber_t agno) { + struct xfs_btree_cur *rmcur; + struct xfs_rmap_irec irec; struct xfs_bag *stack_top = NULL; - struct xfs_slab *rmaps; - struct xfs_slab_cursor *rmaps_cur; - struct xfs_rmap_irec *array_cur; struct xfs_rmap_irec *rmap; - uint64_t n, idx; + uint64_t idx; uint64_t old_stack_nr; xfs_agblock_t sbno; /* first bno of this rmap set */ xfs_agblock_t cbno; /* first bno of this refcount set */ xfs_agblock_t nbno; /* next bno where rmap set changes */ + bool have; int error; if (!xfs_has_reflink(mp)) return 0; - rmaps = ag_rmaps[agno].ar_rmaps; - - error = init_slab_cursor(rmaps, rmap_compare, &rmaps_cur); + error = rmap_init_mem_cursor(mp, NULL, agno, &rmcur); if (error) return error; - error = init_bag(&stack_top); + error = init_bag(&stack_top, sizeof(struct xfs_rmap_irec)); if (error) - goto err; + goto out_cur; - /* While there are rmaps to be processed... */ - n = 0; - while (n < slab_count(rmaps)) { - array_cur = peek_slab_cursor(rmaps_cur); - sbno = cbno = array_cur->rm_startblock; + /* Start the rmapbt cursor to the left of all records. */ + error = -libxfs_btree_goto_left_edge(rmcur); + if (error) + goto out_bag; + + + /* Process reverse mappings into refcount data. */ + while (libxfs_btree_has_more_records(rmcur)) { /* Push all rmaps with pblk == sbno onto the stack */ - for (; - array_cur && array_cur->rm_startblock == sbno; - array_cur = peek_slab_cursor(rmaps_cur)) { - advance_slab_cursor(rmaps_cur); n++; - rmap_dump("push0", agno, array_cur); - error = bag_add(stack_top, array_cur); - if (error) - goto err; - } + error = refcount_walk_rmaps(rmcur, &irec, &have); + if (error) + goto out_bag; + if (!have) + break; + sbno = cbno = irec.rm_startblock; + error = refcount_push_rmaps_at(rmcur, agno, stack_top, sbno, + &irec, &have, "push0"); + if (error) + goto out_bag; mark_inode_rl(mp, stack_top); /* Set nbno to the bno of the next refcount change */ - if (n < slab_count(rmaps) && array_cur) - nbno = array_cur->rm_startblock; - else - nbno = NULLAGBLOCK; - foreach_bag_ptr(stack_top, idx, rmap) { - nbno = min(nbno, RMAP_END(rmap)); - } + error = next_refcount_edge(stack_top, &irec, have, &nbno); + if (error) + goto out_bag; /* Emit reverse mappings, if needed */ ASSERT(nbno > sbno); @@ -993,23 +1123,24 @@ compute_refcounts( while (bag_count(stack_top)) { /* Pop all rmaps that end at nbno */ foreach_bag_ptr_reverse(stack_top, idx, rmap) { - if (RMAP_END(rmap) != nbno) + if (RMAP_NEXT(rmap) != nbno) continue; rmap_dump("pop", agno, rmap); error = bag_remove(stack_top, idx); if (error) - goto err; + goto out_bag; } /* Push array items that start at nbno */ - for (; - array_cur && array_cur->rm_startblock == nbno; - array_cur = peek_slab_cursor(rmaps_cur)) { - advance_slab_cursor(rmaps_cur); n++; - rmap_dump("push1", agno, array_cur); - error = bag_add(stack_top, array_cur); + error = refcount_walk_rmaps(rmcur, &irec, &have); + if (error) + goto out_bag; + if (have) { + error = refcount_push_rmaps_at(rmcur, agno, + stack_top, nbno, &irec, &have, + "push1"); if (error) - goto err; + goto out_bag; } mark_inode_rl(mp, stack_top); @@ -1031,25 +1162,22 @@ compute_refcounts( sbno = nbno; /* Set nbno to the bno of the next refcount change */ - if (n < slab_count(rmaps)) - nbno = array_cur->rm_startblock; - else - nbno = NULLAGBLOCK; - foreach_bag_ptr(stack_top, idx, rmap) { - nbno = min(nbno, RMAP_END(rmap)); - } + error = next_refcount_edge(stack_top, &irec, have, + &nbno); + if (error) + goto out_bag; /* Emit reverse mappings, if needed */ ASSERT(nbno > sbno); } } -err: +out_bag: free_bag(&stack_top); - free_slab_cursor(&rmaps_cur); - +out_cur: + libxfs_btree_del_cursor(rmcur, error); return error; } -#undef RMAP_END +#undef RMAP_NEXT static int count_btree_records( diff --git a/repair/slab.c b/repair/slab.c index 01bc4d426..44ca0468e 100644 --- a/repair/slab.c +++ b/repair/slab.c @@ -78,16 +78,26 @@ struct xfs_slab_cursor { }; /* - * Bags -- each bag is an array of pointers items; when a bag fills up, we - * resize it. + * Bags -- each bag is an array of record items; when a bag fills up, we resize + * it and hope we don't run out of memory. */ #define MIN_BAG_SIZE 4096 struct xfs_bag { uint64_t bg_nr; /* number of pointers */ uint64_t bg_inuse; /* number of slots in use */ - void **bg_ptrs; /* pointers */ + char *bg_items; /* pointer to block of items */ + size_t bg_item_sz; /* size of each item */ }; -#define BAG_END(bag) (&(bag)->bg_ptrs[(bag)->bg_nr]) + +static inline void *bag_ptr(struct xfs_bag *bag, uint64_t idx) +{ + return &bag->bg_items[bag->bg_item_sz * idx]; +} + +static inline void *bag_end(struct xfs_bag *bag) +{ + return bag_ptr(bag, bag->bg_nr); +} /* * Create a slab to hold some objects of a particular size. @@ -382,15 +392,17 @@ slab_count( */ int init_bag( - struct xfs_bag **bag) + struct xfs_bag **bag, + size_t item_sz) { struct xfs_bag *ptr; ptr = calloc(1, sizeof(struct xfs_bag)); if (!ptr) return -ENOMEM; - ptr->bg_ptrs = calloc(MIN_BAG_SIZE, sizeof(void *)); - if (!ptr->bg_ptrs) { + ptr->bg_item_sz = item_sz; + ptr->bg_items = calloc(MIN_BAG_SIZE, item_sz); + if (!ptr->bg_items) { free(ptr); return -ENOMEM; } @@ -411,7 +423,7 @@ free_bag( ptr = *bag; if (!ptr) return; - free(ptr->bg_ptrs); + free(ptr->bg_items); free(ptr); *bag = NULL; } @@ -424,22 +436,23 @@ bag_add( struct xfs_bag *bag, void *ptr) { - void **p, **x; + void *p, *x; - p = &bag->bg_ptrs[bag->bg_inuse]; - if (p == BAG_END(bag)) { + p = bag_ptr(bag, bag->bg_inuse); + if (p == bag_end(bag)) { /* No free space, alloc more pointers */ uint64_t nr; nr = bag->bg_nr * 2; - x = realloc(bag->bg_ptrs, nr * sizeof(void *)); + x = realloc(bag->bg_items, nr * bag->bg_item_sz); if (!x) return -ENOMEM; - bag->bg_ptrs = x; - memset(BAG_END(bag), 0, bag->bg_nr * sizeof(void *)); + bag->bg_items = x; + memset(bag_end(bag), 0, bag->bg_nr * bag->bg_item_sz); bag->bg_nr = nr; + p = bag_ptr(bag, bag->bg_inuse); } - bag->bg_ptrs[bag->bg_inuse] = ptr; + memcpy(p, ptr, bag->bg_item_sz); bag->bg_inuse++; return 0; } @@ -453,8 +466,8 @@ bag_remove( uint64_t nr) { ASSERT(nr < bag->bg_inuse); - memmove(&bag->bg_ptrs[nr], &bag->bg_ptrs[nr + 1], - (bag->bg_inuse - nr - 1) * sizeof(void *)); + memmove(bag_ptr(bag, nr), bag_ptr(bag, nr + 1), + (bag->bg_inuse - nr - 1) * bag->bg_item_sz); bag->bg_inuse--; return 0; } @@ -479,5 +492,5 @@ bag_item( { if (nr >= bag->bg_inuse) return NULL; - return bag->bg_ptrs[nr]; + return bag_ptr(bag, nr); } diff --git a/repair/slab.h b/repair/slab.h index 077b45822..019b16902 100644 --- a/repair/slab.h +++ b/repair/slab.h @@ -28,7 +28,7 @@ void *pop_slab_cursor(struct xfs_slab_cursor *cur); struct xfs_bag; -int init_bag(struct xfs_bag **bagp); +int init_bag(struct xfs_bag **bagp, size_t itemsz); void free_bag(struct xfs_bag **bagp); int bag_add(struct xfs_bag *bag, void *item); int bag_remove(struct xfs_bag *bag, uint64_t idx); From patchwork Wed May 22 03:22:25 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13670348 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 893F92C9D for ; Wed, 22 May 2024 03:22:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716348146; cv=none; b=mTLjcCg1EUJKstlK3YqgkUkH4LfUDfUbQjZt2b5GfOzBCvoKzT+ynEEMWuteDuQmmv76UHjs0UVG09Tl1Q1aVR87HtyopZRd9H2H1W3jgozGYzZ9qGbc2N581j/AC85DJjof++yEitT7twU+Y0xWy/y5Uc6JSp9z67RpjJD3sJY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716348146; c=relaxed/simple; bh=ERfZSpqqP3dUJpWhiqfZq5NWZd1sdtP2ghwX/XjKE0s=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=dBNEy2u0EecUGdv/p8Ra+1QbsAN96x26ULW90QJUkGJl/QirYn4EnIQq8Yl9+eEQ+H2AGnviyVaDacE2R1hyV2hRgBnhrJtac/mPP5Ny6FK2wZq+U5fjOmTckEFC+tt/uOvYSvudz7m6gv20qTUFpjsiQXFQrHJusXKYri4NiPs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Ew2QtIid; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Ew2QtIid" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0E2DAC2BD11; Wed, 22 May 2024 03:22:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1716348146; bh=ERfZSpqqP3dUJpWhiqfZq5NWZd1sdtP2ghwX/XjKE0s=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Ew2QtIidvUgscV5ZS32qHd3CFurimgdxO3N6Ky0bBt34el6xUcK9Mve9R2kFIsU68 rr3r4c2ZgBZbWZR0tE/62amDDJIl7QiHtIJl/Pt/ZRGWEAW/m46nKPo9XId0T+gUR6 BuCVtSw9BL9CSCfOxOnbMI9IeZhJ4bznYEi5Oveb58cOiQgCxqR6oIJh2gBX8wnNTs RS8Xjj4VLyQ4JOkO2gfXOrPB1mwwIfY1grcwzzFSUqOdoMdxhAnBVKmAndWon8hC72 lpAQtbyvvYFDBDgXub1gjj2LshFx4UKiDZyWym2FxsiwKroE8AWIA5tj1iJKVcVn3P WTP0xuF2HzjtQ== Date: Tue, 21 May 2024 20:22:25 -0700 Subject: [PATCH 5/6] xfs_repair: reduce rmap bag memory usage when creating refcounts From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Christoph Hellwig , linux-xfs@vger.kernel.org Message-ID: <171634535462.2483278.10385029560476840841.stgit@frogsfrogsfrogs> In-Reply-To: <171634535383.2483278.14868148193055852399.stgit@frogsfrogsfrogs> References: <171634535383.2483278.14868148193055852399.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 The algorithm that computes reference count records uses a "bag" structure to remember the rmap records corresponding to the current block. In the previous patch we converted the bag structure to store actual rmap records instead of pointers to rmap records owned by another structure as part of preparing for converting this algorithm to use in-memory rmap btrees. However, the memory usage of the bag structure is now excessive -- we only need the physical extent and inode owner information to generate refcount records and mark inodes that require the reflink flag. IOWs, the flags and offset fields are unnecessary. Create a custom structure for the bag, which halves its memory usage. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- repair/rmap.c | 74 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/repair/rmap.c b/repair/rmap.c index f58773cb3..f34e42300 100644 --- a/repair/rmap.c +++ b/repair/rmap.c @@ -46,6 +46,13 @@ struct xfs_ag_rmap { struct xfs_slab *ar_refcount_items; }; +/* Only the parts of struct xfs_rmap_irec that we need to compute refcounts. */ +struct rmap_for_refcount { + xfs_agblock_t rm_startblock; + xfs_extlen_t rm_blockcount; + uint64_t rm_owner; +}; + static struct xfs_ag_rmap *ag_rmaps; bool rmapbt_suspect; static bool refcbt_suspect; @@ -777,16 +784,14 @@ static void rmap_dump( const char *msg, xfs_agnumber_t agno, - struct xfs_rmap_irec *rmap) + const struct rmap_for_refcount *rfr) { - printf("%s: %p agno=%u pblk=%llu own=%lld lblk=%llu len=%u flags=0x%x\n", - msg, rmap, + printf("%s: %p agno=%u agbno=%llu owner=%lld fsbcount=%u\n", + msg, rfr, (unsigned int)agno, - (unsigned long long)rmap->rm_startblock, - (unsigned long long)rmap->rm_owner, - (unsigned long long)rmap->rm_offset, - (unsigned int)rmap->rm_blockcount, - (unsigned int)rmap->rm_flags); + (unsigned long long)rfr->rm_startblock, + (unsigned long long)rfr->rm_owner, + (unsigned int)rfr->rm_blockcount); } #else # define rmap_dump(m, a, r) @@ -865,30 +870,33 @@ rmap_dump( */ static void mark_inode_rl( - struct xfs_mount *mp, + struct xfs_mount *mp, struct xfs_bag *rmaps) { - xfs_agnumber_t iagno; - struct xfs_rmap_irec *rmap; + struct rmap_for_refcount *rfr; struct ino_tree_node *irec; int off; uint64_t idx; - xfs_agino_t ino; if (bag_count(rmaps) < 2) return; /* Reflink flag accounting */ - foreach_bag_ptr(rmaps, idx, rmap) { - ASSERT(!XFS_RMAP_NON_INODE_OWNER(rmap->rm_owner)); - iagno = XFS_INO_TO_AGNO(mp, rmap->rm_owner); - ino = XFS_INO_TO_AGINO(mp, rmap->rm_owner); - pthread_mutex_lock(&ag_locks[iagno].lock); - irec = find_inode_rec(mp, iagno, ino); - off = get_inode_offset(mp, rmap->rm_owner, irec); + foreach_bag_ptr(rmaps, idx, rfr) { + xfs_agnumber_t agno; + xfs_agino_t agino; + + ASSERT(!XFS_RMAP_NON_INODE_OWNER(rfr->rm_owner)); + + agno = XFS_INO_TO_AGNO(mp, rfr->rm_owner); + agino = XFS_INO_TO_AGINO(mp, rfr->rm_owner); + + pthread_mutex_lock(&ag_locks[agno].lock); + irec = find_inode_rec(mp, agno, agino); + off = get_inode_offset(mp, rfr->rm_owner, irec); /* lock here because we might go outside this ag */ set_inode_is_rl(irec, off); - pthread_mutex_unlock(&ag_locks[iagno].lock); + pthread_mutex_unlock(&ag_locks[agno].lock); } } @@ -996,15 +1004,15 @@ next_refcount_edge( bool next_valid, xfs_agblock_t *nbnop) { - struct xfs_rmap_irec *rmap; + struct rmap_for_refcount *rfr; uint64_t idx; xfs_agblock_t nbno = NULLAGBLOCK; if (next_valid) nbno = next_rmap->rm_startblock; - foreach_bag_ptr(stack_top, idx, rmap) - nbno = min(nbno, RMAP_NEXT(rmap)); + foreach_bag_ptr(stack_top, idx, rfr) + nbno = min(nbno, RMAP_NEXT(rfr)); /* * We should have found /something/ because either next_rrm is the next @@ -1039,8 +1047,14 @@ refcount_push_rmaps_at( int error; while (*have && irec->rm_startblock == bno) { - rmap_dump(tag, agno, irec); - error = bag_add(stack_top, irec); + struct rmap_for_refcount rfr = { + .rm_startblock = irec->rm_startblock, + .rm_blockcount = irec->rm_blockcount, + .rm_owner = irec->rm_owner, + }; + + rmap_dump(tag, agno, &rfr); + error = bag_add(stack_top, &rfr); if (error) return error; error = refcount_walk_rmaps(rmcur, irec, have); @@ -1069,7 +1083,7 @@ compute_refcounts( struct xfs_btree_cur *rmcur; struct xfs_rmap_irec irec; struct xfs_bag *stack_top = NULL; - struct xfs_rmap_irec *rmap; + struct rmap_for_refcount *rfr; uint64_t idx; uint64_t old_stack_nr; xfs_agblock_t sbno; /* first bno of this rmap set */ @@ -1085,7 +1099,7 @@ compute_refcounts( if (error) return error; - error = init_bag(&stack_top, sizeof(struct xfs_rmap_irec)); + error = init_bag(&stack_top, sizeof(struct rmap_for_refcount)); if (error) goto out_cur; @@ -1122,10 +1136,10 @@ compute_refcounts( /* While stack isn't empty... */ while (bag_count(stack_top)) { /* Pop all rmaps that end at nbno */ - foreach_bag_ptr_reverse(stack_top, idx, rmap) { - if (RMAP_NEXT(rmap) != nbno) + foreach_bag_ptr_reverse(stack_top, idx, rfr) { + if (RMAP_NEXT(rfr) != nbno) continue; - rmap_dump("pop", agno, rmap); + rmap_dump("pop", agno, rfr); error = bag_remove(stack_top, idx); if (error) goto out_bag; From patchwork Wed May 22 03:22:41 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13670349 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 35C0362A02 for ; Wed, 22 May 2024 03:22:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716348162; cv=none; b=BKquvyghidRvBNEqYxbXRKY3K3drqCW4wpO7g8ncNOZkNqYfOC/g8T5wPHHETPJjbuvAO3+mqsABJhlMq6hNeExVSb42ol71TdUgXBBm6guIeow94RWXV0fB5DUc3dtl1rVYwhD22T09Xb38K4bTBtQjmVqeOzd656MATX3kK+4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716348162; c=relaxed/simple; bh=n5VwZSy1D1ZfcQExFPNhbnalLb5nBYl1WT4fCH3uOcA=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=XYrzViWaq5L1TgM14kzD/r2xp7ja93iYkbU0ZlEe69tXX/V4wnJee11NHVvbBOArlSrva9P7AdNzqizGjm5GX0PJ73r8chxr432Non5SHwxqlT6rsL8jXuprcX0D9YoQ73U5+4IqCM/tfQWA+QXIItf733eSZ67IdE9yu6hhsDo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=p+t+Hn3p; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="p+t+Hn3p" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AB42FC2BD11; Wed, 22 May 2024 03:22:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1716348161; bh=n5VwZSy1D1ZfcQExFPNhbnalLb5nBYl1WT4fCH3uOcA=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=p+t+Hn3pl3qVI2hBYaxKdgCvFHRnIJ2VbwEpWv9jNQMlDgrXhDwIg4ie/Zg+O8OZY 1621+omRGanfQIelXrLIyfzAXBH1tyCUVPsmSH542DaSllsX7q26dWATcXEdDop8Wj 1x4/rSLzEAA1UktTRhdPsuj/9GfTpKYUZgE6Zp6yuQSWyS8qX3xLyZoFe/4r/1WtZS Ux5nXnOidCpjgVzrOBSBDDNizkJ5N5iK/lDsLiIl7WOjuC0U2jp8ErUm52mJ6v4Pmp IGXnYmZMaQkhU5vkDRdHEXfigw5sfx5GOpDOKTmSZQOPsnfObMuC0Jxsaqdqt3ZuHo jE7NiM6rjCsgg== Date: Tue, 21 May 2024 20:22:41 -0700 Subject: [PATCH 6/6] xfs_repair: remove the old rmap collection slabs From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Christoph Hellwig , linux-xfs@vger.kernel.org Message-ID: <171634535477.2483278.4249529489869719511.stgit@frogsfrogsfrogs> In-Reply-To: <171634535383.2483278.14868148193055852399.stgit@frogsfrogsfrogs> References: <171634535383.2483278.14868148193055852399.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 Now that we've switched the offline repair code to use an in-memory rmap btree for everything except recording the rmaps for the newly generated per-AG btrees, get rid of all the old code. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- repair/dinode.c | 9 +- repair/phase4.c | 23 ------ repair/rmap.c | 201 ++++++++++--------------------------------------------- repair/rmap.h | 16 ++-- repair/scan.c | 7 -- 5 files changed, 46 insertions(+), 210 deletions(-) diff --git a/repair/dinode.c b/repair/dinode.c index 9d2f71055..168cbf484 100644 --- a/repair/dinode.c +++ b/repair/dinode.c @@ -628,13 +628,8 @@ _("illegal state %d in block map %" PRIu64 "\n"), break; } } - if (collect_rmaps) { /* && !check_dups */ - error = rmap_add_rec(mp, ino, whichfork, &irec); - if (error) - do_error( -_("couldn't add reverse mapping\n") - ); - } + if (collect_rmaps) /* && !check_dups */ + rmap_add_rec(mp, ino, whichfork, &irec); *tot += irec.br_blockcount; } error = 0; diff --git a/repair/phase4.c b/repair/phase4.c index f267149ab..5e5d8c3c7 100644 --- a/repair/phase4.c +++ b/repair/phase4.c @@ -142,17 +142,7 @@ static void process_ags( xfs_mount_t *mp) { - xfs_agnumber_t i; - int error; - do_inode_prefetch(mp, ag_stride, process_ag_func, true, false); - for (i = 0; i < mp->m_sb.sb_agcount; i++) { - error = rmap_finish_collecting_fork_recs(mp, i); - if (error) - do_error( -_("unable to finish adding attr/data fork reverse-mapping data for AG %u.\n"), - i); - } } static void @@ -161,18 +151,7 @@ check_rmap_btrees( xfs_agnumber_t agno, void *arg) { - int error; - - error = rmap_add_fixed_ag_rec(wq->wq_ctx, agno); - if (error) - do_error( -_("unable to add AG %u metadata reverse-mapping data.\n"), agno); - - error = rmap_fold_raw_recs(wq->wq_ctx, agno); - if (error) - do_error( -_("unable to merge AG %u metadata reverse-mapping data.\n"), agno); - + rmap_add_fixed_ag_rec(wq->wq_ctx, agno); rmaps_verify_btree(wq->wq_ctx, agno); } diff --git a/repair/rmap.c b/repair/rmap.c index f34e42300..519633278 100644 --- a/repair/rmap.c +++ b/repair/rmap.c @@ -30,20 +30,14 @@ struct xfs_ag_rmap { /* rmap buffer target for btree */ struct xfs_buftarg *ar_xmbtp; - /* rmap observations, p4 */ - struct xfs_slab *ar_rmaps; - - /* unmerged rmaps */ - struct xfs_slab *ar_raw_rmaps; - - /* agfl entries from leftover agbt allocations */ - int ar_flcount; - - /* last rmap seen */ - struct xfs_rmap_irec ar_last_rmap; + /* rmaps for rebuilt ag btrees */ + struct xfs_slab *ar_agbtree_rmaps; /* refcount items, p4-5 */ struct xfs_slab *ar_refcount_items; + + /* agfl entries from leftover agbt allocations */ + int ar_flcount; }; /* Only the parts of struct xfs_rmap_irec that we need to compute refcounts. */ @@ -85,6 +79,7 @@ rmaps_destroy( struct xfs_mount *mp, struct xfs_ag_rmap *ag_rmap) { + free_slab(&ag_rmap->ar_agbtree_rmaps); free_slab(&ag_rmap->ar_refcount_items); if (!rmaps_has_observations(ag_rmap)) @@ -123,6 +118,11 @@ rmaps_init_ag( if (error) goto nomem; + error = init_slab(&ag_rmap->ar_agbtree_rmaps, + sizeof(struct xfs_rmap_irec)); + if (error) + goto nomem; + return; nomem: do_error( @@ -137,7 +137,6 @@ rmaps_init( struct xfs_mount *mp) { xfs_agnumber_t i; - int error; if (!rmap_needs_work(mp)) return; @@ -146,21 +145,8 @@ rmaps_init( if (!ag_rmaps) do_error(_("couldn't allocate per-AG reverse map roots\n")); - for (i = 0; i < mp->m_sb.sb_agcount; i++) { + for (i = 0; i < mp->m_sb.sb_agcount; i++) rmaps_init_ag(mp, i, &ag_rmaps[i]); - - error = init_slab(&ag_rmaps[i].ar_rmaps, - sizeof(struct xfs_rmap_irec)); - if (error) - do_error( -_("Insufficient memory while allocating reverse mapping slabs.")); - error = init_slab(&ag_rmaps[i].ar_raw_rmaps, - sizeof(struct xfs_rmap_irec)); - if (error) - do_error( -_("Insufficient memory while allocating raw metadata reverse mapping slabs.")); - ag_rmaps[i].ar_last_rmap.rm_owner = XFS_RMAP_OWN_UNKNOWN; - } } /* @@ -175,11 +161,8 @@ rmaps_free( if (!rmap_needs_work(mp)) return; - for (i = 0; i < mp->m_sb.sb_agcount; i++) { - free_slab(&ag_rmaps[i].ar_rmaps); - free_slab(&ag_rmaps[i].ar_raw_rmaps); + for (i = 0; i < mp->m_sb.sb_agcount; i++) rmaps_destroy(mp, &ag_rmaps[i]); - } free(ag_rmaps); ag_rmaps = NULL; } @@ -294,7 +277,7 @@ rmap_add_mem_rec( * Add an observation about a block mapping in an inode's data or attribute * fork for later btree reconstruction. */ -int +void rmap_add_rec( struct xfs_mount *mp, xfs_ino_t ino, @@ -304,11 +287,9 @@ rmap_add_rec( struct xfs_rmap_irec rmap; xfs_agnumber_t agno; xfs_agblock_t agbno; - struct xfs_rmap_irec *last_rmap; - int error = 0; if (!rmap_needs_work(mp)) - return 0; + return; agno = XFS_FSB_TO_AGNO(mp, irec->br_startblock); agbno = XFS_FSB_TO_AGBNO(mp, irec->br_startblock); @@ -329,36 +310,10 @@ rmap_add_rec( rmap.rm_flags |= XFS_RMAP_UNWRITTEN; rmap_add_mem_rec(mp, agno, &rmap); - - last_rmap = &ag_rmaps[agno].ar_last_rmap; - if (last_rmap->rm_owner == XFS_RMAP_OWN_UNKNOWN) - *last_rmap = rmap; - else if (rmaps_are_mergeable(last_rmap, &rmap)) - last_rmap->rm_blockcount += rmap.rm_blockcount; - else { - error = slab_add(ag_rmaps[agno].ar_rmaps, last_rmap); - if (error) - return error; - *last_rmap = rmap; - } - - return error; -} - -/* Finish collecting inode data/attr fork rmaps. */ -int -rmap_finish_collecting_fork_recs( - struct xfs_mount *mp, - xfs_agnumber_t agno) -{ - if (!rmap_needs_work(mp) || - ag_rmaps[agno].ar_last_rmap.rm_owner == XFS_RMAP_OWN_UNKNOWN) - return 0; - return slab_add(ag_rmaps[agno].ar_rmaps, &ag_rmaps[agno].ar_last_rmap); } /* add a raw rmap; these will be merged later */ -static int +static void __rmap_add_raw_rec( struct xfs_mount *mp, xfs_agnumber_t agno, @@ -382,13 +337,12 @@ __rmap_add_raw_rec( rmap.rm_blockcount = len; rmap_add_mem_rec(mp, agno, &rmap); - return slab_add(ag_rmaps[agno].ar_raw_rmaps, &rmap); } /* * Add a reverse mapping for an inode fork's block mapping btree block. */ -int +void rmap_add_bmbt_rec( struct xfs_mount *mp, xfs_ino_t ino, @@ -399,7 +353,7 @@ rmap_add_bmbt_rec( xfs_agblock_t agbno; if (!rmap_needs_work(mp)) - return 0; + return; agno = XFS_FSB_TO_AGNO(mp, fsbno); agbno = XFS_FSB_TO_AGBNO(mp, fsbno); @@ -407,14 +361,14 @@ rmap_add_bmbt_rec( ASSERT(agno < mp->m_sb.sb_agcount); ASSERT(agbno + 1 <= mp->m_sb.sb_agblocks); - return __rmap_add_raw_rec(mp, agno, agbno, 1, ino, - whichfork == XFS_ATTR_FORK, true); + __rmap_add_raw_rec(mp, agno, agbno, 1, ino, whichfork == XFS_ATTR_FORK, + true); } /* * Add a reverse mapping for a per-AG fixed metadata extent. */ -int +STATIC void rmap_add_ag_rec( struct xfs_mount *mp, xfs_agnumber_t agno, @@ -423,13 +377,13 @@ rmap_add_ag_rec( uint64_t owner) { if (!rmap_needs_work(mp)) - return 0; + return; ASSERT(agno != NULLAGNUMBER); ASSERT(agno < mp->m_sb.sb_agcount); ASSERT(agbno + len <= mp->m_sb.sb_agblocks); - return __rmap_add_raw_rec(mp, agno, agbno, len, owner, false, false); + __rmap_add_raw_rec(mp, agno, agbno, len, owner, false, false); } /* @@ -459,62 +413,7 @@ rmap_add_agbtree_mapping( assert(libxfs_verify_agbext(pag, agbno, len)); libxfs_perag_put(pag); - return slab_add(ag_rmaps[agno].ar_raw_rmaps, &rmap); -} - -/* - * Merge adjacent raw rmaps and add them to the main rmap list. - */ -int -rmap_fold_raw_recs( - struct xfs_mount *mp, - xfs_agnumber_t agno) -{ - struct xfs_slab_cursor *cur = NULL; - struct xfs_rmap_irec *prev, *rec; - uint64_t old_sz; - int error = 0; - - old_sz = slab_count(ag_rmaps[agno].ar_rmaps); - if (slab_count(ag_rmaps[agno].ar_raw_rmaps) == 0) - goto no_raw; - qsort_slab(ag_rmaps[agno].ar_raw_rmaps, rmap_compare); - error = init_slab_cursor(ag_rmaps[agno].ar_raw_rmaps, rmap_compare, - &cur); - if (error) - goto err; - - prev = pop_slab_cursor(cur); - rec = pop_slab_cursor(cur); - while (prev && rec) { - if (rmaps_are_mergeable(prev, rec)) { - prev->rm_blockcount += rec->rm_blockcount; - rec = pop_slab_cursor(cur); - continue; - } - error = slab_add(ag_rmaps[agno].ar_rmaps, prev); - if (error) - goto err; - prev = rec; - rec = pop_slab_cursor(cur); - } - if (prev) { - error = slab_add(ag_rmaps[agno].ar_rmaps, prev); - if (error) - goto err; - } - free_slab(&ag_rmaps[agno].ar_raw_rmaps); - error = init_slab(&ag_rmaps[agno].ar_raw_rmaps, - sizeof(struct xfs_rmap_irec)); - if (error) - do_error( -_("Insufficient memory while allocating raw metadata reverse mapping slabs.")); -no_raw: - if (old_sz) - qsort_slab(ag_rmaps[agno].ar_rmaps, rmap_compare); -err: - free_slab_cursor(&cur); - return error; + return slab_add(ag_rmaps[agno].ar_agbtree_rmaps, &rmap); } static int @@ -551,7 +450,7 @@ popcnt( * Add an allocation group's fixed metadata to the rmap list. This includes * sb/agi/agf/agfl headers, inode chunks, and the log. */ -int +void rmap_add_fixed_ag_rec( struct xfs_mount *mp, xfs_agnumber_t agno) @@ -560,18 +459,14 @@ rmap_add_fixed_ag_rec( xfs_agblock_t agbno; ino_tree_node_t *ino_rec; xfs_agino_t agino; - int error; int startidx; int nr; if (!rmap_needs_work(mp)) - return 0; + return; /* sb/agi/agf/agfl headers */ - error = rmap_add_ag_rec(mp, agno, 0, XFS_BNO_BLOCK(mp), - XFS_RMAP_OWN_FS); - if (error) - goto out; + rmap_add_ag_rec(mp, agno, 0, XFS_BNO_BLOCK(mp), XFS_RMAP_OWN_FS); /* inodes */ ino_rec = findfirst_inode_rec(agno); @@ -589,10 +484,8 @@ rmap_add_fixed_ag_rec( agino = ino_rec->ino_startnum + startidx; agbno = XFS_AGINO_TO_AGBNO(mp, agino); if (XFS_AGINO_TO_OFFSET(mp, agino) == 0) { - error = rmap_add_ag_rec(mp, agno, agbno, nr, + rmap_add_ag_rec(mp, agno, agbno, nr, XFS_RMAP_OWN_INODES); - if (error) - goto out; } } @@ -600,13 +493,9 @@ rmap_add_fixed_ag_rec( fsbno = mp->m_sb.sb_logstart; if (fsbno && XFS_FSB_TO_AGNO(mp, fsbno) == agno) { agbno = XFS_FSB_TO_AGBNO(mp, mp->m_sb.sb_logstart); - error = rmap_add_ag_rec(mp, agno, agbno, mp->m_sb.sb_logblocks, + rmap_add_ag_rec(mp, agno, agbno, mp->m_sb.sb_logblocks, XFS_RMAP_OWN_LOG); - if (error) - goto out; } -out: - return error; } /* @@ -647,12 +536,6 @@ rmap_commit_agbtree_mappings( if (!xfs_has_rmapbt(mp)) return 0; - /* Release the ar_rmaps; they were put into the rmapbt during p5. */ - free_slab(&ag_rmap->ar_rmaps); - error = init_slab(&ag_rmap->ar_rmaps, sizeof(struct xfs_rmap_irec)); - if (error) - goto err; - /* Add the AGFL blocks to the rmap list */ error = -libxfs_trans_read_buf( mp, NULL, mp->m_ddev_targp, @@ -676,7 +559,8 @@ rmap_commit_agbtree_mappings( * space btree blocks, so we must be careful not to create those * records again. Create a bitmap of already-recorded OWN_AG rmaps. */ - error = init_slab_cursor(ag_rmap->ar_raw_rmaps, rmap_compare, &rm_cur); + error = init_slab_cursor(ag_rmap->ar_agbtree_rmaps, rmap_compare, + &rm_cur); if (error) goto err; error = -bitmap_alloc(&own_ag_bitmap); @@ -709,7 +593,7 @@ rmap_commit_agbtree_mappings( agbno = be32_to_cpu(*b); if (!bitmap_test(own_ag_bitmap, agbno, 1)) { - error = rmap_add_ag_rec(mp, agno, agbno, 1, + error = rmap_add_agbtree_mapping(mp, agno, agbno, 1, XFS_RMAP_OWN_AG); if (error) goto err; @@ -720,13 +604,9 @@ rmap_commit_agbtree_mappings( agflbp = NULL; bitmap_free(&own_ag_bitmap); - /* Merge all the raw rmaps into the main list */ - error = rmap_fold_raw_recs(mp, agno); - if (error) - goto err; - /* Create cursors to rmap structures */ - error = init_slab_cursor(ag_rmap->ar_rmaps, rmap_compare, &rm_cur); + error = init_slab_cursor(ag_rmap->ar_agbtree_rmaps, rmap_compare, + &rm_cur); if (error) goto err; @@ -1094,6 +974,8 @@ compute_refcounts( if (!xfs_has_reflink(mp)) return 0; + if (!rmaps_has_observations(&ag_rmaps[agno])) + return 0; error = rmap_init_mem_cursor(mp, NULL, agno, &rmcur); if (error) @@ -1238,17 +1120,6 @@ rmap_record_count( return nr; } -/* - * Return a slab cursor that will return rmap objects in order. - */ -int -rmap_init_cursor( - xfs_agnumber_t agno, - struct xfs_slab_cursor **cur) -{ - return init_slab_cursor(ag_rmaps[agno].ar_rmaps, rmap_compare, cur); -} - /* * Disable the refcount btree check. */ diff --git a/repair/rmap.h b/repair/rmap.h index 2de3ec56f..683a51af3 100644 --- a/repair/rmap.h +++ b/repair/rmap.h @@ -14,23 +14,19 @@ extern bool rmap_needs_work(struct xfs_mount *); extern void rmaps_init(struct xfs_mount *); extern void rmaps_free(struct xfs_mount *); -extern int rmap_add_rec(struct xfs_mount *, xfs_ino_t, int, struct xfs_bmbt_irec *); -extern int rmap_finish_collecting_fork_recs(struct xfs_mount *mp, - xfs_agnumber_t agno); -extern int rmap_add_ag_rec(struct xfs_mount *, xfs_agnumber_t agno, - xfs_agblock_t agbno, xfs_extlen_t len, uint64_t owner); -extern int rmap_add_bmbt_rec(struct xfs_mount *, xfs_ino_t, int, xfs_fsblock_t); -extern int rmap_fold_raw_recs(struct xfs_mount *mp, xfs_agnumber_t agno); -extern bool rmaps_are_mergeable(struct xfs_rmap_irec *r1, struct xfs_rmap_irec *r2); +void rmap_add_rec(struct xfs_mount *mp, xfs_ino_t ino, int whichfork, + struct xfs_bmbt_irec *irec); +void rmap_add_bmbt_rec(struct xfs_mount *mp, xfs_ino_t ino, int whichfork, + xfs_fsblock_t fsbno); +bool rmaps_are_mergeable(struct xfs_rmap_irec *r1, struct xfs_rmap_irec *r2); -extern int rmap_add_fixed_ag_rec(struct xfs_mount *, xfs_agnumber_t); +void rmap_add_fixed_ag_rec(struct xfs_mount *mp, xfs_agnumber_t agno); int rmap_add_agbtree_mapping(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len, uint64_t owner); int rmap_commit_agbtree_mappings(struct xfs_mount *mp, xfs_agnumber_t agno); uint64_t rmap_record_count(struct xfs_mount *mp, xfs_agnumber_t agno); -extern int rmap_init_cursor(xfs_agnumber_t, struct xfs_slab_cursor **); extern void rmap_avoid_check(void); void rmaps_verify_btree(struct xfs_mount *mp, xfs_agnumber_t agno); diff --git a/repair/scan.c b/repair/scan.c index 715be1166..338308ef8 100644 --- a/repair/scan.c +++ b/repair/scan.c @@ -224,7 +224,6 @@ scan_bmapbt( xfs_agnumber_t agno; xfs_agblock_t agbno; int state; - int error; /* * unlike the ag freeblock btrees, if anything looks wrong @@ -415,12 +414,8 @@ _("bad state %d, inode %" PRIu64 " bmap block 0x%" PRIx64 "\n"), if (check_dups && collect_rmaps) { agno = XFS_FSB_TO_AGNO(mp, bno); pthread_mutex_lock(&ag_locks[agno].lock); - error = rmap_add_bmbt_rec(mp, ino, whichfork, bno); + rmap_add_bmbt_rec(mp, ino, whichfork, bno); pthread_mutex_unlock(&ag_locks[agno].lock); - if (error) - do_error( -_("couldn't add inode %"PRIu64" bmbt block %"PRIu64" reverse-mapping data."), - ino, bno); } if (level == 0) {