* [PATCH 48/52] xfs_scrub: trim realtime volumes too
2023-12-31 19:53 ` [PATCHSET v2.0 06/17] xfsprogs: shard the realtime section Darrick J. Wong
@ 2023-12-27 13:00 ` Darrick J. Wong
2023-12-27 13:00 ` [PATCH 49/52] xfs_scrub: use histograms to speed up phase 8 on the realtime volume Darrick J. Wong
` (50 subsequent siblings)
51 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:00 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
On the kernel side, the XFS realtime groups patchset added support for
FITRIM of the realtime volume. This support doesn't actually require
there to be any realtime groups, so teach scrub to run through the whole
region.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
scrub/phase8.c | 32 +++++++++++++++++++++++++++++---
1 file changed, 29 insertions(+), 3 deletions(-)
diff --git a/scrub/phase8.c b/scrub/phase8.c
index c6845555579..25d1ec3693e 100644
--- a/scrub/phase8.c
+++ b/scrub/phase8.c
@@ -59,7 +59,8 @@ fstrim_fsblocks(
struct scrub_ctx *ctx,
uint64_t start_fsb,
uint64_t fsbcount,
- uint64_t minlen_fsb)
+ uint64_t minlen_fsb,
+ bool ignore_einval)
{
uint64_t start = cvt_off_fsb_to_b(&ctx->mnt, start_fsb);
uint64_t len = cvt_off_fsb_to_b(&ctx->mnt, fsbcount);
@@ -72,6 +73,8 @@ fstrim_fsblocks(
run = min(len, FSTRIM_MAX_BYTES);
error = fstrim(ctx, start, run, minlen);
+ if (error == EINVAL && ignore_einval)
+ error = EOPNOTSUPP;
if (error == EOPNOTSUPP) {
/* Pretend we finished all the work. */
progress_add(len);
@@ -177,7 +180,8 @@ fstrim_datadev(
*/
progress_add(geo->blocksize);
fsbcount = min(geo->datablocks - fsbno + 1, geo->agblocks);
- error = fstrim_fsblocks(ctx, fsbno + 1, fsbcount, minlen_fsb);
+ error = fstrim_fsblocks(ctx, fsbno + 1, fsbcount, minlen_fsb,
+ false);
if (error)
return error;
}
@@ -185,15 +189,35 @@ fstrim_datadev(
return 0;
}
+/* Trim the realtime device. */
+static int
+fstrim_rtdev(
+ struct scrub_ctx *ctx)
+{
+ struct xfs_fsop_geom *geo = &ctx->mnt.fsgeom;
+
+ /*
+ * The fstrim ioctl pretends that the realtime volume is in the address
+ * space immediately after the data volume. Ignore EINVAL if someone
+ * tries to run us on an older kernel.
+ */
+ return fstrim_fsblocks(ctx, geo->datablocks, geo->rtblocks, 0, true);
+}
+
/* Trim the filesystem, if desired. */
int
phase8_func(
struct scrub_ctx *ctx)
{
+ int error;
+
if (!fstrim_ok(ctx))
return 0;
- return fstrim_datadev(ctx);
+ error = fstrim_datadev(ctx);
+ if (error)
+ return error;
+ return fstrim_rtdev(ctx);
}
/* Estimate how much work we're going to do. */
@@ -207,6 +231,8 @@ phase8_estimate(
if (fstrim_ok(ctx)) {
*items = cvt_off_fsb_to_b(&ctx->mnt,
ctx->mnt.fsgeom.datablocks);
+ *items += cvt_off_fsb_to_b(&ctx->mnt,
+ ctx->mnt.fsgeom.rtblocks);
} else {
*items = 0;
}
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 49/52] xfs_scrub: use histograms to speed up phase 8 on the realtime volume
2023-12-31 19:53 ` [PATCHSET v2.0 06/17] xfsprogs: shard the realtime section Darrick J. Wong
2023-12-27 13:00 ` [PATCH 48/52] xfs_scrub: trim realtime volumes too Darrick J. Wong
@ 2023-12-27 13:00 ` Darrick J. Wong
2023-12-27 13:00 ` [PATCH 50/52] mkfs: add headers to realtime bitmap blocks Darrick J. Wong
` (49 subsequent siblings)
51 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:00 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Use the same statistical methods that we use on the data volume to
compute the minimum threshold size for fstrims on the realtime volume.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
scrub/phase7.c | 7 +++++++
scrub/phase8.c | 6 +++++-
scrub/xfs_scrub.c | 2 ++
scrub/xfs_scrub.h | 1 +
4 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/scrub/phase7.c b/scrub/phase7.c
index 475d8f157ee..01097b67879 100644
--- a/scrub/phase7.c
+++ b/scrub/phase7.c
@@ -31,6 +31,7 @@ struct summary_counts {
/* Free space histogram, in fsb */
struct histogram datadev_hist;
+ struct histogram rtdev_hist;
};
/*
@@ -56,6 +57,7 @@ summary_count_init(
struct summary_counts *counts = data;
init_freesp_hist(&counts->datadev_hist);
+ init_freesp_hist(&counts->rtdev_hist);
}
/* Record block usage. */
@@ -83,6 +85,8 @@ count_block_summary(
blocks = cvt_b_to_off_fsbt(&ctx->mnt, fsmap->fmr_length);
if (fsmap->fmr_device == ctx->fsinfo.fs_datadev)
hist_add(&counts->datadev_hist, blocks);
+ else if (fsmap->fmr_device == ctx->fsinfo.fs_rtdev)
+ hist_add(&counts->rtdev_hist, blocks);
return 0;
}
@@ -124,7 +128,9 @@ add_summaries(
total->agbytes += item->agbytes;
hist_import(&total->datadev_hist, &item->datadev_hist);
+ hist_import(&total->rtdev_hist, &item->rtdev_hist);
hist_free(&item->datadev_hist);
+ hist_free(&item->rtdev_hist);
return 0;
}
@@ -195,6 +201,7 @@ phase7_func(
/* Preserve free space histograms for phase 8. */
hist_move(&ctx->datadev_hist, &totalcount.datadev_hist);
+ hist_move(&ctx->rtdev_hist, &totalcount.rtdev_hist);
/* Scan the whole fs. */
error = scrub_count_all_inodes(ctx, &counted_inodes);
diff --git a/scrub/phase8.c b/scrub/phase8.c
index 25d1ec3693e..d59bab7009c 100644
--- a/scrub/phase8.c
+++ b/scrub/phase8.c
@@ -195,13 +195,17 @@ fstrim_rtdev(
struct scrub_ctx *ctx)
{
struct xfs_fsop_geom *geo = &ctx->mnt.fsgeom;
+ uint64_t minlen_fsb;
+
+ minlen_fsb = fstrim_compute_minlen(ctx, &ctx->rtdev_hist);
/*
* The fstrim ioctl pretends that the realtime volume is in the address
* space immediately after the data volume. Ignore EINVAL if someone
* tries to run us on an older kernel.
*/
- return fstrim_fsblocks(ctx, geo->datablocks, geo->rtblocks, 0, true);
+ return fstrim_fsblocks(ctx, geo->datablocks, geo->rtblocks,
+ minlen_fsb, true);
}
/* Trim the filesystem, if desired. */
diff --git a/scrub/xfs_scrub.c b/scrub/xfs_scrub.c
index 7c73e4d3cca..c510d9534a8 100644
--- a/scrub/xfs_scrub.c
+++ b/scrub/xfs_scrub.c
@@ -713,6 +713,7 @@ main(
int error;
hist_init(&ctx.datadev_hist);
+ hist_init(&ctx.rtdev_hist);
fprintf(stdout, "EXPERIMENTAL xfs_scrub program in use! Use at your own risk!\n");
fflush(stdout);
@@ -944,6 +945,7 @@ main(
unicrash_unload();
hist_free(&ctx.datadev_hist);
+ hist_free(&ctx.rtdev_hist);
/*
* If we're being run as a service, the return code must fit the LSB
diff --git a/scrub/xfs_scrub.h b/scrub/xfs_scrub.h
index 4d9a028921b..8389551c067 100644
--- a/scrub/xfs_scrub.h
+++ b/scrub/xfs_scrub.h
@@ -94,6 +94,7 @@ struct scrub_ctx {
/* Free space histograms, in fsb */
struct histogram datadev_hist;
+ struct histogram rtdev_hist;
/*
* Pick the largest value for fstrim minlen such that we trim at least
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 50/52] mkfs: add headers to realtime bitmap blocks
2023-12-31 19:53 ` [PATCHSET v2.0 06/17] xfsprogs: shard the realtime section Darrick J. Wong
2023-12-27 13:00 ` [PATCH 48/52] xfs_scrub: trim realtime volumes too Darrick J. Wong
2023-12-27 13:00 ` [PATCH 49/52] xfs_scrub: use histograms to speed up phase 8 on the realtime volume Darrick J. Wong
@ 2023-12-27 13:00 ` Darrick J. Wong
2023-12-27 13:00 ` [PATCH 51/52] mkfs: add headers to realtime summary blocks Darrick J. Wong
` (48 subsequent siblings)
51 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:00 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
When the rtgroups feature is enabled, format rtbitmap blocks with the
appropriate block headers.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
mkfs/proto.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
mkfs/xfs_mkfs.c | 6 +++++-
2 files changed, 56 insertions(+), 1 deletion(-)
diff --git a/mkfs/proto.c b/mkfs/proto.c
index 36df148018f..f5b7859f9a9 100644
--- a/mkfs/proto.c
+++ b/mkfs/proto.c
@@ -852,6 +852,50 @@ rtsummary_create(
mp->m_rsumip = rsumip;
}
+/* Initialize block headers of rt free space files. */
+static int
+init_rtblock_headers(
+ struct xfs_inode *ip,
+ xfs_fileoff_t nrblocks,
+ const struct xfs_buf_ops *ops,
+ uint32_t magic)
+{
+ struct xfs_bmbt_irec map;
+ struct xfs_mount *mp = ip->i_mount;
+ struct xfs_rtbuf_blkinfo *hdr;
+ xfs_fileoff_t off = 0;
+ int error;
+
+ while (off < nrblocks) {
+ struct xfs_buf *bp;
+ xfs_daddr_t daddr;
+ int nimaps = 1;
+
+ error = -libxfs_bmapi_read(ip, off, 1, &map, &nimaps, 0);
+ if (error)
+ return error;
+
+ daddr = XFS_FSB_TO_DADDR(mp, map.br_startblock);
+ error = -libxfs_buf_get(mp->m_ddev_targp, daddr,
+ XFS_FSB_TO_BB(mp, map.br_blockcount), &bp);
+ if (error)
+ return error;
+
+ bp->b_ops = ops;
+ hdr = bp->b_addr;
+ hdr->rt_magic = cpu_to_be32(magic);
+ hdr->rt_owner = cpu_to_be64(ip->i_ino);
+ hdr->rt_blkno = cpu_to_be64(daddr);
+ platform_uuid_copy(&hdr->rt_uuid, &mp->m_sb.sb_meta_uuid);
+ libxfs_buf_mark_dirty(bp);
+ libxfs_buf_relse(bp);
+
+ off = map.br_startoff + map.br_blockcount;
+ }
+
+ return 0;
+}
+
/* Zero the realtime bitmap. */
static void
rtbitmap_init(
@@ -895,6 +939,13 @@ rtbitmap_init(
if (error)
fail(_("Block allocation of the realtime bitmap inode failed"),
error);
+
+ if (xfs_has_rtgroups(mp)) {
+ error = init_rtblock_headers(mp->m_rbmip, mp->m_sb.sb_rbmblocks,
+ &xfs_rtbitmap_buf_ops, XFS_RTBITMAP_MAGIC);
+ if (error)
+ fail(_("Initialization of rtbitmap failed"), error);
+ }
}
/* Zero the realtime summary file. */
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 2330ebebfae..aab1d9130b2 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -909,6 +909,7 @@ struct sb_feat_args {
bool nodalign;
bool nortalign;
bool nrext64;
+ bool rtgroups; /* XFS_SB_FEAT_COMPAT_RTGROUPS */
};
struct cli_params {
@@ -3124,6 +3125,7 @@ validate_rtdev(
struct cli_params *cli)
{
struct libxfs_init *xi = cli->xi;
+ unsigned int rbmblocksize = cfg->blocksize;
if (!xi->rt.dev) {
if (cli->rtsize) {
@@ -3167,8 +3169,10 @@ reported by the device (%u).\n"),
_("cannot have an rt subvolume with zero extents\n"));
usage();
}
+ if (cfg->sb_feat.rtgroups)
+ rbmblocksize -= sizeof(struct xfs_rtbuf_blkinfo);
cfg->rtbmblocks = (xfs_extlen_t)howmany(cfg->rtextents,
- NBBY * cfg->blocksize);
+ NBBY * rbmblocksize);
}
static bool
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 51/52] mkfs: add headers to realtime summary blocks
2023-12-31 19:53 ` [PATCHSET v2.0 06/17] xfsprogs: shard the realtime section Darrick J. Wong
` (2 preceding siblings ...)
2023-12-27 13:00 ` [PATCH 50/52] mkfs: add headers to realtime bitmap blocks Darrick J. Wong
@ 2023-12-27 13:00 ` Darrick J. Wong
2023-12-27 13:01 ` [PATCH 52/52] mkfs: format realtime groups Darrick J. Wong
` (47 subsequent siblings)
51 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:00 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
When the rtgroups feature is enabled, format rtsummary blocks with the
appropriate block headers.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
mkfs/proto.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/mkfs/proto.c b/mkfs/proto.c
index f5b7859f9a9..b89b114d0d6 100644
--- a/mkfs/proto.c
+++ b/mkfs/proto.c
@@ -991,6 +991,14 @@ rtsummary_init(
if (error)
fail(_("Block allocation of the realtime summary inode failed"),
error);
+
+ if (xfs_has_rtgroups(mp)) {
+ error = init_rtblock_headers(mp->m_rsumip,
+ XFS_B_TO_FSB(mp, mp->m_rsumsize),
+ &xfs_rtsummary_buf_ops, XFS_RTSUMMARY_MAGIC);
+ if (error)
+ fail(_("Initialization of rtsummary failed"), error);
+ }
}
/*
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 52/52] mkfs: format realtime groups
2023-12-31 19:53 ` [PATCHSET v2.0 06/17] xfsprogs: shard the realtime section Darrick J. Wong
` (3 preceding siblings ...)
2023-12-27 13:00 ` [PATCH 51/52] mkfs: add headers to realtime summary blocks Darrick J. Wong
@ 2023-12-27 13:01 ` Darrick J. Wong
2023-12-31 23:47 ` [PATCH 01/52] xfs: create incore realtime group structures Darrick J. Wong
` (46 subsequent siblings)
51 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:01 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Create filesystems with the realtime group feature enabled.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libfrog/div64.h | 6 +
libfrog/util.c | 12 ++
libfrog/util.h | 1
libxfs/libxfs_api_defs.h | 1
libxfs/libxfs_priv.h | 6 -
libxfs/topology.c | 42 +++++++
libxfs/topology.h | 3 +
libxfs/xfs_format.h | 1
man/man8/mkfs.xfs.8.in | 44 +++++++
mkfs/proto.c | 45 +++++++-
mkfs/xfs_mkfs.c | 272 ++++++++++++++++++++++++++++++++++++++++++++++
11 files changed, 425 insertions(+), 8 deletions(-)
diff --git a/libfrog/div64.h b/libfrog/div64.h
index 673b01cbab3..4b0d4c3b3c7 100644
--- a/libfrog/div64.h
+++ b/libfrog/div64.h
@@ -93,4 +93,10 @@ howmany_64(uint64_t x, uint32_t y)
return x;
}
+static inline __attribute__((const))
+int is_power_of_2(unsigned long n)
+{
+ return (n != 0 && ((n & (n - 1)) == 0));
+}
+
#endif /* LIBFROG_DIV64_H_ */
diff --git a/libfrog/util.c b/libfrog/util.c
index 46047571a55..4e130c884c1 100644
--- a/libfrog/util.c
+++ b/libfrog/util.c
@@ -36,3 +36,15 @@ memchr_inv(const void *start, int c, size_t bytes)
return NULL;
}
+
+unsigned int
+log2_rounddown(unsigned long long i)
+{
+ int rval;
+
+ for (rval = NBBY * sizeof(i) - 1; rval >= 0; rval--) {
+ if ((1ULL << rval) < i)
+ break;
+ }
+ return rval;
+}
diff --git a/libfrog/util.h b/libfrog/util.h
index ac2f331c93e..b0715576e8d 100644
--- a/libfrog/util.h
+++ b/libfrog/util.h
@@ -7,6 +7,7 @@
#define __LIBFROG_UTIL_H__
unsigned int log2_roundup(unsigned int i);
+unsigned int log2_rounddown(unsigned long long i);
void *memchr_inv(const void *start, int c, size_t bytes);
diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
index a3503e07984..c5dad34f3d2 100644
--- a/libxfs/libxfs_api_defs.h
+++ b/libxfs/libxfs_api_defs.h
@@ -80,6 +80,7 @@
#define xfs_btree_update libxfs_btree_update
#define xfs_btree_space_to_height libxfs_btree_space_to_height
#define xfs_btree_visit_blocks libxfs_btree_visit_blocks
+#define xfs_buf_delwri_queue libxfs_buf_delwri_queue
#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
diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h
index 4e4a51637e6..120a41e20a7 100644
--- a/libxfs/libxfs_priv.h
+++ b/libxfs/libxfs_priv.h
@@ -337,12 +337,6 @@ find_next_zero_bit(const unsigned long *addr, unsigned long size,
}
#define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0)
-static inline __attribute__((const))
-int is_power_of_2(unsigned long n)
-{
- return (n != 0 && ((n & (n - 1)) == 0));
-}
-
/*
* xfs_iroundup: round up argument to next power of two
*/
diff --git a/libxfs/topology.c b/libxfs/topology.c
index 06013d42945..b87731820c4 100644
--- a/libxfs/topology.c
+++ b/libxfs/topology.c
@@ -89,6 +89,48 @@ calc_default_ag_geometry(
*agcount = dblocks / blocks + (dblocks % blocks != 0);
}
+void
+calc_default_rtgroup_geometry(
+ int blocklog,
+ uint64_t rblocks,
+ uint64_t *rgsize,
+ uint64_t *rgcount)
+{
+ uint64_t blocks = 0;
+ int shift = 0;
+
+ /*
+ * For a single underlying storage device over 4TB in size use the
+ * maximum rtgroup size. Between 128MB and 4TB, just use 4 rtgroups
+ * and scale up smoothly between min/max rtgroup sizes.
+ */
+ if (rblocks >= TERABYTES(4, blocklog)) {
+ blocks = XFS_MAX_RGBLOCKS;
+ goto done;
+ }
+ if (rblocks >= MEGABYTES(128, blocklog)) {
+ shift = XFS_NOMULTIDISK_AGLOG;
+ goto calc_blocks;
+ }
+
+ /*
+ * If rblocks is not evenly divisible by the number of desired rt
+ * groups, round "blocks" up so we don't lose the last bit of the
+ * filesystem. The same principle applies to the rt group count, so we
+ * don't lose the last rt group!
+ */
+calc_blocks:
+ ASSERT(shift >= 0 && shift <= XFS_MULTIDISK_AGLOG);
+ blocks = rblocks >> shift;
+ if (rblocks & xfs_mask32lo(shift)) {
+ if (blocks < XFS_MAX_RGBLOCKS)
+ blocks++;
+ }
+done:
+ *rgsize = blocks;
+ *rgcount = rblocks / blocks + (rblocks % blocks != 0);
+}
+
/*
* Check for existing filesystem or partition table on device.
* Returns:
diff --git a/libxfs/topology.h b/libxfs/topology.h
index 1af5b054947..f1174bb4bab 100644
--- a/libxfs/topology.h
+++ b/libxfs/topology.h
@@ -32,6 +32,9 @@ calc_default_ag_geometry(
uint64_t *agsize,
uint64_t *agcount);
+void calc_default_rtgroup_geometry(int blocklog, uint64_t rblocks,
+ uint64_t *rgsize, uint64_t *rgcount);
+
extern int
check_overwrite(
const char *device);
diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
index 59ba13db53e..87476c6bb6c 100644
--- a/libxfs/xfs_format.h
+++ b/libxfs/xfs_format.h
@@ -418,6 +418,7 @@ xfs_sb_has_ro_compat_feature(
XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR| \
XFS_SB_FEAT_INCOMPAT_NREXT64| \
XFS_SB_FEAT_INCOMPAT_PARENT | \
+ XFS_SB_FEAT_INCOMPAT_RTGROUPS | \
XFS_SB_FEAT_INCOMPAT_METADIR)
#define XFS_SB_FEAT_INCOMPAT_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_ALL
diff --git a/man/man8/mkfs.xfs.8.in b/man/man8/mkfs.xfs.8.in
index 587754ff95b..e0175ca04b4 100644
--- a/man/man8/mkfs.xfs.8.in
+++ b/man/man8/mkfs.xfs.8.in
@@ -1116,6 +1116,50 @@ or logical volume containing the section.
.BI noalign
This option disables stripe size detection, enforcing a realtime device with no
stripe geometry.
+.TP
+.BI rtgroups= value
+This feature breaks the realtime section into multiple allocation groups for
+improved scalability.
+This feature is only available if the metadata directory tree feature is
+enabled.
+.IP
+By default,
+.B mkfs.xfs
+will not enable this feature.
+If the option
+.B \-r rtgroups=0
+is used, the rt group feature is not supported and is disabled.
+.TP
+.BI rgcount=
+This is used to specify the number of allocation groups in the realtime
+section.
+The realtime section of the filesystem can be divided into allocation groups to
+improve the performance of XFS.
+More allocation groups imply that more parallelism can be achieved when
+allocating blocks.
+The minimum allocation group size is 2 realtime extents; the maximum size is
+2^31 blocks.
+The rt section of the filesystem is divided into
+.I value
+allocation groups (default value is scaled automatically based
+on the underlying device size).
+.TP
+.BI rgsize= value
+This is an alternative to using the
+.B rgcount
+suboption. The
+.I value
+is the desired size of the realtime allocation group expressed in bytes
+(usually using the
+.BR m " or " g
+suffixes).
+This value must be a multiple of the realtime extent size,
+must be at least two realtime extents, and no more than 2^31 blocks.
+The
+.B rgcount
+and
+.B rgsize
+suboptions are mutually exclusive.
.RE
.PP
.PD 0
diff --git a/mkfs/proto.c b/mkfs/proto.c
index b89b114d0d6..5239f9ec413 100644
--- a/mkfs/proto.c
+++ b/mkfs/proto.c
@@ -1001,6 +1001,46 @@ rtsummary_init(
}
}
+static void
+rtfreesp_init_groups(
+ struct xfs_mount *mp)
+{
+ xfs_rgnumber_t rgno;
+ int error;
+
+ for (rgno = 0; rgno < mp->m_sb.sb_rgcount; rgno++) {
+ struct xfs_trans *tp;
+ xfs_rtblock_t rtbno;
+ xfs_rtxnum_t start_rtx;
+ xfs_rtxnum_t next_rtx;
+
+ rtbno = xfs_rgbno_to_rtb(mp, rgno, mp->m_sb.sb_rextsize);
+ start_rtx = xfs_rtb_to_rtx(mp, rtbno);
+
+ rtbno = xfs_rgbno_to_rtb(mp, rgno + 1, 0);
+ next_rtx = xfs_rtb_to_rtx(mp, rtbno);
+ next_rtx = min(next_rtx, mp->m_sb.sb_rextents);
+
+ error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate,
+ 0, 0, 0, &tp);
+ if (error)
+ res_failed(error);
+
+ libxfs_trans_ijoin(tp, mp->m_rbmip, 0);
+ error = -libxfs_rtfree_extent(tp, start_rtx,
+ next_rtx - start_rtx);
+ if (error) {
+ fail(_("Error initializing the realtime space"),
+ error);
+ }
+ error = -libxfs_trans_commit(tp);
+ if (error)
+ fail(_("Initialization of the realtime space failed"),
+ error);
+
+ }
+}
+
/*
* Free the whole realtime area using transactions.
* Do one transaction per bitmap block.
@@ -1049,7 +1089,10 @@ rtinit(
rtbitmap_init(mp);
rtsummary_init(mp);
- rtfreesp_init(mp);
+ if (xfs_has_rtgroups(mp))
+ rtfreesp_init_groups(mp);
+ else
+ rtfreesp_init(mp);
}
static long
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index aab1d9130b2..66532b8c9b6 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -131,6 +131,9 @@ enum {
R_FILE,
R_NAME,
R_NOALIGN,
+ R_RTGROUPS,
+ R_RGCOUNT,
+ R_RGSIZE,
R_MAX_OPTS,
};
@@ -718,6 +721,9 @@ static struct opt_params ropts = {
[R_FILE] = "file",
[R_NAME] = "name",
[R_NOALIGN] = "noalign",
+ [R_RTGROUPS] = "rtgroups",
+ [R_RGCOUNT] = "rgcount",
+ [R_RGSIZE] = "rgsize",
[R_MAX_OPTS] = NULL,
},
.subopt_params = {
@@ -757,6 +763,27 @@ static struct opt_params ropts = {
.defaultval = 1,
.conflicts = { { NULL, LAST_CONFLICT } },
},
+ { .index = R_RTGROUPS,
+ .conflicts = { { NULL, LAST_CONFLICT } },
+ .minval = 0,
+ .maxval = 1,
+ .defaultval = 1,
+ },
+ { .index = R_RGCOUNT,
+ .conflicts = { { &dopts, R_RGSIZE },
+ { NULL, LAST_CONFLICT } },
+ .minval = 1,
+ .maxval = XFS_MAX_RGNUMBER,
+ .defaultval = SUBOPT_NEEDS_VAL,
+ },
+ { .index = R_RGSIZE,
+ .conflicts = { { &dopts, R_RGCOUNT },
+ { NULL, LAST_CONFLICT } },
+ .convert = true,
+ .minval = 0,
+ .maxval = (unsigned long long)XFS_MAX_RGBLOCKS << XFS_MAX_BLOCKSIZE_LOG,
+ .defaultval = SUBOPT_NEEDS_VAL,
+ },
},
};
@@ -922,6 +949,7 @@ struct cli_params {
/* parameters that depend on sector/block size being validated. */
char *dsize;
char *agsize;
+ char *rgsize;
char *dsu;
char *dirblocksize;
char *logsize;
@@ -943,6 +971,7 @@ struct cli_params {
/* parameters where 0 is not a valid value */
int64_t agcount;
+ int64_t rgcount;
int inodesize;
int inopblock;
int imaxpct;
@@ -999,6 +1028,9 @@ struct mkfs_params {
uint64_t agsize;
uint64_t agcount;
+ uint64_t rgsize;
+ uint64_t rgcount;
+
int imaxpct;
bool loginternal;
@@ -1055,7 +1087,8 @@ usage( void )
/* no-op info only */ [-N]\n\
/* prototype file */ [-p fname]\n\
/* quiet */ [-q]\n\
-/* realtime subvol */ [-r extsize=num,size=num,rtdev=xxx]\n\
+/* realtime subvol */ [-r extsize=num,size=num,rtdev=xxx,rtgroups=0|1,\n\
+ rgcount=n,rgsize=n]\n\
/* sectorsize */ [-s size=num]\n\
/* version */ [-V]\n\
devicename\n\
@@ -1952,6 +1985,15 @@ rtdev_opts_parser(
case R_NOALIGN:
cli->sb_feat.nortalign = getnum(value, opts, subopt);
break;
+ case R_RTGROUPS:
+ cli->sb_feat.rtgroups = getnum(value, opts, subopt);
+ break;
+ case R_RGCOUNT:
+ cli->rgcount = getnum(value, opts, subopt);
+ break;
+ case R_RGSIZE:
+ cli->rgsize = getstr(value, opts, subopt);
+ break;
default:
return -EINVAL;
}
@@ -2447,6 +2489,15 @@ _("cowextsize not supported without reflink support\n"));
usage();
}
+ if (cli->sb_feat.rtgroups && !cli->sb_feat.metadir) {
+ if (cli_opt_set(&mopts, M_METADIR)) {
+ fprintf(stderr,
+_("realtime groups not supported without metadata directory support\n"));
+ usage();
+ }
+ cli->sb_feat.metadir = true;
+ }
+
/*
* Copy features across to config structure now.
*/
@@ -3413,6 +3464,181 @@ an AG size that is one stripe unit smaller or larger, for example %llu.\n"),
cfg->agsize, cfg->agcount);
}
+static uint64_t
+calc_rgsize_extsize_nonpower(
+ struct mkfs_params *cfg)
+{
+ uint64_t try_rgsize, rgsize, rgcount;
+
+ /*
+ * For non-power-of-two rt extent sizes, round the rtgroup size down to
+ * the nearest extent.
+ */
+ calc_default_rtgroup_geometry(cfg->blocklog, cfg->rtblocks, &rgsize,
+ &rgcount);
+ rgsize -= rgsize % cfg->rtextblocks;
+ rgsize = min(XFS_MAX_RGBLOCKS, rgsize);
+
+ /*
+ * If we would be left with a too-small rtgroup, increase or decrease
+ * the size of the group until we have a working geometry.
+ */
+ for (try_rgsize = rgsize;
+ try_rgsize <= XFS_MAX_RGBLOCKS - cfg->rtextblocks;
+ try_rgsize += cfg->rtextblocks) {
+ if (cfg->rtblocks % try_rgsize >= (2 * cfg->rtextblocks))
+ return try_rgsize;
+ }
+ for (try_rgsize = rgsize;
+ try_rgsize > (2 * cfg->rtextblocks);
+ try_rgsize -= cfg->rtextblocks) {
+ if (cfg->rtblocks % try_rgsize >= (2 * cfg->rtextblocks))
+ return try_rgsize;
+ }
+
+ fprintf(stderr,
+_("realtime group size (%llu) not at all congruent with extent size (%llu)\n"),
+ (unsigned long long)rgsize,
+ (unsigned long long)cfg->rtextblocks);
+ usage();
+ return 0;
+}
+
+static uint64_t
+calc_rgsize_extsize_power(
+ struct mkfs_params *cfg)
+{
+ uint64_t try_rgsize, rgsize, rgcount;
+ unsigned int rgsizelog;
+
+ /*
+ * Find the rt group size that is both a power of two and yields at
+ * least as many rt groups as the default geometry specified.
+ */
+ calc_default_rtgroup_geometry(cfg->blocklog, cfg->rtblocks, &rgsize,
+ &rgcount);
+ rgsizelog = log2_rounddown(rgsize);
+ rgsize = min(XFS_MAX_RGBLOCKS, 1U << rgsizelog);
+
+ /*
+ * If we would be left with a too-small rtgroup, increase or decrease
+ * the size of the group by powers of 2 until we have a working
+ * geometry. If that doesn't work, try bumping by the extent size.
+ */
+ for (try_rgsize = rgsize;
+ try_rgsize <= XFS_MAX_RGBLOCKS - cfg->rtextblocks;
+ try_rgsize <<= 2) {
+ if (cfg->rtblocks % try_rgsize >= (2 * cfg->rtextblocks))
+ return try_rgsize;
+ }
+ for (try_rgsize = rgsize;
+ try_rgsize > (2 * cfg->rtextblocks);
+ try_rgsize >>= 2) {
+ if (cfg->rtblocks % try_rgsize >= (2 * cfg->rtextblocks))
+ return try_rgsize;
+ }
+ for (try_rgsize = rgsize;
+ try_rgsize <= XFS_MAX_RGBLOCKS - cfg->rtextblocks;
+ try_rgsize += cfg->rtextblocks) {
+ if (cfg->rtblocks % try_rgsize >= (2 * cfg->rtextblocks))
+ return try_rgsize;
+ }
+ for (try_rgsize = rgsize;
+ try_rgsize > (2 * cfg->rtextblocks);
+ try_rgsize -= cfg->rtextblocks) {
+ if (cfg->rtblocks % try_rgsize >= (2 * cfg->rtextblocks))
+ return try_rgsize;
+ }
+
+ fprintf(stderr,
+_("realtime group size (%llu) not at all congruent with extent size (%llu)\n"),
+ (unsigned long long)rgsize,
+ (unsigned long long)cfg->rtextblocks);
+ usage();
+ return 0;
+}
+
+static void
+calculate_rtgroup_geometry(
+ struct mkfs_params *cfg,
+ struct cli_params *cli)
+{
+ if (!cli->sb_feat.rtgroups) {
+ cfg->rgcount = 0;
+ cfg->rgsize = 0;
+ return;
+ }
+
+ if (cli->rgsize) { /* User-specified rtgroup size */
+ cfg->rgsize = getnum(cli->rgsize, &ropts, R_RGSIZE);
+
+ /*
+ * Check specified agsize is a multiple of blocksize.
+ */
+ if (cfg->rgsize % cfg->blocksize) {
+ fprintf(stderr,
+_("rgsize (%s) not a multiple of fs blk size (%d)\n"),
+ cli->rgsize, cfg->blocksize);
+ usage();
+ }
+ cfg->rgsize /= cfg->blocksize;
+ cfg->rgcount = cfg->rtblocks / cfg->rgsize +
+ (cfg->rtblocks % cfg->rgsize != 0);
+
+ } else if (cli->rgcount) { /* User-specified rtgroup count */
+ cfg->rgcount = cli->rgcount;
+ cfg->rgsize = cfg->rtblocks / cfg->rgcount +
+ (cfg->rtblocks % cfg->rgcount != 0);
+ } else if (cfg->rtblocks == 0) {
+ /*
+ * If nobody specified a realtime device or the rtgroup size,
+ * try 1TB, rounded down to the nearest rt extent.
+ */
+ cfg->rgsize = TERABYTES(1, cfg->blocklog);
+ cfg->rgsize -= cfg->rgsize % cfg->rtextblocks;
+ cfg->rgcount = 0;
+ } else if (!is_power_of_2(cfg->rtextblocks)) {
+ cfg->rgsize = calc_rgsize_extsize_nonpower(cfg);
+ cfg->rgcount = cfg->rtblocks / cfg->rgsize +
+ (cfg->rtblocks % cfg->rgsize != 0);
+ } else {
+ cfg->rgsize = calc_rgsize_extsize_power(cfg);
+ cfg->rgcount = cfg->rtblocks / cfg->rgsize +
+ (cfg->rtblocks % cfg->rgsize != 0);
+ }
+
+ if (cfg->rgsize > XFS_MAX_RGBLOCKS) {
+ fprintf(stderr,
+_("realtime group size (%llu) must be less than the maximum (%u)\n"),
+ (unsigned long long)cfg->rgsize,
+ XFS_MAX_RGBLOCKS);
+ usage();
+ }
+
+ if (cfg->rgsize % cfg->rtextblocks != 0) {
+ fprintf(stderr,
+_("realtime group size (%llu) not a multiple of rt extent size (%llu)\n"),
+ (unsigned long long)cfg->rgsize,
+ (unsigned long long)cfg->rtextblocks);
+ usage();
+ }
+
+ if (cfg->rgsize <= cfg->rtextblocks) {
+ fprintf(stderr,
+_("realtime group size (%llu) must be at least two realtime extents\n"),
+ (unsigned long long)cfg->rgsize);
+ usage();
+ }
+
+ if (cfg->rgcount > XFS_MAX_RGNUMBER) {
+ fprintf(stderr,
+_("realtime group count (%llu) must be less than the maximum (%u)\n"),
+ (unsigned long long)cfg->rgcount,
+ XFS_MAX_RGNUMBER);
+ usage();
+ }
+}
+
static void
calculate_imaxpct(
struct mkfs_params *cfg,
@@ -3552,6 +3778,12 @@ sb_set_features(
if (fp->nrext64)
sbp->sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_NREXT64;
+
+ if (fp->rtgroups) {
+ sbp->sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_RTGROUPS;
+ sbp->sb_rgcount = cfg->rgcount;
+ sbp->sb_rgblocks = cfg->rgsize;
+ }
}
/*
@@ -4327,6 +4559,7 @@ main(
char **argv)
{
xfs_agnumber_t agno;
+ xfs_rgnumber_t rgno;
struct xfs_buf *buf;
int c;
int dry_run = 0;
@@ -4536,6 +4769,7 @@ main(
*/
calculate_initial_ag_geometry(&cfg, &cli, &xi);
align_ag_geometry(&cfg);
+ calculate_rtgroup_geometry(&cfg, &cli);
calculate_imaxpct(&cfg, &cli);
@@ -4636,6 +4870,42 @@ main(
exit(1);
}
+ /* Write all the realtime group superblocks. */
+ for (rgno = 0; rgno < cfg.rgcount; rgno++) {
+ struct xfs_buf *rtsb_bp;
+ struct xfs_buf *sb_bp = libxfs_getsb(mp);
+
+ if (!sb_bp) {
+ fprintf(stderr,
+ _("%s: couldn't grab buffers to write primary rt superblock\n"), progname);
+ exit(1);
+ }
+
+ error = -libxfs_buf_get_uncached(mp->m_rtdev_targp,
+ XFS_FSB_TO_BB(mp, 1), 0,
+ &rtsb_bp);
+ if (error) {
+ fprintf(stderr,
+ _("%s: couldn't grab primary rt superblock\n"), progname);
+ exit(1);
+ }
+ rtsb_bp->b_maps[0].bm_bn = XFS_RTSB_DADDR;
+ rtsb_bp->b_ops = &xfs_rtsb_buf_ops;
+
+ libxfs_rtgroup_update_super(rtsb_bp, sb_bp);
+ libxfs_buf_mark_dirty(rtsb_bp);
+ libxfs_buf_relse(rtsb_bp);
+ libxfs_buf_relse(sb_bp);
+
+ error = -libxfs_rtgroup_update_secondary_sbs(mp);
+ if (error) {
+ fprintf(stderr,
+ _("%s: writing secondary rtgroup headers failed, err=%d\n"),
+ progname, error);
+ exit(1);
+ }
+ }
+
/*
* Initialise the freespace freelists (i.e. AGFLs) in each AG.
*/
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 01/14] xfs: replace shouty XFS_BM{BT,DR} macros
2023-12-31 19:53 ` [PATCHSET v2.0 07/17] xfsprogs: refactor btrees to support records in inode root Darrick J. Wong
@ 2023-12-27 13:01 ` Darrick J. Wong
2023-12-27 13:01 ` [PATCH 02/14] xfs: refactor the allocation and freeing of incore inode fork btree roots Darrick J. Wong
` (12 subsequent siblings)
13 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:01 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Replace all the shouty bmap btree and bmap disk root macros with actual
functions, and fix a type handling error in the xattr code that the
macros previously didn't care about.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
db/bmap.c | 10 +-
db/bmap_inflate.c | 2
db/bmroot.c | 8 +-
db/check.c | 8 +-
db/frag.c | 8 +-
db/metadump.c | 16 ++--
libxfs/xfs_attr_leaf.c | 8 +-
libxfs/xfs_bmap.c | 40 +++++----
libxfs/xfs_bmap_btree.c | 18 ++--
libxfs/xfs_bmap_btree.h | 204 ++++++++++++++++++++++++++++++++---------------
libxfs/xfs_inode_fork.c | 30 +++----
libxfs/xfs_trans_resv.c | 2
repair/bmap_repair.c | 2
repair/dinode.c | 10 +-
repair/prefetch.c | 8 +-
repair/scan.c | 6 +
16 files changed, 228 insertions(+), 152 deletions(-)
diff --git a/db/bmap.c b/db/bmap.c
index 874135f001e..7915772aaee 100644
--- a/db/bmap.c
+++ b/db/bmap.c
@@ -78,8 +78,8 @@ bmap(
push_cur();
rblock = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
fsize = XFS_DFORK_SIZE(dip, mp, whichfork);
- pp = XFS_BMDR_PTR_ADDR(rblock, 1, libxfs_bmdr_maxrecs(fsize, 0));
- kp = XFS_BMDR_KEY_ADDR(rblock, 1);
+ pp = xfs_bmdr_ptr_addr(rblock, 1, libxfs_bmdr_maxrecs(fsize, 0));
+ kp = xfs_bmdr_key_addr(rblock, 1);
bno = select_child(curoffset, kp, pp,
be16_to_cpu(rblock->bb_numrecs));
for (;;) {
@@ -88,9 +88,9 @@ bmap(
block = (struct xfs_btree_block *)iocur_top->data;
if (be16_to_cpu(block->bb_level) == 0)
break;
- pp = XFS_BMBT_PTR_ADDR(mp, block, 1,
+ pp = xfs_bmbt_ptr_addr(mp, block, 1,
libxfs_bmbt_maxrecs(mp, mp->m_sb.sb_blocksize, 0));
- kp = XFS_BMBT_KEY_ADDR(mp, block, 1);
+ kp = xfs_bmbt_key_addr(mp, block, 1);
bno = select_child(curoffset, kp, pp,
be16_to_cpu(block->bb_numrecs));
}
@@ -98,7 +98,7 @@ bmap(
nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib);
nextents = be16_to_cpu(block->bb_numrecs);
xp = (xfs_bmbt_rec_t *)
- XFS_BMBT_REC_ADDR(mp, block, 1);
+ xfs_bmbt_rec_addr(mp, block, 1);
for (ep = xp; ep < &xp[nextents] && n < nex; ep++) {
if (!bmap_one_extent(ep, &curoffset, eoffset,
&n, bep)) {
diff --git a/db/bmap_inflate.c b/db/bmap_inflate.c
index a3ad6ad3832..118d911a1db 100644
--- a/db/bmap_inflate.c
+++ b/db/bmap_inflate.c
@@ -282,7 +282,7 @@ iroot_size(
unsigned int nr_this_level,
void *priv)
{
- return XFS_BMAP_BROOT_SPACE_CALC(cur->bc_mp, nr_this_level);
+ return xfs_bmap_broot_space_calc(cur->bc_mp, nr_this_level);
}
static int
diff --git a/db/bmroot.c b/db/bmroot.c
index 246e390a8a3..7ef07da181e 100644
--- a/db/bmroot.c
+++ b/db/bmroot.c
@@ -89,7 +89,7 @@ bmroota_key_offset(
block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff));
ASSERT(dip->di_forkoff != 0 && (char *)block == XFS_DFORK_APTR(dip));
ASSERT(be16_to_cpu(block->bb_level) > 0);
- kp = XFS_BMDR_KEY_ADDR(block, idx);
+ kp = xfs_bmdr_key_addr(block, idx);
return bitize((int)((char *)kp - (char *)block));
}
@@ -127,7 +127,7 @@ bmroota_ptr_offset(
block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff));
ASSERT(dip->di_forkoff != 0 && (char *)block == XFS_DFORK_APTR(dip));
ASSERT(be16_to_cpu(block->bb_level) > 0);
- pp = XFS_BMDR_PTR_ADDR(block, idx,
+ pp = xfs_bmdr_ptr_addr(block, idx,
libxfs_bmdr_maxrecs(XFS_DFORK_ASIZE(dip, mp), 0));
return bitize((int)((char *)pp - (char *)block));
}
@@ -185,7 +185,7 @@ bmrootd_key_offset(
ASSERT(obj == iocur_top->data);
block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff));
ASSERT(be16_to_cpu(block->bb_level) > 0);
- kp = XFS_BMDR_KEY_ADDR(block, idx);
+ kp = xfs_bmdr_key_addr(block, idx);
return bitize((int)((char *)kp - (char *)block));
}
@@ -222,7 +222,7 @@ bmrootd_ptr_offset(
dip = obj;
block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff));
ASSERT(be16_to_cpu(block->bb_level) > 0);
- pp = XFS_BMDR_PTR_ADDR(block, idx,
+ pp = xfs_bmdr_ptr_addr(block, idx,
libxfs_bmdr_maxrecs(XFS_DFORK_DSIZE(dip, mp), 0));
return bitize((int)((char *)pp - (char *)block));
}
diff --git a/db/check.c b/db/check.c
index 7d0687a9db7..d1c86206c08 100644
--- a/db/check.c
+++ b/db/check.c
@@ -2366,13 +2366,13 @@ process_btinode(
return;
}
if (be16_to_cpu(dib->bb_level) == 0) {
- xfs_bmbt_rec_t *rp = XFS_BMDR_REC_ADDR(dib, 1);
+ xfs_bmbt_rec_t *rp = xfs_bmdr_rec_addr(dib, 1);
process_bmbt_reclist(rp, be16_to_cpu(dib->bb_numrecs), type,
id, totd, blkmapp);
*nex += be16_to_cpu(dib->bb_numrecs);
return;
} else {
- pp = XFS_BMDR_PTR_ADDR(dib, 1, libxfs_bmdr_maxrecs(
+ pp = xfs_bmdr_ptr_addr(dib, 1, libxfs_bmdr_maxrecs(
XFS_DFORK_SIZE(dip, mp, whichfork), 0));
for (i = 0; i < be16_to_cpu(dib->bb_numrecs); i++)
scan_lbtree(get_unaligned_be64(&pp[i]),
@@ -4422,7 +4422,7 @@ scanfunc_bmap(
error++;
return;
}
- rp = XFS_BMBT_REC_ADDR(mp, block, 1);
+ rp = xfs_bmbt_rec_addr(mp, block, 1);
*nex += be16_to_cpu(block->bb_numrecs);
process_bmbt_reclist(rp, be16_to_cpu(block->bb_numrecs), type, id, totd,
blkmapp);
@@ -4438,7 +4438,7 @@ scanfunc_bmap(
error++;
return;
}
- pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[0]);
+ pp = xfs_bmbt_ptr_addr(mp, block, 1, mp->m_bmap_dmxr[0]);
for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
scan_lbtree(be64_to_cpu(pp[i]), level, scanfunc_bmap, type, id,
totd, toti, nex, blkmapp, 0, btype);
diff --git a/db/frag.c b/db/frag.c
index 4efc6ad07f8..1165e824a37 100644
--- a/db/frag.c
+++ b/db/frag.c
@@ -243,11 +243,11 @@ process_btinode(
dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
if (be16_to_cpu(dib->bb_level) == 0) {
- xfs_bmbt_rec_t *rp = XFS_BMDR_REC_ADDR(dib, 1);
+ xfs_bmbt_rec_t *rp = xfs_bmdr_rec_addr(dib, 1);
process_bmbt_reclist(rp, be16_to_cpu(dib->bb_numrecs), extmapp);
return;
}
- pp = XFS_BMDR_PTR_ADDR(dib, 1,
+ pp = xfs_bmdr_ptr_addr(dib, 1,
libxfs_bmdr_maxrecs(XFS_DFORK_SIZE(dip, mp, whichfork), 0));
for (i = 0; i < be16_to_cpu(dib->bb_numrecs); i++)
scan_lbtree(get_unaligned_be64(&pp[i]),
@@ -437,7 +437,7 @@ scanfunc_bmap(
nrecs, typtab[btype].name);
return;
}
- rp = XFS_BMBT_REC_ADDR(mp, block, 1);
+ rp = xfs_bmbt_rec_addr(mp, block, 1);
process_bmbt_reclist(rp, nrecs, extmapp);
return;
}
@@ -447,7 +447,7 @@ scanfunc_bmap(
nrecs, typtab[btype].name);
return;
}
- pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[0]);
+ pp = xfs_bmbt_ptr_addr(mp, block, 1, mp->m_bmap_dmxr[0]);
for (i = 0; i < nrecs; i++)
scan_lbtree(be64_to_cpu(pp[i]), level, scanfunc_bmap, extmapp,
btype);
diff --git a/db/metadump.c b/db/metadump.c
index be4cc01ff26..ccf7b89ccd5 100644
--- a/db/metadump.c
+++ b/db/metadump.c
@@ -250,8 +250,8 @@ zero_btree_node(
if (nrecs > mp->m_bmap_dmxr[1])
return;
- bkp = XFS_BMBT_KEY_ADDR(mp, block, 1);
- bpp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
+ bkp = xfs_bmbt_key_addr(mp, block, 1);
+ bpp = xfs_bmbt_ptr_addr(mp, block, 1, mp->m_bmap_dmxr[1]);
zp1 = (char *)&bkp[nrecs];
zp2 = (char *)&bpp[nrecs];
key_end = (char *)bpp;
@@ -316,7 +316,7 @@ zero_btree_leaf(
if (nrecs > mp->m_bmap_dmxr[0])
return;
- brp = XFS_BMBT_REC_ADDR(mp, block, 1);
+ brp = xfs_bmbt_rec_addr(mp, block, 1);
zp = (char *)&brp[nrecs];
break;
case TYP_INOBT:
@@ -2156,7 +2156,7 @@ scanfunc_bmap(
typtab[btype].name, agno, agbno);
return 1;
}
- return process_bmbt_reclist(XFS_BMBT_REC_ADDR(mp, block, 1),
+ return process_bmbt_reclist(xfs_bmbt_rec_addr(mp, block, 1),
nrecs, sbm->typ, sbm->is_meta);
}
@@ -2166,7 +2166,7 @@ scanfunc_bmap(
nrecs, typtab[btype].name, agno, agbno);
return 1;
}
- pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
+ pp = xfs_bmbt_ptr_addr(mp, block, 1, mp->m_bmap_dmxr[1]);
for (i = 0; i < nrecs; i++) {
xfs_agnumber_t ag;
xfs_agblock_t bno;
@@ -2229,7 +2229,7 @@ process_btinode(
}
if (level == 0) {
- return process_bmbt_reclist(XFS_BMDR_REC_ADDR(dib, 1),
+ return process_bmbt_reclist(xfs_bmdr_rec_addr(dib, 1),
nrecs, itype, is_meta);
}
@@ -2242,13 +2242,13 @@ process_btinode(
return 1;
}
- pp = XFS_BMDR_PTR_ADDR(dib, 1, maxrecs);
+ pp = xfs_bmdr_ptr_addr(dib, 1, maxrecs);
if (metadump.zero_stale_data) {
char *top;
/* Unused btree key space */
- top = (char*)XFS_BMDR_KEY_ADDR(dib, nrecs + 1);
+ top = (char*)xfs_bmdr_key_addr(dib, nrecs + 1);
memset(top, 0, (char*)pp - top);
/* Unused btree ptr space */
diff --git a/libxfs/xfs_attr_leaf.c b/libxfs/xfs_attr_leaf.c
index 14020c09146..28bb72f7a8a 100644
--- a/libxfs/xfs_attr_leaf.c
+++ b/libxfs/xfs_attr_leaf.c
@@ -669,7 +669,7 @@ xfs_attr_shortform_bytesfit(
*/
if (!dp->i_forkoff && dp->i_df.if_bytes >
xfs_default_attroffset(dp))
- dsize = XFS_BMDR_SPACE_CALC(MINDBTPTRS);
+ dsize = xfs_bmdr_space_calc(MINDBTPTRS);
break;
case XFS_DINODE_FMT_BTREE:
/*
@@ -683,7 +683,7 @@ xfs_attr_shortform_bytesfit(
return 0;
return dp->i_forkoff;
}
- dsize = XFS_BMAP_BROOT_SPACE(mp, dp->i_df.if_broot);
+ dsize = xfs_bmap_bmdr_space(dp->i_df.if_broot);
break;
}
@@ -691,11 +691,11 @@ xfs_attr_shortform_bytesfit(
* A data fork btree root must have space for at least
* MINDBTPTRS key/ptr pairs if the data fork is small or empty.
*/
- minforkoff = max_t(int64_t, dsize, XFS_BMDR_SPACE_CALC(MINDBTPTRS));
+ minforkoff = max_t(int64_t, dsize, xfs_bmdr_space_calc(MINDBTPTRS));
minforkoff = roundup(minforkoff, 8) >> 3;
/* attr fork btree root can have at least this many key/ptr pairs */
- maxforkoff = XFS_LITINO(mp) - XFS_BMDR_SPACE_CALC(MINABTPTRS);
+ maxforkoff = XFS_LITINO(mp) - xfs_bmdr_space_calc(MINABTPTRS);
maxforkoff = maxforkoff >> 3; /* rounded down */
if (offset >= maxforkoff)
diff --git a/libxfs/xfs_bmap.c b/libxfs/xfs_bmap.c
index c69cb5c66df..d7cbef76067 100644
--- a/libxfs/xfs_bmap.c
+++ b/libxfs/xfs_bmap.c
@@ -73,9 +73,9 @@ xfs_bmap_compute_maxlevels(
maxleafents = xfs_iext_max_nextents(xfs_has_large_extent_counts(mp),
whichfork);
if (whichfork == XFS_DATA_FORK)
- sz = XFS_BMDR_SPACE_CALC(MINDBTPTRS);
+ sz = xfs_bmdr_space_calc(MINDBTPTRS);
else
- sz = XFS_BMDR_SPACE_CALC(MINABTPTRS);
+ sz = xfs_bmdr_space_calc(MINABTPTRS);
maxrootrecs = xfs_bmdr_maxrecs(sz, 0);
minleafrecs = mp->m_bmap_dmnr[0];
@@ -96,8 +96,8 @@ xfs_bmap_compute_attr_offset(
struct xfs_mount *mp)
{
if (mp->m_sb.sb_inodesize == 256)
- return XFS_LITINO(mp) - XFS_BMDR_SPACE_CALC(MINABTPTRS);
- return XFS_BMDR_SPACE_CALC(6 * MINABTPTRS);
+ return XFS_LITINO(mp) - xfs_bmdr_space_calc(MINABTPTRS);
+ return xfs_bmdr_space_calc(6 * MINABTPTRS);
}
STATIC int /* error */
@@ -270,7 +270,7 @@ xfs_check_block(
prevp = NULL;
for( i = 1; i <= xfs_btree_get_numrecs(block); i++) {
dmxr = mp->m_bmap_dmxr[0];
- keyp = XFS_BMBT_KEY_ADDR(mp, block, i);
+ keyp = xfs_bmbt_key_addr(mp, block, i);
if (prevp) {
ASSERT(be64_to_cpu(prevp->br_startoff) <
@@ -282,15 +282,15 @@ xfs_check_block(
* Compare the block numbers to see if there are dups.
*/
if (root)
- pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, i, sz);
+ pp = xfs_bmap_broot_ptr_addr(mp, block, i, sz);
else
- pp = XFS_BMBT_PTR_ADDR(mp, block, i, dmxr);
+ pp = xfs_bmbt_ptr_addr(mp, block, i, dmxr);
for (j = i+1; j <= be16_to_cpu(block->bb_numrecs); j++) {
if (root)
- thispa = XFS_BMAP_BROOT_PTR_ADDR(mp, block, j, sz);
+ thispa = xfs_bmap_broot_ptr_addr(mp, block, j, sz);
else
- thispa = XFS_BMBT_PTR_ADDR(mp, block, j, dmxr);
+ thispa = xfs_bmbt_ptr_addr(mp, block, j, dmxr);
if (*thispa == *pp) {
xfs_warn(mp, "%s: thispa(%d) == pp(%d) %lld",
__func__, j, i,
@@ -345,7 +345,7 @@ xfs_bmap_check_leaf_extents(
level = be16_to_cpu(block->bb_level);
ASSERT(level > 0);
xfs_check_block(block, mp, 1, ifp->if_broot_bytes);
- pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes);
+ pp = xfs_bmap_broot_ptr_addr(mp, block, 1, ifp->if_broot_bytes);
bno = be64_to_cpu(*pp);
ASSERT(bno != NULLFSBLOCK);
@@ -380,7 +380,7 @@ xfs_bmap_check_leaf_extents(
*/
xfs_check_block(block, mp, 0, 0);
- pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
+ pp = xfs_bmbt_ptr_addr(mp, block, 1, mp->m_bmap_dmxr[1]);
bno = be64_to_cpu(*pp);
if (XFS_IS_CORRUPT(mp, !xfs_verify_fsbno(mp, bno))) {
xfs_btree_mark_sick(cur);
@@ -420,14 +420,14 @@ xfs_bmap_check_leaf_extents(
* conform with the first entry in this one.
*/
- ep = XFS_BMBT_REC_ADDR(mp, block, 1);
+ ep = xfs_bmbt_rec_addr(mp, block, 1);
if (i) {
ASSERT(xfs_bmbt_disk_get_startoff(&last) +
xfs_bmbt_disk_get_blockcount(&last) <=
xfs_bmbt_disk_get_startoff(ep));
}
for (j = 1; j < num_recs; j++) {
- nextp = XFS_BMBT_REC_ADDR(mp, block, j + 1);
+ nextp = xfs_bmbt_rec_addr(mp, block, j + 1);
ASSERT(xfs_bmbt_disk_get_startoff(ep) +
xfs_bmbt_disk_get_blockcount(ep) <=
xfs_bmbt_disk_get_startoff(nextp));
@@ -562,7 +562,7 @@ xfs_bmap_btree_to_extents(
ASSERT(be16_to_cpu(rblock->bb_numrecs) == 1);
ASSERT(xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0) == 1);
- pp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, ifp->if_broot_bytes);
+ pp = xfs_bmap_broot_ptr_addr(mp, rblock, 1, ifp->if_broot_bytes);
cbno = be64_to_cpu(*pp);
#ifdef DEBUG
if (XFS_IS_CORRUPT(cur->bc_mp, !xfs_btree_check_lptr(cur, cbno, 1))) {
@@ -690,7 +690,7 @@ xfs_bmap_extents_to_btree(
for_each_xfs_iext(ifp, &icur, &rec) {
if (isnullstartblock(rec.br_startblock))
continue;
- arp = XFS_BMBT_REC_ADDR(mp, ablock, 1 + cnt);
+ arp = xfs_bmbt_rec_addr(mp, ablock, 1 + cnt);
xfs_bmbt_disk_set_all(arp, &rec);
cnt++;
}
@@ -700,10 +700,10 @@ xfs_bmap_extents_to_btree(
/*
* Fill in the root key and pointer.
*/
- kp = XFS_BMBT_KEY_ADDR(mp, block, 1);
- arp = XFS_BMBT_REC_ADDR(mp, ablock, 1);
+ kp = xfs_bmbt_key_addr(mp, block, 1);
+ arp = xfs_bmbt_rec_addr(mp, ablock, 1);
kp->br_startoff = cpu_to_be64(xfs_bmbt_disk_get_startoff(arp));
- pp = XFS_BMBT_PTR_ADDR(mp, block, 1, xfs_bmbt_get_maxrecs(cur,
+ pp = xfs_bmbt_ptr_addr(mp, block, 1, xfs_bmbt_get_maxrecs(cur,
be16_to_cpu(block->bb_level)));
*pp = cpu_to_be64(args.fsbno);
@@ -872,7 +872,7 @@ xfs_bmap_add_attrfork_btree(
mp = ip->i_mount;
- if (XFS_BMAP_BMDR_SPACE(block) <= xfs_inode_data_fork_size(ip))
+ if (xfs_bmap_bmdr_space(block) <= xfs_inode_data_fork_size(ip))
*flags |= XFS_ILOG_DBROOT;
else {
cur = xfs_bmbt_init_cursor(mp, tp, ip, XFS_DATA_FORK);
@@ -1139,7 +1139,7 @@ xfs_iread_bmbt_block(
}
/* Copy records into the incore cache. */
- frp = XFS_BMBT_REC_ADDR(mp, block, 1);
+ frp = xfs_bmbt_rec_addr(mp, block, 1);
for (j = 0; j < num_recs; j++, frp++, ir->loaded++) {
struct xfs_bmbt_irec new;
xfs_failaddr_t fa;
diff --git a/libxfs/xfs_bmap_btree.c b/libxfs/xfs_bmap_btree.c
index 160f7b08ffd..be4979894a0 100644
--- a/libxfs/xfs_bmap_btree.c
+++ b/libxfs/xfs_bmap_btree.c
@@ -47,10 +47,10 @@ xfs_bmdr_to_bmbt(
ASSERT(be16_to_cpu(rblock->bb_level) > 0);
rblock->bb_numrecs = dblock->bb_numrecs;
dmxr = xfs_bmdr_maxrecs(dblocklen, 0);
- fkp = XFS_BMDR_KEY_ADDR(dblock, 1);
- tkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1);
- fpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr);
- tpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen);
+ fkp = xfs_bmdr_key_addr(dblock, 1);
+ tkp = xfs_bmbt_key_addr(mp, rblock, 1);
+ fpp = xfs_bmdr_ptr_addr(dblock, 1, dmxr);
+ tpp = xfs_bmap_broot_ptr_addr(mp, rblock, 1, rblocklen);
dmxr = be16_to_cpu(dblock->bb_numrecs);
memcpy(tkp, fkp, sizeof(*fkp) * dmxr);
memcpy(tpp, fpp, sizeof(*fpp) * dmxr);
@@ -150,10 +150,10 @@ xfs_bmbt_to_bmdr(
dblock->bb_level = rblock->bb_level;
dblock->bb_numrecs = rblock->bb_numrecs;
dmxr = xfs_bmdr_maxrecs(dblocklen, 0);
- fkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1);
- tkp = XFS_BMDR_KEY_ADDR(dblock, 1);
- fpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen);
- tpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr);
+ fkp = xfs_bmbt_key_addr(mp, rblock, 1);
+ tkp = xfs_bmdr_key_addr(dblock, 1);
+ fpp = xfs_bmap_broot_ptr_addr(mp, rblock, 1, rblocklen);
+ tpp = xfs_bmdr_ptr_addr(dblock, 1, dmxr);
dmxr = be16_to_cpu(dblock->bb_numrecs);
memcpy(tkp, fkp, sizeof(*fkp) * dmxr);
memcpy(tpp, fpp, sizeof(*fpp) * dmxr);
@@ -670,7 +670,7 @@ xfs_bmbt_maxrecs(
int blocklen,
int leaf)
{
- blocklen -= XFS_BMBT_BLOCK_LEN(mp);
+ blocklen -= xfs_bmbt_block_len(mp);
return xfs_bmbt_block_maxrecs(blocklen, leaf);
}
diff --git a/libxfs/xfs_bmap_btree.h b/libxfs/xfs_bmap_btree.h
index 151b8491f60..62fbc4f7c2c 100644
--- a/libxfs/xfs_bmap_btree.h
+++ b/libxfs/xfs_bmap_btree.h
@@ -13,70 +13,6 @@ struct xfs_inode;
struct xfs_trans;
struct xbtree_ifakeroot;
-/*
- * Btree block header size depends on a superblock flag.
- */
-#define XFS_BMBT_BLOCK_LEN(mp) \
- (xfs_has_crc(((mp))) ? \
- XFS_BTREE_LBLOCK_CRC_LEN : XFS_BTREE_LBLOCK_LEN)
-
-#define XFS_BMBT_REC_ADDR(mp, block, index) \
- ((xfs_bmbt_rec_t *) \
- ((char *)(block) + \
- XFS_BMBT_BLOCK_LEN(mp) + \
- ((index) - 1) * sizeof(xfs_bmbt_rec_t)))
-
-#define XFS_BMBT_KEY_ADDR(mp, block, index) \
- ((xfs_bmbt_key_t *) \
- ((char *)(block) + \
- XFS_BMBT_BLOCK_LEN(mp) + \
- ((index) - 1) * sizeof(xfs_bmbt_key_t)))
-
-#define XFS_BMBT_PTR_ADDR(mp, block, index, maxrecs) \
- ((xfs_bmbt_ptr_t *) \
- ((char *)(block) + \
- XFS_BMBT_BLOCK_LEN(mp) + \
- (maxrecs) * sizeof(xfs_bmbt_key_t) + \
- ((index) - 1) * sizeof(xfs_bmbt_ptr_t)))
-
-#define XFS_BMDR_REC_ADDR(block, index) \
- ((xfs_bmdr_rec_t *) \
- ((char *)(block) + \
- sizeof(struct xfs_bmdr_block) + \
- ((index) - 1) * sizeof(xfs_bmdr_rec_t)))
-
-#define XFS_BMDR_KEY_ADDR(block, index) \
- ((xfs_bmdr_key_t *) \
- ((char *)(block) + \
- sizeof(struct xfs_bmdr_block) + \
- ((index) - 1) * sizeof(xfs_bmdr_key_t)))
-
-#define XFS_BMDR_PTR_ADDR(block, index, maxrecs) \
- ((xfs_bmdr_ptr_t *) \
- ((char *)(block) + \
- sizeof(struct xfs_bmdr_block) + \
- (maxrecs) * sizeof(xfs_bmdr_key_t) + \
- ((index) - 1) * sizeof(xfs_bmdr_ptr_t)))
-
-/*
- * These are to be used when we know the size of the block and
- * we don't have a cursor.
- */
-#define XFS_BMAP_BROOT_PTR_ADDR(mp, bb, i, sz) \
- XFS_BMBT_PTR_ADDR(mp, bb, i, xfs_bmbt_maxrecs(mp, sz, 0))
-
-#define XFS_BMAP_BROOT_SPACE_CALC(mp, nrecs) \
- (int)(XFS_BMBT_BLOCK_LEN(mp) + \
- ((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t))))
-
-#define XFS_BMAP_BROOT_SPACE(mp, bb) \
- (XFS_BMAP_BROOT_SPACE_CALC(mp, be16_to_cpu((bb)->bb_numrecs)))
-#define XFS_BMDR_SPACE_CALC(nrecs) \
- (int)(sizeof(xfs_bmdr_block_t) + \
- ((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t))))
-#define XFS_BMAP_BMDR_SPACE(bb) \
- (XFS_BMDR_SPACE_CALC(be16_to_cpu((bb)->bb_numrecs)))
-
/*
* Maximum number of bmap btree levels.
*/
@@ -120,4 +56,144 @@ unsigned int xfs_bmbt_maxlevels_ondisk(void);
int __init xfs_bmbt_init_cur_cache(void);
void xfs_bmbt_destroy_cur_cache(void);
+/*
+ * Btree block header size depends on a superblock flag.
+ */
+static inline size_t
+xfs_bmbt_block_len(struct xfs_mount *mp)
+{
+ return xfs_has_crc(mp) ?
+ XFS_BTREE_LBLOCK_CRC_LEN : XFS_BTREE_LBLOCK_LEN;
+}
+
+/* Addresses of key, pointers, and records within an incore bmbt block. */
+
+static inline struct xfs_bmbt_rec *
+xfs_bmbt_rec_addr(
+ struct xfs_mount *mp,
+ struct xfs_btree_block *block,
+ unsigned int index)
+{
+ return (struct xfs_bmbt_rec *)
+ ((char *)block + xfs_bmbt_block_len(mp) +
+ (index - 1) * sizeof(struct xfs_bmbt_rec));
+}
+
+static inline struct xfs_bmbt_key *
+xfs_bmbt_key_addr(
+ struct xfs_mount *mp,
+ struct xfs_btree_block *block,
+ unsigned int index)
+{
+ return (struct xfs_bmbt_key *)
+ ((char *)block + xfs_bmbt_block_len(mp) +
+ (index - 1) * sizeof(struct xfs_bmbt_key *));
+}
+
+static inline xfs_bmbt_ptr_t *
+xfs_bmbt_ptr_addr(
+ struct xfs_mount *mp,
+ struct xfs_btree_block *block,
+ unsigned int index,
+ unsigned int maxrecs)
+{
+ return (xfs_bmbt_ptr_t *)
+ ((char *)block + xfs_bmbt_block_len(mp) +
+ maxrecs * sizeof(struct xfs_bmbt_key) +
+ (index - 1) * sizeof(xfs_bmbt_ptr_t));
+}
+
+/* Addresses of key, pointers, and records within an ondisk bmbt block. */
+
+static inline struct xfs_bmbt_rec *
+xfs_bmdr_rec_addr(
+ struct xfs_bmdr_block *block,
+ unsigned int index)
+{
+ return (struct xfs_bmbt_rec *)
+ ((char *)(block + 1) +
+ (index - 1) * sizeof(struct xfs_bmbt_rec));
+}
+
+static inline struct xfs_bmbt_key *
+xfs_bmdr_key_addr(
+ struct xfs_bmdr_block *block,
+ unsigned int index)
+{
+ return (struct xfs_bmbt_key *)
+ ((char *)(block + 1) +
+ (index - 1) * sizeof(struct xfs_bmbt_key));
+}
+
+static inline xfs_bmbt_ptr_t *
+xfs_bmdr_ptr_addr(
+ struct xfs_bmdr_block *block,
+ unsigned int index,
+ unsigned int maxrecs)
+{
+ return (xfs_bmbt_ptr_t *)
+ ((char *)(block + 1) +
+ maxrecs * sizeof(struct xfs_bmbt_key) +
+ (index - 1) * sizeof(xfs_bmbt_ptr_t));
+}
+
+/*
+ * Address of pointers within the incore btree root.
+ *
+ * These are to be used when we know the size of the block and
+ * we don't have a cursor.
+ */
+static inline xfs_bmbt_ptr_t *
+xfs_bmap_broot_ptr_addr(
+ struct xfs_mount *mp,
+ struct xfs_btree_block *bb,
+ unsigned int i,
+ unsigned int sz)
+{
+ return xfs_bmbt_ptr_addr(mp, bb, i, xfs_bmbt_maxrecs(mp, sz, 0));
+}
+
+/*
+ * Compute the space required for the incore btree root containing the given
+ * number of records.
+ */
+static inline size_t
+xfs_bmap_broot_space_calc(
+ struct xfs_mount *mp,
+ unsigned int nrecs)
+{
+ return xfs_bmbt_block_len(mp) + \
+ (nrecs * (sizeof(struct xfs_bmbt_key) + sizeof(xfs_bmbt_ptr_t)));
+}
+
+/*
+ * Compute the space required for the incore btree root given the ondisk
+ * btree root block.
+ */
+static inline size_t
+xfs_bmap_broot_space(
+ struct xfs_mount *mp,
+ struct xfs_bmdr_block *bb)
+{
+ return xfs_bmap_broot_space_calc(mp, be16_to_cpu(bb->bb_numrecs));
+}
+
+/* Compute the space required for the ondisk root block. */
+static inline size_t
+xfs_bmdr_space_calc(unsigned int nrecs)
+{
+ return sizeof(struct xfs_bmdr_block) +
+ (nrecs * (sizeof(struct xfs_bmbt_key) + sizeof(xfs_bmbt_ptr_t)));
+}
+
+/*
+ * Compute the space required for the ondisk root block given an incore root
+ * block.
+ */
+static inline size_t
+xfs_bmap_bmdr_space(struct xfs_btree_block *bb)
+{
+ return xfs_bmdr_space_calc(be16_to_cpu(bb->bb_numrecs));
+}
+
#endif /* __XFS_BMAP_BTREE_H__ */
diff --git a/libxfs/xfs_inode_fork.c b/libxfs/xfs_inode_fork.c
index 46da5edfb11..2d67e35c7e3 100644
--- a/libxfs/xfs_inode_fork.c
+++ b/libxfs/xfs_inode_fork.c
@@ -179,7 +179,7 @@ xfs_iformat_btree(
ifp = xfs_ifork_ptr(ip, whichfork);
dfp = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
- size = XFS_BMAP_BROOT_SPACE(mp, dfp);
+ size = xfs_bmap_broot_space(mp, dfp);
nrecs = be16_to_cpu(dfp->bb_numrecs);
level = be16_to_cpu(dfp->bb_level);
@@ -192,7 +192,7 @@ xfs_iformat_btree(
*/
if (unlikely(ifp->if_nextents <= XFS_IFORK_MAXEXT(ip, whichfork) ||
nrecs == 0 ||
- XFS_BMDR_SPACE_CALC(nrecs) >
+ xfs_bmdr_space_calc(nrecs) >
XFS_DFORK_SIZE(dip, mp, whichfork) ||
ifp->if_nextents > ip->i_nblocks) ||
level == 0 || level > XFS_BM_MAXLEVELS(mp, whichfork)) {
@@ -403,7 +403,7 @@ xfs_iroot_realloc(
* allocate it now and get out.
*/
if (ifp->if_broot_bytes == 0) {
- new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, rec_diff);
+ new_size = xfs_bmap_broot_space_calc(mp, rec_diff);
ifp->if_broot = kmem_alloc(new_size, KM_NOFS);
ifp->if_broot_bytes = (int)new_size;
return;
@@ -417,15 +417,15 @@ xfs_iroot_realloc(
*/
cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0);
new_max = cur_max + rec_diff;
- new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max);
+ new_size = xfs_bmap_broot_space_calc(mp, new_max);
ifp->if_broot = krealloc(ifp->if_broot, new_size,
GFP_NOFS | __GFP_NOFAIL);
- op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
+ op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1,
ifp->if_broot_bytes);
- np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
+ np = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1,
(int)new_size);
ifp->if_broot_bytes = (int)new_size;
- ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <=
+ ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <=
xfs_inode_fork_size(ip, whichfork));
memmove(np, op, cur_max * (uint)sizeof(xfs_fsblock_t));
return;
@@ -441,7 +441,7 @@ xfs_iroot_realloc(
new_max = cur_max + rec_diff;
ASSERT(new_max >= 0);
if (new_max > 0)
- new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max);
+ new_size = xfs_bmap_broot_space_calc(mp, new_max);
else
new_size = 0;
if (new_size > 0) {
@@ -450,7 +450,7 @@ xfs_iroot_realloc(
* First copy over the btree block header.
*/
memcpy(new_broot, ifp->if_broot,
- XFS_BMBT_BLOCK_LEN(ip->i_mount));
+ xfs_bmbt_block_len(ip->i_mount));
} else {
new_broot = NULL;
}
@@ -462,16 +462,16 @@ xfs_iroot_realloc(
/*
* First copy the records.
*/
- op = (char *)XFS_BMBT_REC_ADDR(mp, ifp->if_broot, 1);
- np = (char *)XFS_BMBT_REC_ADDR(mp, new_broot, 1);
+ op = (char *)xfs_bmbt_rec_addr(mp, ifp->if_broot, 1);
+ np = (char *)xfs_bmbt_rec_addr(mp, new_broot, 1);
memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_rec_t));
/*
* Then copy the pointers.
*/
- op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
+ op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1,
ifp->if_broot_bytes);
- np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, new_broot, 1,
+ np = (char *)xfs_bmap_broot_ptr_addr(mp, new_broot, 1,
(int)new_size);
memcpy(np, op, new_max * (uint)sizeof(xfs_fsblock_t));
}
@@ -479,7 +479,7 @@ xfs_iroot_realloc(
ifp->if_broot = new_broot;
ifp->if_broot_bytes = (int)new_size;
if (ifp->if_broot)
- ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <=
+ ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <=
xfs_inode_fork_size(ip, whichfork));
return;
}
@@ -652,7 +652,7 @@ xfs_iflush_fork(
if ((iip->ili_fields & brootflag[whichfork]) &&
(ifp->if_broot_bytes > 0)) {
ASSERT(ifp->if_broot != NULL);
- ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <=
+ ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <=
xfs_inode_fork_size(ip, whichfork));
xfs_bmbt_to_bmdr(mp, ifp->if_broot, ifp->if_broot_bytes,
(xfs_bmdr_block_t *)cp,
diff --git a/libxfs/xfs_trans_resv.c b/libxfs/xfs_trans_resv.c
index 74f46539179..800a2f9ecb8 100644
--- a/libxfs/xfs_trans_resv.c
+++ b/libxfs/xfs_trans_resv.c
@@ -128,7 +128,7 @@ xfs_calc_inode_res(
(4 * sizeof(struct xlog_op_header) +
sizeof(struct xfs_inode_log_format) +
mp->m_sb.sb_inodesize +
- 2 * XFS_BMBT_BLOCK_LEN(mp));
+ 2 * xfs_bmbt_block_len(mp));
}
/*
diff --git a/repair/bmap_repair.c b/repair/bmap_repair.c
index 7705980621c..a8cbff67ceb 100644
--- a/repair/bmap_repair.c
+++ b/repair/bmap_repair.c
@@ -285,7 +285,7 @@ xrep_bmap_iroot_size(
{
ASSERT(level > 0);
- return XFS_BMAP_BROOT_SPACE_CALC(cur->bc_mp, nr_this_level);
+ return xfs_bmap_broot_space_calc(cur->bc_mp, nr_this_level);
}
/* Update the inode counters. */
diff --git a/repair/dinode.c b/repair/dinode.c
index 5a57069c29e..31b3cd74139 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -842,19 +842,19 @@ _("bad numrecs 0 in inode %" PRIu64 " bmap btree root block\n"),
/*
* use bmdr/dfork_dsize since the root block is in the data fork
*/
- if (XFS_BMDR_SPACE_CALC(numrecs) > XFS_DFORK_SIZE(dip, mp, whichfork)) {
+ if (xfs_bmdr_space_calc(numrecs) > XFS_DFORK_SIZE(dip, mp, whichfork)) {
do_warn(
- _("indicated size of %s btree root (%d bytes) greater than space in "
+ _("indicated size of %s btree root (%zu bytes) greater than space in "
"inode %" PRIu64 " %s fork\n"),
- forkname, XFS_BMDR_SPACE_CALC(numrecs), lino, forkname);
+ forkname, xfs_bmdr_space_calc(numrecs), lino, forkname);
return(1);
}
init_bm_cursor(&cursor, level + 1);
- pp = XFS_BMDR_PTR_ADDR(dib, 1,
+ pp = xfs_bmdr_ptr_addr(dib, 1,
libxfs_bmdr_maxrecs(XFS_DFORK_SIZE(dip, mp, whichfork), 0));
- pkey = XFS_BMDR_KEY_ADDR(dib, 1);
+ pkey = xfs_bmdr_key_addr(dib, 1);
last_key = NULLFILEOFF;
for (i = 0; i < numrecs; i++) {
diff --git a/repair/prefetch.c b/repair/prefetch.c
index 58fc2dac1a8..5caa41beb74 100644
--- a/repair/prefetch.c
+++ b/repair/prefetch.c
@@ -328,13 +328,13 @@ pf_scanfunc_bmap(
if (numrecs > mp->m_bmap_dmxr[0] || !isadir)
return 0;
return pf_read_bmbt_reclist(args,
- XFS_BMBT_REC_ADDR(mp, block, 1), numrecs);
+ xfs_bmbt_rec_addr(mp, block, 1), numrecs);
}
if (numrecs > mp->m_bmap_dmxr[1])
return 0;
- pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
+ pp = xfs_bmbt_ptr_addr(mp, block, 1, mp->m_bmap_dmxr[1]);
for (i = 0; i < numrecs; i++) {
dbno = get_unaligned_be64(&pp[i]);
@@ -372,11 +372,11 @@ pf_read_btinode(
/*
* use bmdr/dfork_dsize since the root block is in the data fork
*/
- if (XFS_BMDR_SPACE_CALC(numrecs) > XFS_DFORK_DSIZE(dino, mp))
+ if (xfs_bmdr_space_calc(numrecs) > XFS_DFORK_DSIZE(dino, mp))
return;
dsize = XFS_DFORK_DSIZE(dino, mp);
- pp = XFS_BMDR_PTR_ADDR(dib, 1, libxfs_bmdr_maxrecs(dsize, 0));
+ pp = xfs_bmdr_ptr_addr(dib, 1, libxfs_bmdr_maxrecs(dsize, 0));
for (i = 0; i < numrecs; i++) {
dbno = get_unaligned_be64(&pp[i]);
diff --git a/repair/scan.c b/repair/scan.c
index 3857593b165..1cd4d0ad2e1 100644
--- a/repair/scan.c
+++ b/repair/scan.c
@@ -445,7 +445,7 @@ _("inode %" PRIu64 " bad # of bmap records (%" PRIu64 ", min - %u, max - %u)\n")
mp->m_bmap_dmxr[0]);
return(1);
}
- rp = XFS_BMBT_REC_ADDR(mp, block, 1);
+ rp = xfs_bmbt_rec_addr(mp, block, 1);
*nex += numrecs;
/*
* XXX - if we were going to fix up the btree record,
@@ -496,8 +496,8 @@ _("inode %" PRIu64 " bad # of bmap records (%" PRIu64 ", min - %u, max - %u)\n")
ino, numrecs, mp->m_bmap_dmnr[1], mp->m_bmap_dmxr[1]);
return(1);
}
- pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
- pkey = XFS_BMBT_KEY_ADDR(mp, block, 1);
+ pp = xfs_bmbt_ptr_addr(mp, block, 1, mp->m_bmap_dmxr[1]);
+ pkey = xfs_bmbt_key_addr(mp, block, 1);
last_key = NULLFILEOFF;
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 02/14] xfs: refactor the allocation and freeing of incore inode fork btree roots
2023-12-31 19:53 ` [PATCHSET v2.0 07/17] xfsprogs: refactor btrees to support records in inode root Darrick J. Wong
2023-12-27 13:01 ` [PATCH 01/14] xfs: replace shouty XFS_BM{BT,DR} macros Darrick J. Wong
@ 2023-12-27 13:01 ` Darrick J. Wong
2023-12-27 13:01 ` [PATCH 03/14] xfs: refactor creation of bmap " Darrick J. Wong
` (11 subsequent siblings)
13 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:01 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Refactor the code that allocates and freese the incore inode fork btree
roots. This will help us disentangle some of the weird logic when we're
creating and tearing down inode-based btrees.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_inode_fork.c | 53 +++++++++++++++++++++++++++++++++--------------
libxfs/xfs_inode_fork.h | 3 +++
2 files changed, 40 insertions(+), 16 deletions(-)
diff --git a/libxfs/xfs_inode_fork.c b/libxfs/xfs_inode_fork.c
index 2d67e35c7e3..05f7ada0ae3 100644
--- a/libxfs/xfs_inode_fork.c
+++ b/libxfs/xfs_inode_fork.c
@@ -205,8 +205,7 @@ xfs_iformat_btree(
return -EFSCORRUPTED;
}
- ifp->if_broot_bytes = size;
- ifp->if_broot = kmem_alloc(size, KM_NOFS);
+ xfs_iroot_alloc(ip, whichfork, size);
ASSERT(ifp->if_broot != NULL);
/*
* Copy and convert from the on-disk structure
@@ -356,6 +355,32 @@ xfs_iformat_attr_fork(
return error;
}
+/* Allocate a new incore ifork btree root. */
+void
+xfs_iroot_alloc(
+ struct xfs_inode *ip,
+ int whichfork,
+ size_t bytes)
+{
+ struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork);
+
+ ifp->if_broot = kmem_alloc(bytes, KM_NOFS);
+ ifp->if_broot_bytes = bytes;
+}
+
+/* Free all the memory and state associated with an incore ifork btree root. */
+void
+xfs_iroot_free(
+ struct xfs_inode *ip,
+ int whichfork)
+{
+ struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork);
+
+ ifp->if_broot_bytes = 0;
+ kmem_free(ifp->if_broot);
+ ifp->if_broot = NULL;
+}
+
/*
* Reallocate the space for if_broot based on the number of records
* being added or deleted as indicated in rec_diff. Move the records
@@ -404,8 +429,7 @@ xfs_iroot_realloc(
*/
if (ifp->if_broot_bytes == 0) {
new_size = xfs_bmap_broot_space_calc(mp, rec_diff);
- ifp->if_broot = kmem_alloc(new_size, KM_NOFS);
- ifp->if_broot_bytes = (int)new_size;
+ xfs_iroot_alloc(ip, whichfork, new_size);
return;
}
@@ -444,17 +468,15 @@ xfs_iroot_realloc(
new_size = xfs_bmap_broot_space_calc(mp, new_max);
else
new_size = 0;
- if (new_size > 0) {
- new_broot = kmem_alloc(new_size, KM_NOFS);
- /*
- * First copy over the btree block header.
- */
- memcpy(new_broot, ifp->if_broot,
- xfs_bmbt_block_len(ip->i_mount));
- } else {
- new_broot = NULL;
+ if (new_size == 0) {
+ xfs_iroot_free(ip, whichfork);
+ return;
}
+ /* First copy over the btree block header. */
+ new_broot = kmem_alloc(new_size, KM_NOFS);
+ memcpy(new_broot, ifp->if_broot, xfs_bmbt_block_len(ip->i_mount));
+
/*
* Only copy the records and pointers if there are any.
*/
@@ -478,9 +500,8 @@ xfs_iroot_realloc(
kmem_free(ifp->if_broot);
ifp->if_broot = new_broot;
ifp->if_broot_bytes = (int)new_size;
- if (ifp->if_broot)
- ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <=
- xfs_inode_fork_size(ip, whichfork));
+ ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <=
+ xfs_inode_fork_size(ip, whichfork));
return;
}
diff --git a/libxfs/xfs_inode_fork.h b/libxfs/xfs_inode_fork.h
index ebeb925be09..18ea2d27777 100644
--- a/libxfs/xfs_inode_fork.h
+++ b/libxfs/xfs_inode_fork.h
@@ -172,6 +172,9 @@ void xfs_iflush_fork(struct xfs_inode *, struct xfs_dinode *,
void xfs_idestroy_fork(struct xfs_ifork *ifp);
void xfs_idata_realloc(struct xfs_inode *ip, int64_t byte_diff,
int whichfork);
+void xfs_iroot_alloc(struct xfs_inode *ip, int whichfork,
+ size_t bytes);
+void xfs_iroot_free(struct xfs_inode *ip, int whichfork);
void xfs_iroot_realloc(struct xfs_inode *, int, int);
int xfs_iread_extents(struct xfs_trans *, struct xfs_inode *, int);
int xfs_iextents_copy(struct xfs_inode *, struct xfs_bmbt_rec *,
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 03/14] xfs: refactor creation of bmap btree roots
2023-12-31 19:53 ` [PATCHSET v2.0 07/17] xfsprogs: refactor btrees to support records in inode root Darrick J. Wong
2023-12-27 13:01 ` [PATCH 01/14] xfs: replace shouty XFS_BM{BT,DR} macros Darrick J. Wong
2023-12-27 13:01 ` [PATCH 02/14] xfs: refactor the allocation and freeing of incore inode fork btree roots Darrick J. Wong
@ 2023-12-27 13:01 ` Darrick J. Wong
2023-12-27 13:02 ` [PATCH 04/14] xfs: fix a sloppy memory handling bug in xfs_iroot_realloc Darrick J. Wong
` (10 subsequent siblings)
13 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:01 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Now that we've created inode fork helpers to allocate and free btree
roots, create a new bmap btree helper to create a new bmbt root, and
refactor the extents <-> btree conversion functions to use our new
helpers.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_bmap.c | 17 ++++-------------
libxfs/xfs_bmap_btree.c | 16 ++++++++++++++++
libxfs/xfs_bmap_btree.h | 2 ++
3 files changed, 22 insertions(+), 13 deletions(-)
diff --git a/libxfs/xfs_bmap.c b/libxfs/xfs_bmap.c
index d7cbef76067..5935f87833b 100644
--- a/libxfs/xfs_bmap.c
+++ b/libxfs/xfs_bmap.c
@@ -591,7 +591,7 @@ xfs_bmap_btree_to_extents(
xfs_trans_binval(tp, cbp);
if (cur->bc_levels[0].bp == cbp)
cur->bc_levels[0].bp = NULL;
- xfs_iroot_realloc(ip, -1, whichfork);
+ xfs_iroot_free(ip, whichfork);
ASSERT(ifp->if_broot == NULL);
ifp->if_format = XFS_DINODE_FMT_EXTENTS;
*logflagsp |= XFS_ILOG_CORE | xfs_ilog_fext(whichfork);
@@ -631,20 +631,10 @@ xfs_bmap_extents_to_btree(
ifp = xfs_ifork_ptr(ip, whichfork);
ASSERT(ifp->if_format == XFS_DINODE_FMT_EXTENTS);
- /*
- * Make space in the inode incore. This needs to be undone if we fail
- * to expand the root.
- */
- xfs_iroot_realloc(ip, 1, whichfork);
-
- /*
- * Fill in the root.
- */
- block = ifp->if_broot;
- xfs_btree_init_block(mp, block, &xfs_bmbt_ops, 1, 1, ip->i_ino);
/*
* Need a cursor. Can't allocate until bb_level is filled in.
*/
+ xfs_bmbt_iroot_alloc(ip, whichfork);
cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
cur->bc_ino.flags = wasdel ? XFS_BTCUR_BMBT_WASDEL : 0;
/*
@@ -700,6 +690,7 @@ xfs_bmap_extents_to_btree(
/*
* Fill in the root key and pointer.
*/
+ block = ifp->if_broot;
kp = xfs_bmbt_key_addr(mp, block, 1);
arp = xfs_bmbt_rec_addr(mp, ablock, 1);
kp->br_startoff = cpu_to_be64(xfs_bmbt_disk_get_startoff(arp));
@@ -721,7 +712,7 @@ xfs_bmap_extents_to_btree(
out_unreserve_dquot:
xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
out_root_realloc:
- xfs_iroot_realloc(ip, -1, whichfork);
+ xfs_iroot_free(ip, whichfork);
ifp->if_format = XFS_DINODE_FMT_EXTENTS;
ASSERT(ifp->if_broot == NULL);
xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
diff --git a/libxfs/xfs_bmap_btree.c b/libxfs/xfs_bmap_btree.c
index be4979894a0..1dd8d12af8f 100644
--- a/libxfs/xfs_bmap_btree.c
+++ b/libxfs/xfs_bmap_btree.c
@@ -778,3 +778,19 @@ xfs_bmbt_destroy_cur_cache(void)
kmem_cache_destroy(xfs_bmbt_cur_cache);
xfs_bmbt_cur_cache = NULL;
}
+
+/* Create an incore bmbt btree root block. */
+void
+xfs_bmbt_iroot_alloc(
+ struct xfs_inode *ip,
+ int whichfork)
+{
+ struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork);
+
+ xfs_iroot_alloc(ip, whichfork,
+ xfs_bmap_broot_space_calc(ip->i_mount, 1));
+
+ /* Fill in the root. */
+ xfs_btree_init_block(ip->i_mount, ifp->if_broot, &xfs_bmbt_ops, 1, 1,
+ ip->i_ino);
+}
diff --git a/libxfs/xfs_bmap_btree.h b/libxfs/xfs_bmap_btree.h
index 62fbc4f7c2c..3fe9c4f7f1a 100644
--- a/libxfs/xfs_bmap_btree.h
+++ b/libxfs/xfs_bmap_btree.h
@@ -196,4 +196,6 @@ xfs_bmap_bmdr_space(struct xfs_btree_block *bb)
return xfs_bmdr_space_calc(be16_to_cpu(bb->bb_numrecs));
}
+void xfs_bmbt_iroot_alloc(struct xfs_inode *ip, int whichfork);
+
#endif /* __XFS_BMAP_BTREE_H__ */
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 04/14] xfs: fix a sloppy memory handling bug in xfs_iroot_realloc
2023-12-31 19:53 ` [PATCHSET v2.0 07/17] xfsprogs: refactor btrees to support records in inode root Darrick J. Wong
` (2 preceding siblings ...)
2023-12-27 13:01 ` [PATCH 03/14] xfs: refactor creation of bmap " Darrick J. Wong
@ 2023-12-27 13:02 ` Darrick J. Wong
2023-12-27 13:02 ` [PATCH 05/14] xfs: hoist the code that moves the incore inode fork broot memory Darrick J. Wong
` (9 subsequent siblings)
13 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:02 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
While refactoring code, I noticed that when xfs_iroot_realloc tries to
shrink a bmbt root block, it allocates a smaller new block and then
copies "records" and pointers to the new block. However, bmbt root
blocks cannot ever be leaves, which means that it's not technically
correct to copy records. We /should/ be copying keys.
Note that this has never resulted in actual memory corruption because
sizeof(bmbt_rec) == (sizeof(bmbt_key) + sizeof(bmbt_ptr)). However,
this will no longer be true when we start adding realtime rmap stuff,
so fix this now.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_inode_fork.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/libxfs/xfs_inode_fork.c b/libxfs/xfs_inode_fork.c
index 05f7ada0ae3..765e174999d 100644
--- a/libxfs/xfs_inode_fork.c
+++ b/libxfs/xfs_inode_fork.c
@@ -478,15 +478,15 @@ xfs_iroot_realloc(
memcpy(new_broot, ifp->if_broot, xfs_bmbt_block_len(ip->i_mount));
/*
- * Only copy the records and pointers if there are any.
+ * Only copy the keys and pointers if there are any.
*/
if (new_max > 0) {
/*
- * First copy the records.
+ * First copy the keys.
*/
- op = (char *)xfs_bmbt_rec_addr(mp, ifp->if_broot, 1);
- np = (char *)xfs_bmbt_rec_addr(mp, new_broot, 1);
- memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_rec_t));
+ op = (char *)xfs_bmbt_key_addr(mp, ifp->if_broot, 1);
+ np = (char *)xfs_bmbt_key_addr(mp, new_broot, 1);
+ memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_key_t));
/*
* Then copy the pointers.
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 05/14] xfs: hoist the code that moves the incore inode fork broot memory
2023-12-31 19:53 ` [PATCHSET v2.0 07/17] xfsprogs: refactor btrees to support records in inode root Darrick J. Wong
` (3 preceding siblings ...)
2023-12-27 13:02 ` [PATCH 04/14] xfs: fix a sloppy memory handling bug in xfs_iroot_realloc Darrick J. Wong
@ 2023-12-27 13:02 ` Darrick J. Wong
2023-12-27 13:02 ` [PATCH 06/14] xfs: move the zero records logic into xfs_bmap_broot_space_calc Darrick J. Wong
` (8 subsequent siblings)
13 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:02 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Whenever we change the size of the memory buffer holding an inode fork
btree root block, we have to copy the contents over. Refactor all this
into a single function that handles both, in preparation for making
xfs_iroot_realloc more generic.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_inode_fork.c | 99 +++++++++++++++++++++++++++--------------------
1 file changed, 57 insertions(+), 42 deletions(-)
diff --git a/libxfs/xfs_inode_fork.c b/libxfs/xfs_inode_fork.c
index 765e174999d..edf6dff28b4 100644
--- a/libxfs/xfs_inode_fork.c
+++ b/libxfs/xfs_inode_fork.c
@@ -381,6 +381,50 @@ xfs_iroot_free(
ifp->if_broot = NULL;
}
+/* Move the bmap btree root from one incore buffer to another. */
+static void
+xfs_ifork_move_broot(
+ struct xfs_inode *ip,
+ int whichfork,
+ struct xfs_btree_block *dst_broot,
+ size_t dst_bytes,
+ struct xfs_btree_block *src_broot,
+ size_t src_bytes,
+ unsigned int numrecs)
+{
+ struct xfs_mount *mp = ip->i_mount;
+ void *dptr;
+ void *sptr;
+
+ ASSERT(xfs_bmap_bmdr_space(src_broot) <= xfs_inode_fork_size(ip, whichfork));
+
+ /*
+ * We always have to move the pointers because they are not butted
+ * against the btree block header.
+ */
+ if (numrecs) {
+ sptr = xfs_bmap_broot_ptr_addr(mp, src_broot, 1, src_bytes);
+ dptr = xfs_bmap_broot_ptr_addr(mp, dst_broot, 1, dst_bytes);
+ memmove(dptr, sptr, numrecs * sizeof(xfs_fsblock_t));
+ }
+
+ if (src_broot == dst_broot)
+ return;
+
+ /*
+ * If the root is being totally relocated, we have to migrate the block
+ * header and the keys that come after it.
+ */
+ memcpy(dst_broot, src_broot, xfs_bmbt_block_len(mp));
+
+ /* Now copy the keys, which come right after the header. */
+ if (numrecs) {
+ sptr = xfs_bmbt_key_addr(mp, src_broot, 1);
+ dptr = xfs_bmbt_key_addr(mp, dst_broot, 1);
+ memcpy(dptr, sptr, numrecs * sizeof(struct xfs_bmbt_key));
+ }
+}
+
/*
* Reallocate the space for if_broot based on the number of records
* being added or deleted as indicated in rec_diff. Move the records
@@ -407,12 +451,11 @@ xfs_iroot_realloc(
{
struct xfs_mount *mp = ip->i_mount;
int cur_max;
- struct xfs_ifork *ifp;
+ struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork);
struct xfs_btree_block *new_broot;
int new_max;
size_t new_size;
- char *np;
- char *op;
+ size_t old_size = ifp->if_broot_bytes;
/*
* Handle the degenerate case quietly.
@@ -421,13 +464,12 @@ xfs_iroot_realloc(
return;
}
- ifp = xfs_ifork_ptr(ip, whichfork);
if (rec_diff > 0) {
/*
* If there wasn't any memory allocated before, just
* allocate it now and get out.
*/
- if (ifp->if_broot_bytes == 0) {
+ if (old_size == 0) {
new_size = xfs_bmap_broot_space_calc(mp, rec_diff);
xfs_iroot_alloc(ip, whichfork, new_size);
return;
@@ -436,22 +478,16 @@ xfs_iroot_realloc(
/*
* If there is already an existing if_broot, then we need
* to realloc() it and shift the pointers to their new
- * location. The records don't change location because
- * they are kept butted up against the btree block header.
+ * location.
*/
- cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0);
+ cur_max = xfs_bmbt_maxrecs(mp, old_size, 0);
new_max = cur_max + rec_diff;
new_size = xfs_bmap_broot_space_calc(mp, new_max);
ifp->if_broot = krealloc(ifp->if_broot, new_size,
GFP_NOFS | __GFP_NOFAIL);
- op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1,
- ifp->if_broot_bytes);
- np = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1,
- (int)new_size);
- ifp->if_broot_bytes = (int)new_size;
- ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <=
- xfs_inode_fork_size(ip, whichfork));
- memmove(np, op, cur_max * (uint)sizeof(xfs_fsblock_t));
+ ifp->if_broot_bytes = new_size;
+ xfs_ifork_move_broot(ip, whichfork, ifp->if_broot, new_size,
+ ifp->if_broot, old_size, cur_max);
return;
}
@@ -460,8 +496,8 @@ xfs_iroot_realloc(
* if_broot buffer. It must already exist. If we go to zero
* records, just get rid of the root and clear the status bit.
*/
- ASSERT((ifp->if_broot != NULL) && (ifp->if_broot_bytes > 0));
- cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0);
+ ASSERT((ifp->if_broot != NULL) && (old_size > 0));
+ cur_max = xfs_bmbt_maxrecs(mp, old_size, 0);
new_max = cur_max + rec_diff;
ASSERT(new_max >= 0);
if (new_max > 0)
@@ -473,35 +509,14 @@ xfs_iroot_realloc(
return;
}
- /* First copy over the btree block header. */
+ /* Reallocate the btree root and move the contents. */
new_broot = kmem_alloc(new_size, KM_NOFS);
- memcpy(new_broot, ifp->if_broot, xfs_bmbt_block_len(ip->i_mount));
+ xfs_ifork_move_broot(ip, whichfork, new_broot, new_size, ifp->if_broot,
+ old_size, new_max);
- /*
- * Only copy the keys and pointers if there are any.
- */
- if (new_max > 0) {
- /*
- * First copy the keys.
- */
- op = (char *)xfs_bmbt_key_addr(mp, ifp->if_broot, 1);
- np = (char *)xfs_bmbt_key_addr(mp, new_broot, 1);
- memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_key_t));
-
- /*
- * Then copy the pointers.
- */
- op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1,
- ifp->if_broot_bytes);
- np = (char *)xfs_bmap_broot_ptr_addr(mp, new_broot, 1,
- (int)new_size);
- memcpy(np, op, new_max * (uint)sizeof(xfs_fsblock_t));
- }
kmem_free(ifp->if_broot);
ifp->if_broot = new_broot;
ifp->if_broot_bytes = (int)new_size;
- ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <=
- xfs_inode_fork_size(ip, whichfork));
return;
}
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 06/14] xfs: move the zero records logic into xfs_bmap_broot_space_calc
2023-12-31 19:53 ` [PATCHSET v2.0 07/17] xfsprogs: refactor btrees to support records in inode root Darrick J. Wong
` (4 preceding siblings ...)
2023-12-27 13:02 ` [PATCH 05/14] xfs: hoist the code that moves the incore inode fork broot memory Darrick J. Wong
@ 2023-12-27 13:02 ` Darrick J. Wong
2023-12-27 13:02 ` [PATCH 07/14] xfs: rearrange xfs_iroot_realloc a bit Darrick J. Wong
` (7 subsequent siblings)
13 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:02 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
The bmap btree cannot ever have zero records in an incore btree block.
If the number of records drops to zero, that means we're converting the
fork to extents format and are trying to remove the tree. This logic
won't hold for the future realtime rmap btree, so move the logic into
the bmbt code.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_bmap_btree.h | 7 +++++++
libxfs/xfs_inode_fork.c | 6 ++----
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/libxfs/xfs_bmap_btree.h b/libxfs/xfs_bmap_btree.h
index 3fe9c4f7f1a..5a3bae94deb 100644
--- a/libxfs/xfs_bmap_btree.h
+++ b/libxfs/xfs_bmap_btree.h
@@ -162,6 +162,13 @@ xfs_bmap_broot_space_calc(
struct xfs_mount *mp,
unsigned int nrecs)
{
+ /*
+ * If the bmbt root block is empty, we should be converting the fork
+ * to extents format. Hence, the size is zero.
+ */
+ if (nrecs == 0)
+ return 0;
+
return xfs_bmbt_block_len(mp) + \
(nrecs * (sizeof(struct xfs_bmbt_key) + sizeof(xfs_bmbt_ptr_t)));
}
diff --git a/libxfs/xfs_inode_fork.c b/libxfs/xfs_inode_fork.c
index edf6dff28b4..81f054cd212 100644
--- a/libxfs/xfs_inode_fork.c
+++ b/libxfs/xfs_inode_fork.c
@@ -500,10 +500,8 @@ xfs_iroot_realloc(
cur_max = xfs_bmbt_maxrecs(mp, old_size, 0);
new_max = cur_max + rec_diff;
ASSERT(new_max >= 0);
- if (new_max > 0)
- new_size = xfs_bmap_broot_space_calc(mp, new_max);
- else
- new_size = 0;
+
+ new_size = xfs_bmap_broot_space_calc(mp, new_max);
if (new_size == 0) {
xfs_iroot_free(ip, whichfork);
return;
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 07/14] xfs: rearrange xfs_iroot_realloc a bit
2023-12-31 19:53 ` [PATCHSET v2.0 07/17] xfsprogs: refactor btrees to support records in inode root Darrick J. Wong
` (5 preceding siblings ...)
2023-12-27 13:02 ` [PATCH 06/14] xfs: move the zero records logic into xfs_bmap_broot_space_calc Darrick J. Wong
@ 2023-12-27 13:02 ` Darrick J. Wong
2023-12-27 13:03 ` [PATCH 08/14] xfs: standardize the btree maxrecs function parameters Darrick J. Wong
` (6 subsequent siblings)
13 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:02 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Rearrange the innards of xfs_iroot_realloc so that we can reduce
duplicated code prior to genericizing the function. No functional
changes.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_inode_fork.c | 49 +++++++++++++++++++++--------------------------
1 file changed, 22 insertions(+), 27 deletions(-)
diff --git a/libxfs/xfs_inode_fork.c b/libxfs/xfs_inode_fork.c
index 81f054cd212..d070e0524b9 100644
--- a/libxfs/xfs_inode_fork.c
+++ b/libxfs/xfs_inode_fork.c
@@ -445,44 +445,46 @@ xfs_ifork_move_broot(
*/
void
xfs_iroot_realloc(
- xfs_inode_t *ip,
+ struct xfs_inode *ip,
int rec_diff,
int whichfork)
{
struct xfs_mount *mp = ip->i_mount;
- int cur_max;
struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork);
struct xfs_btree_block *new_broot;
- int new_max;
size_t new_size;
size_t old_size = ifp->if_broot_bytes;
+ int cur_max;
+ int new_max;
+
+ /* Handle degenerate cases. */
+ if (rec_diff == 0)
+ return;
/*
- * Handle the degenerate case quietly.
+ * If there wasn't any memory allocated before, just allocate it now
+ * and get out.
*/
- if (rec_diff == 0) {
+ if (old_size == 0) {
+ ASSERT(rec_diff > 0);
+
+ new_size = xfs_bmap_broot_space_calc(mp, rec_diff);
+ xfs_iroot_alloc(ip, whichfork, new_size);
return;
}
+ /* Compute the new and old record count and space requirements. */
+ cur_max = xfs_bmbt_maxrecs(mp, old_size, 0);
+ new_max = cur_max + rec_diff;
+ ASSERT(new_max >= 0);
+ new_size = xfs_bmap_broot_space_calc(mp, new_max);
+
if (rec_diff > 0) {
- /*
- * If there wasn't any memory allocated before, just
- * allocate it now and get out.
- */
- if (old_size == 0) {
- new_size = xfs_bmap_broot_space_calc(mp, rec_diff);
- xfs_iroot_alloc(ip, whichfork, new_size);
- return;
- }
-
/*
* If there is already an existing if_broot, then we need
* to realloc() it and shift the pointers to their new
* location.
*/
- cur_max = xfs_bmbt_maxrecs(mp, old_size, 0);
- new_max = cur_max + rec_diff;
- new_size = xfs_bmap_broot_space_calc(mp, new_max);
ifp->if_broot = krealloc(ifp->if_broot, new_size,
GFP_NOFS | __GFP_NOFAIL);
ifp->if_broot_bytes = new_size;
@@ -494,14 +496,8 @@ xfs_iroot_realloc(
/*
* rec_diff is less than 0. In this case, we are shrinking the
* if_broot buffer. It must already exist. If we go to zero
- * records, just get rid of the root and clear the status bit.
+ * bytes, just get rid of the root and clear the status bit.
*/
- ASSERT((ifp->if_broot != NULL) && (old_size > 0));
- cur_max = xfs_bmbt_maxrecs(mp, old_size, 0);
- new_max = cur_max + rec_diff;
- ASSERT(new_max >= 0);
-
- new_size = xfs_bmap_broot_space_calc(mp, new_max);
if (new_size == 0) {
xfs_iroot_free(ip, whichfork);
return;
@@ -514,8 +510,7 @@ xfs_iroot_realloc(
kmem_free(ifp->if_broot);
ifp->if_broot = new_broot;
- ifp->if_broot_bytes = (int)new_size;
- return;
+ ifp->if_broot_bytes = new_size;
}
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 08/14] xfs: standardize the btree maxrecs function parameters
2023-12-31 19:53 ` [PATCHSET v2.0 07/17] xfsprogs: refactor btrees to support records in inode root Darrick J. Wong
` (6 preceding siblings ...)
2023-12-27 13:02 ` [PATCH 07/14] xfs: rearrange xfs_iroot_realloc a bit Darrick J. Wong
@ 2023-12-27 13:03 ` Darrick J. Wong
2023-12-27 13:03 ` [PATCH 09/14] xfs: generalize the btree root reallocation function Darrick J. Wong
` (5 subsequent siblings)
13 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:03 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Standardize the parameters in xfs_{alloc,bm,ino,rmap,refcount}bt_maxrecs
so that we have consistent calling conventions. This doesn't affect the
kernel that much, but enables us to clean up userspace a bit.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
db/btheight.c | 18 ++++--------------
libxfs/xfs_alloc_btree.c | 6 +++---
libxfs/xfs_alloc_btree.h | 3 ++-
libxfs/xfs_bmap.c | 2 +-
libxfs/xfs_bmap_btree.c | 6 +++---
libxfs/xfs_bmap_btree.h | 5 +++--
libxfs/xfs_ialloc.c | 4 ++--
libxfs/xfs_ialloc_btree.c | 6 +++---
libxfs/xfs_ialloc_btree.h | 3 ++-
libxfs/xfs_inode_fork.c | 2 +-
libxfs/xfs_refcount_btree.c | 5 +++--
libxfs/xfs_refcount_btree.h | 3 ++-
libxfs/xfs_rmap_btree.c | 9 +++++----
libxfs/xfs_rmap_btree.h | 3 ++-
libxfs/xfs_sb.c | 16 ++++++++--------
repair/phase5.c | 16 ++++++++--------
16 files changed, 52 insertions(+), 55 deletions(-)
diff --git a/db/btheight.c b/db/btheight.c
index 0b421ab50a3..6643489c82c 100644
--- a/db/btheight.c
+++ b/db/btheight.c
@@ -12,21 +12,11 @@
#include "input.h"
#include "libfrog/convert.h"
-static int refc_maxrecs(struct xfs_mount *mp, int blocklen, int leaf)
-{
- return libxfs_refcountbt_maxrecs(blocklen, leaf != 0);
-}
-
-static int rmap_maxrecs(struct xfs_mount *mp, int blocklen, int leaf)
-{
- return libxfs_rmapbt_maxrecs(blocklen, leaf);
-}
-
struct btmap {
const char *tag;
unsigned int (*maxlevels)(void);
- int (*maxrecs)(struct xfs_mount *mp, int blocklen,
- int leaf);
+ unsigned int (*maxrecs)(struct xfs_mount *mp, unsigned int blocklen,
+ bool leaf);
} maps[] = {
{
.tag = "bnobt",
@@ -56,12 +46,12 @@ struct btmap {
{
.tag = "refcountbt",
.maxlevels = libxfs_refcountbt_maxlevels_ondisk,
- .maxrecs = refc_maxrecs,
+ .maxrecs = libxfs_refcountbt_maxrecs,
},
{
.tag = "rmapbt",
.maxlevels = libxfs_rmapbt_maxlevels_ondisk,
- .maxrecs = rmap_maxrecs,
+ .maxrecs = libxfs_rmapbt_maxrecs,
},
};
diff --git a/libxfs/xfs_alloc_btree.c b/libxfs/xfs_alloc_btree.c
index 93faa832e5b..a03a8776c21 100644
--- a/libxfs/xfs_alloc_btree.c
+++ b/libxfs/xfs_alloc_btree.c
@@ -609,11 +609,11 @@ xfs_allocbt_block_maxrecs(
/*
* Calculate number of records in an alloc btree block.
*/
-int
+unsigned int
xfs_allocbt_maxrecs(
struct xfs_mount *mp,
- int blocklen,
- int leaf)
+ unsigned int blocklen,
+ bool leaf)
{
blocklen -= XFS_ALLOC_BLOCK_LEN(mp);
return xfs_allocbt_block_maxrecs(blocklen, leaf);
diff --git a/libxfs/xfs_alloc_btree.h b/libxfs/xfs_alloc_btree.h
index 45df893ef6b..f61f51d0bd7 100644
--- a/libxfs/xfs_alloc_btree.h
+++ b/libxfs/xfs_alloc_btree.h
@@ -53,7 +53,8 @@ extern struct xfs_btree_cur *xfs_allocbt_init_cursor(struct xfs_mount *mp,
struct xfs_btree_cur *xfs_allocbt_stage_cursor(struct xfs_mount *mp,
struct xbtree_afakeroot *afake, struct xfs_perag *pag,
xfs_btnum_t btnum);
-extern int xfs_allocbt_maxrecs(struct xfs_mount *, int, int);
+unsigned int xfs_allocbt_maxrecs(struct xfs_mount *mp, unsigned int blocklen,
+ bool leaf);
extern xfs_extlen_t xfs_allocbt_calc_size(struct xfs_mount *mp,
unsigned long long len);
diff --git a/libxfs/xfs_bmap.c b/libxfs/xfs_bmap.c
index 5935f87833b..7fefbb7d21c 100644
--- a/libxfs/xfs_bmap.c
+++ b/libxfs/xfs_bmap.c
@@ -560,7 +560,7 @@ xfs_bmap_btree_to_extents(
ASSERT(ifp->if_format == XFS_DINODE_FMT_BTREE);
ASSERT(be16_to_cpu(rblock->bb_level) == 1);
ASSERT(be16_to_cpu(rblock->bb_numrecs) == 1);
- ASSERT(xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0) == 1);
+ ASSERT(xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, false) == 1);
pp = xfs_bmap_broot_ptr_addr(mp, rblock, 1, ifp->if_broot_bytes);
cbno = be64_to_cpu(*pp);
diff --git a/libxfs/xfs_bmap_btree.c b/libxfs/xfs_bmap_btree.c
index 1dd8d12af8f..1e7b89e7730 100644
--- a/libxfs/xfs_bmap_btree.c
+++ b/libxfs/xfs_bmap_btree.c
@@ -664,11 +664,11 @@ xfs_bmbt_commit_staged_btree(
/*
* Calculate number of records in a bmap btree block.
*/
-int
+unsigned int
xfs_bmbt_maxrecs(
struct xfs_mount *mp,
- int blocklen,
- int leaf)
+ unsigned int blocklen,
+ bool leaf)
{
blocklen -= xfs_bmbt_block_len(mp);
return xfs_bmbt_block_maxrecs(blocklen, leaf);
diff --git a/libxfs/xfs_bmap_btree.h b/libxfs/xfs_bmap_btree.h
index 5a3bae94deb..a9ddc9b42e6 100644
--- a/libxfs/xfs_bmap_btree.h
+++ b/libxfs/xfs_bmap_btree.h
@@ -35,7 +35,8 @@ extern void xfs_bmbt_to_bmdr(struct xfs_mount *, struct xfs_btree_block *, int,
extern int xfs_bmbt_get_maxrecs(struct xfs_btree_cur *, int level);
extern int xfs_bmdr_maxrecs(int blocklen, int leaf);
-extern int xfs_bmbt_maxrecs(struct xfs_mount *, int blocklen, int leaf);
+unsigned int xfs_bmbt_maxrecs(struct xfs_mount *mp, unsigned int blocklen,
+ bool leaf);
extern int xfs_bmbt_change_owner(struct xfs_trans *tp, struct xfs_inode *ip,
int whichfork, xfs_ino_t new_owner,
@@ -150,7 +151,7 @@ xfs_bmap_broot_ptr_addr(
unsigned int i,
unsigned int sz)
{
- return xfs_bmbt_ptr_addr(mp, bb, i, xfs_bmbt_maxrecs(mp, sz, 0));
+ return xfs_bmbt_ptr_addr(mp, bb, i, xfs_bmbt_maxrecs(mp, sz, false));
}
/*
diff --git a/libxfs/xfs_ialloc.c b/libxfs/xfs_ialloc.c
index 19543f76994..8aae4b79c85 100644
--- a/libxfs/xfs_ialloc.c
+++ b/libxfs/xfs_ialloc.c
@@ -2914,8 +2914,8 @@ xfs_ialloc_setup_geometry(
/* Compute inode btree geometry. */
igeo->agino_log = sbp->sb_inopblog + sbp->sb_agblklog;
- igeo->inobt_mxr[0] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 1);
- igeo->inobt_mxr[1] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 0);
+ igeo->inobt_mxr[0] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, true);
+ igeo->inobt_mxr[1] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, false);
igeo->inobt_mnr[0] = igeo->inobt_mxr[0] / 2;
igeo->inobt_mnr[1] = igeo->inobt_mxr[1] / 2;
diff --git a/libxfs/xfs_ialloc_btree.c b/libxfs/xfs_ialloc_btree.c
index 4275244b15c..80d28d3fea5 100644
--- a/libxfs/xfs_ialloc_btree.c
+++ b/libxfs/xfs_ialloc_btree.c
@@ -558,11 +558,11 @@ xfs_inobt_block_maxrecs(
/*
* Calculate number of records in an inobt btree block.
*/
-int
+unsigned int
xfs_inobt_maxrecs(
struct xfs_mount *mp,
- int blocklen,
- int leaf)
+ unsigned int blocklen,
+ bool leaf)
{
blocklen -= XFS_INOBT_BLOCK_LEN(mp);
return xfs_inobt_block_maxrecs(blocklen, leaf);
diff --git a/libxfs/xfs_ialloc_btree.h b/libxfs/xfs_ialloc_btree.h
index 3262c3fe5eb..ed0f619fd33 100644
--- a/libxfs/xfs_ialloc_btree.h
+++ b/libxfs/xfs_ialloc_btree.h
@@ -50,7 +50,8 @@ extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_perag *pag,
struct xfs_trans *tp, struct xfs_buf *agbp, xfs_btnum_t btnum);
struct xfs_btree_cur *xfs_inobt_stage_cursor(struct xfs_perag *pag,
struct xbtree_afakeroot *afake, xfs_btnum_t btnum);
-extern int xfs_inobt_maxrecs(struct xfs_mount *, int, int);
+unsigned int xfs_inobt_maxrecs(struct xfs_mount *mp, unsigned int blocklen,
+ bool leaf);
/* ir_holemask to inode allocation bitmap conversion */
uint64_t xfs_inobt_irec_to_allocmask(const struct xfs_inobt_rec_incore *irec);
diff --git a/libxfs/xfs_inode_fork.c b/libxfs/xfs_inode_fork.c
index d070e0524b9..bb66028bff0 100644
--- a/libxfs/xfs_inode_fork.c
+++ b/libxfs/xfs_inode_fork.c
@@ -474,7 +474,7 @@ xfs_iroot_realloc(
}
/* Compute the new and old record count and space requirements. */
- cur_max = xfs_bmbt_maxrecs(mp, old_size, 0);
+ cur_max = xfs_bmbt_maxrecs(mp, old_size, false);
new_max = cur_max + rec_diff;
ASSERT(new_max >= 0);
new_size = xfs_bmap_broot_space_calc(mp, new_max);
diff --git a/libxfs/xfs_refcount_btree.c b/libxfs/xfs_refcount_btree.c
index ab8925051a9..1fbd250c1a8 100644
--- a/libxfs/xfs_refcount_btree.c
+++ b/libxfs/xfs_refcount_btree.c
@@ -433,9 +433,10 @@ xfs_refcountbt_block_maxrecs(
/*
* Calculate the number of records in a refcount btree block.
*/
-int
+unsigned int
xfs_refcountbt_maxrecs(
- int blocklen,
+ struct xfs_mount *mp,
+ unsigned int blocklen,
bool leaf)
{
blocklen -= XFS_REFCOUNT_BLOCK_LEN;
diff --git a/libxfs/xfs_refcount_btree.h b/libxfs/xfs_refcount_btree.h
index d66b37259be..fe3c20d6779 100644
--- a/libxfs/xfs_refcount_btree.h
+++ b/libxfs/xfs_refcount_btree.h
@@ -50,7 +50,8 @@ extern struct xfs_btree_cur *xfs_refcountbt_init_cursor(struct xfs_mount *mp,
struct xfs_perag *pag);
struct xfs_btree_cur *xfs_refcountbt_stage_cursor(struct xfs_mount *mp,
struct xbtree_afakeroot *afake, struct xfs_perag *pag);
-extern int xfs_refcountbt_maxrecs(int blocklen, bool leaf);
+unsigned int xfs_refcountbt_maxrecs(struct xfs_mount *mp, unsigned int blocklen,
+ bool leaf);
extern void xfs_refcountbt_compute_maxlevels(struct xfs_mount *mp);
extern xfs_extlen_t xfs_refcountbt_calc_size(struct xfs_mount *mp,
diff --git a/libxfs/xfs_rmap_btree.c b/libxfs/xfs_rmap_btree.c
index 7342623ed5e..23ea9cd992f 100644
--- a/libxfs/xfs_rmap_btree.c
+++ b/libxfs/xfs_rmap_btree.c
@@ -587,7 +587,7 @@ xfs_rmapbt_mem_verify(
}
return xfbtree_sblock_verify(bp,
- xfs_rmapbt_maxrecs(xfo_to_b(1), level == 0));
+ xfs_rmapbt_maxrecs(mp, xfo_to_b(1), level == 0));
}
static void
@@ -715,10 +715,11 @@ xfs_rmapbt_block_maxrecs(
/*
* Calculate number of records in an rmap btree block.
*/
-int
+unsigned int
xfs_rmapbt_maxrecs(
- int blocklen,
- int leaf)
+ struct xfs_mount *mp,
+ unsigned int blocklen,
+ bool leaf)
{
blocklen -= XFS_RMAP_BLOCK_LEN;
return xfs_rmapbt_block_maxrecs(blocklen, leaf);
diff --git a/libxfs/xfs_rmap_btree.h b/libxfs/xfs_rmap_btree.h
index 5d0454fd052..415fad8dad7 100644
--- a/libxfs/xfs_rmap_btree.h
+++ b/libxfs/xfs_rmap_btree.h
@@ -48,7 +48,8 @@ struct xfs_btree_cur *xfs_rmapbt_stage_cursor(struct xfs_mount *mp,
struct xbtree_afakeroot *afake, struct xfs_perag *pag);
void xfs_rmapbt_commit_staged_btree(struct xfs_btree_cur *cur,
struct xfs_trans *tp, struct xfs_buf *agbp);
-int xfs_rmapbt_maxrecs(int blocklen, int leaf);
+unsigned int xfs_rmapbt_maxrecs(struct xfs_mount *mp, unsigned int blocklen,
+ bool leaf);
extern void xfs_rmapbt_compute_maxlevels(struct xfs_mount *mp);
extern xfs_extlen_t xfs_rmapbt_calc_size(struct xfs_mount *mp,
diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c
index d04a8e15331..aff2ab79f9b 100644
--- a/libxfs/xfs_sb.c
+++ b/libxfs/xfs_sb.c
@@ -1108,23 +1108,23 @@ xfs_sb_mount_common(
mp->m_rgblklog = log2_if_power2(sbp->sb_rgblocks);
mp->m_rgblkmask = mask64_if_power2(sbp->sb_rgblocks);
- mp->m_alloc_mxr[0] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 1);
- mp->m_alloc_mxr[1] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 0);
+ mp->m_alloc_mxr[0] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, true);
+ mp->m_alloc_mxr[1] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, false);
mp->m_alloc_mnr[0] = mp->m_alloc_mxr[0] / 2;
mp->m_alloc_mnr[1] = mp->m_alloc_mxr[1] / 2;
- mp->m_bmap_dmxr[0] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, 1);
- mp->m_bmap_dmxr[1] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, 0);
+ mp->m_bmap_dmxr[0] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, true);
+ mp->m_bmap_dmxr[1] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, false);
mp->m_bmap_dmnr[0] = mp->m_bmap_dmxr[0] / 2;
mp->m_bmap_dmnr[1] = mp->m_bmap_dmxr[1] / 2;
- mp->m_rmap_mxr[0] = xfs_rmapbt_maxrecs(sbp->sb_blocksize, 1);
- mp->m_rmap_mxr[1] = xfs_rmapbt_maxrecs(sbp->sb_blocksize, 0);
+ mp->m_rmap_mxr[0] = xfs_rmapbt_maxrecs(mp, sbp->sb_blocksize, true);
+ mp->m_rmap_mxr[1] = xfs_rmapbt_maxrecs(mp, sbp->sb_blocksize, false);
mp->m_rmap_mnr[0] = mp->m_rmap_mxr[0] / 2;
mp->m_rmap_mnr[1] = mp->m_rmap_mxr[1] / 2;
- mp->m_refc_mxr[0] = xfs_refcountbt_maxrecs(sbp->sb_blocksize, true);
- mp->m_refc_mxr[1] = xfs_refcountbt_maxrecs(sbp->sb_blocksize, false);
+ mp->m_refc_mxr[0] = xfs_refcountbt_maxrecs(mp, sbp->sb_blocksize, true);
+ mp->m_refc_mxr[1] = xfs_refcountbt_maxrecs(mp, sbp->sb_blocksize, false);
mp->m_refc_mnr[0] = mp->m_refc_mxr[0] / 2;
mp->m_refc_mnr[1] = mp->m_refc_mxr[1] / 2;
diff --git a/repair/phase5.c b/repair/phase5.c
index 983f2169228..74594d53a87 100644
--- a/repair/phase5.c
+++ b/repair/phase5.c
@@ -644,21 +644,21 @@ phase5(xfs_mount_t *mp)
#ifdef XR_BLD_FREE_TRACE
fprintf(stderr, "inobt level 1, maxrec = %d, minrec = %d\n",
- libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, 0),
- libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, 0) / 2);
+ libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, false),
+ libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, false) / 2);
fprintf(stderr, "inobt level 0 (leaf), maxrec = %d, minrec = %d\n",
- libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, 1),
- libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, 1) / 2);
+ libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, true),
+ libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, true) / 2);
fprintf(stderr, "xr inobt level 0 (leaf), maxrec = %d\n",
XR_INOBT_BLOCK_MAXRECS(mp, 0));
fprintf(stderr, "xr inobt level 1 (int), maxrec = %d\n",
XR_INOBT_BLOCK_MAXRECS(mp, 1));
fprintf(stderr, "bnobt level 1, maxrec = %d, minrec = %d\n",
- libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, 0),
- libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, 0) / 2);
+ libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, false),
+ libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, false) / 2);
fprintf(stderr, "bnobt level 0 (leaf), maxrec = %d, minrec = %d\n",
- libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, 1),
- libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, 1) / 2);
+ libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, true),
+ libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, true) / 2);
#endif
/*
* make sure the root and realtime inodes show up allocated
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 09/14] xfs: generalize the btree root reallocation function
2023-12-31 19:53 ` [PATCHSET v2.0 07/17] xfsprogs: refactor btrees to support records in inode root Darrick J. Wong
` (7 preceding siblings ...)
2023-12-27 13:03 ` [PATCH 08/14] xfs: standardize the btree maxrecs function parameters Darrick J. Wong
@ 2023-12-27 13:03 ` Darrick J. Wong
2023-12-27 13:03 ` [PATCH 10/14] xfs: support leaves in the incore btree root block in xfs_iroot_realloc Darrick J. Wong
` (4 subsequent siblings)
13 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:03 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
In preparation for storing realtime rmap btree roots in an inode fork,
make xfs_iroot_realloc take an ops structure that takes care of all the
btree-specific geometry pieces.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_bmap_btree.c | 51 +++++++++++++++++++++++++++++
libxfs/xfs_btree.c | 22 ++++++++-----
libxfs/xfs_btree.h | 3 ++
libxfs/xfs_inode_fork.c | 82 ++++++++++-------------------------------------
libxfs/xfs_inode_fork.h | 23 +++++++++++++
5 files changed, 107 insertions(+), 74 deletions(-)
diff --git a/libxfs/xfs_bmap_btree.c b/libxfs/xfs_bmap_btree.c
index 1e7b89e7730..4156e23a2da 100644
--- a/libxfs/xfs_bmap_btree.c
+++ b/libxfs/xfs_bmap_btree.c
@@ -511,6 +511,56 @@ xfs_bmbt_keys_contiguous(
be64_to_cpu(key2->bmbt.br_startoff));
}
+/* Move the bmap btree root from one incore buffer to another. */
+static void
+xfs_bmbt_broot_move(
+ struct xfs_inode *ip,
+ int whichfork,
+ struct xfs_btree_block *dst_broot,
+ size_t dst_bytes,
+ struct xfs_btree_block *src_broot,
+ size_t src_bytes,
+ unsigned int numrecs)
+{
+ struct xfs_mount *mp = ip->i_mount;
+ void *dptr;
+ void *sptr;
+
+ ASSERT(xfs_bmap_bmdr_space(src_broot) <= xfs_inode_fork_size(ip, whichfork));
+
+ /*
+ * We always have to move the pointers because they are not butted
+ * against the btree block header.
+ */
+ if (numrecs) {
+ sptr = xfs_bmap_broot_ptr_addr(mp, src_broot, 1, src_bytes);
+ dptr = xfs_bmap_broot_ptr_addr(mp, dst_broot, 1, dst_bytes);
+ memmove(dptr, sptr, numrecs * sizeof(xfs_fsblock_t));
+ }
+
+ if (src_broot == dst_broot)
+ return;
+
+ /*
+ * If the root is being totally relocated, we have to migrate the block
+ * header and the keys that come after it.
+ */
+ memcpy(dst_broot, src_broot, xfs_bmbt_block_len(mp));
+
+ /* Now copy the keys, which come right after the header. */
+ if (numrecs) {
+ sptr = xfs_bmbt_key_addr(mp, src_broot, 1);
+ dptr = xfs_bmbt_key_addr(mp, dst_broot, 1);
+ memcpy(dptr, sptr, numrecs * sizeof(struct xfs_bmbt_key));
+ }
+}
+
+static const struct xfs_ifork_broot_ops xfs_bmbt_iroot_ops = {
+ .maxrecs = xfs_bmbt_maxrecs,
+ .size = xfs_bmap_broot_space_calc,
+ .move = xfs_bmbt_broot_move,
+};
+
const struct xfs_btree_ops xfs_bmbt_ops = {
.rec_len = sizeof(xfs_bmbt_rec_t),
.key_len = sizeof(xfs_bmbt_key_t),
@@ -534,6 +584,7 @@ const struct xfs_btree_ops xfs_bmbt_ops = {
.keys_inorder = xfs_bmbt_keys_inorder,
.recs_inorder = xfs_bmbt_recs_inorder,
.keys_contiguous = xfs_bmbt_keys_contiguous,
+ .iroot_ops = &xfs_bmbt_iroot_ops,
};
static struct xfs_btree_cur *
diff --git a/libxfs/xfs_btree.c b/libxfs/xfs_btree.c
index 7cc6379a113..b6f73fcc6d6 100644
--- a/libxfs/xfs_btree.c
+++ b/libxfs/xfs_btree.c
@@ -3068,6 +3068,16 @@ xfs_btree_split(
#define xfs_btree_split __xfs_btree_split
#endif /* __KERNEL__ */
+static inline void
+xfs_btree_iroot_realloc(
+ struct xfs_btree_cur *cur,
+ int rec_diff)
+{
+ ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE);
+
+ xfs_iroot_realloc(cur->bc_ino.ip, cur->bc_ino.whichfork,
+ cur->bc_ops->iroot_ops, rec_diff);
+}
/*
* Copy the old inode root contents into a real block and make the
@@ -3152,9 +3162,7 @@ xfs_btree_new_iroot(
xfs_btree_copy_ptrs(cur, pp, &nptr, 1);
- xfs_iroot_realloc(cur->bc_ino.ip,
- 1 - xfs_btree_get_numrecs(cblock),
- cur->bc_ino.whichfork);
+ xfs_btree_iroot_realloc(cur, 1 - xfs_btree_get_numrecs(cblock));
xfs_btree_setbuf(cur, level, cbp);
@@ -3324,7 +3332,7 @@ xfs_btree_make_block_unfull(
if (numrecs < cur->bc_ops->get_dmaxrecs(cur, level)) {
/* A root block that can be made bigger. */
- xfs_iroot_realloc(ip, 1, cur->bc_ino.whichfork);
+ xfs_btree_iroot_realloc(cur, 1);
*stat = 1;
} else {
/* A root block that needs replacing */
@@ -3732,8 +3740,7 @@ xfs_btree_kill_iroot(
index = numrecs - cur->bc_ops->get_maxrecs(cur, level);
if (index) {
- xfs_iroot_realloc(cur->bc_ino.ip, index,
- cur->bc_ino.whichfork);
+ xfs_btree_iroot_realloc(cur, index);
block = ifp->if_broot;
}
@@ -3930,8 +3937,7 @@ xfs_btree_delrec(
*/
if (level == cur->bc_nlevels - 1) {
if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) {
- xfs_iroot_realloc(cur->bc_ino.ip, -1,
- cur->bc_ino.whichfork);
+ xfs_btree_iroot_realloc(cur, -1);
error = xfs_btree_kill_iroot(cur);
if (error)
diff --git a/libxfs/xfs_btree.h b/libxfs/xfs_btree.h
index 339b5561e5b..7872fc1739b 100644
--- a/libxfs/xfs_btree.h
+++ b/libxfs/xfs_btree.h
@@ -205,6 +205,9 @@ struct xfs_btree_ops {
const union xfs_btree_key *key1,
const union xfs_btree_key *key2,
const union xfs_btree_key *mask);
+
+ /* Functions for manipulating the btree root block. */
+ const struct xfs_ifork_broot_ops *iroot_ops;
};
/*
diff --git a/libxfs/xfs_inode_fork.c b/libxfs/xfs_inode_fork.c
index bb66028bff0..50422bbeb8f 100644
--- a/libxfs/xfs_inode_fork.c
+++ b/libxfs/xfs_inode_fork.c
@@ -381,50 +381,6 @@ xfs_iroot_free(
ifp->if_broot = NULL;
}
-/* Move the bmap btree root from one incore buffer to another. */
-static void
-xfs_ifork_move_broot(
- struct xfs_inode *ip,
- int whichfork,
- struct xfs_btree_block *dst_broot,
- size_t dst_bytes,
- struct xfs_btree_block *src_broot,
- size_t src_bytes,
- unsigned int numrecs)
-{
- struct xfs_mount *mp = ip->i_mount;
- void *dptr;
- void *sptr;
-
- ASSERT(xfs_bmap_bmdr_space(src_broot) <= xfs_inode_fork_size(ip, whichfork));
-
- /*
- * We always have to move the pointers because they are not butted
- * against the btree block header.
- */
- if (numrecs) {
- sptr = xfs_bmap_broot_ptr_addr(mp, src_broot, 1, src_bytes);
- dptr = xfs_bmap_broot_ptr_addr(mp, dst_broot, 1, dst_bytes);
- memmove(dptr, sptr, numrecs * sizeof(xfs_fsblock_t));
- }
-
- if (src_broot == dst_broot)
- return;
-
- /*
- * If the root is being totally relocated, we have to migrate the block
- * header and the keys that come after it.
- */
- memcpy(dst_broot, src_broot, xfs_bmbt_block_len(mp));
-
- /* Now copy the keys, which come right after the header. */
- if (numrecs) {
- sptr = xfs_bmbt_key_addr(mp, src_broot, 1);
- dptr = xfs_bmbt_key_addr(mp, dst_broot, 1);
- memcpy(dptr, sptr, numrecs * sizeof(struct xfs_bmbt_key));
- }
-}
-
/*
* Reallocate the space for if_broot based on the number of records
* being added or deleted as indicated in rec_diff. Move the records
@@ -438,24 +394,21 @@ xfs_ifork_move_broot(
* if we are adding records, one will be allocated. The caller must also
* not request that the number of records go below zero, although
* it can go to zero.
- *
- * ip -- the inode whose if_broot area is changing
- * ext_diff -- the change in the number of records, positive or negative,
- * requested for the if_broot array.
*/
void
xfs_iroot_realloc(
- struct xfs_inode *ip,
- int rec_diff,
- int whichfork)
+ struct xfs_inode *ip,
+ int whichfork,
+ const struct xfs_ifork_broot_ops *ops,
+ int rec_diff)
{
- struct xfs_mount *mp = ip->i_mount;
- struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork);
- struct xfs_btree_block *new_broot;
- size_t new_size;
- size_t old_size = ifp->if_broot_bytes;
- int cur_max;
- int new_max;
+ struct xfs_mount *mp = ip->i_mount;
+ struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork);
+ struct xfs_btree_block *new_broot;
+ size_t new_size;
+ size_t old_size = ifp->if_broot_bytes;
+ int cur_max;
+ int new_max;
/* Handle degenerate cases. */
if (rec_diff == 0)
@@ -468,16 +421,16 @@ xfs_iroot_realloc(
if (old_size == 0) {
ASSERT(rec_diff > 0);
- new_size = xfs_bmap_broot_space_calc(mp, rec_diff);
+ new_size = ops->size(mp, rec_diff);
xfs_iroot_alloc(ip, whichfork, new_size);
return;
}
/* Compute the new and old record count and space requirements. */
- cur_max = xfs_bmbt_maxrecs(mp, old_size, false);
+ cur_max = ops->maxrecs(mp, old_size, false);
new_max = cur_max + rec_diff;
ASSERT(new_max >= 0);
- new_size = xfs_bmap_broot_space_calc(mp, new_max);
+ new_size = ops->size(mp, new_max);
if (rec_diff > 0) {
/*
@@ -488,7 +441,7 @@ xfs_iroot_realloc(
ifp->if_broot = krealloc(ifp->if_broot, new_size,
GFP_NOFS | __GFP_NOFAIL);
ifp->if_broot_bytes = new_size;
- xfs_ifork_move_broot(ip, whichfork, ifp->if_broot, new_size,
+ ops->move(ip, whichfork, ifp->if_broot, new_size,
ifp->if_broot, old_size, cur_max);
return;
}
@@ -505,15 +458,14 @@ xfs_iroot_realloc(
/* Reallocate the btree root and move the contents. */
new_broot = kmem_alloc(new_size, KM_NOFS);
- xfs_ifork_move_broot(ip, whichfork, new_broot, new_size, ifp->if_broot,
- old_size, new_max);
+ ops->move(ip, whichfork, new_broot, new_size, ifp->if_broot,
+ ifp->if_broot_bytes, new_max);
kmem_free(ifp->if_broot);
ifp->if_broot = new_broot;
ifp->if_broot_bytes = new_size;
}
-
/*
* This is called when the amount of space needed for if_data
* is increased or decreased. The change in size is indicated by
diff --git a/libxfs/xfs_inode_fork.h b/libxfs/xfs_inode_fork.h
index 18ea2d27777..1ac9a7a8b5f 100644
--- a/libxfs/xfs_inode_fork.h
+++ b/libxfs/xfs_inode_fork.h
@@ -175,7 +175,6 @@ void xfs_idata_realloc(struct xfs_inode *ip, int64_t byte_diff,
void xfs_iroot_alloc(struct xfs_inode *ip, int whichfork,
size_t bytes);
void xfs_iroot_free(struct xfs_inode *ip, int whichfork);
-void xfs_iroot_realloc(struct xfs_inode *, int, int);
int xfs_iread_extents(struct xfs_trans *, struct xfs_inode *, int);
int xfs_iextents_copy(struct xfs_inode *, struct xfs_bmbt_rec *,
int);
@@ -274,4 +273,26 @@ static inline bool xfs_need_iread_extents(const struct xfs_ifork *ifp)
return smp_load_acquire(&ifp->if_needextents) != 0;
}
+struct xfs_ifork_broot_ops {
+ /* Calculate the number of records/keys in the incore btree block. */
+ unsigned int (*maxrecs)(struct xfs_mount *mp, unsigned int blocksize,
+ bool leaf);
+
+ /* Calculate the bytes required for the incore btree root block. */
+ size_t (*size)(struct xfs_mount *mp, unsigned int nrecs);
+
+ /*
+ * Move an incore btree root from one buffer to another. Note that
+ * src_broot and dst_broot could be the same or they could be totally
+ * separate memory regions.
+ */
+ void (*move)(struct xfs_inode *ip, int whichfork,
+ struct xfs_btree_block *dst_broot, size_t dst_bytes,
+ struct xfs_btree_block *src_broot, size_t src_bytes,
+ unsigned int numrecs);
+};
+
+void xfs_iroot_realloc(struct xfs_inode *ip, int whichfork,
+ const struct xfs_ifork_broot_ops *ops, int rec_diff);
+
#endif /* __XFS_INODE_FORK_H__ */
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 10/14] xfs: support leaves in the incore btree root block in xfs_iroot_realloc
2023-12-31 19:53 ` [PATCHSET v2.0 07/17] xfsprogs: refactor btrees to support records in inode root Darrick J. Wong
` (8 preceding siblings ...)
2023-12-27 13:03 ` [PATCH 09/14] xfs: generalize the btree root reallocation function Darrick J. Wong
@ 2023-12-27 13:03 ` Darrick J. Wong
2023-12-27 13:03 ` [PATCH 11/14] xfs: hoist the node iroot update code out of xfs_btree_new_iroot Darrick J. Wong
` (3 subsequent siblings)
13 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:03 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Add some logic to xfs_iroot_realloc so that we can handle leaf records
in the btree root block correctly.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
db/bmap_inflate.c | 2 +-
libxfs/xfs_bmap_btree.c | 4 +++-
libxfs/xfs_bmap_btree.h | 5 ++++-
libxfs/xfs_inode_fork.c | 12 +++++++-----
libxfs/xfs_inode_fork.h | 5 +++--
repair/bmap_repair.c | 2 +-
6 files changed, 19 insertions(+), 11 deletions(-)
diff --git a/db/bmap_inflate.c b/db/bmap_inflate.c
index 118d911a1db..b08204201c2 100644
--- a/db/bmap_inflate.c
+++ b/db/bmap_inflate.c
@@ -282,7 +282,7 @@ iroot_size(
unsigned int nr_this_level,
void *priv)
{
- return xfs_bmap_broot_space_calc(cur->bc_mp, nr_this_level);
+ return xfs_bmap_broot_space_calc(cur->bc_mp, level, nr_this_level);
}
static int
diff --git a/libxfs/xfs_bmap_btree.c b/libxfs/xfs_bmap_btree.c
index 4156e23a2da..8658e7c390a 100644
--- a/libxfs/xfs_bmap_btree.c
+++ b/libxfs/xfs_bmap_btree.c
@@ -520,6 +520,7 @@ xfs_bmbt_broot_move(
size_t dst_bytes,
struct xfs_btree_block *src_broot,
size_t src_bytes,
+ unsigned int level,
unsigned int numrecs)
{
struct xfs_mount *mp = ip->i_mount;
@@ -527,6 +528,7 @@ xfs_bmbt_broot_move(
void *sptr;
ASSERT(xfs_bmap_bmdr_space(src_broot) <= xfs_inode_fork_size(ip, whichfork));
+ ASSERT(level > 0);
/*
* We always have to move the pointers because they are not butted
@@ -839,7 +841,7 @@ xfs_bmbt_iroot_alloc(
struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork);
xfs_iroot_alloc(ip, whichfork,
- xfs_bmap_broot_space_calc(ip->i_mount, 1));
+ xfs_bmap_broot_space_calc(ip->i_mount, 1, 1));
/* Fill in the root. */
xfs_btree_init_block(ip->i_mount, ifp->if_broot, &xfs_bmbt_ops, 1, 1,
diff --git a/libxfs/xfs_bmap_btree.h b/libxfs/xfs_bmap_btree.h
index a9ddc9b42e6..d20321bfe2f 100644
--- a/libxfs/xfs_bmap_btree.h
+++ b/libxfs/xfs_bmap_btree.h
@@ -161,8 +161,11 @@ xfs_bmap_broot_ptr_addr(
static inline size_t
xfs_bmap_broot_space_calc(
struct xfs_mount *mp,
+ unsigned int level,
unsigned int nrecs)
{
+ ASSERT(level > 0);
+
/*
* If the bmbt root block is empty, we should be converting the fork
* to extents format. Hence, the size is zero.
@@ -183,7 +186,7 @@ xfs_bmap_broot_space(
struct xfs_mount *mp,
struct xfs_bmdr_block *bb)
{
- return xfs_bmap_broot_space_calc(mp, be16_to_cpu(bb->bb_numrecs));
+ return xfs_bmap_broot_space_calc(mp, 1, be16_to_cpu(bb->bb_numrecs));
}
/* Compute the space required for the ondisk root block. */
diff --git a/libxfs/xfs_inode_fork.c b/libxfs/xfs_inode_fork.c
index 50422bbeb8f..ec3a399e798 100644
--- a/libxfs/xfs_inode_fork.c
+++ b/libxfs/xfs_inode_fork.c
@@ -407,6 +407,7 @@ xfs_iroot_realloc(
struct xfs_btree_block *new_broot;
size_t new_size;
size_t old_size = ifp->if_broot_bytes;
+ unsigned int level;
int cur_max;
int new_max;
@@ -421,16 +422,17 @@ xfs_iroot_realloc(
if (old_size == 0) {
ASSERT(rec_diff > 0);
- new_size = ops->size(mp, rec_diff);
+ new_size = ops->size(mp, 0, rec_diff);
xfs_iroot_alloc(ip, whichfork, new_size);
return;
}
/* Compute the new and old record count and space requirements. */
- cur_max = ops->maxrecs(mp, old_size, false);
+ level = be16_to_cpu(ifp->if_broot->bb_level);
+ cur_max = ops->maxrecs(mp, old_size, level == 0);
new_max = cur_max + rec_diff;
ASSERT(new_max >= 0);
- new_size = ops->size(mp, new_max);
+ new_size = ops->size(mp, level, new_max);
if (rec_diff > 0) {
/*
@@ -442,7 +444,7 @@ xfs_iroot_realloc(
GFP_NOFS | __GFP_NOFAIL);
ifp->if_broot_bytes = new_size;
ops->move(ip, whichfork, ifp->if_broot, new_size,
- ifp->if_broot, old_size, cur_max);
+ ifp->if_broot, old_size, level, cur_max);
return;
}
@@ -459,7 +461,7 @@ xfs_iroot_realloc(
/* Reallocate the btree root and move the contents. */
new_broot = kmem_alloc(new_size, KM_NOFS);
ops->move(ip, whichfork, new_broot, new_size, ifp->if_broot,
- ifp->if_broot_bytes, new_max);
+ ifp->if_broot_bytes, level, new_max);
kmem_free(ifp->if_broot);
ifp->if_broot = new_broot;
diff --git a/libxfs/xfs_inode_fork.h b/libxfs/xfs_inode_fork.h
index 1ac9a7a8b5f..9a0136f8273 100644
--- a/libxfs/xfs_inode_fork.h
+++ b/libxfs/xfs_inode_fork.h
@@ -279,7 +279,8 @@ struct xfs_ifork_broot_ops {
bool leaf);
/* Calculate the bytes required for the incore btree root block. */
- size_t (*size)(struct xfs_mount *mp, unsigned int nrecs);
+ size_t (*size)(struct xfs_mount *mp, unsigned int level,
+ unsigned int nrecs);
/*
* Move an incore btree root from one buffer to another. Note that
@@ -289,7 +290,7 @@ struct xfs_ifork_broot_ops {
void (*move)(struct xfs_inode *ip, int whichfork,
struct xfs_btree_block *dst_broot, size_t dst_bytes,
struct xfs_btree_block *src_broot, size_t src_bytes,
- unsigned int numrecs);
+ unsigned int level, unsigned int numrecs);
};
void xfs_iroot_realloc(struct xfs_inode *ip, int whichfork,
diff --git a/repair/bmap_repair.c b/repair/bmap_repair.c
index a8cbff67ceb..dfd1405cca2 100644
--- a/repair/bmap_repair.c
+++ b/repair/bmap_repair.c
@@ -285,7 +285,7 @@ xrep_bmap_iroot_size(
{
ASSERT(level > 0);
- return xfs_bmap_broot_space_calc(cur->bc_mp, nr_this_level);
+ return xfs_bmap_broot_space_calc(cur->bc_mp, level, nr_this_level);
}
/* Update the inode counters. */
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 11/14] xfs: hoist the node iroot update code out of xfs_btree_new_iroot
2023-12-31 19:53 ` [PATCHSET v2.0 07/17] xfsprogs: refactor btrees to support records in inode root Darrick J. Wong
` (9 preceding siblings ...)
2023-12-27 13:03 ` [PATCH 10/14] xfs: support leaves in the incore btree root block in xfs_iroot_realloc Darrick J. Wong
@ 2023-12-27 13:03 ` Darrick J. Wong
2023-12-27 13:04 ` [PATCH 12/14] xfs: hoist the node iroot update code out of xfs_btree_kill_iroot Darrick J. Wong
` (2 subsequent siblings)
13 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:03 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
In preparation for allowing records in an inode btree root, hoist the
code that copies keyptrs from an existing node root into a child block
to a separate function. Note that the new function explicitly computes
the keys of the new child block and stores that in the root block; while
the bmap btree could rely on leaving the key alone, realtime rmap needs
to set the new high key.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_btree.c | 113 ++++++++++++++++++++++++++++++++++------------------
1 file changed, 74 insertions(+), 39 deletions(-)
diff --git a/libxfs/xfs_btree.c b/libxfs/xfs_btree.c
index b6f73fcc6d6..5a21788c707 100644
--- a/libxfs/xfs_btree.c
+++ b/libxfs/xfs_btree.c
@@ -3079,6 +3079,77 @@ xfs_btree_iroot_realloc(
cur->bc_ops->iroot_ops, rec_diff);
}
+/*
+ * Move the keys and pointers from a root block to a separate block.
+ *
+ * Since the keyptr size does not change, all we have to do is increase the
+ * tree height, copy the keyptrs to the new internal node (cblock), shrink
+ * the root, and copy the pointers there.
+ */
+STATIC int
+xfs_btree_promote_node_iroot(
+ struct xfs_btree_cur *cur,
+ struct xfs_btree_block *block,
+ int level,
+ struct xfs_buf *cbp,
+ union xfs_btree_ptr *cptr,
+ struct xfs_btree_block *cblock)
+{
+ union xfs_btree_key *ckp;
+ union xfs_btree_key *kp;
+ union xfs_btree_ptr *cpp;
+ union xfs_btree_ptr *pp;
+ int i;
+ int error;
+ int numrecs = xfs_btree_get_numrecs(block);
+
+ /*
+ * Increase tree height, adjusting the root block level to match.
+ * We cannot change the root btree node size until we've copied the
+ * block contents to the new child block.
+ */
+ be16_add_cpu(&block->bb_level, 1);
+ cur->bc_nlevels++;
+ cur->bc_levels[level + 1].ptr = 1;
+
+ /*
+ * Adjust the root btree record count, then copy the keys from the old
+ * root to the new child block.
+ */
+ xfs_btree_set_numrecs(block, 1);
+ kp = xfs_btree_key_addr(cur, 1, block);
+ ckp = xfs_btree_key_addr(cur, 1, cblock);
+ xfs_btree_copy_keys(cur, ckp, kp, numrecs);
+
+ /* Check the pointers and copy them to the new child block. */
+ pp = xfs_btree_ptr_addr(cur, 1, block);
+ cpp = xfs_btree_ptr_addr(cur, 1, cblock);
+ for (i = 0; i < numrecs; i++) {
+ error = xfs_btree_debug_check_ptr(cur, pp, i, level);
+ if (error)
+ return error;
+ }
+ xfs_btree_copy_ptrs(cur, cpp, pp, numrecs);
+
+ /*
+ * Set the first keyptr to point to the new child block, then shrink
+ * the memory buffer for the root block.
+ */
+ error = xfs_btree_debug_check_ptr(cur, cptr, 0, level);
+ if (error)
+ return error;
+ xfs_btree_copy_ptrs(cur, pp, cptr, 1);
+ xfs_btree_get_keys(cur, cblock, kp);
+ xfs_btree_iroot_realloc(cur, 1 - numrecs);
+
+ /* Attach the new block to the cursor and log it. */
+ xfs_btree_setbuf(cur, level, cbp);
+ xfs_btree_log_block(cur, cbp, XFS_BB_ALL_BITS);
+ xfs_btree_log_keys(cur, cbp, 1, numrecs);
+ xfs_btree_log_ptrs(cur, cbp, 1, numrecs);
+ return 0;
+}
+
/*
* Copy the old inode root contents into a real block and make the
* broot point to it.
@@ -3092,14 +3163,10 @@ xfs_btree_new_iroot(
struct xfs_buf *cbp; /* buffer for cblock */
struct xfs_btree_block *block; /* btree block */
struct xfs_btree_block *cblock; /* child btree block */
- union xfs_btree_key *ckp; /* child key pointer */
- union xfs_btree_ptr *cpp; /* child ptr pointer */
- union xfs_btree_key *kp; /* pointer to btree key */
- union xfs_btree_ptr *pp; /* pointer to block addr */
+ union xfs_btree_ptr *pp;
union xfs_btree_ptr nptr; /* new block addr */
int level; /* btree level */
int error; /* error return code */
- int i; /* loop counter */
XFS_BTREE_STATS_INC(cur, newroot);
@@ -3137,43 +3204,11 @@ xfs_btree_new_iroot(
cblock->bb_u.s.bb_blkno = bno;
}
- be16_add_cpu(&block->bb_level, 1);
- xfs_btree_set_numrecs(block, 1);
- cur->bc_nlevels++;
- ASSERT(cur->bc_nlevels <= cur->bc_maxlevels);
- cur->bc_levels[level + 1].ptr = 1;
-
- kp = xfs_btree_key_addr(cur, 1, block);
- ckp = xfs_btree_key_addr(cur, 1, cblock);
- xfs_btree_copy_keys(cur, ckp, kp, xfs_btree_get_numrecs(cblock));
-
- cpp = xfs_btree_ptr_addr(cur, 1, cblock);
- for (i = 0; i < be16_to_cpu(cblock->bb_numrecs); i++) {
- error = xfs_btree_debug_check_ptr(cur, pp, i, level);
- if (error)
- goto error0;
- }
-
- xfs_btree_copy_ptrs(cur, cpp, pp, xfs_btree_get_numrecs(cblock));
-
- error = xfs_btree_debug_check_ptr(cur, &nptr, 0, level);
+ error = xfs_btree_promote_node_iroot(cur, block, level, cbp, &nptr,
+ cblock);
if (error)
goto error0;
- xfs_btree_copy_ptrs(cur, pp, &nptr, 1);
-
- xfs_btree_iroot_realloc(cur, 1 - xfs_btree_get_numrecs(cblock));
-
- xfs_btree_setbuf(cur, level, cbp);
-
- /*
- * Do all this logging at the end so that
- * the root is at the right level.
- */
- xfs_btree_log_block(cur, cbp, XFS_BB_ALL_BITS);
- xfs_btree_log_keys(cur, cbp, 1, be16_to_cpu(cblock->bb_numrecs));
- xfs_btree_log_ptrs(cur, cbp, 1, be16_to_cpu(cblock->bb_numrecs));
-
*logflags |=
XFS_ILOG_CORE | xfs_ilog_fbroot(cur->bc_ino.whichfork);
*stat = 1;
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 12/14] xfs: hoist the node iroot update code out of xfs_btree_kill_iroot
2023-12-31 19:53 ` [PATCHSET v2.0 07/17] xfsprogs: refactor btrees to support records in inode root Darrick J. Wong
` (10 preceding siblings ...)
2023-12-27 13:03 ` [PATCH 11/14] xfs: hoist the node iroot update code out of xfs_btree_new_iroot Darrick J. Wong
@ 2023-12-27 13:04 ` Darrick J. Wong
2023-12-27 13:04 ` [PATCH 13/14] xfs: support storing records in the inode core root Darrick J. Wong
2023-12-27 13:04 ` [PATCH 14/14] xfs: update btree keys correctly when _insrec splits an inode root block Darrick J. Wong
13 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:04 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
In preparation for allowing records in an inode btree root, hoist the
code that copies keyptrs from an existing node child into the root block
to a separate function. Remove some unnecessary conditionals and clean
up a few function calls in the new function. Note that this change
reorders the ->free_block call with respect to the change in bc_nlevels
to make it easier to support inode root leaf blocks in the next patch.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_btree.c | 94 +++++++++++++++++++++++++++++++++-------------------
1 file changed, 60 insertions(+), 34 deletions(-)
diff --git a/libxfs/xfs_btree.c b/libxfs/xfs_btree.c
index 5a21788c707..0f0198ae0cd 100644
--- a/libxfs/xfs_btree.c
+++ b/libxfs/xfs_btree.c
@@ -3704,6 +3704,63 @@ xfs_btree_insert(
return error;
}
+/*
+ * Move the keyptrs from a child node block to the root block.
+ *
+ * Since the keyptr size does not change, all we have to do is increase the
+ * tree height, copy the keyptrs to the new internal node (cblock), shrink
+ * the root, and copy the pointers there.
+ */
+STATIC int
+xfs_btree_demote_node_child(
+ struct xfs_btree_cur *cur,
+ struct xfs_btree_block *cblock,
+ int level,
+ int numrecs)
+{
+ struct xfs_btree_block *block;
+ union xfs_btree_key *ckp;
+ union xfs_btree_key *kp;
+ union xfs_btree_ptr *cpp;
+ union xfs_btree_ptr *pp;
+ int i;
+ int error;
+ int diff;
+
+ /*
+ * Adjust the root btree node size and the record count to match the
+ * doomed child so that we can copy the keyptrs ahead of changing the
+ * tree shape.
+ */
+ diff = numrecs - cur->bc_ops->get_maxrecs(cur, level);
+ xfs_btree_iroot_realloc(cur, diff);
+ block = xfs_btree_get_iroot(cur);
+
+ xfs_btree_set_numrecs(block, numrecs);
+ ASSERT(block->bb_numrecs == cblock->bb_numrecs);
+
+ /* Copy keys from the doomed block. */
+ kp = xfs_btree_key_addr(cur, 1, block);
+ ckp = xfs_btree_key_addr(cur, 1, cblock);
+ xfs_btree_copy_keys(cur, kp, ckp, numrecs);
+
+ /* Copy pointers from the doomed block. */
+ pp = xfs_btree_ptr_addr(cur, 1, block);
+ cpp = xfs_btree_ptr_addr(cur, 1, cblock);
+ for (i = 0; i < numrecs; i++) {
+ error = xfs_btree_debug_check_ptr(cur, cpp, i, level - 1);
+ if (error)
+ return error;
+ }
+ xfs_btree_copy_ptrs(cur, pp, cpp, numrecs);
+
+ /* Decrease tree height, adjusting the root block level to match. */
+ cur->bc_levels[level - 1].bp = NULL;
+ be16_add_cpu(&block->bb_level, -1);
+ cur->bc_nlevels--;
+ return 0;
+}
+
/*
* Try to merge a non-leaf block back into the inode root.
*
@@ -3716,24 +3773,16 @@ STATIC int
xfs_btree_kill_iroot(
struct xfs_btree_cur *cur)
{
- int whichfork = cur->bc_ino.whichfork;
struct xfs_inode *ip = cur->bc_ino.ip;
- struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork);
struct xfs_btree_block *block;
struct xfs_btree_block *cblock;
- union xfs_btree_key *kp;
- union xfs_btree_key *ckp;
- union xfs_btree_ptr *pp;
- union xfs_btree_ptr *cpp;
struct xfs_buf *cbp;
int level;
- int index;
int numrecs;
int error;
#ifdef DEBUG
union xfs_btree_ptr ptr;
#endif
- int i;
ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE);
ASSERT(cur->bc_nlevels > 1);
@@ -3773,39 +3822,16 @@ xfs_btree_kill_iroot(
ASSERT(xfs_btree_ptr_is_null(cur, &ptr));
#endif
- index = numrecs - cur->bc_ops->get_maxrecs(cur, level);
- if (index) {
- xfs_btree_iroot_realloc(cur, index);
- block = ifp->if_broot;
- }
-
- be16_add_cpu(&block->bb_numrecs, index);
- ASSERT(block->bb_numrecs == cblock->bb_numrecs);
-
- kp = xfs_btree_key_addr(cur, 1, block);
- ckp = xfs_btree_key_addr(cur, 1, cblock);
- xfs_btree_copy_keys(cur, kp, ckp, numrecs);
-
- pp = xfs_btree_ptr_addr(cur, 1, block);
- cpp = xfs_btree_ptr_addr(cur, 1, cblock);
-
- for (i = 0; i < numrecs; i++) {
- error = xfs_btree_debug_check_ptr(cur, cpp, i, level - 1);
- if (error)
- return error;
- }
-
- xfs_btree_copy_ptrs(cur, pp, cpp, numrecs);
+ error = xfs_btree_demote_node_child(cur, cblock, level, numrecs);
+ if (error)
+ return error;
error = xfs_btree_free_block(cur, cbp);
if (error)
return error;
- cur->bc_levels[level - 1].bp = NULL;
- be16_add_cpu(&block->bb_level, -1);
xfs_trans_log_inode(cur->bc_tp, ip,
XFS_ILOG_CORE | xfs_ilog_fbroot(cur->bc_ino.whichfork));
- cur->bc_nlevels--;
out0:
return 0;
}
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 13/14] xfs: support storing records in the inode core root
2023-12-31 19:53 ` [PATCHSET v2.0 07/17] xfsprogs: refactor btrees to support records in inode root Darrick J. Wong
` (11 preceding siblings ...)
2023-12-27 13:04 ` [PATCH 12/14] xfs: hoist the node iroot update code out of xfs_btree_kill_iroot Darrick J. Wong
@ 2023-12-27 13:04 ` Darrick J. Wong
2023-12-27 13:04 ` [PATCH 14/14] xfs: update btree keys correctly when _insrec splits an inode root block Darrick J. Wong
13 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:04 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Add the necessary flags and code so that we can support storing leaf
records in the inode root block of a btree. This hasn't been necessary
before, but the realtime rmapbt will need to be able to do this.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_btree.c | 150 ++++++++++++++++++++++++++++++++++++++++----
libxfs/xfs_btree.h | 1
libxfs/xfs_btree_staging.c | 4 +
3 files changed, 141 insertions(+), 14 deletions(-)
diff --git a/libxfs/xfs_btree.c b/libxfs/xfs_btree.c
index 0f0198ae0cd..df13656ffe6 100644
--- a/libxfs/xfs_btree.c
+++ b/libxfs/xfs_btree.c
@@ -264,6 +264,11 @@ xfs_btree_check_block(
int level, /* level of the btree block */
struct xfs_buf *bp) /* buffer containing block, if any */
{
+ /* Don't check the inode-core root. */
+ if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) &&
+ level == cur->bc_nlevels - 1)
+ return 0;
+
if (cur->bc_flags & XFS_BTREE_LONG_PTRS)
return xfs_btree_check_lblock(cur, block, level, bp);
else
@@ -1544,12 +1549,16 @@ xfs_btree_log_recs(
int first,
int last)
{
+ if (!bp) {
+ xfs_trans_log_inode(cur->bc_tp, cur->bc_ino.ip,
+ xfs_ilog_fbroot(cur->bc_ino.whichfork));
+ return;
+ }
xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLFT_BTREE_BUF);
xfs_trans_log_buf(cur->bc_tp, bp,
xfs_btree_rec_offset(cur, first),
xfs_btree_rec_offset(cur, last + 1) - 1);
-
}
/*
@@ -3079,6 +3088,64 @@ xfs_btree_iroot_realloc(
cur->bc_ops->iroot_ops, rec_diff);
}
+/*
+ * Move the records from a root leaf block to a separate block.
+ *
+ * Trickery here: The amount of memory that we need per record for the incore
+ * root block changes when we convert a leaf block to an internal block.
+ * Therefore, we copy leaf records into the new btree block (cblock) before
+ * freeing the incore root block and changing the tree height.
+ *
+ * Once we've changed the tree height, we allocate a new incore root block
+ * (which will now be an internal root block) and populate it with a pointer to
+ * cblock and the relevant keys.
+ */
+STATIC void
+xfs_btree_promote_leaf_iroot(
+ struct xfs_btree_cur *cur,
+ struct xfs_btree_block *block,
+ struct xfs_buf *cbp,
+ union xfs_btree_ptr *cptr,
+ struct xfs_btree_block *cblock)
+{
+ union xfs_btree_rec *rp;
+ union xfs_btree_rec *crp;
+ union xfs_btree_key *kp;
+ union xfs_btree_ptr *pp;
+ size_t size;
+ int numrecs = xfs_btree_get_numrecs(block);
+
+ /* Copy the records from the leaf root into the new child block. */
+ rp = xfs_btree_rec_addr(cur, 1, block);
+ crp = xfs_btree_rec_addr(cur, 1, cblock);
+ xfs_btree_copy_recs(cur, crp, rp, numrecs);
+
+ /* Zap the old root and change the tree height. */
+ xfs_iroot_free(cur->bc_ino.ip, cur->bc_ino.whichfork);
+ cur->bc_nlevels++;
+ cur->bc_levels[1].ptr = 1;
+
+ /*
+ * Allocate a new internal root block buffer and reinitialize it to
+ * point to a single new child.
+ */
+ size = cur->bc_ops->iroot_ops->size(cur->bc_mp, cur->bc_nlevels - 1, 1);
+ xfs_iroot_alloc(cur->bc_ino.ip, cur->bc_ino.whichfork, size);
+ block = xfs_btree_get_iroot(cur);
+ xfs_btree_init_block(cur->bc_mp, block, cur->bc_ops,
+ cur->bc_nlevels - 1, 1, cur->bc_ino.ip->i_ino);
+
+ pp = xfs_btree_ptr_addr(cur, 1, block);
+ kp = xfs_btree_key_addr(cur, 1, block);
+ xfs_btree_copy_ptrs(cur, pp, cptr, 1);
+ xfs_btree_get_keys(cur, cblock, kp);
+
+ /* Attach the new block to the cursor and log it. */
+ xfs_btree_setbuf(cur, 0, cbp);
+ xfs_btree_log_block(cur, cbp, XFS_BB_ALL_BITS);
+ xfs_btree_log_recs(cur, cbp, 1, numrecs);
+}
+
/*
* Move the keys and pointers from a root block to a separate block.
*
@@ -3163,7 +3230,7 @@ xfs_btree_new_iroot(
struct xfs_buf *cbp; /* buffer for cblock */
struct xfs_btree_block *block; /* btree block */
struct xfs_btree_block *cblock; /* child btree block */
- union xfs_btree_ptr *pp;
+ union xfs_btree_ptr aptr;
union xfs_btree_ptr nptr; /* new block addr */
int level; /* btree level */
int error; /* error return code */
@@ -3175,10 +3242,15 @@ xfs_btree_new_iroot(
level = cur->bc_nlevels - 1;
block = xfs_btree_get_iroot(cur);
- pp = xfs_btree_ptr_addr(cur, 1, block);
+ ASSERT(level > 0 || (cur->bc_flags & XFS_BTREE_IROOT_RECORDS));
+ if (level > 0)
+ aptr = *xfs_btree_ptr_addr(cur, 1, block);
+ else
+ aptr.l = cpu_to_be64(XFS_INO_TO_FSB(cur->bc_mp,
+ cur->bc_ino.ip->i_ino));
/* Allocate the new block. If we can't do it, we're toast. Give up. */
- error = xfs_btree_alloc_block(cur, pp, &nptr, stat);
+ error = xfs_btree_alloc_block(cur, &aptr, &nptr, stat);
if (error)
goto error0;
if (*stat == 0)
@@ -3204,10 +3276,14 @@ xfs_btree_new_iroot(
cblock->bb_u.s.bb_blkno = bno;
}
- error = xfs_btree_promote_node_iroot(cur, block, level, cbp, &nptr,
- cblock);
- if (error)
- goto error0;
+ if (level > 0) {
+ error = xfs_btree_promote_node_iroot(cur, block, level, cbp,
+ &nptr, cblock);
+ if (error)
+ goto error0;
+ } else {
+ xfs_btree_promote_leaf_iroot(cur, block, cbp, &nptr, cblock);
+ }
*logflags |=
XFS_ILOG_CORE | xfs_ilog_fbroot(cur->bc_ino.whichfork);
@@ -3704,6 +3780,45 @@ xfs_btree_insert(
return error;
}
+/*
+ * Move the records from a child leaf block to the root block.
+ *
+ * Trickery here: The amount of memory we need per record for the incore root
+ * block changes when we convert a leaf block to an internal block. Therefore,
+ * we free the incore root block, change the tree height, allocate a new incore
+ * root, and copy the records from the doomed block into the new root.
+ */
+STATIC void
+xfs_btree_demote_leaf_child(
+ struct xfs_btree_cur *cur,
+ struct xfs_btree_block *cblock,
+ int numrecs)
+{
+ union xfs_btree_rec *rp;
+ union xfs_btree_rec *crp;
+ struct xfs_btree_block *block;
+ size_t size;
+
+ /* Zap the old root and change the tree height. */
+ xfs_iroot_free(cur->bc_ino.ip, cur->bc_ino.whichfork);
+ cur->bc_levels[0].bp = NULL;
+ cur->bc_nlevels--;
+
+ /*
+ * Allocate a new internal root block buffer and reinitialize it with
+ * the leaf records in the child.
+ */
+ size = cur->bc_ops->iroot_ops->size(cur->bc_mp, 0, numrecs);
+ xfs_iroot_alloc(cur->bc_ino.ip, cur->bc_ino.whichfork, size);
+ block = xfs_btree_get_iroot(cur);
+ xfs_btree_init_block(cur->bc_mp, block, cur->bc_ops, 0, numrecs,
+ cur->bc_ino.ip->i_ino);
+
+ rp = xfs_btree_rec_addr(cur, 1, block);
+ crp = xfs_btree_rec_addr(cur, 1, cblock);
+ xfs_btree_copy_recs(cur, rp, crp, numrecs);
+}
+
/*
* Move the keyptrs from a child node block to the root block.
*
@@ -3785,14 +3900,19 @@ xfs_btree_kill_iroot(
#endif
ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE);
- ASSERT(cur->bc_nlevels > 1);
+ ASSERT((cur->bc_flags & XFS_BTREE_IROOT_RECORDS) ||
+ cur->bc_nlevels > 1);
/*
* Don't deal with the root block needs to be a leaf case.
* We're just going to turn the thing back into extents anyway.
*/
level = cur->bc_nlevels - 1;
- if (level == 1)
+ if (level == 1 && !(cur->bc_flags & XFS_BTREE_IROOT_RECORDS))
+ goto out0;
+
+ /* If we're already a leaf, jump out. */
+ if (level == 0)
goto out0;
/*
@@ -3822,9 +3942,13 @@ xfs_btree_kill_iroot(
ASSERT(xfs_btree_ptr_is_null(cur, &ptr));
#endif
- error = xfs_btree_demote_node_child(cur, cblock, level, numrecs);
- if (error)
- return error;
+ if (level > 1) {
+ error = xfs_btree_demote_node_child(cur, cblock, level,
+ numrecs);
+ if (error)
+ return error;
+ } else
+ xfs_btree_demote_leaf_child(cur, cblock, numrecs);
error = xfs_btree_free_block(cur, cbp);
if (error)
diff --git a/libxfs/xfs_btree.h b/libxfs/xfs_btree.h
index 7872fc1739b..bb6c2feecea 100644
--- a/libxfs/xfs_btree.h
+++ b/libxfs/xfs_btree.h
@@ -337,6 +337,7 @@ xfs_btree_cur_sizeof(unsigned int nlevels)
* is dynamically allocated and must be freed when the cursor is deleted.
*/
#define XFS_BTREE_STAGING (1<<5)
+#define XFS_BTREE_IROOT_RECORDS (1<<6) /* iroot can store records */
/* btree stored in memory; not compatible with ROOT_IN_INODE */
#ifdef CONFIG_XFS_BTREE_IN_XFILE
diff --git a/libxfs/xfs_btree_staging.c b/libxfs/xfs_btree_staging.c
index ec496915433..8b2e41dacff 100644
--- a/libxfs/xfs_btree_staging.c
+++ b/libxfs/xfs_btree_staging.c
@@ -710,7 +710,9 @@ xfs_btree_bload_compute_geometry(
*
* Note that bmap btrees forbid records in the root.
*/
- if (level != 0 && nr_this_level <= avg_per_block) {
+ if ((level != 0 ||
+ (cur->bc_flags & XFS_BTREE_IROOT_RECORDS)) &&
+ nr_this_level <= avg_per_block) {
nr_blocks++;
break;
}
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 14/14] xfs: update btree keys correctly when _insrec splits an inode root block
2023-12-31 19:53 ` [PATCHSET v2.0 07/17] xfsprogs: refactor btrees to support records in inode root Darrick J. Wong
` (12 preceding siblings ...)
2023-12-27 13:04 ` [PATCH 13/14] xfs: support storing records in the inode core root Darrick J. Wong
@ 2023-12-27 13:04 ` Darrick J. Wong
13 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:04 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
In commit 2c813ad66a72, I partially fixed a bug wherein xfs_btree_insrec
would erroneously try to update the parent's key for a block that had
been split if we decided to insert the new record into the new block.
The solution was to detect this situation and update the in-core key
value that we pass up to the caller so that the caller will (eventually)
add the new block to the parent level of the tree with the correct key.
However, I missed a subtlety about the way inode-rooted btrees work. If
the full block was a maximally sized inode root block, we'll solve that
fullness by moving the root block's records to a new block, resizing the
root block, and updating the root to point to the new block. We don't
pass a pointer to the new block to the caller because that work has
already been done. The new record will /always/ land in the new block,
so in this case we need to use xfs_btree_update_keys to update the keys.
This bug can theoretically manifest itself in the very rare case that we
split a bmbt root block and the new record lands in the very first slot
of the new block, though I've never managed to trigger it in practice.
However, it is very easy to reproduce by running generic/522 with the
realtime rmapbt patchset if rtinherit=1.
Fixes: 2c813ad66a72 ("xfs: support btrees with overlapping intervals for keys")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_btree.c | 29 +++++++++++++++++++++++------
1 file changed, 23 insertions(+), 6 deletions(-)
diff --git a/libxfs/xfs_btree.c b/libxfs/xfs_btree.c
index df13656ffe6..165ce251376 100644
--- a/libxfs/xfs_btree.c
+++ b/libxfs/xfs_btree.c
@@ -3653,14 +3653,31 @@ xfs_btree_insrec(
xfs_btree_log_block(cur, bp, XFS_BB_NUMRECS);
/*
- * If we just inserted into a new tree block, we have to
- * recalculate nkey here because nkey is out of date.
+ * Update btree keys to reflect the newly added record or keyptr.
+ * There are three cases here to be aware of. Normally, all we have to
+ * do is walk towards the root, updating keys as necessary.
*
- * Otherwise we're just updating an existing block (having shoved
- * some records into the new tree block), so use the regular key
- * update mechanism.
+ * If the caller had us target a full block for the insertion, we dealt
+ * with that by calling the _make_block_unfull function. If the
+ * "make unfull" function splits the block, it'll hand us back the key
+ * and pointer of the new block. We haven't yet added the new block to
+ * the next level up, so if we decide to add the new record to the new
+ * block (bp->b_bn != old_bn), we have to update the caller's pointer
+ * so that the caller adds the new block with the correct key.
+ *
+ * However, there is a third possibility-- if the selected block is the
+ * root block of an inode-rooted btree and cannot be expanded further,
+ * the "make unfull" function moves the root block contents to a new
+ * block and updates the root block to point to the new block. In this
+ * case, no block pointer is passed back because the block has already
+ * been added to the btree. In this case, we need to use the regular
+ * key update function, just like the first case. This is critical for
+ * overlapping btrees, because the high key must be updated to reflect
+ * the entire tree, not just the subtree accessible through the first
+ * child of the root (which is now two levels down from the root).
*/
- if (bp && xfs_buf_daddr(bp) != old_bn) {
+ if (!xfs_btree_ptr_is_null(cur, &nptr) &&
+ bp && xfs_buf_daddr(bp) != old_bn) {
xfs_btree_get_keys(cur, block, lkey);
} else if (xfs_btree_needs_key_update(cur, optr)) {
error = xfs_btree_update_keys(cur, level);
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 1/2] xfs: simplify xfs_ag_resv_free signature
2023-12-31 19:53 ` [PATCHSET v2.0 08/17] xfsprogs: enable in-core block reservation for rt metadata Darrick J. Wong
@ 2023-12-27 13:05 ` Darrick J. Wong
2023-12-27 13:05 ` [PATCH 2/2] xfs: allow inode-based btrees to reserve space in the data device Darrick J. Wong
1 sibling, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:05 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
It's not possible to fail at increasing fdblocks, so get rid of all the
error returns here.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
include/xfs_trace.h | 1 -
libxfs/xfs_ag.c | 4 +---
libxfs/xfs_ag_resv.c | 22 +++++-----------------
libxfs/xfs_ag_resv.h | 2 +-
4 files changed, 7 insertions(+), 22 deletions(-)
diff --git a/include/xfs_trace.h b/include/xfs_trace.h
index b3240213364..08ec51fc799 100644
--- a/include/xfs_trace.h
+++ b/include/xfs_trace.h
@@ -269,7 +269,6 @@
#define trace_xfs_ag_resv_critical(...) ((void) 0)
#define trace_xfs_ag_resv_needed(...) ((void) 0)
#define trace_xfs_ag_resv_free(...) ((void) 0)
-#define trace_xfs_ag_resv_free_error(...) ((void) 0)
#define trace_xfs_ag_resv_init(...) ((void) 0)
#define trace_xfs_ag_resv_init_error(...) ((void) 0)
#define trace_xfs_ag_resv_alloc_extent(...) ((void) 0)
diff --git a/libxfs/xfs_ag.c b/libxfs/xfs_ag.c
index ddd5584f23e..f22d58ad040 100644
--- a/libxfs/xfs_ag.c
+++ b/libxfs/xfs_ag.c
@@ -942,9 +942,7 @@ xfs_ag_shrink_space(
* Disable perag reservations so it doesn't cause the allocation request
* to fail. We'll reestablish reservation before we return.
*/
- error = xfs_ag_resv_free(pag);
- if (error)
- return error;
+ xfs_ag_resv_free(pag);
/* internal log shouldn't also show up in the free space btrees */
error = xfs_alloc_vextent_exact_bno(&args,
diff --git a/libxfs/xfs_ag_resv.c b/libxfs/xfs_ag_resv.c
index 3a80b1613e1..542740bb850 100644
--- a/libxfs/xfs_ag_resv.c
+++ b/libxfs/xfs_ag_resv.c
@@ -125,14 +125,13 @@ xfs_ag_resv_needed(
}
/* Clean out a reservation */
-static int
+static void
__xfs_ag_resv_free(
struct xfs_perag *pag,
enum xfs_ag_resv_type type)
{
struct xfs_ag_resv *resv;
xfs_extlen_t oldresv;
- int error;
trace_xfs_ag_resv_free(pag, type, 0);
@@ -148,30 +147,19 @@ __xfs_ag_resv_free(
oldresv = resv->ar_orig_reserved;
else
oldresv = resv->ar_reserved;
- error = xfs_mod_fdblocks(pag->pag_mount, oldresv, true);
+ xfs_mod_fdblocks(pag->pag_mount, oldresv, true);
resv->ar_reserved = 0;
resv->ar_asked = 0;
resv->ar_orig_reserved = 0;
-
- if (error)
- trace_xfs_ag_resv_free_error(pag->pag_mount, pag->pag_agno,
- error, _RET_IP_);
- return error;
}
/* Free a per-AG reservation. */
-int
+void
xfs_ag_resv_free(
struct xfs_perag *pag)
{
- int error;
- int err2;
-
- error = __xfs_ag_resv_free(pag, XFS_AG_RESV_RMAPBT);
- err2 = __xfs_ag_resv_free(pag, XFS_AG_RESV_METADATA);
- if (err2 && !error)
- error = err2;
- return error;
+ __xfs_ag_resv_free(pag, XFS_AG_RESV_RMAPBT);
+ __xfs_ag_resv_free(pag, XFS_AG_RESV_METADATA);
}
static int
diff --git a/libxfs/xfs_ag_resv.h b/libxfs/xfs_ag_resv.h
index b74b210008e..ff20ed93de7 100644
--- a/libxfs/xfs_ag_resv.h
+++ b/libxfs/xfs_ag_resv.h
@@ -6,7 +6,7 @@
#ifndef __XFS_AG_RESV_H__
#define __XFS_AG_RESV_H__
-int xfs_ag_resv_free(struct xfs_perag *pag);
+void xfs_ag_resv_free(struct xfs_perag *pag);
int xfs_ag_resv_init(struct xfs_perag *pag, struct xfs_trans *tp);
bool xfs_ag_resv_critical(struct xfs_perag *pag, enum xfs_ag_resv_type type);
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 2/2] xfs: allow inode-based btrees to reserve space in the data device
2023-12-31 19:53 ` [PATCHSET v2.0 08/17] xfsprogs: enable in-core block reservation for rt metadata Darrick J. Wong
2023-12-27 13:05 ` [PATCH 1/2] xfs: simplify xfs_ag_resv_free signature Darrick J. Wong
@ 2023-12-27 13:05 ` Darrick J. Wong
1 sibling, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:05 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Create a new space reservation scheme so that btree metadata for the
realtime volume can reserve space in the data device to avoid space
underruns.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
include/xfs_inode.h | 5 +
include/xfs_mount.h | 1
include/xfs_trace.h | 7 ++
io/inject.c | 1
libxfs/init.c | 11 +++
libxfs/libxfs_priv.h | 11 +++
libxfs/xfs_ag_resv.c | 3 +
libxfs/xfs_errortag.h | 4 +
libxfs/xfs_imeta.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++++
libxfs/xfs_imeta.h | 11 +++
libxfs/xfs_types.h | 7 ++
11 files changed, 248 insertions(+), 3 deletions(-)
diff --git a/include/xfs_inode.h b/include/xfs_inode.h
index 2675abdffcd..ec73fe192fd 100644
--- a/include/xfs_inode.h
+++ b/include/xfs_inode.h
@@ -216,7 +216,10 @@ typedef struct xfs_inode {
struct xfs_ifork i_df; /* data fork */
struct xfs_ifork i_af; /* attribute fork */
struct xfs_inode_log_item *i_itemp; /* logging information */
- unsigned int i_delayed_blks; /* count of delay alloc blks */
+ uint64_t i_delayed_blks; /* count of delay alloc blks */
+ /* Space that has been set aside to root a btree in this file. */
+ uint64_t i_meta_resv_asked;
+
xfs_fsize_t i_disk_size; /* number of bytes in file */
xfs_rfsblock_t i_nblocks; /* # of direct & btree blocks */
prid_t i_projid; /* owner's project id */
diff --git a/include/xfs_mount.h b/include/xfs_mount.h
index a2fdd7c2f14..51a02e69776 100644
--- a/include/xfs_mount.h
+++ b/include/xfs_mount.h
@@ -99,6 +99,7 @@ typedef struct xfs_mount {
uint m_rmap_maxlevels; /* max rmap btree levels */
uint m_refc_maxlevels; /* max refc btree levels */
unsigned int m_agbtree_maxlevels; /* max level of all AG btrees */
+ unsigned int m_rtbtree_maxlevels; /* max level of all rt btrees */
xfs_extlen_t m_ag_prealloc_blocks; /* reserved ag blocks */
uint m_alloc_set_aside; /* space we can't use */
uint m_ag_max_usable; /* max space per AG */
diff --git a/include/xfs_trace.h b/include/xfs_trace.h
index 08ec51fc799..5010b35b1f6 100644
--- a/include/xfs_trace.h
+++ b/include/xfs_trace.h
@@ -389,4 +389,11 @@
#define trace_xfs_iunlink_remove(...) ((void) 0)
#define trace_xfs_iunlink_map_prev_fallback(...) ((void) 0)
+#define trace_xfs_imeta_resv_alloc_extent(...) ((void) 0)
+#define trace_xfs_imeta_resv_critical(...) ((void) 0)
+#define trace_xfs_imeta_resv_free(...) ((void) 0)
+#define trace_xfs_imeta_resv_free_extent(...) ((void) 0)
+#define trace_xfs_imeta_resv_init(...) ((void) 0)
+#define trace_xfs_imeta_resv_init_error(...) ((void) 0)
+
#endif /* __TRACE_H__ */
diff --git a/io/inject.c b/io/inject.c
index 4b0cd76005c..644baa42b64 100644
--- a/io/inject.c
+++ b/io/inject.c
@@ -64,6 +64,7 @@ error_tag(char *name)
{ XFS_ERRTAG_WB_DELAY_MS, "wb_delay_ms" },
{ XFS_ERRTAG_WRITE_DELAY_MS, "write_delay_ms" },
{ XFS_ERRTAG_SWAPEXT_FINISH_ONE, "swapext_finish_one" },
+ { XFS_ERRTAG_IMETA_RESV_CRITICAL, "imeta_resv_critical" },
{ XFS_ERRTAG_MAX, NULL }
};
int count;
diff --git a/libxfs/init.c b/libxfs/init.c
index 0332a4eeb21..2663485a80d 100644
--- a/libxfs/init.c
+++ b/libxfs/init.c
@@ -651,6 +651,15 @@ xfs_agbtree_compute_maxlevels(
mp->m_agbtree_maxlevels = max(levels, mp->m_refc_maxlevels);
}
+/* Compute maximum possible height for realtime btree types for this fs. */
+static inline void
+xfs_rtbtree_compute_maxlevels(
+ struct xfs_mount *mp)
+{
+ /* This will be filled in later. */
+ mp->m_rtbtree_maxlevels = 0;
+}
+
/* Compute maximum possible height of all btrees. */
void
libxfs_compute_all_maxlevels(
@@ -667,7 +676,7 @@ libxfs_compute_all_maxlevels(
xfs_refcountbt_compute_maxlevels(mp);
xfs_agbtree_compute_maxlevels(mp);
-
+ xfs_rtbtree_compute_maxlevels(mp);
}
/* Mount the metadata files under the metadata directory tree. */
diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h
index 120a41e20a7..bbe7dd63443 100644
--- a/libxfs/libxfs_priv.h
+++ b/libxfs/libxfs_priv.h
@@ -221,6 +221,17 @@ uint32_t get_random_u32(void);
#define get_random_u32() (0)
#endif
+static inline int
+__percpu_counter_compare(uint64_t *count, int64_t rhs, int32_t batch)
+{
+ if (*count > rhs)
+ return 1;
+ else if (*count < rhs)
+ return -1;
+ return 0;
+}
+
+
#define PAGE_SIZE getpagesize()
#define inode_peek_iversion(inode) (inode)->i_version
diff --git a/libxfs/xfs_ag_resv.c b/libxfs/xfs_ag_resv.c
index 542740bb850..5963ff5602b 100644
--- a/libxfs/xfs_ag_resv.c
+++ b/libxfs/xfs_ag_resv.c
@@ -112,6 +112,7 @@ xfs_ag_resv_needed(
case XFS_AG_RESV_RMAPBT:
len -= xfs_perag_resv(pag, type)->ar_reserved;
break;
+ case XFS_AG_RESV_IMETA:
case XFS_AG_RESV_NONE:
/* empty */
break;
@@ -346,6 +347,7 @@ xfs_ag_resv_alloc_extent(
switch (type) {
case XFS_AG_RESV_AGFL:
+ case XFS_AG_RESV_IMETA:
return;
case XFS_AG_RESV_METADATA:
case XFS_AG_RESV_RMAPBT:
@@ -388,6 +390,7 @@ xfs_ag_resv_free_extent(
switch (type) {
case XFS_AG_RESV_AGFL:
+ case XFS_AG_RESV_IMETA:
return;
case XFS_AG_RESV_METADATA:
case XFS_AG_RESV_RMAPBT:
diff --git a/libxfs/xfs_errortag.h b/libxfs/xfs_errortag.h
index 263d62a8d70..f359df69d6b 100644
--- a/libxfs/xfs_errortag.h
+++ b/libxfs/xfs_errortag.h
@@ -64,7 +64,8 @@
#define XFS_ERRTAG_WB_DELAY_MS 42
#define XFS_ERRTAG_WRITE_DELAY_MS 43
#define XFS_ERRTAG_SWAPEXT_FINISH_ONE 44
-#define XFS_ERRTAG_MAX 45
+#define XFS_ERRTAG_IMETA_RESV_CRITICAL 45
+#define XFS_ERRTAG_MAX 46
/*
* Random factors for above tags, 1 means always, 2 means 1/2 time, etc.
@@ -113,5 +114,6 @@
#define XFS_RANDOM_WB_DELAY_MS 3000
#define XFS_RANDOM_WRITE_DELAY_MS 3000
#define XFS_RANDOM_SWAPEXT_FINISH_ONE 1
+#define XFS_RANDOM_IMETA_RESV_CRITICAL 4
#endif /* __XFS_ERRORTAG_H_ */
diff --git a/libxfs/xfs_imeta.c b/libxfs/xfs_imeta.c
index 6ada36d5559..e2b14624381 100644
--- a/libxfs/xfs_imeta.c
+++ b/libxfs/xfs_imeta.c
@@ -26,6 +26,9 @@
#include "xfs_dir2.h"
#include "xfs_dir2_priv.h"
#include "xfs_health.h"
+#include "xfs_errortag.h"
+#include "xfs_btree.h"
+#include "xfs_alloc.h"
/*
* Metadata File Management
@@ -1074,3 +1077,190 @@ xfs_imeta_free_path(
kfree(path->im_path);
kfree(path);
}
+
+/*
+ * Is the amount of space that could be allocated towards a given metadata
+ * file at or beneath a certain threshold?
+ */
+static inline bool
+xfs_imeta_resv_can_cover(
+ struct xfs_inode *ip,
+ int64_t rhs)
+{
+ /*
+ * The amount of space that can be allocated to this metadata file is
+ * the remaining reservation for the particular metadata file + the
+ * global free block count. Take care of the first case to avoid
+ * touching the per-cpu counter.
+ */
+ if (ip->i_delayed_blks >= rhs)
+ return true;
+
+ /*
+ * There aren't enough blocks left in the inode's reservation, but it
+ * isn't critical unless there also isn't enough free space.
+ */
+ return __percpu_counter_compare(&ip->i_mount->m_fdblocks,
+ rhs - ip->i_delayed_blks, 2048) >= 0;
+}
+
+/*
+ * Is this metadata file critically low on blocks? For now we'll define that
+ * as the number of blocks we can get our hands on being less than 10% of what
+ * we reserved or less than some arbitrary number (maximum btree height).
+ */
+bool
+xfs_imeta_resv_critical(
+ struct xfs_inode *ip)
+{
+ uint64_t asked_low_water;
+
+ if (!ip)
+ return false;
+
+ ASSERT(xfs_is_metadir_inode(ip));
+ trace_xfs_imeta_resv_critical(ip, 0);
+
+ if (!xfs_imeta_resv_can_cover(ip, ip->i_mount->m_rtbtree_maxlevels))
+ return true;
+
+ asked_low_water = div_u64(ip->i_meta_resv_asked, 10);
+ if (!xfs_imeta_resv_can_cover(ip, asked_low_water))
+ return true;
+
+ return XFS_TEST_ERROR(false, ip->i_mount,
+ XFS_ERRTAG_IMETA_RESV_CRITICAL);
+}
+
+/* Allocate a block from the metadata file's reservation. */
+void
+xfs_imeta_resv_alloc_extent(
+ struct xfs_inode *ip,
+ struct xfs_alloc_arg *args)
+{
+ int64_t len = args->len;
+
+ ASSERT(xfs_is_metadir_inode(ip));
+ ASSERT(XFS_IS_DQDETACHED(ip->i_mount, ip));
+ ASSERT(args->resv == XFS_AG_RESV_IMETA);
+
+ trace_xfs_imeta_resv_alloc_extent(ip, args->len);
+
+ /*
+ * Allocate the blocks from the metadata inode's block reservation
+ * and update the ondisk sb counter.
+ */
+ if (ip->i_delayed_blks > 0) {
+ int64_t from_resv;
+
+ from_resv = min_t(int64_t, len, ip->i_delayed_blks);
+ ip->i_delayed_blks -= from_resv;
+ xfs_mod_delalloc(ip->i_mount, -from_resv);
+ xfs_trans_mod_sb(args->tp, XFS_TRANS_SB_RES_FDBLOCKS,
+ -from_resv);
+ len -= from_resv;
+ }
+
+ /*
+ * Any allocation in excess of the reservation requires in-core and
+ * on-disk fdblocks updates.
+ */
+ if (len)
+ xfs_trans_mod_sb(args->tp, XFS_TRANS_SB_FDBLOCKS, -len);
+
+ ip->i_nblocks += args->len;
+ xfs_trans_log_inode(args->tp, ip, XFS_ILOG_CORE);
+}
+
+/* Free a block to the metadata file's reservation. */
+void
+xfs_imeta_resv_free_extent(
+ struct xfs_inode *ip,
+ struct xfs_trans *tp,
+ xfs_filblks_t len)
+{
+ int64_t to_resv;
+
+ ASSERT(xfs_is_metadir_inode(ip));
+ ASSERT(XFS_IS_DQDETACHED(ip->i_mount, ip));
+ trace_xfs_imeta_resv_free_extent(ip, len);
+
+ ip->i_nblocks -= len;
+ xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
+ /*
+ * Add the freed blocks back into the inode's delalloc reservation
+ * until it reaches the maximum size. Update the ondisk fdblocks only.
+ */
+ to_resv = ip->i_meta_resv_asked - (ip->i_nblocks + ip->i_delayed_blks);
+ if (to_resv > 0) {
+ to_resv = min_t(int64_t, to_resv, len);
+ ip->i_delayed_blks += to_resv;
+ xfs_mod_delalloc(ip->i_mount, to_resv);
+ xfs_trans_mod_sb(tp, XFS_TRANS_SB_RES_FDBLOCKS, to_resv);
+ len -= to_resv;
+ }
+
+ /*
+ * Everything else goes back to the filesystem, so update the in-core
+ * and on-disk counters.
+ */
+ if (len)
+ xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, len);
+}
+
+/* Release a metadata file's space reservation. */
+void
+xfs_imeta_resv_free_inode(
+ struct xfs_inode *ip)
+{
+ if (!ip)
+ return;
+
+ ASSERT(xfs_is_metadir_inode(ip));
+ trace_xfs_imeta_resv_free(ip, 0);
+
+ xfs_mod_delalloc(ip->i_mount, -ip->i_delayed_blks);
+ xfs_mod_fdblocks(ip->i_mount, ip->i_delayed_blks, true);
+ ip->i_delayed_blks = 0;
+ ip->i_meta_resv_asked = 0;
+}
+
+/* Set up a metadata file's space reservation. */
+int
+xfs_imeta_resv_init_inode(
+ struct xfs_inode *ip,
+ xfs_filblks_t ask)
+{
+ xfs_filblks_t hidden_space;
+ xfs_filblks_t used;
+ int error;
+
+ if (!ip || ip->i_meta_resv_asked > 0)
+ return 0;
+
+ ASSERT(xfs_is_metadir_inode(ip));
+
+ /*
+ * Space taken by all other metadata btrees are accounted on-disk as
+ * used space. We therefore only hide the space that is reserved but
+ * not used by the trees.
+ */
+ used = ip->i_nblocks;
+ if (used > ask)
+ ask = used;
+ hidden_space = ask - used;
+
+ error = xfs_mod_fdblocks(ip->i_mount, -(int64_t)hidden_space, true);
+ if (error) {
+ trace_xfs_imeta_resv_init_error(ip, error, _RET_IP_);
+ return error;
+ }
+
+ xfs_mod_delalloc(ip->i_mount, hidden_space);
+ ip->i_delayed_blks = hidden_space;
+ ip->i_meta_resv_asked = ask;
+
+ trace_xfs_imeta_resv_init(ip, ask);
+ return 0;
+}
diff --git a/libxfs/xfs_imeta.h b/libxfs/xfs_imeta.h
index 3b5953efc01..f6dda8e5af0 100644
--- a/libxfs/xfs_imeta.h
+++ b/libxfs/xfs_imeta.h
@@ -102,6 +102,17 @@ unsigned int xfs_imeta_create_space_res(struct xfs_mount *mp);
unsigned int xfs_imeta_link_space_res(struct xfs_mount *mp);
unsigned int xfs_imeta_unlink_space_res(struct xfs_mount *mp);
+/* Space reservations for metadata inodes. */
+struct xfs_alloc_arg;
+
+bool xfs_imeta_resv_critical(struct xfs_inode *ip);
+void xfs_imeta_resv_alloc_extent(struct xfs_inode *ip,
+ struct xfs_alloc_arg *args);
+void xfs_imeta_resv_free_extent(struct xfs_inode *ip, struct xfs_trans *tp,
+ xfs_filblks_t len);
+void xfs_imeta_resv_free_inode(struct xfs_inode *ip);
+int xfs_imeta_resv_init_inode(struct xfs_inode *ip, xfs_filblks_t ask);
+
/* Must be implemented by the libxfs client */
int xfs_imeta_iget(struct xfs_trans *tp, xfs_ino_t ino, unsigned char ftype,
struct xfs_inode **ipp);
diff --git a/libxfs/xfs_types.h b/libxfs/xfs_types.h
index 195471c4385..ad2ce83874f 100644
--- a/libxfs/xfs_types.h
+++ b/libxfs/xfs_types.h
@@ -221,6 +221,13 @@ enum xfs_ag_resv_type {
* altering fdblocks. If you think you need this you're wrong.
*/
XFS_AG_RESV_IGNORE,
+
+ /*
+ * This allocation activity is being done on behalf of a metadata file.
+ * These files maintain their own permanent space reservations and are
+ * required to adjust fdblocks using the xfs_imeta_resv_* helpers.
+ */
+ XFS_AG_RESV_IMETA,
};
/* Results of scanning a btree keyspace to check occupancy. */
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 1/8] xfs: clean up extent free log intent item tracepoint callsites
2023-12-31 19:54 ` [PATCHSET v2.0 09/17] xfsprogs: extent free log intent cleanups Darrick J. Wong
@ 2023-12-27 13:05 ` Darrick J. Wong
2023-12-27 13:05 ` [PATCH 2/8] xfs: convert "skip_discard" to a proper flags bitset Darrick J. Wong
` (6 subsequent siblings)
7 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:05 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Pass the incore EFI structure to the tracepoints instead of open-coding
the argument passing. This cleans up the call sites a bit.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
include/xfs_trace.h | 5 ++---
libxfs/xfs_alloc.c | 7 +++----
2 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/include/xfs_trace.h b/include/xfs_trace.h
index 5010b35b1f6..a6ae0ca13b6 100644
--- a/include/xfs_trace.h
+++ b/include/xfs_trace.h
@@ -13,8 +13,8 @@
#define trace_xfbtree_trans_cancel_buf(...) ((void) 0)
#define trace_xfbtree_trans_commit_buf(...) ((void) 0)
+#define trace_xfs_agfl_free_defer(...) ((void) 0)
#define trace_xfs_agfl_reset(a,b,c,d) ((void) 0)
-#define trace_xfs_agfl_free_defer(a,b,c,d,e) ((void) 0)
#define trace_xfs_alloc_cur_check(a,b,c,d,e,f) ((void) 0)
#define trace_xfs_alloc_cur(a) ((void) 0)
#define trace_xfs_alloc_cur_left(a) ((void) 0)
@@ -242,8 +242,7 @@
#define trace_xfs_defer_item_pause(...) ((void) 0)
#define trace_xfs_defer_item_unpause(...) ((void) 0)
-#define trace_xfs_bmap_free_defer(...) ((void) 0)
-#define trace_xfs_bmap_free_deferred(...) ((void) 0)
+#define trace_xfs_extent_free_defer(...) ((void) 0)
#define trace_xfs_rmap_map(...) ((void) 0)
#define trace_xfs_rmap_map_error(...) ((void) 0)
diff --git a/libxfs/xfs_alloc.c b/libxfs/xfs_alloc.c
index 3d7686eadab..08cdfe7e3d3 100644
--- a/libxfs/xfs_alloc.c
+++ b/libxfs/xfs_alloc.c
@@ -2569,7 +2569,7 @@ xfs_defer_agfl_block(
xefi->xefi_owner = oinfo->oi_owner;
xefi->xefi_agresv = XFS_AG_RESV_AGFL;
- trace_xfs_agfl_free_defer(mp, agno, 0, agbno, 1);
+ trace_xfs_agfl_free_defer(mp, xefi);
xfs_extent_free_get_group(mp, xefi);
xfs_defer_add(tp, &xefi->xefi_list, &xfs_agfl_free_defer_type);
@@ -2631,9 +2631,8 @@ xfs_defer_extent_free(
} else {
xefi->xefi_owner = XFS_RMAP_OWN_NULL;
}
- trace_xfs_bmap_free_defer(mp,
- XFS_FSB_TO_AGNO(tp->t_mountp, bno), 0,
- XFS_FSB_TO_AGBNO(tp->t_mountp, bno), len);
+
+ trace_xfs_extent_free_defer(mp, xefi);
xfs_extent_free_get_group(mp, xefi);
*dfpp = xfs_defer_add(tp, &xefi->xefi_list, &xfs_extent_free_defer_type);
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 2/8] xfs: convert "skip_discard" to a proper flags bitset
2023-12-31 19:54 ` [PATCHSET v2.0 09/17] xfsprogs: extent free log intent cleanups Darrick J. Wong
2023-12-27 13:05 ` [PATCH 1/8] xfs: clean up extent free log intent item tracepoint callsites Darrick J. Wong
@ 2023-12-27 13:05 ` Darrick J. Wong
2023-12-27 13:06 ` [PATCH 3/8] xfs: pass the fsbno to xfs_perag_intent_get Darrick J. Wong
` (5 subsequent siblings)
7 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:05 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Convert the boolean to skip discard on free into a proper flags field so
that we can add more flags in the next patch.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_ag.c | 2 +-
libxfs/xfs_alloc.c | 13 +++++++------
libxfs/xfs_alloc.h | 9 +++++++--
libxfs/xfs_bmap.c | 12 ++++++++----
libxfs/xfs_bmap_btree.c | 2 +-
libxfs/xfs_ialloc.c | 5 ++---
libxfs/xfs_ialloc_btree.c | 2 +-
libxfs/xfs_refcount.c | 6 +++---
libxfs/xfs_refcount_btree.c | 2 +-
repair/bulkload.c | 3 ++-
10 files changed, 33 insertions(+), 23 deletions(-)
diff --git a/libxfs/xfs_ag.c b/libxfs/xfs_ag.c
index f22d58ad040..ac6b0090825 100644
--- a/libxfs/xfs_ag.c
+++ b/libxfs/xfs_ag.c
@@ -978,7 +978,7 @@ xfs_ag_shrink_space(
goto resv_err;
err2 = xfs_free_extent_later(*tpp, args.fsbno, delta, NULL,
- XFS_AG_RESV_NONE, true);
+ XFS_AG_RESV_NONE, XFS_FREE_EXTENT_SKIP_DISCARD);
if (err2)
goto resv_err;
diff --git a/libxfs/xfs_alloc.c b/libxfs/xfs_alloc.c
index 08cdfe7e3d3..442a045378c 100644
--- a/libxfs/xfs_alloc.c
+++ b/libxfs/xfs_alloc.c
@@ -2587,7 +2587,7 @@ xfs_defer_extent_free(
xfs_filblks_t len,
const struct xfs_owner_info *oinfo,
enum xfs_ag_resv_type type,
- bool skip_discard,
+ unsigned int free_flags,
struct xfs_defer_pending **dfpp)
{
struct xfs_extent_free_item *xefi;
@@ -2607,6 +2607,7 @@ xfs_defer_extent_free(
ASSERT(len < mp->m_sb.sb_agblocks);
ASSERT(agbno + len <= mp->m_sb.sb_agblocks);
#endif
+ ASSERT(!(free_flags & ~XFS_FREE_EXTENT_ALL_FLAGS));
ASSERT(xfs_extfree_item_cache != NULL);
ASSERT(type != XFS_AG_RESV_AGFL);
@@ -2618,7 +2619,7 @@ xfs_defer_extent_free(
xefi->xefi_startblock = bno;
xefi->xefi_blockcount = (xfs_extlen_t)len;
xefi->xefi_agresv = type;
- if (skip_discard)
+ if (free_flags & XFS_FREE_EXTENT_SKIP_DISCARD)
xefi->xefi_flags |= XFS_EFI_SKIP_DISCARD;
if (oinfo) {
ASSERT(oinfo->oi_offset == 0);
@@ -2646,11 +2647,11 @@ xfs_free_extent_later(
xfs_filblks_t len,
const struct xfs_owner_info *oinfo,
enum xfs_ag_resv_type type,
- bool skip_discard)
+ unsigned int free_flags)
{
struct xfs_defer_pending *dontcare = NULL;
- return xfs_defer_extent_free(tp, bno, len, oinfo, type, skip_discard,
+ return xfs_defer_extent_free(tp, bno, len, oinfo, type, free_flags,
&dontcare);
}
@@ -2675,13 +2676,13 @@ xfs_free_extent_later(
int
xfs_alloc_schedule_autoreap(
const struct xfs_alloc_arg *args,
- bool skip_discard,
+ unsigned int free_flags,
struct xfs_alloc_autoreap *aarp)
{
int error;
error = xfs_defer_extent_free(args->tp, args->fsbno, args->len,
- &args->oinfo, args->resv, skip_discard, &aarp->dfp);
+ &args->oinfo, args->resv, free_flags, &aarp->dfp);
if (error)
return error;
diff --git a/libxfs/xfs_alloc.h b/libxfs/xfs_alloc.h
index 0b956f8b9d5..2da543fb90e 100644
--- a/libxfs/xfs_alloc.h
+++ b/libxfs/xfs_alloc.h
@@ -233,7 +233,12 @@ xfs_buf_to_agfl_bno(
int xfs_free_extent_later(struct xfs_trans *tp, xfs_fsblock_t bno,
xfs_filblks_t len, const struct xfs_owner_info *oinfo,
- enum xfs_ag_resv_type type, bool skip_discard);
+ enum xfs_ag_resv_type type, unsigned int free_flags);
+
+/* Don't issue a discard for the blocks freed. */
+#define XFS_FREE_EXTENT_SKIP_DISCARD (1U << 0)
+
+#define XFS_FREE_EXTENT_ALL_FLAGS (XFS_FREE_EXTENT_SKIP_DISCARD)
/*
* List of extents to be free "later".
@@ -262,7 +267,7 @@ struct xfs_alloc_autoreap {
};
int xfs_alloc_schedule_autoreap(const struct xfs_alloc_arg *args,
- bool skip_discard, struct xfs_alloc_autoreap *aarp);
+ unsigned int free_flags, struct xfs_alloc_autoreap *aarp);
void xfs_alloc_cancel_autoreap(struct xfs_trans *tp,
struct xfs_alloc_autoreap *aarp);
void xfs_alloc_commit_autoreap(struct xfs_trans *tp,
diff --git a/libxfs/xfs_bmap.c b/libxfs/xfs_bmap.c
index 7fefbb7d21c..323f60b1128 100644
--- a/libxfs/xfs_bmap.c
+++ b/libxfs/xfs_bmap.c
@@ -582,7 +582,7 @@ xfs_bmap_btree_to_extents(
xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, whichfork);
error = xfs_free_extent_later(cur->bc_tp, cbno, 1, &oinfo,
- XFS_AG_RESV_NONE, false);
+ XFS_AG_RESV_NONE, 0);
if (error)
return error;
@@ -5260,11 +5260,15 @@ xfs_bmap_del_extent_real(
if (xfs_is_reflink_inode(ip) && whichfork == XFS_DATA_FORK) {
xfs_refcount_decrease_extent(tp, del);
} else {
+ unsigned int efi_flags = 0;
+
+ if ((bflags & XFS_BMAPI_NODISCARD) ||
+ del->br_state == XFS_EXT_UNWRITTEN)
+ efi_flags |= XFS_FREE_EXTENT_SKIP_DISCARD;
+
error = xfs_free_extent_later(tp, del->br_startblock,
del->br_blockcount, NULL,
- XFS_AG_RESV_NONE,
- ((bflags & XFS_BMAPI_NODISCARD) ||
- del->br_state == XFS_EXT_UNWRITTEN));
+ XFS_AG_RESV_NONE, efi_flags);
if (error)
return error;
}
diff --git a/libxfs/xfs_bmap_btree.c b/libxfs/xfs_bmap_btree.c
index 8658e7c390a..f98cc408540 100644
--- a/libxfs/xfs_bmap_btree.c
+++ b/libxfs/xfs_bmap_btree.c
@@ -269,7 +269,7 @@ xfs_bmbt_free_block(
xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, cur->bc_ino.whichfork);
error = xfs_free_extent_later(cur->bc_tp, fsbno, 1, &oinfo,
- XFS_AG_RESV_NONE, false);
+ XFS_AG_RESV_NONE, 0);
if (error)
return error;
diff --git a/libxfs/xfs_ialloc.c b/libxfs/xfs_ialloc.c
index 8aae4b79c85..935f8127c0e 100644
--- a/libxfs/xfs_ialloc.c
+++ b/libxfs/xfs_ialloc.c
@@ -1960,7 +1960,7 @@ xfs_difree_inode_chunk(
return xfs_free_extent_later(tp,
XFS_AGB_TO_FSB(mp, agno, sagbno),
M_IGEO(mp)->ialloc_blks, &XFS_RMAP_OINFO_INODES,
- XFS_AG_RESV_NONE, false);
+ XFS_AG_RESV_NONE, 0);
}
/* holemask is only 16-bits (fits in an unsigned long) */
@@ -2006,8 +2006,7 @@ xfs_difree_inode_chunk(
ASSERT(contigblk % mp->m_sb.sb_spino_align == 0);
error = xfs_free_extent_later(tp,
XFS_AGB_TO_FSB(mp, agno, agbno), contigblk,
- &XFS_RMAP_OINFO_INODES, XFS_AG_RESV_NONE,
- false);
+ &XFS_RMAP_OINFO_INODES, XFS_AG_RESV_NONE, 0);
if (error)
return error;
diff --git a/libxfs/xfs_ialloc_btree.c b/libxfs/xfs_ialloc_btree.c
index 80d28d3fea5..a5f2ccec2e9 100644
--- a/libxfs/xfs_ialloc_btree.c
+++ b/libxfs/xfs_ialloc_btree.c
@@ -160,7 +160,7 @@ __xfs_inobt_free_block(
xfs_inobt_mod_blockcount(cur, -1);
fsbno = XFS_DADDR_TO_FSB(cur->bc_mp, xfs_buf_daddr(bp));
return xfs_free_extent_later(cur->bc_tp, fsbno, 1,
- &XFS_RMAP_OINFO_INOBT, resv, false);
+ &XFS_RMAP_OINFO_INOBT, resv, 0);
}
STATIC int
diff --git a/libxfs/xfs_refcount.c b/libxfs/xfs_refcount.c
index fe63b9eec8a..6c6634675c2 100644
--- a/libxfs/xfs_refcount.c
+++ b/libxfs/xfs_refcount.c
@@ -1172,7 +1172,7 @@ xfs_refcount_adjust_extents(
tmp.rc_startblock);
error = xfs_free_extent_later(cur->bc_tp, fsbno,
tmp.rc_blockcount, NULL,
- XFS_AG_RESV_NONE, false);
+ XFS_AG_RESV_NONE, 0);
if (error)
goto out_error;
}
@@ -1236,7 +1236,7 @@ xfs_refcount_adjust_extents(
ext.rc_startblock);
error = xfs_free_extent_later(cur->bc_tp, fsbno,
ext.rc_blockcount, NULL,
- XFS_AG_RESV_NONE, false);
+ XFS_AG_RESV_NONE, 0);
if (error)
goto out_error;
}
@@ -2021,7 +2021,7 @@ xfs_refcount_recover_cow_leftovers(
/* Free the block. */
error = xfs_free_extent_later(tp, fsb,
rr->rr_rrec.rc_blockcount, NULL,
- XFS_AG_RESV_NONE, false);
+ XFS_AG_RESV_NONE, 0);
if (error)
goto out_trans;
diff --git a/libxfs/xfs_refcount_btree.c b/libxfs/xfs_refcount_btree.c
index 1fbd250c1a8..c57e89f4be8 100644
--- a/libxfs/xfs_refcount_btree.c
+++ b/libxfs/xfs_refcount_btree.c
@@ -107,7 +107,7 @@ xfs_refcountbt_free_block(
be32_add_cpu(&agf->agf_refcount_blocks, -1);
xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_BLOCKS);
return xfs_free_extent_later(cur->bc_tp, fsbno, 1,
- &XFS_RMAP_OINFO_REFC, XFS_AG_RESV_METADATA, false);
+ &XFS_RMAP_OINFO_REFC, XFS_AG_RESV_METADATA, 0);
}
STATIC int
diff --git a/repair/bulkload.c b/repair/bulkload.c
index a97839f549d..e9c52afd23c 100644
--- a/repair/bulkload.c
+++ b/repair/bulkload.c
@@ -196,7 +196,8 @@ bulkload_free_extent(
*/
fsbno = XFS_AGB_TO_FSB(sc->mp, resv->pag->pag_agno, free_agbno);
error = -libxfs_free_extent_later(sc->tp, fsbno, free_aglen,
- &bkl->oinfo, XFS_AG_RESV_NONE, true);
+ &bkl->oinfo, XFS_AG_RESV_NONE,
+ XFS_FREE_EXTENT_SKIP_DISCARD);
if (error)
return error;
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 3/8] xfs: pass the fsbno to xfs_perag_intent_get
2023-12-31 19:54 ` [PATCHSET v2.0 09/17] xfsprogs: extent free log intent cleanups Darrick J. Wong
2023-12-27 13:05 ` [PATCH 1/8] xfs: clean up extent free log intent item tracepoint callsites Darrick J. Wong
2023-12-27 13:05 ` [PATCH 2/8] xfs: convert "skip_discard" to a proper flags bitset Darrick J. Wong
@ 2023-12-27 13:06 ` Darrick J. Wong
2023-12-27 13:06 ` [PATCH 4/8] xfs: add a xefi_entry helper Darrick J. Wong
` (4 subsequent siblings)
7 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:06 UTC (permalink / raw)
To: cem, djwong; +Cc: Christoph Hellwig, linux-xfs
From: Christoph Hellwig <hch@lst.de>
All callers of xfs_perag_intent_get have a fsbno and need boilerplate
code to turn that into an agno. Just pass the fsbno to
xfs_perag_intent_get and look up the agno there.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
include/xfs_mount.h | 3 ++-
libxfs/defer_item.c | 21 ++++-----------------
2 files changed, 6 insertions(+), 18 deletions(-)
diff --git a/include/xfs_mount.h b/include/xfs_mount.h
index 51a02e69776..1284e848835 100644
--- a/include/xfs_mount.h
+++ b/include/xfs_mount.h
@@ -317,7 +317,8 @@ struct xfs_defer_drain { /* empty */ };
#define xfs_defer_drain_init(dr) ((void)0)
#define xfs_defer_drain_free(dr) ((void)0)
-#define xfs_perag_intent_get(mp, agno) xfs_perag_get((mp), (agno))
+#define xfs_perag_intent_get(mp, agno) \
+ xfs_perag_get((mp), XFS_FSB_TO_AGNO((mp), (agno)))
#define xfs_perag_intent_put(pag) xfs_perag_put(pag)
static inline void xfs_perag_intent_hold(struct xfs_perag *pag) {}
diff --git a/libxfs/defer_item.c b/libxfs/defer_item.c
index fbd035d9b94..2958dcb85e5 100644
--- a/libxfs/defer_item.c
+++ b/libxfs/defer_item.c
@@ -79,10 +79,7 @@ xfs_extent_free_get_group(
struct xfs_mount *mp,
struct xfs_extent_free_item *xefi)
{
- xfs_agnumber_t agno;
-
- agno = XFS_FSB_TO_AGNO(mp, xefi->xefi_startblock);
- xefi->xefi_pag = xfs_perag_intent_get(mp, agno);
+ xefi->xefi_pag = xfs_perag_intent_get(mp, xefi->xefi_startblock);
}
/* Release an active AG ref after some freeing work. */
@@ -256,10 +253,7 @@ xfs_rmap_update_get_group(
struct xfs_mount *mp,
struct xfs_rmap_intent *ri)
{
- xfs_agnumber_t agno;
-
- agno = XFS_FSB_TO_AGNO(mp, ri->ri_bmap.br_startblock);
- ri->ri_pag = xfs_perag_intent_get(mp, agno);
+ ri->ri_pag = xfs_perag_intent_get(mp, ri->ri_bmap.br_startblock);
}
/* Release an active AG ref after finishing rmapping work. */
@@ -369,10 +363,7 @@ xfs_refcount_update_get_group(
struct xfs_mount *mp,
struct xfs_refcount_intent *ri)
{
- xfs_agnumber_t agno;
-
- agno = XFS_FSB_TO_AGNO(mp, ri->ri_startblock);
- ri->ri_pag = xfs_perag_intent_get(mp, agno);
+ ri->ri_pag = xfs_perag_intent_get(mp, ri->ri_startblock);
}
/* Release an active AG ref after finishing refcounting work. */
@@ -490,8 +481,6 @@ xfs_bmap_update_get_group(
struct xfs_mount *mp,
struct xfs_bmap_intent *bi)
{
- xfs_agnumber_t agno;
-
if (xfs_ifork_is_realtime(bi->bi_owner, bi->bi_whichfork)) {
if (xfs_has_rtgroups(mp)) {
xfs_rgnumber_t rgno;
@@ -505,8 +494,6 @@ xfs_bmap_update_get_group(
return;
}
- agno = XFS_FSB_TO_AGNO(mp, bi->bi_bmap.br_startblock);
-
/*
* Bump the intent count on behalf of the deferred rmap and refcount
* intent items that that we can queue when we finish this bmap work.
@@ -514,7 +501,7 @@ xfs_bmap_update_get_group(
* intent drops the intent count, ensuring that the intent count
* remains nonzero across the transaction roll.
*/
- bi->bi_pag = xfs_perag_intent_get(mp, agno);
+ bi->bi_pag = xfs_perag_intent_get(mp, bi->bi_bmap.br_startblock);
}
/* Add this deferred BUI to the transaction. */
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 4/8] xfs: add a xefi_entry helper
2023-12-31 19:54 ` [PATCHSET v2.0 09/17] xfsprogs: extent free log intent cleanups Darrick J. Wong
` (2 preceding siblings ...)
2023-12-27 13:06 ` [PATCH 3/8] xfs: pass the fsbno to xfs_perag_intent_get Darrick J. Wong
@ 2023-12-27 13:06 ` Darrick J. Wong
2023-12-27 13:06 ` [PATCH 5/8] xfs: reuse xfs_extent_free_cancel_item Darrick J. Wong
` (3 subsequent siblings)
7 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:06 UTC (permalink / raw)
To: cem, djwong; +Cc: Christoph Hellwig, linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Add a helper to translate from the item list head to the
xfs_extent_free_item structure and use it so shorten assignments and
avoid the need for extra local variables.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/defer_item.c | 24 ++++++++++--------------
1 file changed, 10 insertions(+), 14 deletions(-)
diff --git a/libxfs/defer_item.c b/libxfs/defer_item.c
index 2958dcb85e5..5fa54962267 100644
--- a/libxfs/defer_item.c
+++ b/libxfs/defer_item.c
@@ -32,6 +32,11 @@
/* Extent Freeing */
+static inline struct xfs_extent_free_item *xefi_entry(const struct list_head *e)
+{
+ return list_entry(e, struct xfs_extent_free_item, xefi_list);
+}
+
/* Sort bmap items by AG. */
static int
xfs_extent_free_diff_items(
@@ -39,11 +44,8 @@ xfs_extent_free_diff_items(
const struct list_head *a,
const struct list_head *b)
{
- const struct xfs_extent_free_item *ra;
- const struct xfs_extent_free_item *rb;
-
- ra = container_of(a, struct xfs_extent_free_item, xefi_list);
- rb = container_of(b, struct xfs_extent_free_item, xefi_list);
+ struct xfs_extent_free_item *ra = xefi_entry(a);
+ struct xfs_extent_free_item *rb = xefi_entry(b);
return ra->xefi_pag->pag_agno - rb->xefi_pag->pag_agno;
}
@@ -99,12 +101,10 @@ xfs_extent_free_finish_item(
struct xfs_btree_cur **state)
{
struct xfs_owner_info oinfo = { };
- struct xfs_extent_free_item *xefi;
+ struct xfs_extent_free_item *xefi = xefi_entry(item);
xfs_agblock_t agbno;
int error = 0;
- xefi = container_of(item, struct xfs_extent_free_item, xefi_list);
-
oinfo.oi_owner = xefi->xefi_owner;
if (xefi->xefi_flags & XFS_EFI_ATTR_FORK)
oinfo.oi_flags |= XFS_OWNER_INFO_ATTR_FORK;
@@ -143,9 +143,7 @@ STATIC void
xfs_extent_free_cancel_item(
struct list_head *item)
{
- struct xfs_extent_free_item *xefi;
-
- xefi = container_of(item, struct xfs_extent_free_item, xefi_list);
+ struct xfs_extent_free_item *xefi = xefi_entry(item);
xfs_extent_free_put_group(xefi);
kmem_cache_free(xfs_extfree_item_cache, xefi);
@@ -173,13 +171,11 @@ xfs_agfl_free_finish_item(
{
struct xfs_owner_info oinfo = { };
struct xfs_mount *mp = tp->t_mountp;
- struct xfs_extent_free_item *xefi;
+ struct xfs_extent_free_item *xefi = xefi_entry(item);
struct xfs_buf *agbp;
int error;
xfs_agblock_t agbno;
- xefi = container_of(item, struct xfs_extent_free_item, xefi_list);
-
ASSERT(xefi->xefi_blockcount == 1);
agbno = XFS_FSB_TO_AGBNO(mp, xefi->xefi_startblock);
oinfo.oi_owner = xefi->xefi_owner;
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 5/8] xfs: reuse xfs_extent_free_cancel_item
2023-12-31 19:54 ` [PATCHSET v2.0 09/17] xfsprogs: extent free log intent cleanups Darrick J. Wong
` (3 preceding siblings ...)
2023-12-27 13:06 ` [PATCH 4/8] xfs: add a xefi_entry helper Darrick J. Wong
@ 2023-12-27 13:06 ` Darrick J. Wong
2023-12-27 13:06 ` [PATCH 6/8] xfs: remove duplicate asserts in xfs_defer_extent_free Darrick J. Wong
` (2 subsequent siblings)
7 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:06 UTC (permalink / raw)
To: cem, djwong; +Cc: Christoph Hellwig, linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Reuse xfs_extent_free_cancel_item to put the AG/RTG and free the item in
a few places that currently open code the logic.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/defer_item.c | 32 ++++++++++++++------------------
1 file changed, 14 insertions(+), 18 deletions(-)
diff --git a/libxfs/defer_item.c b/libxfs/defer_item.c
index 5fa54962267..b159f22c1c0 100644
--- a/libxfs/defer_item.c
+++ b/libxfs/defer_item.c
@@ -92,6 +92,17 @@ xfs_extent_free_put_group(
xfs_perag_intent_put(xefi->xefi_pag);
}
+/* Cancel a free extent. */
+STATIC void
+xfs_extent_free_cancel_item(
+ struct list_head *item)
+{
+ struct xfs_extent_free_item *xefi = xefi_entry(item);
+
+ xfs_extent_free_put_group(xefi);
+ kmem_cache_free(xfs_extfree_item_cache, xefi);
+}
+
/* Process a free extent. */
STATIC int
xfs_extent_free_finish_item(
@@ -123,11 +134,8 @@ xfs_extent_free_finish_item(
* Don't free the XEFI if we need a new transaction to complete
* processing of it.
*/
- if (error == -EAGAIN)
- return error;
-
- xfs_extent_free_put_group(xefi);
- kmem_cache_free(xfs_extfree_item_cache, xefi);
+ if (error != -EAGAIN)
+ xfs_extent_free_cancel_item(item);
return error;
}
@@ -138,17 +146,6 @@ xfs_extent_free_abort_intent(
{
}
-/* Cancel a free extent. */
-STATIC void
-xfs_extent_free_cancel_item(
- struct list_head *item)
-{
- struct xfs_extent_free_item *xefi = xefi_entry(item);
-
- xfs_extent_free_put_group(xefi);
- kmem_cache_free(xfs_extfree_item_cache, xefi);
-}
-
const struct xfs_defer_op_type xfs_extent_free_defer_type = {
.name = "extent_free",
.create_intent = xfs_extent_free_create_intent,
@@ -185,8 +182,7 @@ xfs_agfl_free_finish_item(
error = xfs_free_agfl_block(tp, xefi->xefi_pag->pag_agno,
agbno, agbp, &oinfo);
- xfs_extent_free_put_group(xefi);
- kmem_cache_free(xfs_extfree_item_cache, xefi);
+ xfs_extent_free_cancel_item(item);
return error;
}
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 6/8] xfs: remove duplicate asserts in xfs_defer_extent_free
2023-12-31 19:54 ` [PATCHSET v2.0 09/17] xfsprogs: extent free log intent cleanups Darrick J. Wong
` (4 preceding siblings ...)
2023-12-27 13:06 ` [PATCH 5/8] xfs: reuse xfs_extent_free_cancel_item Darrick J. Wong
@ 2023-12-27 13:06 ` Darrick J. Wong
2023-12-27 13:07 ` [PATCH 7/8] xfs: remove xfs_defer_agfl_block Darrick J. Wong
2023-12-27 13:07 ` [PATCH 8/8] xfs: move xfs_extent_free_defer_add to xfs_extfree_item.c Darrick J. Wong
7 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:06 UTC (permalink / raw)
To: cem, djwong; +Cc: Christoph Hellwig, linux-xfs
From: Christoph Hellwig <hch@lst.de>
The bno/len verification is already done by the calls to
xfs_verify_rtbext / xfs_verify_fsbext, and reporting a corruption error
seem like the better handling than tripping an assert anyway.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_alloc.c | 13 -------------
1 file changed, 13 deletions(-)
diff --git a/libxfs/xfs_alloc.c b/libxfs/xfs_alloc.c
index 442a045378c..160563b1b26 100644
--- a/libxfs/xfs_alloc.c
+++ b/libxfs/xfs_alloc.c
@@ -2592,23 +2592,10 @@ xfs_defer_extent_free(
{
struct xfs_extent_free_item *xefi;
struct xfs_mount *mp = tp->t_mountp;
-#ifdef DEBUG
- xfs_agnumber_t agno;
- xfs_agblock_t agbno;
- ASSERT(bno != NULLFSBLOCK);
- ASSERT(len > 0);
ASSERT(len <= XFS_MAX_BMBT_EXTLEN);
ASSERT(!isnullstartblock(bno));
- agno = XFS_FSB_TO_AGNO(mp, bno);
- agbno = XFS_FSB_TO_AGBNO(mp, bno);
- ASSERT(agno < mp->m_sb.sb_agcount);
- ASSERT(agbno < mp->m_sb.sb_agblocks);
- ASSERT(len < mp->m_sb.sb_agblocks);
- ASSERT(agbno + len <= mp->m_sb.sb_agblocks);
-#endif
ASSERT(!(free_flags & ~XFS_FREE_EXTENT_ALL_FLAGS));
- ASSERT(xfs_extfree_item_cache != NULL);
ASSERT(type != XFS_AG_RESV_AGFL);
if (XFS_IS_CORRUPT(mp, !xfs_verify_fsbext(mp, bno, len)))
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 7/8] xfs: remove xfs_defer_agfl_block
2023-12-31 19:54 ` [PATCHSET v2.0 09/17] xfsprogs: extent free log intent cleanups Darrick J. Wong
` (5 preceding siblings ...)
2023-12-27 13:06 ` [PATCH 6/8] xfs: remove duplicate asserts in xfs_defer_extent_free Darrick J. Wong
@ 2023-12-27 13:07 ` Darrick J. Wong
2023-12-27 13:07 ` [PATCH 8/8] xfs: move xfs_extent_free_defer_add to xfs_extfree_item.c Darrick J. Wong
7 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:07 UTC (permalink / raw)
To: cem, djwong; +Cc: Christoph Hellwig, linux-xfs
From: Christoph Hellwig <hch@lst.de>
xfs_free_extent_later can handle the extra AGFL special casing with
very little extra logic.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_alloc.c | 67 +++++++++++++++++-----------------------------------
1 file changed, 22 insertions(+), 45 deletions(-)
diff --git a/libxfs/xfs_alloc.c b/libxfs/xfs_alloc.c
index 160563b1b26..2cbdbd4c416 100644
--- a/libxfs/xfs_alloc.c
+++ b/libxfs/xfs_alloc.c
@@ -2534,48 +2534,6 @@ xfs_agfl_reset(
clear_bit(XFS_AGSTATE_AGFL_NEEDS_RESET, &pag->pag_opstate);
}
-/*
- * Defer an AGFL block free. This is effectively equivalent to
- * xfs_free_extent_later() with some special handling particular to AGFL blocks.
- *
- * Deferring AGFL frees helps prevent log reservation overruns due to too many
- * allocation operations in a transaction. AGFL frees are prone to this problem
- * because for one they are always freed one at a time. Further, an immediate
- * AGFL block free can cause a btree join and require another block free before
- * the real allocation can proceed. Deferring the free disconnects freeing up
- * the AGFL slot from freeing the block.
- */
-static int
-xfs_defer_agfl_block(
- struct xfs_trans *tp,
- xfs_agnumber_t agno,
- xfs_agblock_t agbno,
- struct xfs_owner_info *oinfo)
-{
- struct xfs_mount *mp = tp->t_mountp;
- struct xfs_extent_free_item *xefi;
- xfs_fsblock_t fsbno = XFS_AGB_TO_FSB(mp, agno, agbno);
-
- ASSERT(xfs_extfree_item_cache != NULL);
- ASSERT(oinfo != NULL);
-
- if (XFS_IS_CORRUPT(mp, !xfs_verify_fsbno(mp, fsbno)))
- return -EFSCORRUPTED;
-
- xefi = kmem_cache_zalloc(xfs_extfree_item_cache,
- GFP_KERNEL | __GFP_NOFAIL);
- xefi->xefi_startblock = fsbno;
- xefi->xefi_blockcount = 1;
- xefi->xefi_owner = oinfo->oi_owner;
- xefi->xefi_agresv = XFS_AG_RESV_AGFL;
-
- trace_xfs_agfl_free_defer(mp, xefi);
-
- xfs_extent_free_get_group(mp, xefi);
- xfs_defer_add(tp, &xefi->xefi_list, &xfs_agfl_free_defer_type);
- return 0;
-}
-
/*
* Add the extent to the list of extents to be free at transaction end.
* The list is maintained sorted (by block number).
@@ -2623,7 +2581,13 @@ xfs_defer_extent_free(
trace_xfs_extent_free_defer(mp, xefi);
xfs_extent_free_get_group(mp, xefi);
- *dfpp = xfs_defer_add(tp, &xefi->xefi_list, &xfs_extent_free_defer_type);
+
+ if (xefi->xefi_agresv == XFS_AG_RESV_AGFL)
+ *dfpp = xfs_defer_add(tp, &xefi->xefi_list,
+ &xfs_agfl_free_defer_type);
+ else
+ *dfpp = xfs_defer_add(tp, &xefi->xefi_list,
+ &xfs_extent_free_defer_type);
return 0;
}
@@ -2881,8 +2845,21 @@ xfs_alloc_fix_freelist(
if (error)
goto out_agbp_relse;
- /* defer agfl frees */
- error = xfs_defer_agfl_block(tp, args->agno, bno, &targs.oinfo);
+ /*
+ * Defer the AGFL block free.
+ *
+ * This helps to prevent log reservation overruns due to too
+ * many allocation operations in a transaction. AGFL frees are
+ * prone to this problem because for one they are always freed
+ * one at a time. Further, an immediate AGFL block free can
+ * cause a btree join and require another block free before the
+ * real allocation can proceed.
+ * Deferring the free disconnects freeing up the AGFL slot from
+ * freeing the block.
+ */
+ error = xfs_free_extent_later(tp,
+ XFS_AGB_TO_FSB(mp, args->agno, bno), 1,
+ &targs.oinfo, XFS_AG_RESV_AGFL, 0);
if (error)
goto out_agbp_relse;
}
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 8/8] xfs: move xfs_extent_free_defer_add to xfs_extfree_item.c
2023-12-31 19:54 ` [PATCHSET v2.0 09/17] xfsprogs: extent free log intent cleanups Darrick J. Wong
` (6 preceding siblings ...)
2023-12-27 13:07 ` [PATCH 7/8] xfs: remove xfs_defer_agfl_block Darrick J. Wong
@ 2023-12-27 13:07 ` Darrick J. Wong
7 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:07 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Move the code that adds the incore xfs_extent_free_item deferred work
data to a transaction live with the EFI log item code. This means that
the allocator code no longer has to know about the inner workings of the
EFI log items.
As a consequence, we can get rid of the _{get,put}_group helpers.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/defer_item.c | 28 +++++++++++++++-------------
libxfs/defer_item.h | 6 ++++++
libxfs/xfs_alloc.c | 12 ++----------
libxfs/xfs_alloc.h | 3 ---
4 files changed, 23 insertions(+), 26 deletions(-)
diff --git a/libxfs/defer_item.c b/libxfs/defer_item.c
index b159f22c1c0..9b9bce17f4e 100644
--- a/libxfs/defer_item.c
+++ b/libxfs/defer_item.c
@@ -27,6 +27,7 @@
#include "defer_item.h"
#include "xfs_ag.h"
#include "xfs_swapext.h"
+#include "defer_item.h"
/* Dummy defer item ops, since we don't do logging. */
@@ -75,21 +76,22 @@ xfs_extent_free_create_done(
return NULL;
}
-/* Take an active ref to the AG containing the space we're freeing. */
+/* Add this deferred EFI to the transaction. */
void
-xfs_extent_free_get_group(
- struct xfs_mount *mp,
- struct xfs_extent_free_item *xefi)
+xfs_extent_free_defer_add(
+ struct xfs_trans *tp,
+ struct xfs_extent_free_item *xefi,
+ struct xfs_defer_pending **dfpp)
{
+ struct xfs_mount *mp = tp->t_mountp;
+
xefi->xefi_pag = xfs_perag_intent_get(mp, xefi->xefi_startblock);
-}
-
-/* Release an active AG ref after some freeing work. */
-static inline void
-xfs_extent_free_put_group(
- struct xfs_extent_free_item *xefi)
-{
- xfs_perag_intent_put(xefi->xefi_pag);
+ if (xefi->xefi_agresv == XFS_AG_RESV_AGFL)
+ *dfpp = xfs_defer_add(tp, &xefi->xefi_list,
+ &xfs_agfl_free_defer_type);
+ else
+ *dfpp = xfs_defer_add(tp, &xefi->xefi_list,
+ &xfs_extent_free_defer_type);
}
/* Cancel a free extent. */
@@ -99,7 +101,7 @@ xfs_extent_free_cancel_item(
{
struct xfs_extent_free_item *xefi = xefi_entry(item);
- xfs_extent_free_put_group(xefi);
+ xfs_perag_intent_put(xefi->xefi_pag);
kmem_cache_free(xfs_extfree_item_cache, xefi);
}
diff --git a/libxfs/defer_item.h b/libxfs/defer_item.h
index a3ef9e079d0..79e957eb8ff 100644
--- a/libxfs/defer_item.h
+++ b/libxfs/defer_item.h
@@ -14,4 +14,10 @@ struct xfs_swapext_intent;
void xfs_swapext_defer_add(struct xfs_trans *tp, struct xfs_swapext_intent *sxi);
+struct xfs_extent_free_item;
+
+void xfs_extent_free_defer_add(struct xfs_trans *tp,
+ struct xfs_extent_free_item *xefi,
+ struct xfs_defer_pending **dfpp);
+
#endif /* __LIBXFS_DEFER_ITEM_H_ */
diff --git a/libxfs/xfs_alloc.c b/libxfs/xfs_alloc.c
index 2cbdbd4c416..36af2c087b0 100644
--- a/libxfs/xfs_alloc.c
+++ b/libxfs/xfs_alloc.c
@@ -23,6 +23,7 @@
#include "xfs_ag_resv.h"
#include "xfs_bmap.h"
#include "xfs_health.h"
+#include "defer_item.h"
struct kmem_cache *xfs_extfree_item_cache;
@@ -2578,16 +2579,7 @@ xfs_defer_extent_free(
xefi->xefi_owner = XFS_RMAP_OWN_NULL;
}
- trace_xfs_extent_free_defer(mp, xefi);
-
- xfs_extent_free_get_group(mp, xefi);
-
- if (xefi->xefi_agresv == XFS_AG_RESV_AGFL)
- *dfpp = xfs_defer_add(tp, &xefi->xefi_list,
- &xfs_agfl_free_defer_type);
- else
- *dfpp = xfs_defer_add(tp, &xefi->xefi_list,
- &xfs_extent_free_defer_type);
+ xfs_extent_free_defer_add(tp, xefi, dfpp);
return 0;
}
diff --git a/libxfs/xfs_alloc.h b/libxfs/xfs_alloc.h
index 2da543fb90e..0ed71a31fe7 100644
--- a/libxfs/xfs_alloc.h
+++ b/libxfs/xfs_alloc.h
@@ -254,9 +254,6 @@ struct xfs_extent_free_item {
enum xfs_ag_resv_type xefi_agresv;
};
-void xfs_extent_free_get_group(struct xfs_mount *mp,
- struct xfs_extent_free_item *xefi);
-
#define XFS_EFI_SKIP_DISCARD (1U << 0) /* don't issue discard */
#define XFS_EFI_ATTR_FORK (1U << 1) /* freeing attr fork block */
#define XFS_EFI_BMBT_BLOCK (1U << 2) /* freeing bmap btree block */
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 1/3] xfs: support logging EFIs for realtime extents
2023-12-31 19:54 ` [PATCHSET v2.0 10/17] xfsprogs: widen EFI format to support rt Darrick J. Wong
@ 2023-12-27 13:07 ` Darrick J. Wong
2023-12-27 13:07 ` [PATCH 2/3] xfs: support error injection when freeing rt extents Darrick J. Wong
2023-12-27 13:08 ` [PATCH 3/3] xfs_logprint: report realtime EFIs Darrick J. Wong
2 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:07 UTC (permalink / raw)
To: cem, djwong; +Cc: Christoph Hellwig, linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Teach the EFI mechanism how to free realtime extents. We're going to
need this to enforce proper ordering of operations when we enable
realtime rmap.
Declare a new log intent item type (XFS_LI_EFI_RT) and a separate defer
ops for rt extents. This keeps the ondisk artifacts and processing code
completely separate between the rt and non-rt cases. Hopefully this
will make it easier to debug filesystem problems.
Previous versions of this patch accomplished this by setting the high
bit in each rt EFI extent. This was found to be less transparent by
reviewers.
[Contains a bug fix and cleanups from hch]
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/defer_item.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++
libxfs/xfs_alloc.c | 16 ++++++++--
libxfs/xfs_alloc.h | 17 +++++++++--
libxfs/xfs_defer.c | 6 ++++
libxfs/xfs_defer.h | 1 +
libxfs/xfs_log_format.h | 6 +++-
6 files changed, 115 insertions(+), 6 deletions(-)
diff --git a/libxfs/defer_item.c b/libxfs/defer_item.c
index 9b9bce17f4e..82b70575bc5 100644
--- a/libxfs/defer_item.c
+++ b/libxfs/defer_item.c
@@ -85,6 +85,17 @@ xfs_extent_free_defer_add(
{
struct xfs_mount *mp = tp->t_mountp;
+ if (xfs_efi_is_realtime(xefi)) {
+ xfs_rgnumber_t rgno;
+
+ rgno = xfs_rtb_to_rgno(mp, xefi->xefi_startblock);
+ xefi->xefi_rtg = xfs_rtgroup_get(mp, rgno);
+
+ *dfpp = xfs_defer_add(tp, &xefi->xefi_list,
+ &xfs_rtextent_free_defer_type);
+ return;
+ }
+
xefi->xefi_pag = xfs_perag_intent_get(mp, xefi->xefi_startblock);
if (xefi->xefi_agresv == XFS_AG_RESV_AGFL)
*dfpp = xfs_defer_add(tp, &xefi->xefi_list,
@@ -157,6 +168,70 @@ const struct xfs_defer_op_type xfs_extent_free_defer_type = {
.cancel_item = xfs_extent_free_cancel_item,
};
+/* Sort bmap items by rtgroup. */
+static int
+xfs_rtextent_free_diff_items(
+ void *priv,
+ const struct list_head *a,
+ const struct list_head *b)
+{
+ struct xfs_extent_free_item *ra = xefi_entry(a);
+ struct xfs_extent_free_item *rb = xefi_entry(b);
+
+ return ra->xefi_rtg->rtg_rgno - rb->xefi_rtg->rtg_rgno;
+}
+
+static struct xfs_log_item *
+xfs_rtextent_free_create_intent(
+ struct xfs_trans *tp,
+ struct list_head *items,
+ unsigned int count,
+ bool sort)
+{
+ struct xfs_mount *mp = tp->t_mountp;
+
+ if (sort)
+ list_sort(mp, items, xfs_rtextent_free_diff_items);
+ return NULL;
+}
+
+/* Cancel a free extent. */
+STATIC void
+xfs_rtextent_free_cancel_item(
+ struct list_head *item)
+{
+ struct xfs_extent_free_item *xefi = xefi_entry(item);
+
+ xfs_rtgroup_put(xefi->xefi_rtg);
+ kmem_cache_free(xfs_extfree_item_cache, xefi);
+}
+
+STATIC int
+xfs_rtextent_free_finish_item(
+ struct xfs_trans *tp,
+ struct xfs_log_item *done,
+ struct list_head *item,
+ struct xfs_btree_cur **state)
+{
+ struct xfs_extent_free_item *xefi = xefi_entry(item);
+ int error;
+
+ error = xfs_rtfree_blocks(tp, xefi->xefi_startblock,
+ xefi->xefi_blockcount);
+ if (error != -EAGAIN)
+ xfs_rtextent_free_cancel_item(item);
+ return error;
+}
+
+const struct xfs_defer_op_type xfs_rtextent_free_defer_type = {
+ .name = "rtextent_free",
+ .create_intent = xfs_rtextent_free_create_intent,
+ .abort_intent = xfs_extent_free_abort_intent,
+ .create_done = xfs_extent_free_create_done,
+ .finish_item = xfs_rtextent_free_finish_item,
+ .cancel_item = xfs_rtextent_free_cancel_item,
+};
+
/*
* AGFL blocks are accounted differently in the reserve pools and are not
* inserted into the busy extent list.
diff --git a/libxfs/xfs_alloc.c b/libxfs/xfs_alloc.c
index 36af2c087b0..589e9ef3003 100644
--- a/libxfs/xfs_alloc.c
+++ b/libxfs/xfs_alloc.c
@@ -2555,10 +2555,18 @@ xfs_defer_extent_free(
ASSERT(len <= XFS_MAX_BMBT_EXTLEN);
ASSERT(!isnullstartblock(bno));
ASSERT(!(free_flags & ~XFS_FREE_EXTENT_ALL_FLAGS));
- ASSERT(type != XFS_AG_RESV_AGFL);
- if (XFS_IS_CORRUPT(mp, !xfs_verify_fsbext(mp, bno, len)))
- return -EFSCORRUPTED;
+ if (free_flags & XFS_FREE_EXTENT_REALTIME) {
+ if (type != XFS_AG_RESV_NONE) {
+ ASSERT(type == XFS_AG_RESV_NONE);
+ return -EFSCORRUPTED;
+ }
+ if (XFS_IS_CORRUPT(mp, !xfs_verify_rtbext(mp, bno, len)))
+ return -EFSCORRUPTED;
+ } else {
+ if (XFS_IS_CORRUPT(mp, !xfs_verify_fsbext(mp, bno, len)))
+ return -EFSCORRUPTED;
+ }
xefi = kmem_cache_zalloc(xfs_extfree_item_cache,
GFP_KERNEL | __GFP_NOFAIL);
@@ -2567,6 +2575,8 @@ xfs_defer_extent_free(
xefi->xefi_agresv = type;
if (free_flags & XFS_FREE_EXTENT_SKIP_DISCARD)
xefi->xefi_flags |= XFS_EFI_SKIP_DISCARD;
+ if (free_flags & XFS_FREE_EXTENT_REALTIME)
+ xefi->xefi_flags |= XFS_EFI_REALTIME;
if (oinfo) {
ASSERT(oinfo->oi_offset == 0);
diff --git a/libxfs/xfs_alloc.h b/libxfs/xfs_alloc.h
index 0ed71a31fe7..130026e981e 100644
--- a/libxfs/xfs_alloc.h
+++ b/libxfs/xfs_alloc.h
@@ -238,7 +238,11 @@ int xfs_free_extent_later(struct xfs_trans *tp, xfs_fsblock_t bno,
/* Don't issue a discard for the blocks freed. */
#define XFS_FREE_EXTENT_SKIP_DISCARD (1U << 0)
-#define XFS_FREE_EXTENT_ALL_FLAGS (XFS_FREE_EXTENT_SKIP_DISCARD)
+/* Free blocks on the realtime device. */
+#define XFS_FREE_EXTENT_REALTIME (1U << 1)
+
+#define XFS_FREE_EXTENT_ALL_FLAGS (XFS_FREE_EXTENT_SKIP_DISCARD | \
+ XFS_FREE_EXTENT_REALTIME)
/*
* List of extents to be free "later".
@@ -249,7 +253,10 @@ struct xfs_extent_free_item {
uint64_t xefi_owner;
xfs_fsblock_t xefi_startblock;/* starting fs block number */
xfs_extlen_t xefi_blockcount;/* number of blocks in extent */
- struct xfs_perag *xefi_pag;
+ union {
+ struct xfs_perag *xefi_pag;
+ struct xfs_rtgroup *xefi_rtg;
+ };
unsigned int xefi_flags;
enum xfs_ag_resv_type xefi_agresv;
};
@@ -258,6 +265,12 @@ struct xfs_extent_free_item {
#define XFS_EFI_ATTR_FORK (1U << 1) /* freeing attr fork block */
#define XFS_EFI_BMBT_BLOCK (1U << 2) /* freeing bmap btree block */
#define XFS_EFI_CANCELLED (1U << 3) /* dont actually free the space */
+#define XFS_EFI_REALTIME (1U << 4) /* freeing realtime extent */
+
+static inline bool xfs_efi_is_realtime(const struct xfs_extent_free_item *xefi)
+{
+ return xefi->xefi_flags & XFS_EFI_REALTIME;
+}
struct xfs_alloc_autoreap {
struct xfs_defer_pending *dfp;
diff --git a/libxfs/xfs_defer.c b/libxfs/xfs_defer.c
index 41e607d55f0..4a1139913b9 100644
--- a/libxfs/xfs_defer.c
+++ b/libxfs/xfs_defer.c
@@ -839,6 +839,12 @@ xfs_defer_add(
ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
+ if (!ops->finish_item) {
+ ASSERT(ops->finish_item != NULL);
+ xfs_force_shutdown(tp->t_mountp, SHUTDOWN_CORRUPT_INCORE);
+ return NULL;
+ }
+
dfp = xfs_defer_find_last(tp, ops);
if (!dfp || !xfs_defer_can_append(dfp, ops))
dfp = xfs_defer_alloc(tp, ops);
diff --git a/libxfs/xfs_defer.h b/libxfs/xfs_defer.h
index c9a1fe3fe36..b4e1c386768 100644
--- a/libxfs/xfs_defer.h
+++ b/libxfs/xfs_defer.h
@@ -71,6 +71,7 @@ extern const struct xfs_defer_op_type xfs_refcount_update_defer_type;
extern const struct xfs_defer_op_type xfs_rmap_update_defer_type;
extern const struct xfs_defer_op_type xfs_extent_free_defer_type;
extern const struct xfs_defer_op_type xfs_agfl_free_defer_type;
+extern const struct xfs_defer_op_type xfs_rtextent_free_defer_type;
extern const struct xfs_defer_op_type xfs_attr_defer_type;
extern const struct xfs_defer_op_type xfs_swapext_defer_type;
diff --git a/libxfs/xfs_log_format.h b/libxfs/xfs_log_format.h
index bded03634e5..1f5fe4a588e 100644
--- a/libxfs/xfs_log_format.h
+++ b/libxfs/xfs_log_format.h
@@ -248,6 +248,8 @@ typedef struct xfs_trans_header {
#define XFS_LI_ATTRD 0x1247 /* attr set/remove done */
#define XFS_LI_SXI 0x1248 /* extent swap intent */
#define XFS_LI_SXD 0x1249 /* extent swap done */
+#define XFS_LI_EFI_RT 0x124a /* realtime extent free intent */
+#define XFS_LI_EFD_RT 0x124b /* realtime extent free done */
#define XFS_LI_TYPE_DESC \
{ XFS_LI_EFI, "XFS_LI_EFI" }, \
@@ -267,7 +269,9 @@ typedef struct xfs_trans_header {
{ XFS_LI_ATTRI, "XFS_LI_ATTRI" }, \
{ XFS_LI_ATTRD, "XFS_LI_ATTRD" }, \
{ XFS_LI_SXI, "XFS_LI_SXI" }, \
- { XFS_LI_SXD, "XFS_LI_SXD" }
+ { XFS_LI_SXD, "XFS_LI_SXD" }, \
+ { XFS_LI_EFI_RT, "XFS_LI_EFI_RT" }, \
+ { XFS_LI_EFD_RT, "XFS_LI_EFD_RT" }
/*
* Inode Log Item Format definitions.
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 2/3] xfs: support error injection when freeing rt extents
2023-12-31 19:54 ` [PATCHSET v2.0 10/17] xfsprogs: widen EFI format to support rt Darrick J. Wong
2023-12-27 13:07 ` [PATCH 1/3] xfs: support logging EFIs for realtime extents Darrick J. Wong
@ 2023-12-27 13:07 ` Darrick J. Wong
2023-12-27 13:08 ` [PATCH 3/3] xfs_logprint: report realtime EFIs Darrick J. Wong
2 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:07 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
A handful of fstests expect to be able to test what happens when extent
free intents fail to actually free the extent. Now that we're
supporting EFIs for realtime extents, add to xfs_rtfree_extent the same
injection point that exists in the regular extent freeing code.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_rtbitmap.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/libxfs/xfs_rtbitmap.c b/libxfs/xfs_rtbitmap.c
index 7d29a72be6b..a42e54b28b9 100644
--- a/libxfs/xfs_rtbitmap.c
+++ b/libxfs/xfs_rtbitmap.c
@@ -16,6 +16,7 @@
#include "xfs_trans.h"
#include "xfs_rtbitmap.h"
#include "xfs_health.h"
+#include "xfs_errortag.h"
/*
* Realtime allocator bitmap functions shared with userspace.
@@ -1036,6 +1037,9 @@ xfs_rtfree_extent(
ASSERT(mp->m_rbmip->i_itemp != NULL);
ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
+ if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_FREE_EXTENT))
+ return -EIO;
+
error = xfs_rtcheck_alloc_range(&args, start, len);
if (error)
return error;
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 3/3] xfs_logprint: report realtime EFIs
2023-12-31 19:54 ` [PATCHSET v2.0 10/17] xfsprogs: widen EFI format to support rt Darrick J. Wong
2023-12-27 13:07 ` [PATCH 1/3] xfs: support logging EFIs for realtime extents Darrick J. Wong
2023-12-27 13:07 ` [PATCH 2/3] xfs: support error injection when freeing rt extents Darrick J. Wong
@ 2023-12-27 13:08 ` Darrick J. Wong
2 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:08 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Decode the EFI format just enough to report if an EFI targets the
realtime device or not.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
logprint/log_misc.c | 2 ++
logprint/log_print_all.c | 8 ++++++
logprint/log_redo.c | 57 +++++++++++++++++++++++++++++++++++-----------
3 files changed, 53 insertions(+), 14 deletions(-)
diff --git a/logprint/log_misc.c b/logprint/log_misc.c
index 565e7b76284..9d63f376390 100644
--- a/logprint/log_misc.c
+++ b/logprint/log_misc.c
@@ -997,12 +997,14 @@ xlog_print_record(
&i, num_ops);
break;
}
+ case XFS_LI_EFI_RT:
case XFS_LI_EFI: {
skip = xlog_print_trans_efi(&ptr,
be32_to_cpu(op_head->oh_len),
continued);
break;
}
+ case XFS_LI_EFD_RT:
case XFS_LI_EFD: {
skip = xlog_print_trans_efd(&ptr,
be32_to_cpu(op_head->oh_len));
diff --git a/logprint/log_print_all.c b/logprint/log_print_all.c
index 6e528fcd097..d030efa9efb 100644
--- a/logprint/log_print_all.c
+++ b/logprint/log_print_all.c
@@ -410,9 +410,11 @@ xlog_recover_print_logitem(
case XFS_LI_INODE:
xlog_recover_print_inode(item);
break;
+ case XFS_LI_EFD_RT:
case XFS_LI_EFD:
xlog_recover_print_efd(item);
break;
+ case XFS_LI_EFI_RT:
case XFS_LI_EFI:
xlog_recover_print_efi(item);
break;
@@ -474,6 +476,12 @@ xlog_recover_print_item(
case XFS_LI_INODE:
printf("INO");
break;
+ case XFS_LI_EFD_RT:
+ printf("EFD_RT");
+ break;
+ case XFS_LI_EFI_RT:
+ printf("EFI_RT");
+ break;
case XFS_LI_EFD:
printf("EFD");
break;
diff --git a/logprint/log_redo.c b/logprint/log_redo.c
index 948924d5bcb..0cc3cd4ba28 100644
--- a/logprint/log_redo.c
+++ b/logprint/log_redo.c
@@ -67,6 +67,7 @@ xlog_print_trans_efi(
uint src_len,
int continued)
{
+ const char *item_name = "EFI?";
xfs_efi_log_format_t *src_f, *f = NULL;
uint dst_len;
xfs_extent_t *ex;
@@ -103,8 +104,14 @@ xlog_print_trans_efi(
goto error;
}
- printf(_("EFI: #regs: %d num_extents: %d id: 0x%llx\n"),
- f->efi_size, f->efi_nextents, (unsigned long long)f->efi_id);
+ switch (f->efi_type) {
+ case XFS_LI_EFI: item_name = "EFI"; break;
+ case XFS_LI_EFI_RT: item_name = "EFI_RT"; break;
+ }
+
+ printf(_("%s: #regs: %d num_extents: %u id: 0x%llx\n"),
+ item_name, f->efi_size, f->efi_nextents,
+ (unsigned long long)f->efi_id);
if (continued) {
printf(_("EFI free extent data skipped (CONTINUE set, no space)\n"));
@@ -113,7 +120,7 @@ xlog_print_trans_efi(
ex = f->efi_extents;
for (i=0; i < f->efi_nextents; i++) {
- printf("(s: 0x%llx, l: %d) ",
+ printf("(s: 0x%llx, l: %u) ",
(unsigned long long)ex->ext_start, ex->ext_len);
if (i % 4 == 3) printf("\n");
ex++;
@@ -130,6 +137,7 @@ void
xlog_recover_print_efi(
struct xlog_recover_item *item)
{
+ const char *item_name = "EFI?";
xfs_efi_log_format_t *f, *src_f;
xfs_extent_t *ex;
int i;
@@ -155,12 +163,18 @@ xlog_recover_print_efi(
return;
}
- printf(_(" EFI: #regs:%d num_extents:%d id:0x%llx\n"),
- f->efi_size, f->efi_nextents, (unsigned long long)f->efi_id);
+ switch (f->efi_type) {
+ case XFS_LI_EFI: item_name = "EFI"; break;
+ case XFS_LI_EFI_RT: item_name = "EFI_RT"; break;
+ }
+
+ printf(_(" %s: #regs:%d num_extents:%u id:0x%llx\n"),
+ item_name, f->efi_size, f->efi_nextents,
+ (unsigned long long)f->efi_id);
ex = f->efi_extents;
printf(" ");
for (i=0; i< f->efi_nextents; i++) {
- printf("(s: 0x%llx, l: %d) ",
+ printf("(s: 0x%llx, l: %u) ",
(unsigned long long)ex->ext_start, ex->ext_len);
if (i % 4 == 3)
printf("\n");
@@ -174,8 +188,10 @@ xlog_recover_print_efi(
int
xlog_print_trans_efd(char **ptr, uint len)
{
- xfs_efd_log_format_t *f;
- xfs_efd_log_format_t lbuf;
+ const char *item_name = "EFD?";
+ xfs_efd_log_format_t *f;
+ xfs_efd_log_format_t lbuf;
+
/* size without extents at end */
uint core_size = sizeof(xfs_efd_log_format_t);
@@ -185,11 +201,17 @@ xlog_print_trans_efd(char **ptr, uint len)
*/
memmove(&lbuf, *ptr, min(core_size, len));
f = &lbuf;
+
+ switch (f->efd_type) {
+ case XFS_LI_EFD: item_name = "EFD"; break;
+ case XFS_LI_EFD_RT: item_name = "EFD_RT"; break;
+ }
+
*ptr += len;
if (len >= core_size) {
- printf(_("EFD: #regs: %d num_extents: %d id: 0x%llx\n"),
- f->efd_size, f->efd_nextents,
- (unsigned long long)f->efd_efi_id);
+ printf(_("%s: #regs: %d num_extents: %d id: 0x%llx\n"),
+ item_name, f->efd_size, f->efd_nextents,
+ (unsigned long long)f->efd_efi_id);
/* don't print extents as they are not used */
@@ -204,18 +226,25 @@ void
xlog_recover_print_efd(
struct xlog_recover_item *item)
{
+ const char *item_name = "EFD?";
xfs_efd_log_format_t *f;
f = (xfs_efd_log_format_t *)item->ri_buf[0].i_addr;
+
+ switch (f->efd_type) {
+ case XFS_LI_EFD: item_name = "EFD"; break;
+ case XFS_LI_EFD_RT: item_name = "EFD_RT"; break;
+ }
+
/*
* An xfs_efd_log_format structure contains a variable length array
* as the last field.
* Each element is of size xfs_extent_32_t or xfs_extent_64_t.
* However, the extents are never used and won't be printed.
*/
- printf(_(" EFD: #regs: %d num_extents: %d id: 0x%llx\n"),
- f->efd_size, f->efd_nextents,
- (unsigned long long)f->efd_efi_id);
+ printf(_(" %s: #regs: %d num_extents: %d id: 0x%llx\n"),
+ item_name, f->efd_size, f->efd_nextents,
+ (unsigned long long)f->efd_efi_id);
}
/* Reverse Mapping Update Items */
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 1/9] xfs: attach rtgroup objects to btree cursors
2023-12-31 19:54 ` [PATCHSET v2.0 11/17] xfsprogs: rmap log intent cleanups Darrick J. Wong
@ 2023-12-27 13:08 ` Darrick J. Wong
2023-12-27 13:08 ` [PATCH 2/9] xfs: give rmap btree cursor error tracepoints their own class Darrick J. Wong
` (7 subsequent siblings)
8 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:08 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Make it so that we can attach realtime group objects to btree cursors.
This will be crucial for enabling rmap btrees in realtime groups.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_btree.c | 4 ++++
libxfs/xfs_btree.h | 2 ++
2 files changed, 6 insertions(+)
diff --git a/libxfs/xfs_btree.c b/libxfs/xfs_btree.c
index 165ce251376..e0276ad655a 100644
--- a/libxfs/xfs_btree.c
+++ b/libxfs/xfs_btree.c
@@ -28,6 +28,7 @@
#include "xfile.h"
#include "xfbtree.h"
#include "xfs_btree_mem.h"
+#include "xfs_rtgroup.h"
/*
* Btree magic numbers.
@@ -473,6 +474,9 @@ xfs_btree_del_cursor(
xfs_is_shutdown(cur->bc_mp) || error != 0);
if (unlikely(cur->bc_flags & XFS_BTREE_STAGING))
kmem_free(cur->bc_ops);
+ if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) &&
+ !(cur->bc_flags & XFS_BTREE_IN_XFILE) && cur->bc_ino.rtg)
+ xfs_rtgroup_put(cur->bc_ino.rtg);
if (!(cur->bc_flags & XFS_BTREE_LONG_PTRS) &&
!(cur->bc_flags & XFS_BTREE_IN_XFILE) && cur->bc_ag.pag)
xfs_perag_put(cur->bc_ag.pag);
diff --git a/libxfs/xfs_btree.h b/libxfs/xfs_btree.h
index bb6c2feecea..ce0bc5dfffe 100644
--- a/libxfs/xfs_btree.h
+++ b/libxfs/xfs_btree.h
@@ -12,6 +12,7 @@ struct xfs_mount;
struct xfs_trans;
struct xfs_ifork;
struct xfs_perag;
+struct xfs_rtgroup;
/*
* Generic key, ptr and record wrapper structures.
@@ -247,6 +248,7 @@ struct xfs_btree_cur_ag {
/* Btree-in-inode cursor information */
struct xfs_btree_cur_ino {
struct xfs_inode *ip;
+ struct xfs_rtgroup *rtg; /* if realtime metadata */
struct xbtree_ifakeroot *ifake; /* for staging cursor */
int allocated;
short forksize;
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 2/9] xfs: give rmap btree cursor error tracepoints their own class
2023-12-31 19:54 ` [PATCHSET v2.0 11/17] xfsprogs: rmap log intent cleanups Darrick J. Wong
2023-12-27 13:08 ` [PATCH 1/9] xfs: attach rtgroup objects to btree cursors Darrick J. Wong
@ 2023-12-27 13:08 ` Darrick J. Wong
2023-12-27 13:08 ` [PATCH 3/9] xfs: prepare rmap btree tracepoints for widening Darrick J. Wong
` (6 subsequent siblings)
8 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:08 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Create a new tracepoint class for btree-related errors, then convert all
the rmap tracepoints to use it. Also fix the one tracepoint that was
abusing the old class by making it a separate tracepoint.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_rmap.c | 33 +++++++++++----------------------
1 file changed, 11 insertions(+), 22 deletions(-)
diff --git a/libxfs/xfs_rmap.c b/libxfs/xfs_rmap.c
index 8df591840dc..5b2cac8302a 100644
--- a/libxfs/xfs_rmap.c
+++ b/libxfs/xfs_rmap.c
@@ -110,8 +110,7 @@ xfs_rmap_update(
xfs_rmap_irec_offset_pack(irec));
error = xfs_btree_update(cur, &rec);
if (error)
- trace_xfs_rmap_update_error(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, error, _RET_IP_);
+ trace_xfs_rmap_update_error(cur, error, _RET_IP_);
return error;
}
@@ -154,8 +153,7 @@ xfs_rmap_insert(
}
done:
if (error)
- trace_xfs_rmap_insert_error(rcur->bc_mp,
- rcur->bc_ag.pag->pag_agno, error, _RET_IP_);
+ trace_xfs_rmap_insert_error(rcur, error, _RET_IP_);
return error;
}
@@ -193,8 +191,7 @@ xfs_rmap_delete(
}
done:
if (error)
- trace_xfs_rmap_delete_error(rcur->bc_mp,
- rcur->bc_ag.pag->pag_agno, error, _RET_IP_);
+ trace_xfs_rmap_delete_error(rcur, error, _RET_IP_);
return error;
}
@@ -815,8 +812,7 @@ xfs_rmap_unmap(
unwritten, oinfo);
out_error:
if (error)
- trace_xfs_rmap_unmap_error(mp, cur->bc_ag.pag->pag_agno,
- error, _RET_IP_);
+ trace_xfs_rmap_unmap_error(cur, error, _RET_IP_);
return error;
}
@@ -1138,8 +1134,7 @@ xfs_rmap_map(
unwritten, oinfo);
out_error:
if (error)
- trace_xfs_rmap_map_error(mp, cur->bc_ag.pag->pag_agno,
- error, _RET_IP_);
+ trace_xfs_rmap_map_error(cur, error, _RET_IP_);
return error;
}
@@ -1334,8 +1329,7 @@ xfs_rmap_convert(
RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX)
state &= ~RMAP_RIGHT_CONTIG;
- trace_xfs_rmap_convert_state(mp, cur->bc_ag.pag->pag_agno, state,
- _RET_IP_);
+ trace_xfs_rmap_convert_state(cur, state, _RET_IP_);
/* reset the cursor back to PREV */
error = xfs_rmap_lookup_le(cur, bno, owner, offset, oldext, NULL, &i);
@@ -1688,8 +1682,7 @@ xfs_rmap_convert(
unwritten, oinfo);
done:
if (error)
- trace_xfs_rmap_convert_error(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, error, _RET_IP_);
+ trace_xfs_rmap_convert_error(cur, error, _RET_IP_);
return error;
}
@@ -1812,8 +1805,7 @@ xfs_rmap_convert_shared(
RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX)
state &= ~RMAP_RIGHT_CONTIG;
- trace_xfs_rmap_convert_state(mp, cur->bc_ag.pag->pag_agno, state,
- _RET_IP_);
+ trace_xfs_rmap_convert_state(cur, state, _RET_IP_);
/*
* Switch out based on the FILLING and CONTIG state bits.
*/
@@ -2115,8 +2107,7 @@ xfs_rmap_convert_shared(
unwritten, oinfo);
done:
if (error)
- trace_xfs_rmap_convert_error(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, error, _RET_IP_);
+ trace_xfs_rmap_convert_error(cur, error, _RET_IP_);
return error;
}
@@ -2315,8 +2306,7 @@ xfs_rmap_unmap_shared(
unwritten, oinfo);
out_error:
if (error)
- trace_xfs_rmap_unmap_error(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, error, _RET_IP_);
+ trace_xfs_rmap_unmap_error(cur, error, _RET_IP_);
return error;
}
@@ -2476,8 +2466,7 @@ xfs_rmap_map_shared(
unwritten, oinfo);
out_error:
if (error)
- trace_xfs_rmap_map_error(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, error, _RET_IP_);
+ trace_xfs_rmap_map_error(cur, error, _RET_IP_);
return error;
}
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 3/9] xfs: prepare rmap btree tracepoints for widening
2023-12-31 19:54 ` [PATCHSET v2.0 11/17] xfsprogs: rmap log intent cleanups Darrick J. Wong
2023-12-27 13:08 ` [PATCH 1/9] xfs: attach rtgroup objects to btree cursors Darrick J. Wong
2023-12-27 13:08 ` [PATCH 2/9] xfs: give rmap btree cursor error tracepoints their own class Darrick J. Wong
@ 2023-12-27 13:08 ` Darrick J. Wong
2023-12-27 13:09 ` [PATCH 4/9] xfs: clean up rmap log intent item tracepoint callsites Darrick J. Wong
` (5 subsequent siblings)
8 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:08 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Prepare the rmap btree tracepoints for use with realtime rmap btrees by
making them take the btree cursor object as a parameter. This will save
us a lot of trouble later on.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_rmap.c | 184 +++++++++++++++++++++--------------------------------
1 file changed, 73 insertions(+), 111 deletions(-)
diff --git a/libxfs/xfs_rmap.c b/libxfs/xfs_rmap.c
index 5b2cac8302a..3c4f705ce59 100644
--- a/libxfs/xfs_rmap.c
+++ b/libxfs/xfs_rmap.c
@@ -99,8 +99,7 @@ xfs_rmap_update(
union xfs_btree_rec rec;
int error;
- trace_xfs_rmap_update(cur->bc_mp, cur->bc_ag.pag->pag_agno,
- irec->rm_startblock, irec->rm_blockcount,
+ trace_xfs_rmap_update(cur, irec->rm_startblock, irec->rm_blockcount,
irec->rm_owner, irec->rm_offset, irec->rm_flags);
rec.rmap.rm_startblock = cpu_to_be32(irec->rm_startblock);
@@ -126,8 +125,7 @@ xfs_rmap_insert(
int i;
int error;
- trace_xfs_rmap_insert(rcur->bc_mp, rcur->bc_ag.pag->pag_agno, agbno,
- len, owner, offset, flags);
+ trace_xfs_rmap_insert(rcur, agbno, len, owner, offset, flags);
error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
if (error)
@@ -169,8 +167,7 @@ xfs_rmap_delete(
int i;
int error;
- trace_xfs_rmap_delete(rcur->bc_mp, rcur->bc_ag.pag->pag_agno, agbno,
- len, owner, offset, flags);
+ trace_xfs_rmap_delete(rcur, agbno, len, owner, offset, flags);
error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
if (error)
@@ -338,8 +335,7 @@ xfs_rmap_find_left_neighbor_helper(
{
struct xfs_find_left_neighbor_info *info = priv;
- trace_xfs_rmap_find_left_neighbor_candidate(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, rec->rm_startblock,
+ trace_xfs_rmap_find_left_neighbor_candidate(cur, rec->rm_startblock,
rec->rm_blockcount, rec->rm_owner, rec->rm_offset,
rec->rm_flags);
@@ -389,8 +385,8 @@ xfs_rmap_find_left_neighbor(
info.high.rm_blockcount = 0;
info.irec = irec;
- trace_xfs_rmap_find_left_neighbor_query(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, bno, 0, owner, offset, flags);
+ trace_xfs_rmap_find_left_neighbor_query(cur, bno, 0, owner, offset,
+ flags);
/*
* Historically, we always used the range query to walk every reverse
@@ -421,8 +417,7 @@ xfs_rmap_find_left_neighbor(
return error;
*stat = 1;
- trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, irec->rm_startblock,
+ trace_xfs_rmap_find_left_neighbor_result(cur, irec->rm_startblock,
irec->rm_blockcount, irec->rm_owner, irec->rm_offset,
irec->rm_flags);
return 0;
@@ -437,8 +432,7 @@ xfs_rmap_lookup_le_range_helper(
{
struct xfs_find_left_neighbor_info *info = priv;
- trace_xfs_rmap_lookup_le_range_candidate(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, rec->rm_startblock,
+ trace_xfs_rmap_lookup_le_range_candidate(cur, rec->rm_startblock,
rec->rm_blockcount, rec->rm_owner, rec->rm_offset,
rec->rm_flags);
@@ -485,8 +479,7 @@ xfs_rmap_lookup_le_range(
*stat = 0;
info.irec = irec;
- trace_xfs_rmap_lookup_le_range(cur->bc_mp, cur->bc_ag.pag->pag_agno,
- bno, 0, owner, offset, flags);
+ trace_xfs_rmap_lookup_le_range(cur, bno, 0, owner, offset, flags);
/*
* Historically, we always used the range query to walk every reverse
@@ -517,8 +510,7 @@ xfs_rmap_lookup_le_range(
return error;
*stat = 1;
- trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, irec->rm_startblock,
+ trace_xfs_rmap_lookup_le_range_result(cur, irec->rm_startblock,
irec->rm_blockcount, irec->rm_owner, irec->rm_offset,
irec->rm_flags);
return 0;
@@ -630,8 +622,7 @@ xfs_rmap_unmap(
(flags & XFS_RMAP_BMBT_BLOCK);
if (unwritten)
flags |= XFS_RMAP_UNWRITTEN;
- trace_xfs_rmap_unmap(mp, cur->bc_ag.pag->pag_agno, bno, len,
- unwritten, oinfo);
+ trace_xfs_rmap_unmap(cur, bno, len, unwritten, oinfo);
/*
* We should always have a left record because there's a static record
@@ -647,10 +638,9 @@ xfs_rmap_unmap(
goto out_error;
}
- trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, ltrec.rm_startblock,
- ltrec.rm_blockcount, ltrec.rm_owner,
- ltrec.rm_offset, ltrec.rm_flags);
+ trace_xfs_rmap_lookup_le_range_result(cur, ltrec.rm_startblock,
+ ltrec.rm_blockcount, ltrec.rm_owner, ltrec.rm_offset,
+ ltrec.rm_flags);
ltoff = ltrec.rm_offset;
/*
@@ -717,10 +707,9 @@ xfs_rmap_unmap(
if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) {
/* exact match, simply remove the record from rmap tree */
- trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
- ltrec.rm_startblock, ltrec.rm_blockcount,
- ltrec.rm_owner, ltrec.rm_offset,
- ltrec.rm_flags);
+ trace_xfs_rmap_delete(cur, ltrec.rm_startblock,
+ ltrec.rm_blockcount, ltrec.rm_owner,
+ ltrec.rm_offset, ltrec.rm_flags);
error = xfs_btree_delete(cur, &i);
if (error)
goto out_error;
@@ -796,8 +785,7 @@ xfs_rmap_unmap(
else
cur->bc_rec.r.rm_offset = offset + len;
cur->bc_rec.r.rm_flags = flags;
- trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno,
- cur->bc_rec.r.rm_startblock,
+ trace_xfs_rmap_insert(cur, cur->bc_rec.r.rm_startblock,
cur->bc_rec.r.rm_blockcount,
cur->bc_rec.r.rm_owner,
cur->bc_rec.r.rm_offset,
@@ -808,8 +796,7 @@ xfs_rmap_unmap(
}
out_done:
- trace_xfs_rmap_unmap_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
- unwritten, oinfo);
+ trace_xfs_rmap_unmap_done(cur, bno, len, unwritten, oinfo);
out_error:
if (error)
trace_xfs_rmap_unmap_error(cur, error, _RET_IP_);
@@ -973,8 +960,7 @@ xfs_rmap_map(
(flags & XFS_RMAP_BMBT_BLOCK);
if (unwritten)
flags |= XFS_RMAP_UNWRITTEN;
- trace_xfs_rmap_map(mp, cur->bc_ag.pag->pag_agno, bno, len,
- unwritten, oinfo);
+ trace_xfs_rmap_map(cur, bno, len, unwritten, oinfo);
ASSERT(!xfs_rmap_should_skip_owner_update(oinfo));
/*
@@ -987,8 +973,7 @@ xfs_rmap_map(
if (error)
goto out_error;
if (have_lt) {
- trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, ltrec.rm_startblock,
+ trace_xfs_rmap_lookup_le_range_result(cur, ltrec.rm_startblock,
ltrec.rm_blockcount, ltrec.rm_owner,
ltrec.rm_offset, ltrec.rm_flags);
@@ -1026,10 +1011,10 @@ xfs_rmap_map(
error = -EFSCORRUPTED;
goto out_error;
}
- trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, gtrec.rm_startblock,
- gtrec.rm_blockcount, gtrec.rm_owner,
- gtrec.rm_offset, gtrec.rm_flags);
+ trace_xfs_rmap_find_right_neighbor_result(cur,
+ gtrec.rm_startblock, gtrec.rm_blockcount,
+ gtrec.rm_owner, gtrec.rm_offset,
+ gtrec.rm_flags);
if (!xfs_rmap_is_mergeable(>rec, owner, flags))
have_gt = 0;
}
@@ -1066,12 +1051,9 @@ xfs_rmap_map(
* result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr|
*/
ltrec.rm_blockcount += gtrec.rm_blockcount;
- trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
- gtrec.rm_startblock,
- gtrec.rm_blockcount,
- gtrec.rm_owner,
- gtrec.rm_offset,
- gtrec.rm_flags);
+ trace_xfs_rmap_delete(cur, gtrec.rm_startblock,
+ gtrec.rm_blockcount, gtrec.rm_owner,
+ gtrec.rm_offset, gtrec.rm_flags);
error = xfs_btree_delete(cur, &i);
if (error)
goto out_error;
@@ -1118,8 +1100,7 @@ xfs_rmap_map(
cur->bc_rec.r.rm_owner = owner;
cur->bc_rec.r.rm_offset = offset;
cur->bc_rec.r.rm_flags = flags;
- trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno, len,
- owner, offset, flags);
+ trace_xfs_rmap_insert(cur, bno, len, owner, offset, flags);
error = xfs_btree_insert(cur, &i);
if (error)
goto out_error;
@@ -1130,8 +1111,7 @@ xfs_rmap_map(
}
}
- trace_xfs_rmap_map_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
- unwritten, oinfo);
+ trace_xfs_rmap_map_done(cur, bno, len, unwritten, oinfo);
out_error:
if (error)
trace_xfs_rmap_map_error(cur, error, _RET_IP_);
@@ -1208,8 +1188,7 @@ xfs_rmap_convert(
(flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))));
oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0;
new_endoff = offset + len;
- trace_xfs_rmap_convert(mp, cur->bc_ag.pag->pag_agno, bno, len,
- unwritten, oinfo);
+ trace_xfs_rmap_convert(cur, bno, len, unwritten, oinfo);
/*
* For the initial lookup, look for an exact match or the left-adjacent
@@ -1225,10 +1204,9 @@ xfs_rmap_convert(
goto done;
}
- trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, PREV.rm_startblock,
- PREV.rm_blockcount, PREV.rm_owner,
- PREV.rm_offset, PREV.rm_flags);
+ trace_xfs_rmap_lookup_le_range_result(cur, PREV.rm_startblock,
+ PREV.rm_blockcount, PREV.rm_owner, PREV.rm_offset,
+ PREV.rm_flags);
ASSERT(PREV.rm_offset <= offset);
ASSERT(PREV.rm_offset + PREV.rm_blockcount >= new_endoff);
@@ -1269,10 +1247,9 @@ xfs_rmap_convert(
error = -EFSCORRUPTED;
goto done;
}
- trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, LEFT.rm_startblock,
- LEFT.rm_blockcount, LEFT.rm_owner,
- LEFT.rm_offset, LEFT.rm_flags);
+ trace_xfs_rmap_find_left_neighbor_result(cur,
+ LEFT.rm_startblock, LEFT.rm_blockcount,
+ LEFT.rm_owner, LEFT.rm_offset, LEFT.rm_flags);
if (LEFT.rm_startblock + LEFT.rm_blockcount == bno &&
LEFT.rm_offset + LEFT.rm_blockcount == offset &&
xfs_rmap_is_mergeable(&LEFT, owner, newext))
@@ -1310,10 +1287,10 @@ xfs_rmap_convert(
error = -EFSCORRUPTED;
goto done;
}
- trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, RIGHT.rm_startblock,
- RIGHT.rm_blockcount, RIGHT.rm_owner,
- RIGHT.rm_offset, RIGHT.rm_flags);
+ trace_xfs_rmap_find_right_neighbor_result(cur,
+ RIGHT.rm_startblock, RIGHT.rm_blockcount,
+ RIGHT.rm_owner, RIGHT.rm_offset,
+ RIGHT.rm_flags);
if (bno + len == RIGHT.rm_startblock &&
offset + len == RIGHT.rm_offset &&
xfs_rmap_is_mergeable(&RIGHT, owner, newext))
@@ -1360,10 +1337,9 @@ xfs_rmap_convert(
error = -EFSCORRUPTED;
goto done;
}
- trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
- RIGHT.rm_startblock, RIGHT.rm_blockcount,
- RIGHT.rm_owner, RIGHT.rm_offset,
- RIGHT.rm_flags);
+ trace_xfs_rmap_delete(cur, RIGHT.rm_startblock,
+ RIGHT.rm_blockcount, RIGHT.rm_owner,
+ RIGHT.rm_offset, RIGHT.rm_flags);
error = xfs_btree_delete(cur, &i);
if (error)
goto done;
@@ -1380,10 +1356,9 @@ xfs_rmap_convert(
error = -EFSCORRUPTED;
goto done;
}
- trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
- PREV.rm_startblock, PREV.rm_blockcount,
- PREV.rm_owner, PREV.rm_offset,
- PREV.rm_flags);
+ trace_xfs_rmap_delete(cur, PREV.rm_startblock,
+ PREV.rm_blockcount, PREV.rm_owner,
+ PREV.rm_offset, PREV.rm_flags);
error = xfs_btree_delete(cur, &i);
if (error)
goto done;
@@ -1412,10 +1387,9 @@ xfs_rmap_convert(
* Setting all of a previous oldext extent to newext.
* The left neighbor is contiguous, the right is not.
*/
- trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
- PREV.rm_startblock, PREV.rm_blockcount,
- PREV.rm_owner, PREV.rm_offset,
- PREV.rm_flags);
+ trace_xfs_rmap_delete(cur, PREV.rm_startblock,
+ PREV.rm_blockcount, PREV.rm_owner,
+ PREV.rm_offset, PREV.rm_flags);
error = xfs_btree_delete(cur, &i);
if (error)
goto done;
@@ -1452,10 +1426,9 @@ xfs_rmap_convert(
error = -EFSCORRUPTED;
goto done;
}
- trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
- RIGHT.rm_startblock, RIGHT.rm_blockcount,
- RIGHT.rm_owner, RIGHT.rm_offset,
- RIGHT.rm_flags);
+ trace_xfs_rmap_delete(cur, RIGHT.rm_startblock,
+ RIGHT.rm_blockcount, RIGHT.rm_owner,
+ RIGHT.rm_offset, RIGHT.rm_flags);
error = xfs_btree_delete(cur, &i);
if (error)
goto done;
@@ -1533,8 +1506,7 @@ xfs_rmap_convert(
NEW.rm_blockcount = len;
NEW.rm_flags = newext;
cur->bc_rec.r = NEW;
- trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno,
- len, owner, offset, newext);
+ trace_xfs_rmap_insert(cur, bno, len, owner, offset, newext);
error = xfs_btree_insert(cur, &i);
if (error)
goto done;
@@ -1592,8 +1564,7 @@ xfs_rmap_convert(
NEW.rm_blockcount = len;
NEW.rm_flags = newext;
cur->bc_rec.r = NEW;
- trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno,
- len, owner, offset, newext);
+ trace_xfs_rmap_insert(cur, bno, len, owner, offset, newext);
error = xfs_btree_insert(cur, &i);
if (error)
goto done;
@@ -1624,9 +1595,8 @@ xfs_rmap_convert(
NEW = PREV;
NEW.rm_blockcount = offset - PREV.rm_offset;
cur->bc_rec.r = NEW;
- trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno,
- NEW.rm_startblock, NEW.rm_blockcount,
- NEW.rm_owner, NEW.rm_offset,
+ trace_xfs_rmap_insert(cur, NEW.rm_startblock,
+ NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset,
NEW.rm_flags);
error = xfs_btree_insert(cur, &i);
if (error)
@@ -1653,8 +1623,7 @@ xfs_rmap_convert(
/* new middle extent - newext */
cur->bc_rec.r.rm_flags &= ~XFS_RMAP_UNWRITTEN;
cur->bc_rec.r.rm_flags |= newext;
- trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno, len,
- owner, offset, newext);
+ trace_xfs_rmap_insert(cur, bno, len, owner, offset, newext);
error = xfs_btree_insert(cur, &i);
if (error)
goto done;
@@ -1678,8 +1647,7 @@ xfs_rmap_convert(
ASSERT(0);
}
- trace_xfs_rmap_convert_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
- unwritten, oinfo);
+ trace_xfs_rmap_convert_done(cur, bno, len, unwritten, oinfo);
done:
if (error)
trace_xfs_rmap_convert_error(cur, error, _RET_IP_);
@@ -1718,8 +1686,7 @@ xfs_rmap_convert_shared(
(flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))));
oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0;
new_endoff = offset + len;
- trace_xfs_rmap_convert(mp, cur->bc_ag.pag->pag_agno, bno, len,
- unwritten, oinfo);
+ trace_xfs_rmap_convert(cur, bno, len, unwritten, oinfo);
/*
* For the initial lookup, look for and exact match or the left-adjacent
@@ -1788,10 +1755,10 @@ xfs_rmap_convert_shared(
error = -EFSCORRUPTED;
goto done;
}
- trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, RIGHT.rm_startblock,
- RIGHT.rm_blockcount, RIGHT.rm_owner,
- RIGHT.rm_offset, RIGHT.rm_flags);
+ trace_xfs_rmap_find_right_neighbor_result(cur,
+ RIGHT.rm_startblock, RIGHT.rm_blockcount,
+ RIGHT.rm_owner, RIGHT.rm_offset,
+ RIGHT.rm_flags);
if (xfs_rmap_is_mergeable(&RIGHT, owner, newext))
state |= RMAP_RIGHT_CONTIG;
}
@@ -2103,8 +2070,7 @@ xfs_rmap_convert_shared(
ASSERT(0);
}
- trace_xfs_rmap_convert_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
- unwritten, oinfo);
+ trace_xfs_rmap_convert_done(cur, bno, len, unwritten, oinfo);
done:
if (error)
trace_xfs_rmap_convert_error(cur, error, _RET_IP_);
@@ -2145,8 +2111,7 @@ xfs_rmap_unmap_shared(
xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
if (unwritten)
flags |= XFS_RMAP_UNWRITTEN;
- trace_xfs_rmap_unmap(mp, cur->bc_ag.pag->pag_agno, bno, len,
- unwritten, oinfo);
+ trace_xfs_rmap_unmap(cur, bno, len, unwritten, oinfo);
/*
* We should always have a left record because there's a static record
@@ -2302,8 +2267,7 @@ xfs_rmap_unmap_shared(
goto out_error;
}
- trace_xfs_rmap_unmap_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
- unwritten, oinfo);
+ trace_xfs_rmap_unmap_done(cur, bno, len, unwritten, oinfo);
out_error:
if (error)
trace_xfs_rmap_unmap_error(cur, error, _RET_IP_);
@@ -2341,8 +2305,7 @@ xfs_rmap_map_shared(
xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
if (unwritten)
flags |= XFS_RMAP_UNWRITTEN;
- trace_xfs_rmap_map(mp, cur->bc_ag.pag->pag_agno, bno, len,
- unwritten, oinfo);
+ trace_xfs_rmap_map(cur, bno, len, unwritten, oinfo);
/* Is there a left record that abuts our range? */
error = xfs_rmap_find_left_neighbor(cur, bno, owner, offset, flags,
@@ -2367,10 +2330,10 @@ xfs_rmap_map_shared(
error = -EFSCORRUPTED;
goto out_error;
}
- trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, gtrec.rm_startblock,
- gtrec.rm_blockcount, gtrec.rm_owner,
- gtrec.rm_offset, gtrec.rm_flags);
+ trace_xfs_rmap_find_right_neighbor_result(cur,
+ gtrec.rm_startblock, gtrec.rm_blockcount,
+ gtrec.rm_owner, gtrec.rm_offset,
+ gtrec.rm_flags);
if (!xfs_rmap_is_mergeable(>rec, owner, flags))
have_gt = 0;
@@ -2462,8 +2425,7 @@ xfs_rmap_map_shared(
goto out_error;
}
- trace_xfs_rmap_map_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
- unwritten, oinfo);
+ trace_xfs_rmap_map_done(cur, bno, len, unwritten, oinfo);
out_error:
if (error)
trace_xfs_rmap_map_error(cur, error, _RET_IP_);
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 4/9] xfs: clean up rmap log intent item tracepoint callsites
2023-12-31 19:54 ` [PATCHSET v2.0 11/17] xfsprogs: rmap log intent cleanups Darrick J. Wong
` (2 preceding siblings ...)
2023-12-27 13:08 ` [PATCH 3/9] xfs: prepare rmap btree tracepoints for widening Darrick J. Wong
@ 2023-12-27 13:09 ` Darrick J. Wong
2023-12-27 13:09 ` [PATCH 5/9] xfs: add a ri_entry helper Darrick J. Wong
` (4 subsequent siblings)
8 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:09 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Pass the incore rmap structure to the tracepoints instead of open-coding
the argument passing.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_rmap.c | 22 +++++-----------------
libxfs/xfs_rmap.h | 10 ++++++++++
2 files changed, 15 insertions(+), 17 deletions(-)
diff --git a/libxfs/xfs_rmap.c b/libxfs/xfs_rmap.c
index 3c4f705ce59..3c00b05d8d0 100644
--- a/libxfs/xfs_rmap.c
+++ b/libxfs/xfs_rmap.c
@@ -2575,20 +2575,15 @@ xfs_rmap_finish_one(
struct xfs_rmap_intent *ri,
struct xfs_btree_cur **pcur)
{
+ struct xfs_owner_info oinfo;
struct xfs_mount *mp = tp->t_mountp;
struct xfs_btree_cur *rcur;
struct xfs_buf *agbp = NULL;
- int error = 0;
- struct xfs_owner_info oinfo;
xfs_agblock_t bno;
bool unwritten;
+ int error = 0;
- bno = XFS_FSB_TO_AGBNO(mp, ri->ri_bmap.br_startblock);
-
- trace_xfs_rmap_deferred(mp, ri->ri_pag->pag_agno, ri->ri_type, bno,
- ri->ri_owner, ri->ri_whichfork,
- ri->ri_bmap.br_startoff, ri->ri_bmap.br_blockcount,
- ri->ri_bmap.br_state);
+ trace_xfs_rmap_deferred(mp, ri);
if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_RMAP_FINISH_ONE))
return -EIO;
@@ -2663,15 +2658,6 @@ __xfs_rmap_add(
{
struct xfs_rmap_intent *ri;
- trace_xfs_rmap_defer(tp->t_mountp,
- XFS_FSB_TO_AGNO(tp->t_mountp, bmap->br_startblock),
- type,
- XFS_FSB_TO_AGBNO(tp->t_mountp, bmap->br_startblock),
- owner, whichfork,
- bmap->br_startoff,
- bmap->br_blockcount,
- bmap->br_state);
-
ri = kmem_cache_alloc(xfs_rmap_intent_cache, GFP_NOFS | __GFP_NOFAIL);
INIT_LIST_HEAD(&ri->ri_list);
ri->ri_type = type;
@@ -2679,6 +2665,8 @@ __xfs_rmap_add(
ri->ri_whichfork = whichfork;
ri->ri_bmap = *bmap;
+ trace_xfs_rmap_defer(tp->t_mountp, ri);
+
xfs_rmap_update_get_group(tp->t_mountp, ri);
xfs_defer_add(tp, &ri->ri_list, &xfs_rmap_update_defer_type);
}
diff --git a/libxfs/xfs_rmap.h b/libxfs/xfs_rmap.h
index 3a153b4801b..f16b07d851d 100644
--- a/libxfs/xfs_rmap.h
+++ b/libxfs/xfs_rmap.h
@@ -157,6 +157,16 @@ enum xfs_rmap_intent_type {
XFS_RMAP_FREE,
};
+#define XFS_RMAP_INTENT_STRINGS \
+ { XFS_RMAP_MAP, "map" }, \
+ { XFS_RMAP_MAP_SHARED, "map_shared" }, \
+ { XFS_RMAP_UNMAP, "unmap" }, \
+ { XFS_RMAP_UNMAP_SHARED, "unmap_shared" }, \
+ { XFS_RMAP_CONVERT, "cvt" }, \
+ { XFS_RMAP_CONVERT_SHARED, "cvt_shared" }, \
+ { XFS_RMAP_ALLOC, "alloc" }, \
+ { XFS_RMAP_FREE, "free" }
+
struct xfs_rmap_intent {
struct list_head ri_list;
enum xfs_rmap_intent_type ri_type;
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 5/9] xfs: add a ri_entry helper
2023-12-31 19:54 ` [PATCHSET v2.0 11/17] xfsprogs: rmap log intent cleanups Darrick J. Wong
` (3 preceding siblings ...)
2023-12-27 13:09 ` [PATCH 4/9] xfs: clean up rmap log intent item tracepoint callsites Darrick J. Wong
@ 2023-12-27 13:09 ` Darrick J. Wong
2023-12-27 13:09 ` [PATCH 6/9] xfs: reuse xfs_rmap_update_cancel_item Darrick J. Wong
` (3 subsequent siblings)
8 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:09 UTC (permalink / raw)
To: cem, djwong; +Cc: Christoph Hellwig, linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Add a helper to translate from the item list head to the
rmap_intent_item structure and use it so shorten assignments and avoid
the need for extra local variables.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/defer_item.c | 20 +++++++++-----------
1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/libxfs/defer_item.c b/libxfs/defer_item.c
index 82b70575bc5..8fc27e9efd4 100644
--- a/libxfs/defer_item.c
+++ b/libxfs/defer_item.c
@@ -275,6 +275,11 @@ const struct xfs_defer_op_type xfs_agfl_free_defer_type = {
/* Reverse Mapping */
+static inline struct xfs_rmap_intent *ri_entry(const struct list_head *e)
+{
+ return list_entry(e, struct xfs_rmap_intent, ri_list);
+}
+
/* Sort rmap intents by AG. */
static int
xfs_rmap_update_diff_items(
@@ -282,11 +287,8 @@ xfs_rmap_update_diff_items(
const struct list_head *a,
const struct list_head *b)
{
- const struct xfs_rmap_intent *ra;
- const struct xfs_rmap_intent *rb;
-
- ra = container_of(a, struct xfs_rmap_intent, ri_list);
- rb = container_of(b, struct xfs_rmap_intent, ri_list);
+ struct xfs_rmap_intent *ra = ri_entry(a);
+ struct xfs_rmap_intent *rb = ri_entry(b);
return ra->ri_pag->pag_agno - rb->ri_pag->pag_agno;
}
@@ -341,11 +343,9 @@ xfs_rmap_update_finish_item(
struct list_head *item,
struct xfs_btree_cur **state)
{
- struct xfs_rmap_intent *ri;
+ struct xfs_rmap_intent *ri = ri_entry(item);
int error;
- ri = container_of(item, struct xfs_rmap_intent, ri_list);
-
error = xfs_rmap_finish_one(tp, ri, state);
xfs_rmap_update_put_group(ri);
@@ -365,9 +365,7 @@ STATIC void
xfs_rmap_update_cancel_item(
struct list_head *item)
{
- struct xfs_rmap_intent *ri;
-
- ri = container_of(item, struct xfs_rmap_intent, ri_list);
+ struct xfs_rmap_intent *ri = ri_entry(item);
xfs_rmap_update_put_group(ri);
kmem_cache_free(xfs_rmap_intent_cache, ri);
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 6/9] xfs: reuse xfs_rmap_update_cancel_item
2023-12-31 19:54 ` [PATCHSET v2.0 11/17] xfsprogs: rmap log intent cleanups Darrick J. Wong
` (4 preceding siblings ...)
2023-12-27 13:09 ` [PATCH 5/9] xfs: add a ri_entry helper Darrick J. Wong
@ 2023-12-27 13:09 ` Darrick J. Wong
2023-12-27 13:09 ` [PATCH 7/9] xfs: don't bother calling xfs_rmap_finish_one_cleanup in xfs_rmap_finish_one Darrick J. Wong
` (2 subsequent siblings)
8 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:09 UTC (permalink / raw)
To: cem, djwong; +Cc: Christoph Hellwig, linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Reuse xfs_rmap_update_cancel_item to put the AG/RTG and free the item in
a few places that currently open code the logic.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/defer_item.c | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/libxfs/defer_item.c b/libxfs/defer_item.c
index 8fc27e9efd4..e7277b54532 100644
--- a/libxfs/defer_item.c
+++ b/libxfs/defer_item.c
@@ -335,6 +335,17 @@ xfs_rmap_update_put_group(
xfs_perag_intent_put(ri->ri_pag);
}
+/* Cancel a deferred rmap update. */
+STATIC void
+xfs_rmap_update_cancel_item(
+ struct list_head *item)
+{
+ struct xfs_rmap_intent *ri = ri_entry(item);
+
+ xfs_rmap_update_put_group(ri);
+ kmem_cache_free(xfs_rmap_intent_cache, ri);
+}
+
/* Process a deferred rmap update. */
STATIC int
xfs_rmap_update_finish_item(
@@ -348,8 +359,7 @@ xfs_rmap_update_finish_item(
error = xfs_rmap_finish_one(tp, ri, state);
- xfs_rmap_update_put_group(ri);
- kmem_cache_free(xfs_rmap_intent_cache, ri);
+ xfs_rmap_update_cancel_item(item);
return error;
}
@@ -360,17 +370,6 @@ xfs_rmap_update_abort_intent(
{
}
-/* Cancel a deferred rmap update. */
-STATIC void
-xfs_rmap_update_cancel_item(
- struct list_head *item)
-{
- struct xfs_rmap_intent *ri = ri_entry(item);
-
- xfs_rmap_update_put_group(ri);
- kmem_cache_free(xfs_rmap_intent_cache, ri);
-}
-
const struct xfs_defer_op_type xfs_rmap_update_defer_type = {
.name = "rmap",
.create_intent = xfs_rmap_update_create_intent,
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 7/9] xfs: don't bother calling xfs_rmap_finish_one_cleanup in xfs_rmap_finish_one
2023-12-31 19:54 ` [PATCHSET v2.0 11/17] xfsprogs: rmap log intent cleanups Darrick J. Wong
` (5 preceding siblings ...)
2023-12-27 13:09 ` [PATCH 6/9] xfs: reuse xfs_rmap_update_cancel_item Darrick J. Wong
@ 2023-12-27 13:09 ` Darrick J. Wong
2023-12-27 13:10 ` [PATCH 8/9] xfs: simplify usage of the rcur local variable " Darrick J. Wong
2023-12-27 13:10 ` [PATCH 9/9] xfs: move xfs_rmap_update_defer_add to xfs_rmap_item.c Darrick J. Wong
8 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:09 UTC (permalink / raw)
To: cem, djwong; +Cc: Christoph Hellwig, linux-xfs
From: Christoph Hellwig <hch@lst.de>
In xfs_rmap_finish_one we known the cursor is non-zero when calling
xfs_rmap_finish_one_cleanup and we pass a 0 error variable. This means
xfs_rmap_finish_one_cleanup is just doing a xfs_btree_del_cursor.
Open code that and move xfs_rmap_finish_one_cleanup to
fs/xfs/xfs_rmap_item.c.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
[djwong: minor porting changes]
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_rmap.c | 19 +------------------
libxfs/xfs_rmap.h | 2 --
2 files changed, 1 insertion(+), 20 deletions(-)
diff --git a/libxfs/xfs_rmap.c b/libxfs/xfs_rmap.c
index 3c00b05d8d0..a1a9f4927bd 100644
--- a/libxfs/xfs_rmap.c
+++ b/libxfs/xfs_rmap.c
@@ -2513,23 +2513,6 @@ xfs_rmap_query_all(
return xfs_btree_query_all(cur, xfs_rmap_query_range_helper, &query);
}
-/* Clean up after calling xfs_rmap_finish_one. */
-void
-xfs_rmap_finish_one_cleanup(
- struct xfs_trans *tp,
- struct xfs_btree_cur *rcur,
- int error)
-{
- struct xfs_buf *agbp;
-
- if (rcur == NULL)
- return;
- agbp = rcur->bc_ag.agbp;
- xfs_btree_del_cursor(rcur, error);
- if (error)
- xfs_trans_brelse(tp, agbp);
-}
-
/* Commit an rmap operation into the ondisk tree. */
int
__xfs_rmap_finish_intent(
@@ -2594,7 +2577,7 @@ xfs_rmap_finish_one(
*/
rcur = *pcur;
if (rcur != NULL && rcur->bc_ag.pag != ri->ri_pag) {
- xfs_rmap_finish_one_cleanup(tp, rcur, 0);
+ xfs_btree_del_cursor(rcur, 0);
rcur = NULL;
*pcur = NULL;
}
diff --git a/libxfs/xfs_rmap.h b/libxfs/xfs_rmap.h
index f16b07d851d..2513ee36aa2 100644
--- a/libxfs/xfs_rmap.h
+++ b/libxfs/xfs_rmap.h
@@ -192,8 +192,6 @@ void xfs_rmap_alloc_extent(struct xfs_trans *tp, xfs_agnumber_t agno,
void xfs_rmap_free_extent(struct xfs_trans *tp, xfs_agnumber_t agno,
xfs_agblock_t bno, xfs_extlen_t len, uint64_t owner);
-void xfs_rmap_finish_one_cleanup(struct xfs_trans *tp,
- struct xfs_btree_cur *rcur, int error);
int xfs_rmap_finish_one(struct xfs_trans *tp, struct xfs_rmap_intent *ri,
struct xfs_btree_cur **pcur);
int __xfs_rmap_finish_intent(struct xfs_btree_cur *rcur,
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 8/9] xfs: simplify usage of the rcur local variable in xfs_rmap_finish_one
2023-12-31 19:54 ` [PATCHSET v2.0 11/17] xfsprogs: rmap log intent cleanups Darrick J. Wong
` (6 preceding siblings ...)
2023-12-27 13:09 ` [PATCH 7/9] xfs: don't bother calling xfs_rmap_finish_one_cleanup in xfs_rmap_finish_one Darrick J. Wong
@ 2023-12-27 13:10 ` Darrick J. Wong
2023-12-27 13:10 ` [PATCH 9/9] xfs: move xfs_rmap_update_defer_add to xfs_rmap_item.c Darrick J. Wong
8 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:10 UTC (permalink / raw)
To: cem, djwong; +Cc: Christoph Hellwig, linux-xfs
From: Christoph Hellwig <hch@lst.de>
Only update rcur when we know the final *pcur value.
Signed-off-by: Christoph Hellwig <hch@lst.de>
[djwong: don't leave the caller with a dangling ref]
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/defer_item.c | 18 ++++++++++++++++++
libxfs/xfs_rmap.c | 6 ++----
2 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/libxfs/defer_item.c b/libxfs/defer_item.c
index e7277b54532..d3df56f0a2b 100644
--- a/libxfs/defer_item.c
+++ b/libxfs/defer_item.c
@@ -28,6 +28,7 @@
#include "xfs_ag.h"
#include "xfs_swapext.h"
#include "defer_item.h"
+#include "xfs_btree.h"
/* Dummy defer item ops, since we don't do logging. */
@@ -370,6 +371,23 @@ xfs_rmap_update_abort_intent(
{
}
+/* Clean up after calling xfs_rmap_finish_one. */
+STATIC void
+xfs_rmap_finish_one_cleanup(
+ struct xfs_trans *tp,
+ struct xfs_btree_cur *rcur,
+ int error)
+{
+ struct xfs_buf *agbp = NULL;
+
+ if (rcur == NULL)
+ return;
+ agbp = rcur->bc_ag.agbp;
+ xfs_btree_del_cursor(rcur, error);
+ if (error && agbp)
+ xfs_trans_brelse(tp, agbp);
+}
+
const struct xfs_defer_op_type xfs_rmap_update_defer_type = {
.name = "rmap",
.create_intent = xfs_rmap_update_create_intent,
diff --git a/libxfs/xfs_rmap.c b/libxfs/xfs_rmap.c
index a1a9f4927bd..183e840b7f1 100644
--- a/libxfs/xfs_rmap.c
+++ b/libxfs/xfs_rmap.c
@@ -2560,7 +2560,7 @@ xfs_rmap_finish_one(
{
struct xfs_owner_info oinfo;
struct xfs_mount *mp = tp->t_mountp;
- struct xfs_btree_cur *rcur;
+ struct xfs_btree_cur *rcur = *pcur;
struct xfs_buf *agbp = NULL;
xfs_agblock_t bno;
bool unwritten;
@@ -2575,7 +2575,6 @@ xfs_rmap_finish_one(
* If we haven't gotten a cursor or the cursor AG doesn't match
* the startblock, get one now.
*/
- rcur = *pcur;
if (rcur != NULL && rcur->bc_ag.pag != ri->ri_pag) {
xfs_btree_del_cursor(rcur, 0);
rcur = NULL;
@@ -2597,9 +2596,8 @@ xfs_rmap_finish_one(
return -EFSCORRUPTED;
}
- rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, ri->ri_pag);
+ *pcur = rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, ri->ri_pag);
}
- *pcur = rcur;
xfs_rmap_ino_owner(&oinfo, ri->ri_owner, ri->ri_whichfork,
ri->ri_bmap.br_startoff);
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 9/9] xfs: move xfs_rmap_update_defer_add to xfs_rmap_item.c
2023-12-31 19:54 ` [PATCHSET v2.0 11/17] xfsprogs: rmap log intent cleanups Darrick J. Wong
` (7 preceding siblings ...)
2023-12-27 13:10 ` [PATCH 8/9] xfs: simplify usage of the rcur local variable " Darrick J. Wong
@ 2023-12-27 13:10 ` Darrick J. Wong
8 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:10 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Move the code that adds the incore xfs_rmap_update_item deferred work
data to a transaction live with the RUI log item code. This means that
the rmap code no longer has to know about the inner workings of the RUI
log items.
As a consequence, we can get rid of the _{get,put}_group helpers.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/defer_item.c | 21 +++++++++------------
libxfs/defer_item.h | 4 ++++
libxfs/xfs_rmap.c | 6 ++----
libxfs/xfs_rmap.h | 3 ---
4 files changed, 15 insertions(+), 19 deletions(-)
diff --git a/libxfs/defer_item.c b/libxfs/defer_item.c
index d3df56f0a2b..5399a20f186 100644
--- a/libxfs/defer_item.c
+++ b/libxfs/defer_item.c
@@ -319,21 +319,18 @@ xfs_rmap_update_create_done(
return NULL;
}
-/* Take an active ref to the AG containing the space we're rmapping. */
+/* Add this deferred RUI to the transaction. */
void
-xfs_rmap_update_get_group(
- struct xfs_mount *mp,
+xfs_rmap_defer_add(
+ struct xfs_trans *tp,
struct xfs_rmap_intent *ri)
{
+ struct xfs_mount *mp = tp->t_mountp;
+
+ trace_xfs_rmap_defer(mp, ri);
+
ri->ri_pag = xfs_perag_intent_get(mp, ri->ri_bmap.br_startblock);
-}
-
-/* Release an active AG ref after finishing rmapping work. */
-static inline void
-xfs_rmap_update_put_group(
- struct xfs_rmap_intent *ri)
-{
- xfs_perag_intent_put(ri->ri_pag);
+ xfs_defer_add(tp, &ri->ri_list, &xfs_rmap_update_defer_type);
}
/* Cancel a deferred rmap update. */
@@ -343,7 +340,7 @@ xfs_rmap_update_cancel_item(
{
struct xfs_rmap_intent *ri = ri_entry(item);
- xfs_rmap_update_put_group(ri);
+ xfs_perag_intent_put(ri->ri_pag);
kmem_cache_free(xfs_rmap_intent_cache, ri);
}
diff --git a/libxfs/defer_item.h b/libxfs/defer_item.h
index 79e957eb8ff..3ef31ad0aec 100644
--- a/libxfs/defer_item.h
+++ b/libxfs/defer_item.h
@@ -20,4 +20,8 @@ void xfs_extent_free_defer_add(struct xfs_trans *tp,
struct xfs_extent_free_item *xefi,
struct xfs_defer_pending **dfpp);
+struct xfs_rmap_intent;
+
+void xfs_rmap_defer_add(struct xfs_trans *tp, struct xfs_rmap_intent *ri);
+
#endif /* __LIBXFS_DEFER_ITEM_H_ */
diff --git a/libxfs/xfs_rmap.c b/libxfs/xfs_rmap.c
index 183e840b7f1..24daf0ffb66 100644
--- a/libxfs/xfs_rmap.c
+++ b/libxfs/xfs_rmap.c
@@ -23,6 +23,7 @@
#include "xfs_inode.h"
#include "xfs_ag.h"
#include "xfs_health.h"
+#include "defer_item.h"
struct kmem_cache *xfs_rmap_intent_cache;
@@ -2646,10 +2647,7 @@ __xfs_rmap_add(
ri->ri_whichfork = whichfork;
ri->ri_bmap = *bmap;
- trace_xfs_rmap_defer(tp->t_mountp, ri);
-
- xfs_rmap_update_get_group(tp->t_mountp, ri);
- xfs_defer_add(tp, &ri->ri_list, &xfs_rmap_update_defer_type);
+ xfs_rmap_defer_add(tp, ri);
}
/* Map an extent into a file. */
diff --git a/libxfs/xfs_rmap.h b/libxfs/xfs_rmap.h
index 2513ee36aa2..e6240efd6fe 100644
--- a/libxfs/xfs_rmap.h
+++ b/libxfs/xfs_rmap.h
@@ -176,9 +176,6 @@ struct xfs_rmap_intent {
struct xfs_perag *ri_pag;
};
-void xfs_rmap_update_get_group(struct xfs_mount *mp,
- struct xfs_rmap_intent *ri);
-
/* functions for updating the rmapbt based on bmbt map/unmap operations */
void xfs_rmap_map_extent(struct xfs_trans *tp, struct xfs_inode *ip,
int whichfork, struct xfs_bmbt_irec *imap);
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 01/47] xfs: simplify the xfs_rmap_{alloc,free}_extent calling conventions
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
@ 2023-12-27 13:10 ` Darrick J. Wong
2023-12-27 13:11 ` [PATCH 02/47] xfs: introduce realtime rmap btree definitions Darrick J. Wong
` (45 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:10 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Simplify the calling conventions by allowing callers to pass a fsbno
(xfs_fsblock_t) directly into these functions, since we're just going to
set it in a struct anyway.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_refcount.c | 6 ++----
libxfs/xfs_rmap.c | 12 +++++-------
libxfs/xfs_rmap.h | 8 ++++----
repair/rmap.c | 8 ++++----
4 files changed, 15 insertions(+), 19 deletions(-)
diff --git a/libxfs/xfs_refcount.c b/libxfs/xfs_refcount.c
index 6c6634675c2..9f933d953b9 100644
--- a/libxfs/xfs_refcount.c
+++ b/libxfs/xfs_refcount.c
@@ -1886,8 +1886,7 @@ xfs_refcount_alloc_cow_extent(
__xfs_refcount_add(tp, XFS_REFCOUNT_ALLOC_COW, fsb, len);
/* Add rmap entry */
- xfs_rmap_alloc_extent(tp, XFS_FSB_TO_AGNO(mp, fsb),
- XFS_FSB_TO_AGBNO(mp, fsb), len, XFS_RMAP_OWN_COW);
+ xfs_rmap_alloc_extent(tp, fsb, len, XFS_RMAP_OWN_COW);
}
/* Forget a CoW staging event in the refcount btree. */
@@ -1903,8 +1902,7 @@ xfs_refcount_free_cow_extent(
return;
/* Remove rmap entry */
- xfs_rmap_free_extent(tp, XFS_FSB_TO_AGNO(mp, fsb),
- XFS_FSB_TO_AGBNO(mp, fsb), len, XFS_RMAP_OWN_COW);
+ xfs_rmap_free_extent(tp, fsb, len, XFS_RMAP_OWN_COW);
__xfs_refcount_add(tp, XFS_REFCOUNT_FREE_COW, fsb, len);
}
diff --git a/libxfs/xfs_rmap.c b/libxfs/xfs_rmap.c
index 24daf0ffb66..3e95599ab8a 100644
--- a/libxfs/xfs_rmap.c
+++ b/libxfs/xfs_rmap.c
@@ -526,7 +526,7 @@ xfs_rmap_free_check_owner(
struct xfs_btree_cur *cur,
uint64_t ltoff,
struct xfs_rmap_irec *rec,
- xfs_filblks_t len,
+ xfs_extlen_t len,
uint64_t owner,
uint64_t offset,
unsigned int flags)
@@ -2717,8 +2717,7 @@ xfs_rmap_convert_extent(
void
xfs_rmap_alloc_extent(
struct xfs_trans *tp,
- xfs_agnumber_t agno,
- xfs_agblock_t bno,
+ xfs_fsblock_t fsbno,
xfs_extlen_t len,
uint64_t owner)
{
@@ -2727,7 +2726,7 @@ xfs_rmap_alloc_extent(
if (!xfs_rmap_update_is_needed(tp->t_mountp, XFS_DATA_FORK))
return;
- bmap.br_startblock = XFS_AGB_TO_FSB(tp->t_mountp, agno, bno);
+ bmap.br_startblock = fsbno;
bmap.br_blockcount = len;
bmap.br_startoff = 0;
bmap.br_state = XFS_EXT_NORM;
@@ -2739,8 +2738,7 @@ xfs_rmap_alloc_extent(
void
xfs_rmap_free_extent(
struct xfs_trans *tp,
- xfs_agnumber_t agno,
- xfs_agblock_t bno,
+ xfs_fsblock_t fsbno,
xfs_extlen_t len,
uint64_t owner)
{
@@ -2749,7 +2747,7 @@ xfs_rmap_free_extent(
if (!xfs_rmap_update_is_needed(tp->t_mountp, XFS_DATA_FORK))
return;
- bmap.br_startblock = XFS_AGB_TO_FSB(tp->t_mountp, agno, bno);
+ bmap.br_startblock = fsbno;
bmap.br_blockcount = len;
bmap.br_startoff = 0;
bmap.br_state = XFS_EXT_NORM;
diff --git a/libxfs/xfs_rmap.h b/libxfs/xfs_rmap.h
index e6240efd6fe..0ccfd7d88e5 100644
--- a/libxfs/xfs_rmap.h
+++ b/libxfs/xfs_rmap.h
@@ -184,10 +184,10 @@ void xfs_rmap_unmap_extent(struct xfs_trans *tp, struct xfs_inode *ip,
void xfs_rmap_convert_extent(struct xfs_mount *mp, struct xfs_trans *tp,
struct xfs_inode *ip, int whichfork,
struct xfs_bmbt_irec *imap);
-void xfs_rmap_alloc_extent(struct xfs_trans *tp, xfs_agnumber_t agno,
- xfs_agblock_t bno, xfs_extlen_t len, uint64_t owner);
-void xfs_rmap_free_extent(struct xfs_trans *tp, xfs_agnumber_t agno,
- xfs_agblock_t bno, xfs_extlen_t len, uint64_t owner);
+void xfs_rmap_alloc_extent(struct xfs_trans *tp, xfs_fsblock_t fsbno,
+ xfs_extlen_t len, uint64_t owner);
+void xfs_rmap_free_extent(struct xfs_trans *tp, xfs_fsblock_t fsbno,
+ xfs_extlen_t len, uint64_t owner);
int xfs_rmap_finish_one(struct xfs_trans *tp, struct xfs_rmap_intent *ri,
struct xfs_btree_cur **pcur);
diff --git a/repair/rmap.c b/repair/rmap.c
index 37fcf923644..265199d2117 100644
--- a/repair/rmap.c
+++ b/repair/rmap.c
@@ -1278,7 +1278,6 @@ rmap_diffkeys(
{
__u64 oa;
__u64 ob;
- int64_t d;
struct xfs_rmap_irec tmp;
tmp = *kp1;
@@ -1288,9 +1287,10 @@ rmap_diffkeys(
tmp.rm_flags &= ~XFS_RMAP_REC_FLAGS;
ob = libxfs_rmap_irec_offset_pack(&tmp);
- d = (int64_t)kp1->rm_startblock - kp2->rm_startblock;
- if (d)
- return d;
+ if (kp1->rm_startblock > kp2->rm_startblock)
+ return 1;
+ else if (kp2->rm_startblock > kp1->rm_startblock)
+ return -1;
if (kp1->rm_owner > kp2->rm_owner)
return 1;
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 02/47] xfs: introduce realtime rmap btree definitions
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
2023-12-27 13:10 ` [PATCH 01/47] xfs: simplify the xfs_rmap_{alloc,free}_extent calling conventions Darrick J. Wong
@ 2023-12-27 13:11 ` Darrick J. Wong
2023-12-27 13:11 ` [PATCH 03/47] xfs: define the on-disk realtime rmap btree format Darrick J. Wong
` (44 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:11 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Add new realtime rmap btree definitions. The realtime rmap btree will
be rooted from a hidden inode, but has its own shape and therefore
needs to have most of its own separate types.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_btree.h | 1 +
libxfs/xfs_format.h | 7 +++++++
libxfs/xfs_types.h | 5 +++--
3 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/libxfs/xfs_btree.h b/libxfs/xfs_btree.h
index ce0bc5dfffe..e6571c9157d 100644
--- a/libxfs/xfs_btree.h
+++ b/libxfs/xfs_btree.h
@@ -64,6 +64,7 @@ union xfs_btree_rec {
#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)
+#define XFS_BTNUM_RTRMAP ((xfs_btnum_t)XFS_BTNUM_RTRMAPi)
struct xfs_btree_ops;
uint32_t xfs_btree_magic(struct xfs_mount *mp, const struct xfs_btree_ops *ops);
diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
index 87476c6bb6c..b47d4f16143 100644
--- a/libxfs/xfs_format.h
+++ b/libxfs/xfs_format.h
@@ -1746,6 +1746,13 @@ typedef __be32 xfs_rmap_ptr_t;
XFS_FIBT_BLOCK(mp) + 1 : \
XFS_IBT_BLOCK(mp) + 1)
+/*
+ * Realtime Reverse mapping btree format definitions
+ *
+ * This is a btree for reverse mapping records for realtime volumes
+ */
+#define XFS_RTRMAP_CRC_MAGIC 0x4d415052 /* 'MAPR' */
+
/*
* Reference Count Btree format definitions
*
diff --git a/libxfs/xfs_types.h b/libxfs/xfs_types.h
index ad2ce83874f..b3edc57dc65 100644
--- a/libxfs/xfs_types.h
+++ b/libxfs/xfs_types.h
@@ -126,7 +126,7 @@ 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_RCBAGi,
- XFS_BTNUM_MAX
+ XFS_BTNUM_RTRMAPi, XFS_BTNUM_MAX
} xfs_btnum_t;
#define XFS_BTNUM_STRINGS \
@@ -137,7 +137,8 @@ typedef enum {
{ XFS_BTNUM_INOi, "inobt" }, \
{ XFS_BTNUM_FINOi, "finobt" }, \
{ XFS_BTNUM_REFCi, "refcbt" }, \
- { XFS_BTNUM_RCBAGi, "rcbagbt" }
+ { XFS_BTNUM_RCBAGi, "rcbagbt" }, \
+ { XFS_BTNUM_RTRMAPi, "rtrmapbt" }
struct xfs_name {
const unsigned char *name;
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 03/47] xfs: define the on-disk realtime rmap btree format
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
2023-12-27 13:10 ` [PATCH 01/47] xfs: simplify the xfs_rmap_{alloc,free}_extent calling conventions Darrick J. Wong
2023-12-27 13:11 ` [PATCH 02/47] xfs: introduce realtime rmap btree definitions Darrick J. Wong
@ 2023-12-27 13:11 ` Darrick J. Wong
2023-12-27 13:11 ` [PATCH 04/47] xfs: realtime rmap btree transaction reservations Darrick J. Wong
` (43 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:11 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Start filling out the rtrmap btree implementation. Start with the
on-disk btree format; add everything needed to read, write and
manipulate rmap btree blocks. This prepares the way for connecting the
btree operations implementation.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
include/libxfs.h | 1
include/xfs_mount.h | 9 +
libxfs/Makefile | 2
libxfs/init.c | 5 -
libxfs/xfs_btree.c | 5 +
libxfs/xfs_format.h | 3
libxfs/xfs_ondisk.h | 1
libxfs/xfs_rtrmap_btree.c | 305 +++++++++++++++++++++++++++++++++++++++++++++
libxfs/xfs_rtrmap_btree.h | 83 ++++++++++++
libxfs/xfs_sb.c | 6 +
libxfs/xfs_shared.h | 2
11 files changed, 420 insertions(+), 2 deletions(-)
create mode 100644 libxfs/xfs_rtrmap_btree.c
create mode 100644 libxfs/xfs_rtrmap_btree.h
diff --git a/include/libxfs.h b/include/libxfs.h
index 8d2e321b914..3ab93158cf7 100644
--- a/include/libxfs.h
+++ b/include/libxfs.h
@@ -93,6 +93,7 @@ struct iomap;
#include "imeta_utils.h"
#include "xfs_rtbitmap.h"
#include "xfs_rtgroup.h"
+#include "xfs_rtrmap_btree.h"
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
diff --git a/include/xfs_mount.h b/include/xfs_mount.h
index 1284e848835..4e4da5bc4fa 100644
--- a/include/xfs_mount.h
+++ b/include/xfs_mount.h
@@ -92,11 +92,14 @@ typedef struct xfs_mount {
uint m_bmap_dmnr[2]; /* XFS_BMAP_BLOCK_DMINRECS */
uint m_rmap_mxr[2]; /* max rmap btree records */
uint m_rmap_mnr[2]; /* min rmap btree records */
+ uint m_rtrmap_mxr[2]; /* max rtrmap btree records */
+ uint m_rtrmap_mnr[2]; /* min rtrmap btree records */
uint m_refc_mxr[2]; /* max refc btree records */
uint m_refc_mnr[2]; /* min refc btree records */
uint m_alloc_maxlevels; /* max alloc btree levels */
uint m_bm_maxlevels[2]; /* max bmap btree levels */
uint m_rmap_maxlevels; /* max rmap btree levels */
+ uint m_rtrmap_maxlevels; /* max rtrmap btree level */
uint m_refc_maxlevels; /* max refc btree levels */
unsigned int m_agbtree_maxlevels; /* max level of all AG btrees */
unsigned int m_rtbtree_maxlevels; /* max level of all rt btrees */
@@ -233,6 +236,12 @@ __XFS_HAS_FEAT(large_extent_counts, NREXT64)
__XFS_HAS_FEAT(metadir, METADIR)
__XFS_HAS_FEAT(rtgroups, RTGROUPS)
+static inline bool xfs_has_rtrmapbt(struct xfs_mount *mp)
+{
+ return xfs_has_rtgroups(mp) && xfs_has_realtime(mp) &&
+ xfs_has_rmapbt(mp);
+}
+
/* Kernel mount features that we don't support */
#define __XFS_UNSUPP_FEAT(name) \
static inline bool xfs_has_ ## name (struct xfs_mount *mp) \
diff --git a/libxfs/Makefile b/libxfs/Makefile
index a37a5263199..0b3e8c896bd 100644
--- a/libxfs/Makefile
+++ b/libxfs/Makefile
@@ -63,6 +63,7 @@ HFILES = \
xfs_rmap_btree.h \
xfs_rtbitmap.h \
xfs_rtgroup.h \
+ xfs_rtrmap_btree.h \
xfs_sb.h \
xfs_shared.h \
xfs_swapext.h \
@@ -121,6 +122,7 @@ CFILES = cache.c \
xfs_rmap_btree.c \
xfs_rtbitmap.c \
xfs_rtgroup.c \
+ xfs_rtrmap_btree.c \
xfs_sb.c \
xfs_swapext.c \
xfs_symlink_remote.c \
diff --git a/libxfs/init.c b/libxfs/init.c
index 2663485a80d..9a4dfe02945 100644
--- a/libxfs/init.c
+++ b/libxfs/init.c
@@ -21,6 +21,7 @@
#include "xfs_trans.h"
#include "xfs_rmap_btree.h"
#include "xfs_refcount_btree.h"
+#include "xfs_imeta.h"
#include "libfrog/platform.h"
#include "xfile.h"
@@ -656,8 +657,7 @@ static inline void
xfs_rtbtree_compute_maxlevels(
struct xfs_mount *mp)
{
- /* This will be filled in later. */
- mp->m_rtbtree_maxlevels = 0;
+ mp->m_rtbtree_maxlevels = mp->m_rtrmap_maxlevels;
}
/* Compute maximum possible height of all btrees. */
@@ -673,6 +673,7 @@ libxfs_compute_all_maxlevels(
igeo->attr_fork_offset = xfs_bmap_compute_attr_offset(mp);
xfs_ialloc_setup_geometry(mp);
xfs_rmapbt_compute_maxlevels(mp);
+ xfs_rtrmapbt_compute_maxlevels(mp);
xfs_refcountbt_compute_maxlevels(mp);
xfs_agbtree_compute_maxlevels(mp);
diff --git a/libxfs/xfs_btree.c b/libxfs/xfs_btree.c
index e0276ad655a..ea0d5d71d03 100644
--- a/libxfs/xfs_btree.c
+++ b/libxfs/xfs_btree.c
@@ -29,6 +29,7 @@
#include "xfbtree.h"
#include "xfs_btree_mem.h"
#include "xfs_rtgroup.h"
+#include "xfs_rtrmap_btree.h"
/*
* Btree magic numbers.
@@ -5525,6 +5526,9 @@ xfs_btree_init_cur_caches(void)
if (error)
goto err;
error = xfs_refcountbt_init_cur_cache();
+ if (error)
+ goto err;
+ error = xfs_rtrmapbt_init_cur_cache();
if (error)
goto err;
@@ -5543,6 +5547,7 @@ xfs_btree_destroy_cur_caches(void)
xfs_bmbt_destroy_cur_cache();
xfs_rmapbt_destroy_cur_cache();
xfs_refcountbt_destroy_cur_cache();
+ xfs_rtrmapbt_destroy_cur_cache();
}
/* Move the btree cursor before the first record. */
diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
index b47d4f16143..5317c6438f0 100644
--- a/libxfs/xfs_format.h
+++ b/libxfs/xfs_format.h
@@ -1753,6 +1753,9 @@ typedef __be32 xfs_rmap_ptr_t;
*/
#define XFS_RTRMAP_CRC_MAGIC 0x4d415052 /* 'MAPR' */
+/* inode-based btree pointer type */
+typedef __be64 xfs_rtrmap_ptr_t;
+
/*
* Reference Count Btree format definitions
*
diff --git a/libxfs/xfs_ondisk.h b/libxfs/xfs_ondisk.h
index 70b96efa269..897a1b72f8d 100644
--- a/libxfs/xfs_ondisk.h
+++ b/libxfs/xfs_ondisk.h
@@ -77,6 +77,7 @@ xfs_check_ondisk_structs(void)
XFS_CHECK_STRUCT_SIZE(union xfs_rtword_raw, 4);
XFS_CHECK_STRUCT_SIZE(union xfs_suminfo_raw, 4);
XFS_CHECK_STRUCT_SIZE(struct xfs_rtbuf_blkinfo, 48);
+ XFS_CHECK_STRUCT_SIZE(xfs_rtrmap_ptr_t, 8);
/*
* m68k has problems with xfs_attr_leaf_name_remote_t, but we pad it to
diff --git a/libxfs/xfs_rtrmap_btree.c b/libxfs/xfs_rtrmap_btree.c
new file mode 100644
index 00000000000..1b6375af818
--- /dev/null
+++ b/libxfs/xfs_rtrmap_btree.c
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018-2024 Oracle. All Rights Reserved.
+ * Author: Darrick J. Wong <djwong@kernel.org>
+ */
+#include "libxfs_priv.h"
+#include "xfs_fs.h"
+#include "xfs_shared.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_bit.h"
+#include "xfs_sb.h"
+#include "xfs_mount.h"
+#include "xfs_defer.h"
+#include "xfs_inode.h"
+#include "xfs_trans.h"
+#include "xfs_alloc.h"
+#include "xfs_btree.h"
+#include "xfs_btree_staging.h"
+#include "xfs_rtrmap_btree.h"
+#include "xfs_trace.h"
+#include "xfs_cksum.h"
+#include "xfs_rtgroup.h"
+
+static struct kmem_cache *xfs_rtrmapbt_cur_cache;
+
+/*
+ * Realtime Reverse Map btree.
+ *
+ * This is a btree used to track the owner(s) of a given extent in the realtime
+ * device. See the comments in xfs_rmap_btree.c for more information.
+ *
+ * This tree is basically the same as the regular rmap btree except that it
+ * is rooted in an inode and does not live in free space.
+ */
+
+static struct xfs_btree_cur *
+xfs_rtrmapbt_dup_cursor(
+ struct xfs_btree_cur *cur)
+{
+ struct xfs_btree_cur *new;
+
+ new = xfs_rtrmapbt_init_cursor(cur->bc_mp, cur->bc_tp, cur->bc_ino.rtg,
+ cur->bc_ino.ip);
+
+ /* Copy the flags values since init cursor doesn't get them. */
+ new->bc_ino.flags = cur->bc_ino.flags;
+
+ return new;
+}
+
+static xfs_failaddr_t
+xfs_rtrmapbt_verify(
+ struct xfs_buf *bp)
+{
+ struct xfs_mount *mp = bp->b_target->bt_mount;
+ struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
+ xfs_failaddr_t fa;
+ int level;
+
+ if (!xfs_verify_magic(bp, block->bb_magic))
+ return __this_address;
+
+ if (!xfs_has_rmapbt(mp))
+ 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 > mp->m_rtrmap_maxlevels)
+ return __this_address;
+
+ return xfs_btree_lblock_verify(bp, mp->m_rtrmap_mxr[level != 0]);
+}
+
+static void
+xfs_rtrmapbt_read_verify(
+ struct xfs_buf *bp)
+{
+ xfs_failaddr_t fa;
+
+ if (!xfs_btree_lblock_verify_crc(bp))
+ xfs_verifier_error(bp, -EFSBADCRC, __this_address);
+ else {
+ fa = xfs_rtrmapbt_verify(bp);
+ if (fa)
+ xfs_verifier_error(bp, -EFSCORRUPTED, fa);
+ }
+
+ if (bp->b_error)
+ trace_xfs_btree_corrupt(bp, _RET_IP_);
+}
+
+static void
+xfs_rtrmapbt_write_verify(
+ struct xfs_buf *bp)
+{
+ xfs_failaddr_t fa;
+
+ fa = xfs_rtrmapbt_verify(bp);
+ if (fa) {
+ trace_xfs_btree_corrupt(bp, _RET_IP_);
+ xfs_verifier_error(bp, -EFSCORRUPTED, fa);
+ return;
+ }
+ xfs_btree_lblock_calc_crc(bp);
+
+}
+
+const struct xfs_buf_ops xfs_rtrmapbt_buf_ops = {
+ .name = "xfs_rtrmapbt",
+ .magic = { 0, cpu_to_be32(XFS_RTRMAP_CRC_MAGIC) },
+ .verify_read = xfs_rtrmapbt_read_verify,
+ .verify_write = xfs_rtrmapbt_write_verify,
+ .verify_struct = xfs_rtrmapbt_verify,
+};
+
+const struct xfs_btree_ops xfs_rtrmapbt_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_LONG_PTRS | XFS_BTREE_ROOT_IN_INODE |
+ XFS_BTREE_CRC_BLOCKS | XFS_BTREE_OVERLAPPING |
+ XFS_BTREE_IROOT_RECORDS,
+
+ .dup_cursor = xfs_rtrmapbt_dup_cursor,
+ .buf_ops = &xfs_rtrmapbt_buf_ops,
+};
+
+/* Initialize a new rt rmap btree cursor. */
+static struct xfs_btree_cur *
+xfs_rtrmapbt_init_common(
+ struct xfs_mount *mp,
+ struct xfs_trans *tp,
+ struct xfs_rtgroup *rtg,
+ struct xfs_inode *ip)
+{
+ struct xfs_btree_cur *cur;
+
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
+
+ cur = xfs_btree_alloc_cursor(mp, tp, XFS_BTNUM_RTRMAP,
+ &xfs_rtrmapbt_ops, mp->m_rtrmap_maxlevels,
+ xfs_rtrmapbt_cur_cache);
+ cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_rmap_2);
+
+ cur->bc_ino.ip = ip;
+ cur->bc_ino.allocated = 0;
+ cur->bc_ino.flags = 0;
+
+ cur->bc_ino.rtg = xfs_rtgroup_hold(rtg);
+ return cur;
+}
+
+/* Allocate a new rt rmap btree cursor. */
+struct xfs_btree_cur *
+xfs_rtrmapbt_init_cursor(
+ struct xfs_mount *mp,
+ struct xfs_trans *tp,
+ struct xfs_rtgroup *rtg,
+ struct xfs_inode *ip)
+{
+ struct xfs_btree_cur *cur;
+ struct xfs_ifork *ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK);
+
+ cur = xfs_rtrmapbt_init_common(mp, tp, rtg, ip);
+ cur->bc_nlevels = be16_to_cpu(ifp->if_broot->bb_level) + 1;
+ cur->bc_ino.forksize = xfs_inode_fork_size(ip, XFS_DATA_FORK);
+ cur->bc_ino.whichfork = XFS_DATA_FORK;
+ return cur;
+}
+
+/* Create a new rt reverse mapping btree cursor with a fake root for staging. */
+struct xfs_btree_cur *
+xfs_rtrmapbt_stage_cursor(
+ struct xfs_mount *mp,
+ struct xfs_rtgroup *rtg,
+ struct xfs_inode *ip,
+ struct xbtree_ifakeroot *ifake)
+{
+ struct xfs_btree_cur *cur;
+
+ cur = xfs_rtrmapbt_init_common(mp, NULL, rtg, ip);
+ cur->bc_nlevels = ifake->if_levels;
+ cur->bc_ino.forksize = ifake->if_fork_size;
+ cur->bc_ino.whichfork = -1;
+ xfs_btree_stage_ifakeroot(cur, ifake, NULL);
+ return cur;
+}
+
+/*
+ * Install a new rt reverse mapping btree root. Caller is responsible for
+ * invalidating and freeing the old btree blocks.
+ */
+void
+xfs_rtrmapbt_commit_staged_btree(
+ struct xfs_btree_cur *cur,
+ struct xfs_trans *tp)
+{
+ struct xbtree_ifakeroot *ifake = cur->bc_ino.ifake;
+ struct xfs_ifork *ifp;
+ int flags = XFS_ILOG_CORE | XFS_ILOG_DBROOT;
+
+ ASSERT(cur->bc_flags & XFS_BTREE_STAGING);
+
+ /*
+ * Free any resources hanging off the real fork, then shallow-copy the
+ * staging fork's contents into the real fork to transfer everything
+ * we just built.
+ */
+ ifp = xfs_ifork_ptr(cur->bc_ino.ip, XFS_DATA_FORK);
+ xfs_idestroy_fork(ifp);
+ memcpy(ifp, ifake->if_fork, sizeof(struct xfs_ifork));
+
+ xfs_trans_log_inode(tp, cur->bc_ino.ip, flags);
+ xfs_btree_commit_ifakeroot(cur, tp, XFS_DATA_FORK, &xfs_rtrmapbt_ops);
+}
+
+/* Calculate number of records in a rt reverse mapping btree block. */
+static inline unsigned int
+xfs_rtrmapbt_block_maxrecs(
+ unsigned int blocklen,
+ bool leaf)
+{
+ if (leaf)
+ return blocklen / sizeof(struct xfs_rmap_rec);
+ return blocklen /
+ (2 * sizeof(struct xfs_rmap_key) + sizeof(xfs_rtrmap_ptr_t));
+}
+
+/*
+ * Calculate number of records in an rt reverse mapping btree block.
+ */
+unsigned int
+xfs_rtrmapbt_maxrecs(
+ struct xfs_mount *mp,
+ unsigned int blocklen,
+ bool leaf)
+{
+ blocklen -= XFS_RTRMAP_BLOCK_LEN;
+ return xfs_rtrmapbt_block_maxrecs(blocklen, leaf);
+}
+
+/* Compute the max possible height for realtime reverse mapping btrees. */
+unsigned int
+xfs_rtrmapbt_maxlevels_ondisk(void)
+{
+ unsigned int minrecs[2];
+ unsigned int blocklen;
+
+ blocklen = XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_LBLOCK_CRC_LEN;
+
+ minrecs[0] = xfs_rtrmapbt_block_maxrecs(blocklen, true) / 2;
+ minrecs[1] = xfs_rtrmapbt_block_maxrecs(blocklen, false) / 2;
+
+ /* We need at most one record for every block in an rt group. */
+ return xfs_btree_compute_maxlevels(minrecs, XFS_MAX_RGBLOCKS);
+}
+
+int __init
+xfs_rtrmapbt_init_cur_cache(void)
+{
+ xfs_rtrmapbt_cur_cache = kmem_cache_create("xfs_rtrmapbt_cur",
+ xfs_btree_cur_sizeof(xfs_rtrmapbt_maxlevels_ondisk()),
+ 0, 0, NULL);
+
+ if (!xfs_rtrmapbt_cur_cache)
+ return -ENOMEM;
+ return 0;
+}
+
+void
+xfs_rtrmapbt_destroy_cur_cache(void)
+{
+ kmem_cache_destroy(xfs_rtrmapbt_cur_cache);
+ xfs_rtrmapbt_cur_cache = NULL;
+}
+
+/* Compute the maximum height of an rt reverse mapping btree. */
+void
+xfs_rtrmapbt_compute_maxlevels(
+ struct xfs_mount *mp)
+{
+ unsigned int d_maxlevels, r_maxlevels;
+
+ if (!xfs_has_rtrmapbt(mp)) {
+ mp->m_rtrmap_maxlevels = 0;
+ return;
+ }
+
+ /*
+ * The realtime rmapbt lives on the data device, which means that its
+ * maximum height is constrained by the size of the data device and
+ * the height required to store one rmap record for each block in an
+ * rt group.
+ */
+ d_maxlevels = xfs_btree_space_to_height(mp->m_rtrmap_mnr,
+ mp->m_sb.sb_dblocks);
+ r_maxlevels = xfs_btree_compute_maxlevels(mp->m_rtrmap_mnr,
+ mp->m_sb.sb_rgblocks);
+
+ /* Add one level to handle the inode root level. */
+ mp->m_rtrmap_maxlevels = min(d_maxlevels, r_maxlevels) + 1;
+}
diff --git a/libxfs/xfs_rtrmap_btree.h b/libxfs/xfs_rtrmap_btree.h
new file mode 100644
index 00000000000..0f732679719
--- /dev/null
+++ b/libxfs/xfs_rtrmap_btree.h
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2018-2024 Oracle. All Rights Reserved.
+ * Author: Darrick J. Wong <djwong@kernel.org>
+ */
+#ifndef __XFS_RTRMAP_BTREE_H__
+#define __XFS_RTRMAP_BTREE_H__
+
+struct xfs_buf;
+struct xfs_btree_cur;
+struct xfs_mount;
+struct xbtree_ifakeroot;
+struct xfs_rtgroup;
+
+/* rmaps only exist on crc enabled filesystems */
+#define XFS_RTRMAP_BLOCK_LEN XFS_BTREE_LBLOCK_CRC_LEN
+
+struct xfs_btree_cur *xfs_rtrmapbt_init_cursor(struct xfs_mount *mp,
+ struct xfs_trans *tp, struct xfs_rtgroup *rtg,
+ struct xfs_inode *ip);
+struct xfs_btree_cur *xfs_rtrmapbt_stage_cursor(struct xfs_mount *mp,
+ struct xfs_rtgroup *rtg, struct xfs_inode *ip,
+ struct xbtree_ifakeroot *ifake);
+void xfs_rtrmapbt_commit_staged_btree(struct xfs_btree_cur *cur,
+ struct xfs_trans *tp);
+unsigned int xfs_rtrmapbt_maxrecs(struct xfs_mount *mp, unsigned int blocklen,
+ bool leaf);
+void xfs_rtrmapbt_compute_maxlevels(struct xfs_mount *mp);
+
+/*
+ * Addresses of records, keys, and pointers within an incore rtrmapbt block.
+ *
+ * (note that some of these may appear unused, but they are used in userspace)
+ */
+static inline struct xfs_rmap_rec *
+xfs_rtrmap_rec_addr(
+ struct xfs_btree_block *block,
+ unsigned int index)
+{
+ return (struct xfs_rmap_rec *)
+ ((char *)block + XFS_RTRMAP_BLOCK_LEN +
+ (index - 1) * sizeof(struct xfs_rmap_rec));
+}
+
+static inline struct xfs_rmap_key *
+xfs_rtrmap_key_addr(
+ struct xfs_btree_block *block,
+ unsigned int index)
+{
+ return (struct xfs_rmap_key *)
+ ((char *)block + XFS_RTRMAP_BLOCK_LEN +
+ (index - 1) * 2 * sizeof(struct xfs_rmap_key));
+}
+
+static inline struct xfs_rmap_key *
+xfs_rtrmap_high_key_addr(
+ struct xfs_btree_block *block,
+ unsigned int index)
+{
+ return (struct xfs_rmap_key *)
+ ((char *)block + XFS_RTRMAP_BLOCK_LEN +
+ sizeof(struct xfs_rmap_key) +
+ (index - 1) * 2 * sizeof(struct xfs_rmap_key));
+}
+
+static inline xfs_rtrmap_ptr_t *
+xfs_rtrmap_ptr_addr(
+ struct xfs_btree_block *block,
+ unsigned int index,
+ unsigned int maxrecs)
+{
+ return (xfs_rtrmap_ptr_t *)
+ ((char *)block + XFS_RTRMAP_BLOCK_LEN +
+ maxrecs * 2 * sizeof(struct xfs_rmap_key) +
+ (index - 1) * sizeof(xfs_rtrmap_ptr_t));
+}
+
+unsigned int xfs_rtrmapbt_maxlevels_ondisk(void);
+
+int __init xfs_rtrmapbt_init_cur_cache(void);
+void xfs_rtrmapbt_destroy_cur_cache(void);
+
+#endif /* __XFS_RTRMAP_BTREE_H__ */
diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c
index aff2ab79f9b..891b71190d5 100644
--- a/libxfs/xfs_sb.c
+++ b/libxfs/xfs_sb.c
@@ -26,6 +26,7 @@
#include "xfs_rtbitmap.h"
#include "xfs_swapext.h"
#include "xfs_rtgroup.h"
+#include "xfs_rtrmap_btree.h"
/*
* Physical superblock buffer manipulations. Shared with libxfs in userspace.
@@ -1123,6 +1124,11 @@ xfs_sb_mount_common(
mp->m_rmap_mnr[0] = mp->m_rmap_mxr[0] / 2;
mp->m_rmap_mnr[1] = mp->m_rmap_mxr[1] / 2;
+ mp->m_rtrmap_mxr[0] = xfs_rtrmapbt_maxrecs(mp, sbp->sb_blocksize, true);
+ mp->m_rtrmap_mxr[1] = xfs_rtrmapbt_maxrecs(mp, sbp->sb_blocksize, false);
+ mp->m_rtrmap_mnr[0] = mp->m_rtrmap_mxr[0] / 2;
+ mp->m_rtrmap_mnr[1] = mp->m_rtrmap_mxr[1] / 2;
+
mp->m_refc_mxr[0] = xfs_refcountbt_maxrecs(mp, sbp->sb_blocksize, true);
mp->m_refc_mxr[1] = xfs_refcountbt_maxrecs(mp, sbp->sb_blocksize, false);
mp->m_refc_mnr[0] = mp->m_refc_mxr[0] / 2;
diff --git a/libxfs/xfs_shared.h b/libxfs/xfs_shared.h
index 8ad4b67d6fe..adb742267c9 100644
--- a/libxfs/xfs_shared.h
+++ b/libxfs/xfs_shared.h
@@ -42,6 +42,7 @@ extern const struct xfs_buf_ops xfs_rtbitmap_buf_ops;
extern const struct xfs_buf_ops xfs_rtsummary_buf_ops;
extern const struct xfs_buf_ops xfs_rtbuf_ops;
extern const struct xfs_buf_ops xfs_rtsb_buf_ops;
+extern const struct xfs_buf_ops xfs_rtrmapbt_buf_ops;
extern const struct xfs_buf_ops xfs_sb_buf_ops;
extern const struct xfs_buf_ops xfs_sb_quiet_buf_ops;
extern const struct xfs_buf_ops xfs_symlink_buf_ops;
@@ -54,6 +55,7 @@ extern const struct xfs_btree_ops xfs_finobt_ops;
extern const struct xfs_btree_ops xfs_bmbt_ops;
extern const struct xfs_btree_ops xfs_refcountbt_ops;
extern const struct xfs_btree_ops xfs_rmapbt_ops;
+extern const struct xfs_btree_ops xfs_rtrmapbt_ops;
/* log size calculation functions */
int xfs_log_calc_unit_res(struct xfs_mount *mp, int unit_bytes);
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 04/47] xfs: realtime rmap btree transaction reservations
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (2 preceding siblings ...)
2023-12-27 13:11 ` [PATCH 03/47] xfs: define the on-disk realtime rmap btree format Darrick J. Wong
@ 2023-12-27 13:11 ` Darrick J. Wong
2023-12-27 13:11 ` [PATCH 05/47] xfs: add realtime rmap btree operations Darrick J. Wong
` (42 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:11 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Make sure that there's enough log reservation to handle mapping
and unmapping realtime extents. We have to reserve enough space
to handle a split in the rtrmapbt to add the record and a second
split in the regular rmapbt to record the rtrmapbt split.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_swapext.c | 4 +++-
libxfs/xfs_trans_resv.c | 12 ++++++++++--
libxfs/xfs_trans_space.h | 13 +++++++++++++
3 files changed, 26 insertions(+), 3 deletions(-)
diff --git a/libxfs/xfs_swapext.c b/libxfs/xfs_swapext.c
index 1f7fbe76a89..36283ea72cd 100644
--- a/libxfs/xfs_swapext.c
+++ b/libxfs/xfs_swapext.c
@@ -759,7 +759,9 @@ xfs_swapext_rmapbt_blocks(
if (!xfs_has_rmapbt(mp))
return 0;
if (XFS_IS_REALTIME_INODE(req->ip1))
- return 0;
+ return howmany_64(req->nr_exchanges,
+ XFS_MAX_CONTIG_RTRMAPS_PER_BLOCK(mp)) *
+ XFS_RTRMAPADD_SPACE_RES(mp);
return howmany_64(req->nr_exchanges,
XFS_MAX_CONTIG_RMAPS_PER_BLOCK(mp)) *
diff --git a/libxfs/xfs_trans_resv.c b/libxfs/xfs_trans_resv.c
index 800a2f9ecb8..18efae57975 100644
--- a/libxfs/xfs_trans_resv.c
+++ b/libxfs/xfs_trans_resv.c
@@ -211,7 +211,9 @@ xfs_calc_inode_chunk_res(
* Per-extent log reservation for the btree changes involved in freeing or
* allocating a realtime extent. We have to be able to log as many rtbitmap
* blocks as needed to mark inuse XFS_BMBT_MAX_EXTLEN blocks' worth of realtime
- * extents, as well as the realtime summary block.
+ * extents, as well as the realtime summary block (t1). Realtime rmap btree
+ * operations happen in a second transaction, so factor in a couple of rtrmapbt
+ * splits (t2).
*/
static unsigned int
xfs_rtalloc_block_count(
@@ -220,10 +222,16 @@ xfs_rtalloc_block_count(
{
unsigned int rtbmp_blocks;
xfs_rtxlen_t rtxlen;
+ unsigned int t1, t2 = 0;
rtxlen = xfs_extlen_to_rtxlen(mp, XFS_MAX_BMBT_EXTLEN);
rtbmp_blocks = xfs_rtbitmap_blockcount(mp, rtxlen);
- return (rtbmp_blocks + 1) * num_ops;
+ t1 = (rtbmp_blocks + 1) * num_ops;
+
+ if (xfs_has_rmapbt(mp))
+ t2 = num_ops * (2 * mp->m_rtrmap_maxlevels - 1);
+
+ return max(t1, t2);
}
/*
diff --git a/libxfs/xfs_trans_space.h b/libxfs/xfs_trans_space.h
index 1155ff2d37e..d89b570aafc 100644
--- a/libxfs/xfs_trans_space.h
+++ b/libxfs/xfs_trans_space.h
@@ -14,6 +14,19 @@
#define XFS_MAX_CONTIG_BMAPS_PER_BLOCK(mp) \
(((mp)->m_bmap_dmxr[0]) - ((mp)->m_bmap_dmnr[0]))
+/* Worst case number of realtime rmaps that can be held in a block. */
+#define XFS_MAX_CONTIG_RTRMAPS_PER_BLOCK(mp) \
+ (((mp)->m_rtrmap_mxr[0]) - ((mp)->m_rtrmap_mnr[0]))
+
+/* Adding one realtime rmap could split every level to the top of the tree. */
+#define XFS_RTRMAPADD_SPACE_RES(mp) ((mp)->m_rtrmap_maxlevels)
+
+/* Blocks we might need to add "b" realtime rmaps to a tree. */
+#define XFS_NRTRMAPADD_SPACE_RES(mp, b) \
+ ((((b) + XFS_MAX_CONTIG_RTRMAPS_PER_BLOCK(mp) - 1) / \
+ XFS_MAX_CONTIG_RTRMAPS_PER_BLOCK(mp)) * \
+ XFS_RTRMAPADD_SPACE_RES(mp))
+
/* Worst case number of rmaps that can be held in a block. */
#define XFS_MAX_CONTIG_RMAPS_PER_BLOCK(mp) \
(((mp)->m_rmap_mxr[0]) - ((mp)->m_rmap_mnr[0]))
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 05/47] xfs: add realtime rmap btree operations
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (3 preceding siblings ...)
2023-12-27 13:11 ` [PATCH 04/47] xfs: realtime rmap btree transaction reservations Darrick J. Wong
@ 2023-12-27 13:11 ` Darrick J. Wong
2023-12-27 13:12 ` [PATCH 06/47] xfs: prepare rmap functions to deal with rtrmapbt Darrick J. Wong
` (41 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:11 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Implement the generic btree operations needed to manipulate rtrmap
btree blocks. This is different from the regular rmapbt in that we
allocate space from the filesystem at large, and are neither
constrained to the free space nor any particular AG.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_btree.c | 70 ++++++++++++
libxfs/xfs_btree.h | 5 +
libxfs/xfs_rtrmap_btree.c | 271 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 346 insertions(+)
diff --git a/libxfs/xfs_btree.c b/libxfs/xfs_btree.c
index ea0d5d71d03..f599dd17d30 100644
--- a/libxfs/xfs_btree.c
+++ b/libxfs/xfs_btree.c
@@ -30,6 +30,9 @@
#include "xfs_btree_mem.h"
#include "xfs_rtgroup.h"
#include "xfs_rtrmap_btree.h"
+#include "xfs_bmap.h"
+#include "xfs_rmap.h"
+#include "xfs_imeta.h"
/*
* Btree magic numbers.
@@ -5576,3 +5579,70 @@ xfs_btree_goto_left_edge(
return 0;
}
+
+/* Allocate a block for an inode-rooted metadata btree. */
+int
+xfs_btree_alloc_imeta_block(
+ struct xfs_btree_cur *cur,
+ const union xfs_btree_ptr *start,
+ union xfs_btree_ptr *new,
+ int *stat)
+{
+ struct xfs_alloc_arg args = {
+ .mp = cur->bc_mp,
+ .tp = cur->bc_tp,
+ .resv = XFS_AG_RESV_IMETA,
+ .minlen = 1,
+ .maxlen = 1,
+ .prod = 1,
+ };
+ struct xfs_inode *ip = cur->bc_ino.ip;
+ int error;
+
+ ASSERT(xfs_is_metadir_inode(ip));
+ ASSERT(XFS_IS_DQDETACHED(cur->bc_mp, ip));
+
+ xfs_rmap_ino_bmbt_owner(&args.oinfo, ip->i_ino, cur->bc_ino.whichfork);
+ error = xfs_alloc_vextent_start_ag(&args,
+ XFS_INO_TO_FSB(cur->bc_mp, ip->i_ino));
+ if (error)
+ return error;
+ if (args.fsbno == NULLFSBLOCK) {
+ *stat = 0;
+ return 0;
+ }
+ ASSERT(args.len == 1);
+
+ xfs_imeta_resv_alloc_extent(ip, &args);
+ cur->bc_ino.allocated++;
+
+ new->l = cpu_to_be64(args.fsbno);
+ *stat = 1;
+ return 0;
+}
+
+/* Free a block from an inode-rooted metadata btree. */
+int
+xfs_btree_free_imeta_block(
+ struct xfs_btree_cur *cur,
+ struct xfs_buf *bp)
+{
+ struct xfs_owner_info oinfo;
+ struct xfs_mount *mp = cur->bc_mp;
+ struct xfs_inode *ip = cur->bc_ino.ip;
+ struct xfs_trans *tp = cur->bc_tp;
+ xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, xfs_buf_daddr(bp));
+ int error;
+
+ ASSERT(xfs_is_metadir_inode(ip));
+ ASSERT(XFS_IS_DQDETACHED(cur->bc_mp, ip));
+
+ xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, cur->bc_ino.whichfork);
+ error = xfs_free_extent_later(tp, fsbno, 1, &oinfo, XFS_AG_RESV_IMETA,
+ 0);
+ if (error)
+ return error;
+
+ xfs_imeta_resv_free_extent(ip, tp, 1);
+ return 0;
+}
diff --git a/libxfs/xfs_btree.h b/libxfs/xfs_btree.h
index e6571c9157d..3559cf5d3a6 100644
--- a/libxfs/xfs_btree.h
+++ b/libxfs/xfs_btree.h
@@ -764,4 +764,9 @@ void xfs_btree_destroy_cur_caches(void);
int xfs_btree_goto_left_edge(struct xfs_btree_cur *cur);
+int xfs_btree_alloc_imeta_block(struct xfs_btree_cur *cur,
+ const union xfs_btree_ptr *start, union xfs_btree_ptr *newp,
+ int *stat);
+int xfs_btree_free_imeta_block(struct xfs_btree_cur *cur, struct xfs_buf *bp);
+
#endif /* __XFS_BTREE_H__ */
diff --git a/libxfs/xfs_rtrmap_btree.c b/libxfs/xfs_rtrmap_btree.c
index 1b6375af818..a2cb497379f 100644
--- a/libxfs/xfs_rtrmap_btree.c
+++ b/libxfs/xfs_rtrmap_btree.c
@@ -18,10 +18,12 @@
#include "xfs_alloc.h"
#include "xfs_btree.h"
#include "xfs_btree_staging.h"
+#include "xfs_rmap.h"
#include "xfs_rtrmap_btree.h"
#include "xfs_trace.h"
#include "xfs_cksum.h"
#include "xfs_rtgroup.h"
+#include "xfs_bmap.h"
static struct kmem_cache *xfs_rtrmapbt_cur_cache;
@@ -50,6 +52,182 @@ xfs_rtrmapbt_dup_cursor(
return new;
}
+STATIC int
+xfs_rtrmapbt_get_minrecs(
+ struct xfs_btree_cur *cur,
+ int level)
+{
+ if (level == cur->bc_nlevels - 1) {
+ struct xfs_ifork *ifp = xfs_btree_ifork_ptr(cur);
+
+ return xfs_rtrmapbt_maxrecs(cur->bc_mp, ifp->if_broot_bytes,
+ level == 0) / 2;
+ }
+
+ return cur->bc_mp->m_rtrmap_mnr[level != 0];
+}
+
+STATIC int
+xfs_rtrmapbt_get_maxrecs(
+ struct xfs_btree_cur *cur,
+ int level)
+{
+ if (level == cur->bc_nlevels - 1) {
+ struct xfs_ifork *ifp = xfs_btree_ifork_ptr(cur);
+
+ return xfs_rtrmapbt_maxrecs(cur->bc_mp, ifp->if_broot_bytes,
+ level == 0);
+ }
+
+ return cur->bc_mp->m_rtrmap_mxr[level != 0];
+}
+
+/*
+ * Convert the ondisk record's offset field into the ondisk key's offset field.
+ * Fork and bmbt are significant parts of the rmap record key, but written
+ * status is merely a record attribute.
+ */
+static inline __be64 ondisk_rec_offset_to_key(const union xfs_btree_rec *rec)
+{
+ return rec->rmap.rm_offset & ~cpu_to_be64(XFS_RMAP_OFF_UNWRITTEN);
+}
+
+STATIC void
+xfs_rtrmapbt_init_key_from_rec(
+ union xfs_btree_key *key,
+ const union xfs_btree_rec *rec)
+{
+ key->rmap.rm_startblock = rec->rmap.rm_startblock;
+ key->rmap.rm_owner = rec->rmap.rm_owner;
+ key->rmap.rm_offset = ondisk_rec_offset_to_key(rec);
+}
+
+STATIC void
+xfs_rtrmapbt_init_high_key_from_rec(
+ union xfs_btree_key *key,
+ const union xfs_btree_rec *rec)
+{
+ uint64_t off;
+ int adj;
+
+ adj = be32_to_cpu(rec->rmap.rm_blockcount) - 1;
+
+ key->rmap.rm_startblock = rec->rmap.rm_startblock;
+ be32_add_cpu(&key->rmap.rm_startblock, adj);
+ key->rmap.rm_owner = rec->rmap.rm_owner;
+ key->rmap.rm_offset = ondisk_rec_offset_to_key(rec);
+ if (XFS_RMAP_NON_INODE_OWNER(be64_to_cpu(rec->rmap.rm_owner)) ||
+ XFS_RMAP_IS_BMBT_BLOCK(be64_to_cpu(rec->rmap.rm_offset)))
+ return;
+ off = be64_to_cpu(key->rmap.rm_offset);
+ off = (XFS_RMAP_OFF(off) + adj) | (off & ~XFS_RMAP_OFF_MASK);
+ key->rmap.rm_offset = cpu_to_be64(off);
+}
+
+STATIC void
+xfs_rtrmapbt_init_rec_from_cur(
+ struct xfs_btree_cur *cur,
+ union xfs_btree_rec *rec)
+{
+ rec->rmap.rm_startblock = cpu_to_be32(cur->bc_rec.r.rm_startblock);
+ rec->rmap.rm_blockcount = cpu_to_be32(cur->bc_rec.r.rm_blockcount);
+ rec->rmap.rm_owner = cpu_to_be64(cur->bc_rec.r.rm_owner);
+ rec->rmap.rm_offset = cpu_to_be64(
+ xfs_rmap_irec_offset_pack(&cur->bc_rec.r));
+}
+
+STATIC void
+xfs_rtrmapbt_init_ptr_from_cur(
+ struct xfs_btree_cur *cur,
+ union xfs_btree_ptr *ptr)
+{
+ ptr->l = 0;
+}
+
+/*
+ * Mask the appropriate parts of the ondisk key field for a key comparison.
+ * Fork and bmbt are significant parts of the rmap record key, but written
+ * status is merely a record attribute.
+ */
+static inline uint64_t offset_keymask(uint64_t offset)
+{
+ return offset & ~XFS_RMAP_OFF_UNWRITTEN;
+}
+
+STATIC int64_t
+xfs_rtrmapbt_key_diff(
+ struct xfs_btree_cur *cur,
+ const union xfs_btree_key *key)
+{
+ struct xfs_rmap_irec *rec = &cur->bc_rec.r;
+ const struct xfs_rmap_key *kp = &key->rmap;
+ __u64 x, y;
+ int64_t d;
+
+ d = (int64_t)be32_to_cpu(kp->rm_startblock) - rec->rm_startblock;
+ if (d)
+ return d;
+
+ x = be64_to_cpu(kp->rm_owner);
+ y = rec->rm_owner;
+ if (x > y)
+ return 1;
+ else if (y > x)
+ return -1;
+
+ x = offset_keymask(be64_to_cpu(kp->rm_offset));
+ y = offset_keymask(xfs_rmap_irec_offset_pack(rec));
+ if (x > y)
+ return 1;
+ else if (y > x)
+ return -1;
+ return 0;
+}
+
+STATIC int64_t
+xfs_rtrmapbt_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 xfs_rmap_key *kp1 = &k1->rmap;
+ const struct xfs_rmap_key *kp2 = &k2->rmap;
+ int64_t d;
+ __u64 x, y;
+
+ /* Doesn't make sense to mask off the physical space part */
+ ASSERT(!mask || mask->rmap.rm_startblock);
+
+ d = (int64_t)be32_to_cpu(kp1->rm_startblock) -
+ be32_to_cpu(kp2->rm_startblock);
+ if (d)
+ return d;
+
+ if (!mask || mask->rmap.rm_owner) {
+ x = be64_to_cpu(kp1->rm_owner);
+ y = be64_to_cpu(kp2->rm_owner);
+ if (x > y)
+ return 1;
+ else if (y > x)
+ return -1;
+ }
+
+ if (!mask || mask->rmap.rm_offset) {
+ /* Doesn't make sense to allow offset but not owner */
+ ASSERT(!mask || mask->rmap.rm_owner);
+
+ x = offset_keymask(be64_to_cpu(kp1->rm_offset));
+ y = offset_keymask(be64_to_cpu(kp2->rm_offset));
+ if (x > y)
+ return 1;
+ else if (y > x)
+ return -1;
+ }
+
+ return 0;
+}
+
static xfs_failaddr_t
xfs_rtrmapbt_verify(
struct xfs_buf *bp)
@@ -116,6 +294,86 @@ const struct xfs_buf_ops xfs_rtrmapbt_buf_ops = {
.verify_struct = xfs_rtrmapbt_verify,
};
+STATIC int
+xfs_rtrmapbt_keys_inorder(
+ struct xfs_btree_cur *cur,
+ const union xfs_btree_key *k1,
+ const union xfs_btree_key *k2)
+{
+ uint32_t x;
+ uint32_t y;
+ uint64_t a;
+ uint64_t b;
+
+ x = be32_to_cpu(k1->rmap.rm_startblock);
+ y = be32_to_cpu(k2->rmap.rm_startblock);
+ if (x < y)
+ return 1;
+ else if (x > y)
+ return 0;
+ a = be64_to_cpu(k1->rmap.rm_owner);
+ b = be64_to_cpu(k2->rmap.rm_owner);
+ if (a < b)
+ return 1;
+ else if (a > b)
+ return 0;
+ a = offset_keymask(be64_to_cpu(k1->rmap.rm_offset));
+ b = offset_keymask(be64_to_cpu(k2->rmap.rm_offset));
+ if (a <= b)
+ return 1;
+ return 0;
+}
+
+STATIC int
+xfs_rtrmapbt_recs_inorder(
+ struct xfs_btree_cur *cur,
+ const union xfs_btree_rec *r1,
+ const union xfs_btree_rec *r2)
+{
+ uint32_t x;
+ uint32_t y;
+ uint64_t a;
+ uint64_t b;
+
+ x = be32_to_cpu(r1->rmap.rm_startblock);
+ y = be32_to_cpu(r2->rmap.rm_startblock);
+ if (x < y)
+ return 1;
+ else if (x > y)
+ return 0;
+ a = be64_to_cpu(r1->rmap.rm_owner);
+ b = be64_to_cpu(r2->rmap.rm_owner);
+ if (a < b)
+ return 1;
+ else if (a > b)
+ return 0;
+ a = offset_keymask(be64_to_cpu(r1->rmap.rm_offset));
+ b = offset_keymask(be64_to_cpu(r2->rmap.rm_offset));
+ if (a <= b)
+ return 1;
+ return 0;
+}
+
+STATIC enum xbtree_key_contig
+xfs_rtrmapbt_keys_contiguous(
+ struct xfs_btree_cur *cur,
+ const union xfs_btree_key *key1,
+ const union xfs_btree_key *key2,
+ const union xfs_btree_key *mask)
+{
+ ASSERT(!mask || mask->rmap.rm_startblock);
+
+ /*
+ * We only support checking contiguity of the physical space component.
+ * If any callers ever need more specificity than that, they'll have to
+ * implement it here.
+ */
+ ASSERT(!mask || (!mask->rmap.rm_owner && !mask->rmap.rm_offset));
+
+ return xbtree_key_contig(be32_to_cpu(key1->rmap.rm_startblock),
+ be32_to_cpu(key2->rmap.rm_startblock));
+}
+
const struct xfs_btree_ops xfs_rtrmapbt_ops = {
.rec_len = sizeof(struct xfs_rmap_rec),
.key_len = 2 * sizeof(struct xfs_rmap_key),
@@ -125,7 +383,20 @@ const struct xfs_btree_ops xfs_rtrmapbt_ops = {
XFS_BTREE_IROOT_RECORDS,
.dup_cursor = xfs_rtrmapbt_dup_cursor,
+ .alloc_block = xfs_btree_alloc_imeta_block,
+ .free_block = xfs_btree_free_imeta_block,
+ .get_minrecs = xfs_rtrmapbt_get_minrecs,
+ .get_maxrecs = xfs_rtrmapbt_get_maxrecs,
+ .init_key_from_rec = xfs_rtrmapbt_init_key_from_rec,
+ .init_high_key_from_rec = xfs_rtrmapbt_init_high_key_from_rec,
+ .init_rec_from_cur = xfs_rtrmapbt_init_rec_from_cur,
+ .init_ptr_from_cur = xfs_rtrmapbt_init_ptr_from_cur,
+ .key_diff = xfs_rtrmapbt_key_diff,
.buf_ops = &xfs_rtrmapbt_buf_ops,
+ .diff_two_keys = xfs_rtrmapbt_diff_two_keys,
+ .keys_inorder = xfs_rtrmapbt_keys_inorder,
+ .recs_inorder = xfs_rtrmapbt_recs_inorder,
+ .keys_contiguous = xfs_rtrmapbt_keys_contiguous,
};
/* Initialize a new rt rmap btree cursor. */
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 06/47] xfs: prepare rmap functions to deal with rtrmapbt
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (4 preceding siblings ...)
2023-12-27 13:11 ` [PATCH 05/47] xfs: add realtime rmap btree operations Darrick J. Wong
@ 2023-12-27 13:12 ` Darrick J. Wong
2023-12-27 13:12 ` [PATCH 07/47] xfs: add a realtime flag to the rmap update log redo items Darrick J. Wong
` (40 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:12 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Prepare the high-level rmap functions to deal with the new realtime
rmapbt and its slightly different conventions. Provide the ability
to talk to either rmapbt or rtrmapbt formats from the same high
level code.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_rmap.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++
libxfs/xfs_rmap.h | 3 ++
2 files changed, 69 insertions(+)
diff --git a/libxfs/xfs_rmap.c b/libxfs/xfs_rmap.c
index 3e95599ab8a..007f17cc644 100644
--- a/libxfs/xfs_rmap.c
+++ b/libxfs/xfs_rmap.c
@@ -24,6 +24,7 @@
#include "xfs_ag.h"
#include "xfs_health.h"
#include "defer_item.h"
+#include "xfs_rtgroup.h"
struct kmem_cache *xfs_rmap_intent_cache;
@@ -263,11 +264,72 @@ xfs_rmap_check_irec(
return NULL;
}
+xfs_failaddr_t
+xfs_rtrmap_check_irec(
+ struct xfs_rtgroup *rtg,
+ const struct xfs_rmap_irec *irec)
+{
+ struct xfs_mount *mp = rtg->rtg_mount;
+ bool is_inode;
+ bool is_unwritten;
+ bool is_bmbt;
+ bool is_attr;
+
+ if (irec->rm_blockcount == 0)
+ return __this_address;
+
+ if (irec->rm_owner == XFS_RMAP_OWN_FS) {
+ if (irec->rm_startblock != 0)
+ return __this_address;
+ if (irec->rm_blockcount != mp->m_sb.sb_rextsize)
+ return __this_address;
+ if (irec->rm_offset != 0)
+ return __this_address;
+ } else {
+ if (!xfs_verify_rgbext(rtg, irec->rm_startblock,
+ irec->rm_blockcount))
+ return __this_address;
+ }
+
+ if (!(xfs_verify_ino(mp, irec->rm_owner) ||
+ (irec->rm_owner <= XFS_RMAP_OWN_FS &&
+ irec->rm_owner >= XFS_RMAP_OWN_MIN)))
+ return __this_address;
+
+ /* Check flags. */
+ is_inode = !XFS_RMAP_NON_INODE_OWNER(irec->rm_owner);
+ is_bmbt = irec->rm_flags & XFS_RMAP_BMBT_BLOCK;
+ is_attr = irec->rm_flags & XFS_RMAP_ATTR_FORK;
+ is_unwritten = irec->rm_flags & XFS_RMAP_UNWRITTEN;
+
+ if (!is_inode && irec->rm_owner != XFS_RMAP_OWN_FS)
+ return __this_address;
+
+ if (!is_inode && irec->rm_offset != 0)
+ return __this_address;
+
+ if (is_bmbt || is_attr)
+ return __this_address;
+
+ if (is_unwritten && !is_inode)
+ return __this_address;
+
+ /* Check for a valid fork offset, if applicable. */
+ if (is_inode &&
+ !xfs_verify_fileext(mp, irec->rm_offset, irec->rm_blockcount))
+ return __this_address;
+
+ return NULL;
+}
+
static inline xfs_failaddr_t
xfs_rmap_check_btrec(
struct xfs_btree_cur *cur,
const struct xfs_rmap_irec *irec)
{
+ if (cur->bc_btnum == XFS_BTNUM_RTRMAP)
+ return xfs_rtrmap_check_irec(cur->bc_ino.rtg, irec);
+
if (cur->bc_flags & XFS_BTREE_IN_XFILE)
return xfs_rmap_check_irec(cur->bc_mem.pag, irec);
return xfs_rmap_check_irec(cur->bc_ag.pag, irec);
@@ -284,6 +346,10 @@ xfs_rmap_complain_bad_rec(
if (cur->bc_flags & XFS_BTREE_IN_XFILE)
xfs_warn(mp,
"In-Memory Reverse Mapping BTree record corruption detected at %pS!", fa);
+ else if (cur->bc_btnum == XFS_BTNUM_RTRMAP)
+ xfs_warn(mp,
+ "RT Reverse Mapping BTree record corruption in rtgroup %u detected at %pS!",
+ cur->bc_ino.rtg->rtg_rgno, fa);
else
xfs_warn(mp,
"Reverse Mapping BTree record corruption in AG %d detected at %pS!",
diff --git a/libxfs/xfs_rmap.h b/libxfs/xfs_rmap.h
index 0ccfd7d88e5..762f2f40b6e 100644
--- a/libxfs/xfs_rmap.h
+++ b/libxfs/xfs_rmap.h
@@ -7,6 +7,7 @@
#define __XFS_RMAP_H__
struct xfs_perag;
+struct xfs_rtgroup;
static inline void
xfs_rmap_ino_bmbt_owner(
@@ -206,6 +207,8 @@ xfs_failaddr_t xfs_rmap_btrec_to_irec(const union xfs_btree_rec *rec,
struct xfs_rmap_irec *irec);
xfs_failaddr_t xfs_rmap_check_irec(struct xfs_perag *pag,
const struct xfs_rmap_irec *irec);
+xfs_failaddr_t xfs_rtrmap_check_irec(struct xfs_rtgroup *rtg,
+ const struct xfs_rmap_irec *irec);
int xfs_rmap_has_records(struct xfs_btree_cur *cur, xfs_agblock_t bno,
xfs_extlen_t len, enum xbtree_recpacking *outcome);
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 07/47] xfs: add a realtime flag to the rmap update log redo items
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (5 preceding siblings ...)
2023-12-27 13:12 ` [PATCH 06/47] xfs: prepare rmap functions to deal with rtrmapbt Darrick J. Wong
@ 2023-12-27 13:12 ` Darrick J. Wong
2023-12-27 13:12 ` [PATCH 08/47] xfs: add realtime reverse map inode to metadata directory Darrick J. Wong
` (39 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:12 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Extend the rmap update (RUI) log items with a new realtime flag that
indicates that the updates apply against the realtime rmapbt. We'll
wire up the actual rmap code later.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/defer_item.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++-
libxfs/xfs_defer.h | 1
libxfs/xfs_log_format.h | 6 ++-
libxfs/xfs_refcount.c | 4 +-
libxfs/xfs_rmap.c | 32 +++++++++++++---
libxfs/xfs_rmap.h | 12 ++++--
6 files changed, 138 insertions(+), 13 deletions(-)
diff --git a/libxfs/defer_item.c b/libxfs/defer_item.c
index 5399a20f186..a82d23c17cf 100644
--- a/libxfs/defer_item.c
+++ b/libxfs/defer_item.c
@@ -29,6 +29,7 @@
#include "xfs_swapext.h"
#include "defer_item.h"
#include "xfs_btree.h"
+#include "xfs_rtgroup.h"
/* Dummy defer item ops, since we don't do logging. */
@@ -329,8 +330,23 @@ xfs_rmap_defer_add(
trace_xfs_rmap_defer(mp, ri);
- ri->ri_pag = xfs_perag_intent_get(mp, ri->ri_bmap.br_startblock);
- xfs_defer_add(tp, &ri->ri_list, &xfs_rmap_update_defer_type);
+ /*
+ * Deferred rmap updates for the realtime and data sections must use
+ * separate transactions to finish deferred work because updates to
+ * realtime metadata files can lock AGFs to allocate btree blocks and
+ * we don't want that mixing with the AGF locks taken to finish data
+ * section updates.
+ */
+ if (ri->ri_realtime) {
+ xfs_rgnumber_t rgno;
+
+ rgno = xfs_rtb_to_rgno(mp, ri->ri_bmap.br_startblock);
+ ri->ri_rtg = xfs_rtgroup_get(mp, rgno);
+ xfs_defer_add(tp, &ri->ri_list, &xfs_rtrmap_update_defer_type);
+ } else {
+ ri->ri_pag = xfs_perag_intent_get(mp, ri->ri_bmap.br_startblock);
+ xfs_defer_add(tp, &ri->ri_list, &xfs_rmap_update_defer_type);
+ }
}
/* Cancel a deferred rmap update. */
@@ -395,6 +411,82 @@ const struct xfs_defer_op_type xfs_rmap_update_defer_type = {
.cancel_item = xfs_rmap_update_cancel_item,
};
+/* Sort rmap intents by rtgroup. */
+static int
+xfs_rtrmap_update_diff_items(
+ void *priv,
+ const struct list_head *a,
+ const struct list_head *b)
+{
+ struct xfs_rmap_intent *ra = ri_entry(a);
+ struct xfs_rmap_intent *rb = ri_entry(b);
+
+ return ra->ri_rtg->rtg_rgno - rb->ri_rtg->rtg_rgno;
+}
+
+static struct xfs_log_item *
+xfs_rtrmap_update_create_intent(
+ struct xfs_trans *tp,
+ struct list_head *items,
+ unsigned int count,
+ bool sort)
+{
+ struct xfs_mount *mp = tp->t_mountp;
+
+ if (sort)
+ list_sort(mp, items, xfs_rtrmap_update_diff_items);
+ return NULL;
+}
+
+/* Cancel a deferred realtime rmap update. */
+STATIC void
+xfs_rtrmap_update_cancel_item(
+ struct list_head *item)
+{
+ struct xfs_rmap_intent *ri = ri_entry(item);
+
+ xfs_rtgroup_put(ri->ri_rtg);
+ kmem_cache_free(xfs_rmap_intent_cache, ri);
+}
+
+/* Process a deferred realtime rmap update. */
+STATIC int
+xfs_rtrmap_update_finish_item(
+ struct xfs_trans *tp,
+ struct xfs_log_item *done,
+ struct list_head *item,
+ struct xfs_btree_cur **state)
+{
+ struct xfs_rmap_intent *ri = ri_entry(item);
+ int error;
+
+ error = xfs_rtrmap_finish_one(tp, ri, state);
+
+ xfs_rtrmap_update_cancel_item(item);
+ return error;
+}
+
+/* Clean up after calling xfs_rtrmap_finish_one. */
+STATIC void
+xfs_rtrmap_finish_one_cleanup(
+ struct xfs_trans *tp,
+ struct xfs_btree_cur *rcur,
+ int error)
+{
+ if (rcur)
+ xfs_btree_del_cursor(rcur, error);
+}
+
+const struct xfs_defer_op_type xfs_rtrmap_update_defer_type = {
+ .name = "rtrmap",
+ .create_intent = xfs_rtrmap_update_create_intent,
+ .abort_intent = xfs_rmap_update_abort_intent,
+ .create_done = xfs_rmap_update_create_done,
+ .finish_item = xfs_rtrmap_update_finish_item,
+ .finish_cleanup = xfs_rtrmap_finish_one_cleanup,
+ .cancel_item = xfs_rtrmap_update_cancel_item,
+};
+
/* Reference Counting */
/* Sort refcount intents by AG. */
diff --git a/libxfs/xfs_defer.h b/libxfs/xfs_defer.h
index b4e1c386768..fddcb4cccbc 100644
--- a/libxfs/xfs_defer.h
+++ b/libxfs/xfs_defer.h
@@ -69,6 +69,7 @@ struct xfs_defer_op_type {
extern const struct xfs_defer_op_type xfs_bmap_update_defer_type;
extern const struct xfs_defer_op_type xfs_refcount_update_defer_type;
extern const struct xfs_defer_op_type xfs_rmap_update_defer_type;
+extern const struct xfs_defer_op_type xfs_rtrmap_update_defer_type;
extern const struct xfs_defer_op_type xfs_extent_free_defer_type;
extern const struct xfs_defer_op_type xfs_agfl_free_defer_type;
extern const struct xfs_defer_op_type xfs_rtextent_free_defer_type;
diff --git a/libxfs/xfs_log_format.h b/libxfs/xfs_log_format.h
index 1f5fe4a588e..ea4e88d6657 100644
--- a/libxfs/xfs_log_format.h
+++ b/libxfs/xfs_log_format.h
@@ -250,6 +250,8 @@ typedef struct xfs_trans_header {
#define XFS_LI_SXD 0x1249 /* extent swap done */
#define XFS_LI_EFI_RT 0x124a /* realtime extent free intent */
#define XFS_LI_EFD_RT 0x124b /* realtime extent free done */
+#define XFS_LI_RUI_RT 0x124c /* realtime rmap update intent */
+#define XFS_LI_RUD_RT 0x124d /* realtime rmap update done */
#define XFS_LI_TYPE_DESC \
{ XFS_LI_EFI, "XFS_LI_EFI" }, \
@@ -271,7 +273,9 @@ typedef struct xfs_trans_header {
{ XFS_LI_SXI, "XFS_LI_SXI" }, \
{ XFS_LI_SXD, "XFS_LI_SXD" }, \
{ XFS_LI_EFI_RT, "XFS_LI_EFI_RT" }, \
- { XFS_LI_EFD_RT, "XFS_LI_EFD_RT" }
+ { XFS_LI_EFD_RT, "XFS_LI_EFD_RT" }, \
+ { XFS_LI_RUI_RT, "XFS_LI_RUI_RT" }, \
+ { XFS_LI_RUD_RT, "XFS_LI_RUD_RT" }
/*
* Inode Log Item Format definitions.
diff --git a/libxfs/xfs_refcount.c b/libxfs/xfs_refcount.c
index 9f933d953b9..0e8daab9986 100644
--- a/libxfs/xfs_refcount.c
+++ b/libxfs/xfs_refcount.c
@@ -1886,7 +1886,7 @@ xfs_refcount_alloc_cow_extent(
__xfs_refcount_add(tp, XFS_REFCOUNT_ALLOC_COW, fsb, len);
/* Add rmap entry */
- xfs_rmap_alloc_extent(tp, fsb, len, XFS_RMAP_OWN_COW);
+ xfs_rmap_alloc_extent(tp, false, fsb, len, XFS_RMAP_OWN_COW);
}
/* Forget a CoW staging event in the refcount btree. */
@@ -1902,7 +1902,7 @@ xfs_refcount_free_cow_extent(
return;
/* Remove rmap entry */
- xfs_rmap_free_extent(tp, fsb, len, XFS_RMAP_OWN_COW);
+ xfs_rmap_free_extent(tp, false, fsb, len, XFS_RMAP_OWN_COW);
__xfs_refcount_add(tp, XFS_REFCOUNT_FREE_COW, fsb, len);
}
diff --git a/libxfs/xfs_rmap.c b/libxfs/xfs_rmap.c
index 007f17cc644..00544d6a20f 100644
--- a/libxfs/xfs_rmap.c
+++ b/libxfs/xfs_rmap.c
@@ -2681,6 +2681,21 @@ xfs_rmap_finish_one(
return 0;
}
+/*
+ * Process one of the deferred realtime rmap operations. We pass back the
+ * btree cursor to reduce overhead.
+ */
+int
+xfs_rtrmap_finish_one(
+ struct xfs_trans *tp,
+ struct xfs_rmap_intent *ri,
+ struct xfs_btree_cur **pcur)
+{
+ /* coming in a subsequent patch */
+ ASSERT(0);
+ return -EFSCORRUPTED;
+}
+
/*
* Don't defer an rmap if we aren't an rmap filesystem.
*/
@@ -2701,6 +2716,7 @@ __xfs_rmap_add(
struct xfs_trans *tp,
enum xfs_rmap_intent_type type,
uint64_t owner,
+ bool isrt,
int whichfork,
struct xfs_bmbt_irec *bmap)
{
@@ -2712,6 +2728,7 @@ __xfs_rmap_add(
ri->ri_owner = owner;
ri->ri_whichfork = whichfork;
ri->ri_bmap = *bmap;
+ ri->ri_realtime = isrt;
xfs_rmap_defer_add(tp, ri);
}
@@ -2725,6 +2742,7 @@ xfs_rmap_map_extent(
struct xfs_bmbt_irec *PREV)
{
enum xfs_rmap_intent_type type = XFS_RMAP_MAP;
+ bool isrt = xfs_ifork_is_realtime(ip, whichfork);
if (!xfs_rmap_update_is_needed(tp->t_mountp, whichfork))
return;
@@ -2732,7 +2750,7 @@ xfs_rmap_map_extent(
if (whichfork != XFS_ATTR_FORK && xfs_is_reflink_inode(ip))
type = XFS_RMAP_MAP_SHARED;
- __xfs_rmap_add(tp, type, ip->i_ino, whichfork, PREV);
+ __xfs_rmap_add(tp, type, ip->i_ino, isrt, whichfork, PREV);
}
/* Unmap an extent out of a file. */
@@ -2744,6 +2762,7 @@ xfs_rmap_unmap_extent(
struct xfs_bmbt_irec *PREV)
{
enum xfs_rmap_intent_type type = XFS_RMAP_UNMAP;
+ bool isrt = xfs_ifork_is_realtime(ip, whichfork);
if (!xfs_rmap_update_is_needed(tp->t_mountp, whichfork))
return;
@@ -2751,7 +2770,7 @@ xfs_rmap_unmap_extent(
if (whichfork != XFS_ATTR_FORK && xfs_is_reflink_inode(ip))
type = XFS_RMAP_UNMAP_SHARED;
- __xfs_rmap_add(tp, type, ip->i_ino, whichfork, PREV);
+ __xfs_rmap_add(tp, type, ip->i_ino, isrt, whichfork, PREV);
}
/*
@@ -2769,6 +2788,7 @@ xfs_rmap_convert_extent(
struct xfs_bmbt_irec *PREV)
{
enum xfs_rmap_intent_type type = XFS_RMAP_CONVERT;
+ bool isrt = xfs_ifork_is_realtime(ip, whichfork);
if (!xfs_rmap_update_is_needed(mp, whichfork))
return;
@@ -2776,13 +2796,14 @@ xfs_rmap_convert_extent(
if (whichfork != XFS_ATTR_FORK && xfs_is_reflink_inode(ip))
type = XFS_RMAP_CONVERT_SHARED;
- __xfs_rmap_add(tp, type, ip->i_ino, whichfork, PREV);
+ __xfs_rmap_add(tp, type, ip->i_ino, isrt, whichfork, PREV);
}
/* Schedule the creation of an rmap for non-file data. */
void
xfs_rmap_alloc_extent(
struct xfs_trans *tp,
+ bool isrt,
xfs_fsblock_t fsbno,
xfs_extlen_t len,
uint64_t owner)
@@ -2797,13 +2818,14 @@ xfs_rmap_alloc_extent(
bmap.br_startoff = 0;
bmap.br_state = XFS_EXT_NORM;
- __xfs_rmap_add(tp, XFS_RMAP_ALLOC, owner, XFS_DATA_FORK, &bmap);
+ __xfs_rmap_add(tp, XFS_RMAP_ALLOC, owner, isrt, XFS_DATA_FORK, &bmap);
}
/* Schedule the deletion of an rmap for non-file data. */
void
xfs_rmap_free_extent(
struct xfs_trans *tp,
+ bool isrt,
xfs_fsblock_t fsbno,
xfs_extlen_t len,
uint64_t owner)
@@ -2818,7 +2840,7 @@ xfs_rmap_free_extent(
bmap.br_startoff = 0;
bmap.br_state = XFS_EXT_NORM;
- __xfs_rmap_add(tp, XFS_RMAP_FREE, owner, XFS_DATA_FORK, &bmap);
+ __xfs_rmap_add(tp, XFS_RMAP_FREE, owner, isrt, XFS_DATA_FORK, &bmap);
}
/* Compare rmap records. Returns -1 if a < b, 1 if a > b, and 0 if equal. */
diff --git a/libxfs/xfs_rmap.h b/libxfs/xfs_rmap.h
index 762f2f40b6e..3719fc4cbc2 100644
--- a/libxfs/xfs_rmap.h
+++ b/libxfs/xfs_rmap.h
@@ -174,7 +174,11 @@ struct xfs_rmap_intent {
int ri_whichfork;
uint64_t ri_owner;
struct xfs_bmbt_irec ri_bmap;
- struct xfs_perag *ri_pag;
+ union {
+ struct xfs_perag *ri_pag;
+ struct xfs_rtgroup *ri_rtg;
+ };
+ bool ri_realtime;
};
/* functions for updating the rmapbt based on bmbt map/unmap operations */
@@ -185,11 +189,13 @@ void xfs_rmap_unmap_extent(struct xfs_trans *tp, struct xfs_inode *ip,
void xfs_rmap_convert_extent(struct xfs_mount *mp, struct xfs_trans *tp,
struct xfs_inode *ip, int whichfork,
struct xfs_bmbt_irec *imap);
-void xfs_rmap_alloc_extent(struct xfs_trans *tp, xfs_fsblock_t fsbno,
+void xfs_rmap_alloc_extent(struct xfs_trans *tp, bool isrt, xfs_fsblock_t fsbno,
xfs_extlen_t len, uint64_t owner);
-void xfs_rmap_free_extent(struct xfs_trans *tp, xfs_fsblock_t fsbno,
+void xfs_rmap_free_extent(struct xfs_trans *tp, bool isrt, xfs_fsblock_t fsbno,
xfs_extlen_t len, uint64_t owner);
+int xfs_rtrmap_finish_one(struct xfs_trans *tp, struct xfs_rmap_intent *ri,
+ struct xfs_btree_cur **pcur);
int xfs_rmap_finish_one(struct xfs_trans *tp, struct xfs_rmap_intent *ri,
struct xfs_btree_cur **pcur);
int __xfs_rmap_finish_intent(struct xfs_btree_cur *rcur,
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 08/47] xfs: add realtime reverse map inode to metadata directory
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (6 preceding siblings ...)
2023-12-27 13:12 ` [PATCH 07/47] xfs: add a realtime flag to the rmap update log redo items Darrick J. Wong
@ 2023-12-27 13:12 ` Darrick J. Wong
2023-12-27 13:12 ` [PATCH 09/47] xfs: add metadata reservations for realtime rmap btrees Darrick J. Wong
` (38 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:12 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Add a metadir path to select the realtime rmap btree inode and load
it at mount time. The rtrmapbt inode will have a unique extent format
code, which means that we also have to update the inode validation and
flush routines to look for it.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/init.c | 8 ++++++++
libxfs/xfs_format.h | 6 ++++--
libxfs/xfs_inode_buf.c | 10 ++++++++++
libxfs/xfs_inode_fork.c | 9 +++++++++
libxfs/xfs_rtgroup.h | 3 +++
libxfs/xfs_rtrmap_btree.c | 33 +++++++++++++++++++++++++++++++++
libxfs/xfs_rtrmap_btree.h | 4 ++++
7 files changed, 71 insertions(+), 2 deletions(-)
diff --git a/libxfs/init.c b/libxfs/init.c
index 9a4dfe02945..ba0b9a87f2d 100644
--- a/libxfs/init.c
+++ b/libxfs/init.c
@@ -969,6 +969,14 @@ libxfs_mount(
void
libxfs_rtmount_destroy(xfs_mount_t *mp)
{
+ struct xfs_rtgroup *rtg;
+ xfs_rgnumber_t rgno;
+
+ for_each_rtgroup(mp, rgno, rtg) {
+ if (rtg->rtg_rmapip)
+ libxfs_imeta_irele(rtg->rtg_rmapip);
+ rtg->rtg_rmapip = NULL;
+ }
if (mp->m_rsumip)
libxfs_imeta_irele(mp->m_rsumip);
if (mp->m_rbmip)
diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
index 5317c6438f0..d374240fc58 100644
--- a/libxfs/xfs_format.h
+++ b/libxfs/xfs_format.h
@@ -1026,7 +1026,8 @@ enum xfs_dinode_fmt {
XFS_DINODE_FMT_LOCAL, /* bulk data */
XFS_DINODE_FMT_EXTENTS, /* struct xfs_bmbt_rec */
XFS_DINODE_FMT_BTREE, /* struct xfs_bmdr_block */
- XFS_DINODE_FMT_UUID /* added long ago, but never used */
+ XFS_DINODE_FMT_UUID, /* added long ago, but never used */
+ XFS_DINODE_FMT_RMAP, /* reverse mapping btree */
};
#define XFS_INODE_FORMAT_STR \
@@ -1034,7 +1035,8 @@ enum xfs_dinode_fmt {
{ XFS_DINODE_FMT_LOCAL, "local" }, \
{ XFS_DINODE_FMT_EXTENTS, "extent" }, \
{ XFS_DINODE_FMT_BTREE, "btree" }, \
- { XFS_DINODE_FMT_UUID, "uuid" }
+ { XFS_DINODE_FMT_UUID, "uuid" }, \
+ { XFS_DINODE_FMT_RMAP, "rmap" }
/*
* Max values for extnum and aextnum.
diff --git a/libxfs/xfs_inode_buf.c b/libxfs/xfs_inode_buf.c
index 8d100595756..9755ae33813 100644
--- a/libxfs/xfs_inode_buf.c
+++ b/libxfs/xfs_inode_buf.c
@@ -408,6 +408,12 @@ xfs_dinode_verify_fork(
if (di_nextents > max_extents)
return __this_address;
break;
+ case XFS_DINODE_FMT_RMAP:
+ if (!xfs_has_rtrmapbt(mp))
+ return __this_address;
+ if (!(dip->di_flags2 & cpu_to_be64(XFS_DIFLAG2_METADIR)))
+ return __this_address;
+ break;
default:
return __this_address;
}
@@ -427,6 +433,10 @@ xfs_dinode_verify_forkoff(
if (dip->di_forkoff != (roundup(sizeof(xfs_dev_t), 8) >> 3))
return __this_address;
break;
+ case XFS_DINODE_FMT_RMAP:
+ if (!(xfs_has_metadir(mp) && xfs_has_parent(mp)))
+ return __this_address;
+ fallthrough;
case XFS_DINODE_FMT_LOCAL: /* fall through ... */
case XFS_DINODE_FMT_EXTENTS: /* fall through ... */
case XFS_DINODE_FMT_BTREE:
diff --git a/libxfs/xfs_inode_fork.c b/libxfs/xfs_inode_fork.c
index ec3a399e798..2e8f84e57a4 100644
--- a/libxfs/xfs_inode_fork.c
+++ b/libxfs/xfs_inode_fork.c
@@ -262,6 +262,11 @@ xfs_iformat_data_fork(
return xfs_iformat_extents(ip, dip, XFS_DATA_FORK);
case XFS_DINODE_FMT_BTREE:
return xfs_iformat_btree(ip, dip, XFS_DATA_FORK);
+ case XFS_DINODE_FMT_RMAP:
+ if (!xfs_has_rtrmapbt(ip->i_mount))
+ return -EFSCORRUPTED;
+ ASSERT(0); /* to be implemented later */
+ return -EFSCORRUPTED;
default:
xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__,
dip, sizeof(*dip), __this_address);
@@ -651,6 +656,10 @@ xfs_iflush_fork(
}
break;
+ case XFS_DINODE_FMT_RMAP:
+ ASSERT(0); /* to be implemented later */
+ break;
+
default:
ASSERT(0);
break;
diff --git a/libxfs/xfs_rtgroup.h b/libxfs/xfs_rtgroup.h
index 0a63f14b5aa..77503bda355 100644
--- a/libxfs/xfs_rtgroup.h
+++ b/libxfs/xfs_rtgroup.h
@@ -22,6 +22,9 @@ struct xfs_rtgroup {
/* for rcu-safe freeing */
struct rcu_head rcu_head;
+ /* reverse mapping btree inode */
+ struct xfs_inode *rtg_rmapip;
+
/* Number of blocks in this group */
xfs_rgblock_t rtg_blockcount;
diff --git a/libxfs/xfs_rtrmap_btree.c b/libxfs/xfs_rtrmap_btree.c
index a2cb497379f..d788ef60333 100644
--- a/libxfs/xfs_rtrmap_btree.c
+++ b/libxfs/xfs_rtrmap_btree.c
@@ -24,6 +24,7 @@
#include "xfs_cksum.h"
#include "xfs_rtgroup.h"
#include "xfs_bmap.h"
+#include "xfs_imeta.h"
static struct kmem_cache *xfs_rtrmapbt_cur_cache;
@@ -474,6 +475,7 @@ xfs_rtrmapbt_commit_staged_btree(
int flags = XFS_ILOG_CORE | XFS_ILOG_DBROOT;
ASSERT(cur->bc_flags & XFS_BTREE_STAGING);
+ ASSERT(ifake->if_fork->if_format == XFS_DINODE_FMT_RMAP);
/*
* Free any resources hanging off the real fork, then shallow-copy the
@@ -574,3 +576,34 @@ xfs_rtrmapbt_compute_maxlevels(
/* Add one level to handle the inode root level. */
mp->m_rtrmap_maxlevels = min(d_maxlevels, r_maxlevels) + 1;
}
+
+#define XFS_RTRMAP_NAMELEN 17
+
+/* Create the metadata directory path for an rtrmap btree inode. */
+int
+xfs_rtrmapbt_create_path(
+ struct xfs_mount *mp,
+ xfs_rgnumber_t rgno,
+ struct xfs_imeta_path **pathp)
+{
+ struct xfs_imeta_path *path;
+ unsigned char *fname;
+ int error;
+
+ error = xfs_imeta_create_file_path(mp, 2, &path);
+ if (error)
+ return error;
+
+ fname = kmalloc(XFS_RTRMAP_NAMELEN, GFP_KERNEL);
+ if (!fname) {
+ xfs_imeta_free_path(path);
+ return -ENOMEM;
+ }
+
+ snprintf(fname, XFS_RTRMAP_NAMELEN, "%u.rmap", rgno);
+ path->im_path[0] = "realtime";
+ path->im_path[1] = fname;
+ path->im_dynamicmask = 0x2;
+ *pathp = path;
+ return 0;
+}
diff --git a/libxfs/xfs_rtrmap_btree.h b/libxfs/xfs_rtrmap_btree.h
index 0f732679719..29b69866018 100644
--- a/libxfs/xfs_rtrmap_btree.h
+++ b/libxfs/xfs_rtrmap_btree.h
@@ -11,6 +11,7 @@ struct xfs_btree_cur;
struct xfs_mount;
struct xbtree_ifakeroot;
struct xfs_rtgroup;
+struct xfs_imeta_path;
/* rmaps only exist on crc enabled filesystems */
#define XFS_RTRMAP_BLOCK_LEN XFS_BTREE_LBLOCK_CRC_LEN
@@ -80,4 +81,7 @@ unsigned int xfs_rtrmapbt_maxlevels_ondisk(void);
int __init xfs_rtrmapbt_init_cur_cache(void);
void xfs_rtrmapbt_destroy_cur_cache(void);
+int xfs_rtrmapbt_create_path(struct xfs_mount *mp, xfs_rgnumber_t rgno,
+ struct xfs_imeta_path **pathp);
+
#endif /* __XFS_RTRMAP_BTREE_H__ */
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 09/47] xfs: add metadata reservations for realtime rmap btrees
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (7 preceding siblings ...)
2023-12-27 13:12 ` [PATCH 08/47] xfs: add realtime reverse map inode to metadata directory Darrick J. Wong
@ 2023-12-27 13:12 ` Darrick J. Wong
2023-12-27 13:13 ` [PATCH 10/47] xfs: wire up a new inode fork type for the realtime rmap Darrick J. Wong
` (37 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:12 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Reserve some free blocks so that we will always have enough free blocks
in the data volume to handle expansion of the realtime rmap btree.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_rtrmap_btree.c | 39 +++++++++++++++++++++++++++++++++++++++
libxfs/xfs_rtrmap_btree.h | 2 ++
2 files changed, 41 insertions(+)
diff --git a/libxfs/xfs_rtrmap_btree.c b/libxfs/xfs_rtrmap_btree.c
index d788ef60333..cb24c2f7351 100644
--- a/libxfs/xfs_rtrmap_btree.c
+++ b/libxfs/xfs_rtrmap_btree.c
@@ -607,3 +607,42 @@ xfs_rtrmapbt_create_path(
*pathp = path;
return 0;
}
+
+/* Calculate the rtrmap btree size for some records. */
+static unsigned long long
+xfs_rtrmapbt_calc_size(
+ struct xfs_mount *mp,
+ unsigned long long len)
+{
+ return xfs_btree_calc_size(mp->m_rtrmap_mnr, len);
+}
+
+/*
+ * Calculate the maximum rmap btree size.
+ */
+static unsigned long long
+xfs_rtrmapbt_max_size(
+ struct xfs_mount *mp,
+ xfs_rtblock_t rtblocks)
+{
+ /* Bail out if we're uninitialized, which can happen in mkfs. */
+ if (mp->m_rtrmap_mxr[0] == 0)
+ return 0;
+
+ return xfs_rtrmapbt_calc_size(mp, rtblocks);
+}
+
+/*
+ * Figure out how many blocks to reserve and how many are used by this btree.
+ */
+xfs_filblks_t
+xfs_rtrmapbt_calc_reserves(
+ struct xfs_mount *mp)
+{
+ if (!xfs_has_rtrmapbt(mp))
+ return 0;
+
+ /* 1/64th (~1.5%) of the space, and enough for 1 record per block. */
+ return max_t(xfs_filblks_t, mp->m_sb.sb_rgblocks >> 6,
+ xfs_rtrmapbt_max_size(mp, mp->m_sb.sb_rgblocks));
+}
diff --git a/libxfs/xfs_rtrmap_btree.h b/libxfs/xfs_rtrmap_btree.h
index 29b69866018..b7950e6d45d 100644
--- a/libxfs/xfs_rtrmap_btree.h
+++ b/libxfs/xfs_rtrmap_btree.h
@@ -84,4 +84,6 @@ void xfs_rtrmapbt_destroy_cur_cache(void);
int xfs_rtrmapbt_create_path(struct xfs_mount *mp, xfs_rgnumber_t rgno,
struct xfs_imeta_path **pathp);
+xfs_filblks_t xfs_rtrmapbt_calc_reserves(struct xfs_mount *mp);
+
#endif /* __XFS_RTRMAP_BTREE_H__ */
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 10/47] xfs: wire up a new inode fork type for the realtime rmap
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (8 preceding siblings ...)
2023-12-27 13:12 ` [PATCH 09/47] xfs: add metadata reservations for realtime rmap btrees Darrick J. Wong
@ 2023-12-27 13:13 ` Darrick J. Wong
2023-12-27 13:13 ` [PATCH 11/47] xfs: allow inodes with zero extents but nonzero nblocks Darrick J. Wong
` (36 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:13 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Plumb in the pieces we need to embed the root of the realtime rmap
btree in an inode's data fork, complete with new fork type and
on-disk interpretation functions.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_format.h | 8 ++
libxfs/xfs_inode_fork.c | 8 +-
libxfs/xfs_ondisk.h | 1
libxfs/xfs_rtrmap_btree.c | 220 +++++++++++++++++++++++++++++++++++++++++++++
libxfs/xfs_rtrmap_btree.h | 112 +++++++++++++++++++++++
5 files changed, 346 insertions(+), 3 deletions(-)
diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
index d374240fc58..1c1910256a9 100644
--- a/libxfs/xfs_format.h
+++ b/libxfs/xfs_format.h
@@ -1755,6 +1755,14 @@ typedef __be32 xfs_rmap_ptr_t;
*/
#define XFS_RTRMAP_CRC_MAGIC 0x4d415052 /* 'MAPR' */
+/*
+ * rtrmap root header, on-disk form only.
+ */
+struct xfs_rtrmap_root {
+ __be16 bb_level; /* 0 is a leaf */
+ __be16 bb_numrecs; /* current # of data records */
+};
+
/* inode-based btree pointer type */
typedef __be64 xfs_rtrmap_ptr_t;
diff --git a/libxfs/xfs_inode_fork.c b/libxfs/xfs_inode_fork.c
index 2e8f84e57a4..0e6cd5bacdb 100644
--- a/libxfs/xfs_inode_fork.c
+++ b/libxfs/xfs_inode_fork.c
@@ -25,6 +25,7 @@
#include "xfs_errortag.h"
#include "xfs_health.h"
#include "xfs_symlink_remote.h"
+#include "xfs_rtrmap_btree.h"
struct kmem_cache *xfs_ifork_cache;
@@ -265,8 +266,7 @@ xfs_iformat_data_fork(
case XFS_DINODE_FMT_RMAP:
if (!xfs_has_rtrmapbt(ip->i_mount))
return -EFSCORRUPTED;
- ASSERT(0); /* to be implemented later */
- return -EFSCORRUPTED;
+ return xfs_iformat_rtrmap(ip, dip);
default:
xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__,
dip, sizeof(*dip), __this_address);
@@ -657,7 +657,9 @@ xfs_iflush_fork(
break;
case XFS_DINODE_FMT_RMAP:
- ASSERT(0); /* to be implemented later */
+ ASSERT(whichfork == XFS_DATA_FORK);
+ if (iip->ili_fields & brootflag[whichfork])
+ xfs_iflush_rtrmap(ip, dip);
break;
default:
diff --git a/libxfs/xfs_ondisk.h b/libxfs/xfs_ondisk.h
index 897a1b72f8d..102a3574fc6 100644
--- a/libxfs/xfs_ondisk.h
+++ b/libxfs/xfs_ondisk.h
@@ -78,6 +78,7 @@ xfs_check_ondisk_structs(void)
XFS_CHECK_STRUCT_SIZE(union xfs_suminfo_raw, 4);
XFS_CHECK_STRUCT_SIZE(struct xfs_rtbuf_blkinfo, 48);
XFS_CHECK_STRUCT_SIZE(xfs_rtrmap_ptr_t, 8);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_rtrmap_root, 4);
/*
* m68k has problems with xfs_attr_leaf_name_remote_t, but we pad it to
diff --git a/libxfs/xfs_rtrmap_btree.c b/libxfs/xfs_rtrmap_btree.c
index cb24c2f7351..921bf7e1b11 100644
--- a/libxfs/xfs_rtrmap_btree.c
+++ b/libxfs/xfs_rtrmap_btree.c
@@ -83,6 +83,39 @@ xfs_rtrmapbt_get_maxrecs(
return cur->bc_mp->m_rtrmap_mxr[level != 0];
}
+/* Calculate number of records in the ondisk realtime rmap btree inode root. */
+unsigned int
+xfs_rtrmapbt_droot_maxrecs(
+ unsigned int blocklen,
+ bool leaf)
+{
+ blocklen -= sizeof(struct xfs_rtrmap_root);
+
+ if (leaf)
+ return blocklen / sizeof(struct xfs_rmap_rec);
+ return blocklen / (2 * sizeof(struct xfs_rmap_key) +
+ sizeof(xfs_rtrmap_ptr_t));
+}
+
+/*
+ * Get the maximum records we could store in the on-disk format.
+ *
+ * For non-root nodes this is equivalent to xfs_rtrmapbt_get_maxrecs, but
+ * for the root node this checks the available space in the dinode fork
+ * so that we can resize the in-memory buffer to match it. After a
+ * resize to the maximum size this function returns the same value
+ * as xfs_rtrmapbt_get_maxrecs for the root node, too.
+ */
+STATIC int
+xfs_rtrmapbt_get_dmaxrecs(
+ struct xfs_btree_cur *cur,
+ int level)
+{
+ if (level != cur->bc_nlevels - 1)
+ return cur->bc_mp->m_rtrmap_mxr[level != 0];
+ return xfs_rtrmapbt_droot_maxrecs(cur->bc_ino.forksize, level == 0);
+}
+
/*
* Convert the ondisk record's offset field into the ondisk key's offset field.
* Fork and bmbt are significant parts of the rmap record key, but written
@@ -375,6 +408,64 @@ xfs_rtrmapbt_keys_contiguous(
be32_to_cpu(key2->rmap.rm_startblock));
}
+/* Move the rtrmap btree root from one incore buffer to another. */
+static void
+xfs_rtrmapbt_broot_move(
+ struct xfs_inode *ip,
+ int whichfork,
+ struct xfs_btree_block *dst_broot,
+ size_t dst_bytes,
+ struct xfs_btree_block *src_broot,
+ size_t src_bytes,
+ unsigned int level,
+ unsigned int numrecs)
+{
+ struct xfs_mount *mp = ip->i_mount;
+ void *dptr;
+ void *sptr;
+
+ ASSERT(xfs_rtrmap_droot_space(src_broot) <=
+ xfs_inode_fork_size(ip, whichfork));
+
+ /*
+ * We always have to move the pointers because they are not butted
+ * against the btree block header.
+ */
+ if (numrecs && level > 0) {
+ sptr = xfs_rtrmap_broot_ptr_addr(mp, src_broot, 1, src_bytes);
+ dptr = xfs_rtrmap_broot_ptr_addr(mp, dst_broot, 1, dst_bytes);
+ memmove(dptr, sptr, numrecs * sizeof(xfs_fsblock_t));
+ }
+
+ if (src_broot == dst_broot)
+ return;
+
+ /*
+ * If the root is being totally relocated, we have to migrate the block
+ * header and the keys/records that come after it.
+ */
+ memcpy(dst_broot, src_broot, XFS_RTRMAP_BLOCK_LEN);
+
+ if (!numrecs)
+ return;
+
+ if (level == 0) {
+ sptr = xfs_rtrmap_rec_addr(src_broot, 1);
+ dptr = xfs_rtrmap_rec_addr(dst_broot, 1);
+ memcpy(dptr, sptr, numrecs * sizeof(struct xfs_rmap_rec));
+ } else {
+ sptr = xfs_rtrmap_key_addr(src_broot, 1);
+ dptr = xfs_rtrmap_key_addr(dst_broot, 1);
+ memcpy(dptr, sptr, numrecs * 2 * sizeof(struct xfs_rmap_key));
+ }
+}
+
+static const struct xfs_ifork_broot_ops xfs_rtrmapbt_iroot_ops = {
+ .maxrecs = xfs_rtrmapbt_maxrecs,
+ .size = xfs_rtrmap_broot_space_calc,
+ .move = xfs_rtrmapbt_broot_move,
+};
+
const struct xfs_btree_ops xfs_rtrmapbt_ops = {
.rec_len = sizeof(struct xfs_rmap_rec),
.key_len = 2 * sizeof(struct xfs_rmap_key),
@@ -388,6 +479,7 @@ const struct xfs_btree_ops xfs_rtrmapbt_ops = {
.free_block = xfs_btree_free_imeta_block,
.get_minrecs = xfs_rtrmapbt_get_minrecs,
.get_maxrecs = xfs_rtrmapbt_get_maxrecs,
+ .get_dmaxrecs = xfs_rtrmapbt_get_dmaxrecs,
.init_key_from_rec = xfs_rtrmapbt_init_key_from_rec,
.init_high_key_from_rec = xfs_rtrmapbt_init_high_key_from_rec,
.init_rec_from_cur = xfs_rtrmapbt_init_rec_from_cur,
@@ -398,6 +490,7 @@ const struct xfs_btree_ops xfs_rtrmapbt_ops = {
.keys_inorder = xfs_rtrmapbt_keys_inorder,
.recs_inorder = xfs_rtrmapbt_recs_inorder,
.keys_contiguous = xfs_rtrmapbt_keys_contiguous,
+ .iroot_ops = &xfs_rtrmapbt_iroot_ops,
};
/* Initialize a new rt rmap btree cursor. */
@@ -646,3 +739,130 @@ xfs_rtrmapbt_calc_reserves(
return max_t(xfs_filblks_t, mp->m_sb.sb_rgblocks >> 6,
xfs_rtrmapbt_max_size(mp, mp->m_sb.sb_rgblocks));
}
+
+/* Convert on-disk form of btree root to in-memory form. */
+STATIC void
+xfs_rtrmapbt_from_disk(
+ struct xfs_inode *ip,
+ struct xfs_rtrmap_root *dblock,
+ unsigned int dblocklen,
+ struct xfs_btree_block *rblock)
+{
+ struct xfs_mount *mp = ip->i_mount;
+ struct xfs_rmap_key *fkp;
+ __be64 *fpp;
+ struct xfs_rmap_key *tkp;
+ __be64 *tpp;
+ struct xfs_rmap_rec *frp;
+ struct xfs_rmap_rec *trp;
+ unsigned int rblocklen = xfs_rtrmap_broot_space(mp, dblock);
+ unsigned int numrecs;
+ unsigned int maxrecs;
+
+ xfs_btree_init_block(mp, rblock, &xfs_rtrmapbt_ops, 0, 0, ip->i_ino);
+
+ rblock->bb_level = dblock->bb_level;
+ rblock->bb_numrecs = dblock->bb_numrecs;
+ numrecs = be16_to_cpu(dblock->bb_numrecs);
+
+ if (be16_to_cpu(rblock->bb_level) > 0) {
+ maxrecs = xfs_rtrmapbt_droot_maxrecs(dblocklen, false);
+ fkp = xfs_rtrmap_droot_key_addr(dblock, 1);
+ tkp = xfs_rtrmap_key_addr(rblock, 1);
+ fpp = xfs_rtrmap_droot_ptr_addr(dblock, 1, maxrecs);
+ tpp = xfs_rtrmap_broot_ptr_addr(mp, rblock, 1, rblocklen);
+ memcpy(tkp, fkp, 2 * sizeof(*fkp) * numrecs);
+ memcpy(tpp, fpp, sizeof(*fpp) * numrecs);
+ } else {
+ frp = xfs_rtrmap_droot_rec_addr(dblock, 1);
+ trp = xfs_rtrmap_rec_addr(rblock, 1);
+ memcpy(trp, frp, sizeof(*frp) * numrecs);
+ }
+}
+
+/* Load a realtime reverse mapping btree root in from disk. */
+int
+xfs_iformat_rtrmap(
+ struct xfs_inode *ip,
+ struct xfs_dinode *dip)
+{
+ struct xfs_mount *mp = ip->i_mount;
+ struct xfs_ifork *ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK);
+ struct xfs_rtrmap_root *dfp = XFS_DFORK_PTR(dip, XFS_DATA_FORK);
+ unsigned int numrecs;
+ unsigned int level;
+ int dsize;
+
+ dsize = XFS_DFORK_SIZE(dip, mp, XFS_DATA_FORK);
+ numrecs = be16_to_cpu(dfp->bb_numrecs);
+ level = be16_to_cpu(dfp->bb_level);
+
+ if (level > mp->m_rtrmap_maxlevels ||
+ xfs_rtrmap_droot_space_calc(level, numrecs) > dsize)
+ return -EFSCORRUPTED;
+
+ xfs_iroot_alloc(ip, XFS_DATA_FORK,
+ xfs_rtrmap_broot_space_calc(mp, level, numrecs));
+ xfs_rtrmapbt_from_disk(ip, dfp, dsize, ifp->if_broot);
+ return 0;
+}
+
+/* Convert in-memory form of btree root to on-disk form. */
+void
+xfs_rtrmapbt_to_disk(
+ struct xfs_mount *mp,
+ struct xfs_btree_block *rblock,
+ unsigned int rblocklen,
+ struct xfs_rtrmap_root *dblock,
+ unsigned int dblocklen)
+{
+ struct xfs_rmap_key *fkp;
+ __be64 *fpp;
+ struct xfs_rmap_key *tkp;
+ __be64 *tpp;
+ struct xfs_rmap_rec *frp;
+ struct xfs_rmap_rec *trp;
+ unsigned int numrecs;
+ unsigned int maxrecs;
+
+ ASSERT(rblock->bb_magic == cpu_to_be32(XFS_RTRMAP_CRC_MAGIC));
+ ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid));
+ ASSERT(rblock->bb_u.l.bb_blkno == cpu_to_be64(XFS_BUF_DADDR_NULL));
+ ASSERT(rblock->bb_u.l.bb_leftsib == cpu_to_be64(NULLFSBLOCK));
+ ASSERT(rblock->bb_u.l.bb_rightsib == cpu_to_be64(NULLFSBLOCK));
+
+ dblock->bb_level = rblock->bb_level;
+ dblock->bb_numrecs = rblock->bb_numrecs;
+ numrecs = be16_to_cpu(rblock->bb_numrecs);
+
+ if (be16_to_cpu(rblock->bb_level) > 0) {
+ maxrecs = xfs_rtrmapbt_droot_maxrecs(dblocklen, false);
+ fkp = xfs_rtrmap_key_addr(rblock, 1);
+ tkp = xfs_rtrmap_droot_key_addr(dblock, 1);
+ fpp = xfs_rtrmap_broot_ptr_addr(mp, rblock, 1, rblocklen);
+ tpp = xfs_rtrmap_droot_ptr_addr(dblock, 1, maxrecs);
+ memcpy(tkp, fkp, 2 * sizeof(*fkp) * numrecs);
+ memcpy(tpp, fpp, sizeof(*fpp) * numrecs);
+ } else {
+ frp = xfs_rtrmap_rec_addr(rblock, 1);
+ trp = xfs_rtrmap_droot_rec_addr(dblock, 1);
+ memcpy(trp, frp, sizeof(*frp) * numrecs);
+ }
+}
+
+/* Flush a realtime reverse mapping btree root out to disk. */
+void
+xfs_iflush_rtrmap(
+ struct xfs_inode *ip,
+ struct xfs_dinode *dip)
+{
+ struct xfs_ifork *ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK);
+ struct xfs_rtrmap_root *dfp = XFS_DFORK_PTR(dip, XFS_DATA_FORK);
+
+ ASSERT(ifp->if_broot != NULL);
+ ASSERT(ifp->if_broot_bytes > 0);
+ ASSERT(xfs_rtrmap_droot_space(ifp->if_broot) <=
+ xfs_inode_fork_size(ip, XFS_DATA_FORK));
+ xfs_rtrmapbt_to_disk(ip->i_mount, ifp->if_broot, ifp->if_broot_bytes,
+ dfp, XFS_DFORK_SIZE(dip, ip->i_mount, XFS_DATA_FORK));
+}
diff --git a/libxfs/xfs_rtrmap_btree.h b/libxfs/xfs_rtrmap_btree.h
index b7950e6d45d..2b26a05f907 100644
--- a/libxfs/xfs_rtrmap_btree.h
+++ b/libxfs/xfs_rtrmap_btree.h
@@ -27,6 +27,7 @@ void xfs_rtrmapbt_commit_staged_btree(struct xfs_btree_cur *cur,
unsigned int xfs_rtrmapbt_maxrecs(struct xfs_mount *mp, unsigned int blocklen,
bool leaf);
void xfs_rtrmapbt_compute_maxlevels(struct xfs_mount *mp);
+unsigned int xfs_rtrmapbt_droot_maxrecs(unsigned int blocklen, bool leaf);
/*
* Addresses of records, keys, and pointers within an incore rtrmapbt block.
@@ -86,4 +87,115 @@ int xfs_rtrmapbt_create_path(struct xfs_mount *mp, xfs_rgnumber_t rgno,
xfs_filblks_t xfs_rtrmapbt_calc_reserves(struct xfs_mount *mp);
+/* Addresses of key, pointers, and records within an ondisk rtrmapbt block. */
+
+static inline struct xfs_rmap_rec *
+xfs_rtrmap_droot_rec_addr(
+ struct xfs_rtrmap_root *block,
+ unsigned int index)
+{
+ return (struct xfs_rmap_rec *)
+ ((char *)(block + 1) +
+ (index - 1) * sizeof(struct xfs_rmap_rec));
+}
+
+static inline struct xfs_rmap_key *
+xfs_rtrmap_droot_key_addr(
+ struct xfs_rtrmap_root *block,
+ unsigned int index)
+{
+ return (struct xfs_rmap_key *)
+ ((char *)(block + 1) +
+ (index - 1) * 2 * sizeof(struct xfs_rmap_key));
+}
+
+static inline xfs_rtrmap_ptr_t *
+xfs_rtrmap_droot_ptr_addr(
+ struct xfs_rtrmap_root *block,
+ unsigned int index,
+ unsigned int maxrecs)
+{
+ return (xfs_rtrmap_ptr_t *)
+ ((char *)(block + 1) +
+ maxrecs * 2 * sizeof(struct xfs_rmap_key) +
+ (index - 1) * sizeof(xfs_rtrmap_ptr_t));
+}
+
+/*
+ * Address of pointers within the incore btree root.
+ *
+ * These are to be used when we know the size of the block and
+ * we don't have a cursor.
+ */
+static inline xfs_rtrmap_ptr_t *
+xfs_rtrmap_broot_ptr_addr(
+ struct xfs_mount *mp,
+ struct xfs_btree_block *bb,
+ unsigned int index,
+ unsigned int block_size)
+{
+ return xfs_rtrmap_ptr_addr(bb, index,
+ xfs_rtrmapbt_maxrecs(mp, block_size, false));
+}
+
+/*
+ * Compute the space required for the incore btree root containing the given
+ * number of records.
+ */
+static inline size_t
+xfs_rtrmap_broot_space_calc(
+ struct xfs_mount *mp,
+ unsigned int level,
+ unsigned int nrecs)
+{
+ size_t sz = XFS_RTRMAP_BLOCK_LEN;
+
+ if (level > 0)
+ return sz + nrecs * (2 * sizeof(struct xfs_rmap_key) +
+ sizeof(xfs_rtrmap_ptr_t));
+ return sz + nrecs * sizeof(struct xfs_rmap_rec);
+}
+
+/*
+ * Compute the space required for the incore btree root given the ondisk
+ * btree root block.
+ */
+static inline size_t
+xfs_rtrmap_broot_space(struct xfs_mount *mp, struct xfs_rtrmap_root *bb)
+{
+ return xfs_rtrmap_broot_space_calc(mp, be16_to_cpu(bb->bb_level),
+ be16_to_cpu(bb->bb_numrecs));
+}
+
+/* Compute the space required for the ondisk root block. */
+static inline size_t
+xfs_rtrmap_droot_space_calc(
+ unsigned int level,
+ unsigned int nrecs)
+{
+ size_t sz = sizeof(struct xfs_rtrmap_root);
+
+ if (level > 0)
+ return sz + nrecs * (2 * sizeof(struct xfs_rmap_key) +
+ sizeof(xfs_rtrmap_ptr_t));
+ return sz + nrecs * sizeof(struct xfs_rmap_rec);
+}
+
+/*
+ * Compute the space required for the ondisk root block given an incore root
+ * block.
+ */
+static inline size_t
+xfs_rtrmap_droot_space(struct xfs_btree_block *bb)
+{
+ return xfs_rtrmap_droot_space_calc(be16_to_cpu(bb->bb_level),
+ be16_to_cpu(bb->bb_numrecs));
+}
+
+int xfs_iformat_rtrmap(struct xfs_inode *ip, struct xfs_dinode *dip);
+void xfs_rtrmapbt_to_disk(struct xfs_mount *mp, struct xfs_btree_block *rblock,
+ unsigned int rblocklen, struct xfs_rtrmap_root *dblock,
+ unsigned int dblocklen);
+void xfs_iflush_rtrmap(struct xfs_inode *ip, struct xfs_dinode *dip);
+
#endif /* __XFS_RTRMAP_BTREE_H__ */
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 11/47] xfs: allow inodes with zero extents but nonzero nblocks
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (9 preceding siblings ...)
2023-12-27 13:13 ` [PATCH 10/47] xfs: wire up a new inode fork type for the realtime rmap Darrick J. Wong
@ 2023-12-27 13:13 ` Darrick J. Wong
2023-12-27 13:13 ` [PATCH 12/47] xfs: use realtime EFI to free extents when realtime rmap is enabled Darrick J. Wong
` (35 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:13 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Metadata inodes that store btrees will have zero extents and a nonzero
nblocks. Adjust the inode verifier so that this combination is not
flagged.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_inode_buf.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/libxfs/xfs_inode_buf.c b/libxfs/xfs_inode_buf.c
index 9755ae33813..e7bf8ff7046 100644
--- a/libxfs/xfs_inode_buf.c
+++ b/libxfs/xfs_inode_buf.c
@@ -598,9 +598,6 @@ xfs_dinode_verify(
if (mode && nextents + naextents > nblocks)
return __this_address;
- if (nextents + naextents == 0 && nblocks != 0)
- return __this_address;
-
if (S_ISDIR(mode) && nextents > mp->m_dir_geo->max_extents)
return __this_address;
@@ -704,6 +701,19 @@ xfs_dinode_verify(
return fa;
}
+ /* metadata inodes containing btrees always have zero extent count */
+ if (flags2 & XFS_DIFLAG2_METADIR) {
+ switch (XFS_DFORK_FORMAT(dip, XFS_DATA_FORK)) {
+ case XFS_DINODE_FMT_RMAP:
+ break;
+ default:
+ if (nextents + naextents == 0 && nblocks != 0)
+ return __this_address;
+ break;
+ }
+ } else if (nextents + naextents == 0 && nblocks != 0)
+ return __this_address;
+
return NULL;
}
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 12/47] xfs: use realtime EFI to free extents when realtime rmap is enabled
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (10 preceding siblings ...)
2023-12-27 13:13 ` [PATCH 11/47] xfs: allow inodes with zero extents but nonzero nblocks Darrick J. Wong
@ 2023-12-27 13:13 ` Darrick J. Wong
2023-12-27 13:13 ` [PATCH 13/47] xfs: wire up rmap map and unmap to the realtime rmapbt Darrick J. Wong
` (34 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:13 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
When rmap is enabled, XFS expects a certain order of operations, which
is: 1) remove the file mapping, 2) remove the reverse mapping, and then
3) free the blocks. xfs_bmap_del_extent_real tries to do 1 and 3 in the
same transaction, which means that when rtrmap is enabled, we have to
use realtime EFIs to maintain the expected order.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_bmap.c | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/libxfs/xfs_bmap.c b/libxfs/xfs_bmap.c
index 323f60b1128..b84d1ad57f1 100644
--- a/libxfs/xfs_bmap.c
+++ b/libxfs/xfs_bmap.c
@@ -5051,7 +5051,6 @@ xfs_bmap_del_extent_real(
{
xfs_fsblock_t del_endblock=0; /* first block past del */
xfs_fileoff_t del_endoff; /* first offset past del */
- int do_fx; /* free extent at end of routine */
int error; /* error return value */
struct xfs_bmbt_irec got; /* current extent entry */
xfs_fileoff_t got_endoff; /* first offset past got */
@@ -5064,6 +5063,8 @@ xfs_bmap_del_extent_real(
uint qfield; /* quota field to update */
uint32_t state = xfs_bmap_fork_to_state(whichfork);
struct xfs_bmbt_irec old;
+ bool isrt = xfs_ifork_is_realtime(ip, whichfork);
+ bool want_free = !(bflags & XFS_BMAPI_REMAP);
*logflagsp = 0;
@@ -5095,18 +5096,24 @@ xfs_bmap_del_extent_real(
return -ENOSPC;
*logflagsp = XFS_ILOG_CORE;
- if (xfs_ifork_is_realtime(ip, whichfork)) {
- if (!(bflags & XFS_BMAPI_REMAP)) {
+ if (isrt) {
+ /*
+ * Historically, we did not use EFIs to free realtime extents.
+ * However, when reverse mapping is enabled, we must maintain
+ * the same order of operations as the data device, which is:
+ * Remove the file mapping, remove the reverse mapping, and
+ * then free the blocks. This means that we must delay the
+ * freeing until after we've scheduled the rmap update.
+ */
+ if (want_free && !xfs_has_rtrmapbt(mp)) {
error = xfs_rtfree_blocks(tp, del->br_startblock,
del->br_blockcount);
if (error)
return error;
+ want_free = false;
}
-
- do_fx = 0;
qfield = XFS_TRANS_DQ_RTBCOUNT;
} else {
- do_fx = 1;
qfield = XFS_TRANS_DQ_BCOUNT;
}
nblks = del->br_blockcount;
@@ -5256,7 +5263,7 @@ xfs_bmap_del_extent_real(
/*
* If we need to, add to list of extents to delete.
*/
- if (do_fx && !(bflags & XFS_BMAPI_REMAP)) {
+ if (want_free) {
if (xfs_is_reflink_inode(ip) && whichfork == XFS_DATA_FORK) {
xfs_refcount_decrease_extent(tp, del);
} else {
@@ -5265,6 +5272,8 @@ xfs_bmap_del_extent_real(
if ((bflags & XFS_BMAPI_NODISCARD) ||
del->br_state == XFS_EXT_UNWRITTEN)
efi_flags |= XFS_FREE_EXTENT_SKIP_DISCARD;
+ if (isrt)
+ efi_flags |= XFS_FREE_EXTENT_REALTIME;
error = xfs_free_extent_later(tp, del->br_startblock,
del->br_blockcount, NULL,
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 13/47] xfs: wire up rmap map and unmap to the realtime rmapbt
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (11 preceding siblings ...)
2023-12-27 13:13 ` [PATCH 12/47] xfs: use realtime EFI to free extents when realtime rmap is enabled Darrick J. Wong
@ 2023-12-27 13:13 ` Darrick J. Wong
2023-12-27 13:14 ` [PATCH 14/47] xfs: create routine to allocate and initialize a realtime rmap btree inode Darrick J. Wong
` (33 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:13 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Connect the map and unmap reverse-mapping operations to the realtime
rmapbt via the deferred operation callbacks. This enables us to
perform rmap operations against the correct btree.
[Contains a minor bugfix from hch]
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_rmap.c | 37 ++++++++++++++++++++++++++++++++++---
libxfs/xfs_rtgroup.c | 9 +++++++++
libxfs/xfs_rtgroup.h | 5 ++++-
3 files changed, 47 insertions(+), 4 deletions(-)
diff --git a/libxfs/xfs_rmap.c b/libxfs/xfs_rmap.c
index 00544d6a20f..cf2968cbd7f 100644
--- a/libxfs/xfs_rmap.c
+++ b/libxfs/xfs_rmap.c
@@ -25,6 +25,7 @@
#include "xfs_health.h"
#include "defer_item.h"
#include "xfs_rtgroup.h"
+#include "xfs_rtrmap_btree.h"
struct kmem_cache *xfs_rmap_intent_cache;
@@ -2691,9 +2692,39 @@ xfs_rtrmap_finish_one(
struct xfs_rmap_intent *ri,
struct xfs_btree_cur **pcur)
{
- /* coming in a subsequent patch */
- ASSERT(0);
- return -EFSCORRUPTED;
+ struct xfs_owner_info oinfo;
+ struct xfs_mount *mp = tp->t_mountp;
+ struct xfs_btree_cur *rcur = *pcur;
+ xfs_rgnumber_t rgno;
+ xfs_rgblock_t bno;
+ bool unwritten;
+
+ trace_xfs_rmap_deferred(mp, ri);
+
+ if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_RMAP_FINISH_ONE))
+ return -EIO;
+
+ /*
+ * If we haven't gotten a cursor or the cursor rtgroup doesn't match
+ * the startblock, get one now.
+ */
+ if (rcur != NULL && rcur->bc_ino.rtg != ri->ri_rtg) {
+ xfs_btree_del_cursor(rcur, 0);
+ rcur = NULL;
+ }
+ if (rcur == NULL) {
+ xfs_rtgroup_lock(tp, ri->ri_rtg, XFS_RTGLOCK_RMAP);
+ *pcur = rcur = xfs_rtrmapbt_init_cursor(mp, tp, ri->ri_rtg,
+ ri->ri_rtg->rtg_rmapip);
+ }
+
+ xfs_rmap_ino_owner(&oinfo, ri->ri_owner, ri->ri_whichfork,
+ ri->ri_bmap.br_startoff);
+ unwritten = ri->ri_bmap.br_state == XFS_EXT_UNWRITTEN;
+ bno = xfs_rtb_to_rgbno(mp, ri->ri_bmap.br_startblock, &rgno);
+
+ return __xfs_rmap_finish_intent(rcur, ri->ri_type, bno,
+ ri->ri_bmap.br_blockcount, &oinfo, unwritten);
}
/*
diff --git a/libxfs/xfs_rtgroup.c b/libxfs/xfs_rtgroup.c
index 4ef6b9e9094..449cd57cf9e 100644
--- a/libxfs/xfs_rtgroup.c
+++ b/libxfs/xfs_rtgroup.c
@@ -549,6 +549,12 @@ xfs_rtgroup_lock(
xfs_rtbitmap_lock(tp, rtg->rtg_mount);
else if (rtglock_flags & XFS_RTGLOCK_BITMAP_SHARED)
xfs_rtbitmap_lock_shared(rtg->rtg_mount, XFS_RBMLOCK_BITMAP);
+
+ if ((rtglock_flags & XFS_RTGLOCK_RMAP) && rtg->rtg_rmapip) {
+ xfs_ilock(rtg->rtg_rmapip, XFS_ILOCK_EXCL);
+ if (tp)
+ xfs_trans_ijoin(tp, rtg->rtg_rmapip, XFS_ILOCK_EXCL);
+ }
}
/* Unlock metadata inodes associated with this rt group. */
@@ -561,6 +567,9 @@ xfs_rtgroup_unlock(
ASSERT(!(rtglock_flags & XFS_RTGLOCK_BITMAP_SHARED) ||
!(rtglock_flags & XFS_RTGLOCK_BITMAP));
+ if ((rtglock_flags & XFS_RTGLOCK_RMAP) && rtg->rtg_rmapip)
+ xfs_iunlock(rtg->rtg_rmapip, XFS_ILOCK_EXCL);
+
if (rtglock_flags & XFS_RTGLOCK_BITMAP)
xfs_rtbitmap_unlock(rtg->rtg_mount);
else if (rtglock_flags & XFS_RTGLOCK_BITMAP_SHARED)
diff --git a/libxfs/xfs_rtgroup.h b/libxfs/xfs_rtgroup.h
index 77503bda355..559a5135820 100644
--- a/libxfs/xfs_rtgroup.h
+++ b/libxfs/xfs_rtgroup.h
@@ -231,9 +231,12 @@ int xfs_rtgroup_init_secondary_super(struct xfs_mount *mp, xfs_rgnumber_t rgno,
#define XFS_RTGLOCK_BITMAP (1U << 0)
/* Lock the rt bitmap inode in shared mode */
#define XFS_RTGLOCK_BITMAP_SHARED (1U << 1)
+/* Lock the rt rmap inode in exclusive mode */
+#define XFS_RTGLOCK_RMAP (1U << 2)
#define XFS_RTGLOCK_ALL_FLAGS (XFS_RTGLOCK_BITMAP | \
- XFS_RTGLOCK_BITMAP_SHARED)
+ XFS_RTGLOCK_BITMAP_SHARED | \
+ XFS_RTGLOCK_RMAP)
void xfs_rtgroup_lock(struct xfs_trans *tp, struct xfs_rtgroup *rtg,
unsigned int rtglock_flags);
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 14/47] xfs: create routine to allocate and initialize a realtime rmap btree inode
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (12 preceding siblings ...)
2023-12-27 13:13 ` [PATCH 13/47] xfs: wire up rmap map and unmap to the realtime rmapbt Darrick J. Wong
@ 2023-12-27 13:14 ` Darrick J. Wong
2023-12-27 13:14 ` [PATCH 15/47] xfs: report realtime rmap btree corruption errors to the health system Darrick J. Wong
` (32 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:14 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Create a library routine to allocate and initialize an empty realtime
rmapbt inode. We'll use this for mkfs and repair.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_rtrmap_btree.c | 34 ++++++++++++++++++++++++++++++++++
libxfs/xfs_rtrmap_btree.h | 4 ++++
2 files changed, 38 insertions(+)
diff --git a/libxfs/xfs_rtrmap_btree.c b/libxfs/xfs_rtrmap_btree.c
index 921bf7e1b11..832a58cfe13 100644
--- a/libxfs/xfs_rtrmap_btree.c
+++ b/libxfs/xfs_rtrmap_btree.c
@@ -866,3 +866,37 @@ xfs_iflush_rtrmap(
xfs_rtrmapbt_to_disk(ip->i_mount, ifp->if_broot, ifp->if_broot_bytes,
dfp, XFS_DFORK_SIZE(dip, ip->i_mount, XFS_DATA_FORK));
}
+
+/*
+ * Create a realtime rmap btree inode.
+ *
+ * Regardless of the return value, the caller must clean up @upd. If a new
+ * inode is returned through @*ipp, the caller must finish setting up the incore
+ * inode and release it.
+ */
+int
+xfs_rtrmapbt_create(
+ struct xfs_imeta_update *upd,
+ struct xfs_inode **ipp)
+{
+ struct xfs_mount *mp = upd->mp;
+ struct xfs_ifork *ifp;
+ int error;
+
+ error = xfs_imeta_create(upd, S_IFREG, ipp);
+ if (error)
+ return error;
+
+ ifp = xfs_ifork_ptr(upd->ip, XFS_DATA_FORK);
+ ifp->if_format = XFS_DINODE_FMT_RMAP;
+ ASSERT(ifp->if_broot_bytes == 0);
+ ASSERT(ifp->if_bytes == 0);
+
+ /* Initialize the empty incore btree root. */
+ xfs_iroot_alloc(upd->ip, XFS_DATA_FORK,
+ xfs_rtrmap_broot_space_calc(mp, 0, 0));
+ xfs_btree_init_block(mp, ifp->if_broot, &xfs_rtrmapbt_ops, 0, 0,
+ upd->ip->i_ino);
+ xfs_trans_log_inode(upd->tp, upd->ip, XFS_ILOG_CORE | XFS_ILOG_DBROOT);
+ return 0;
+}
diff --git a/libxfs/xfs_rtrmap_btree.h b/libxfs/xfs_rtrmap_btree.h
index 2b26a05f907..108ab8c0aea 100644
--- a/libxfs/xfs_rtrmap_btree.h
+++ b/libxfs/xfs_rtrmap_btree.h
@@ -198,4 +198,8 @@ void xfs_rtrmapbt_to_disk(struct xfs_mount *mp, struct xfs_btree_block *rblock,
unsigned int dblocklen);
void xfs_iflush_rtrmap(struct xfs_inode *ip, struct xfs_dinode *dip);
+struct xfs_imeta_update;
+
+int xfs_rtrmapbt_create(struct xfs_imeta_update *upd, struct xfs_inode **ipp);
+
#endif /* __XFS_RTRMAP_BTREE_H__ */
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 15/47] xfs: report realtime rmap btree corruption errors to the health system
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (13 preceding siblings ...)
2023-12-27 13:14 ` [PATCH 14/47] xfs: create routine to allocate and initialize a realtime rmap btree inode Darrick J. Wong
@ 2023-12-27 13:14 ` Darrick J. Wong
2023-12-27 13:14 ` [PATCH 16/47] xfs: allow queued realtime intents to drain before scrubbing Darrick J. Wong
` (31 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:14 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Whenever we encounter corrupt realtime rmap btree blocks, we should
report that to the health monitoring system for later reporting.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_fs_staging.h | 1 +
libxfs/xfs_health.h | 4 +++-
libxfs/xfs_inode_fork.c | 4 +++-
libxfs/xfs_rtrmap_btree.c | 5 ++++-
man/man2/ioctl_xfs_rtgroup_geometry.2 | 3 +++
5 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/libxfs/xfs_fs_staging.h b/libxfs/xfs_fs_staging.h
index 1f573314877..9d5d6af62b6 100644
--- a/libxfs/xfs_fs_staging.h
+++ b/libxfs/xfs_fs_staging.h
@@ -216,6 +216,7 @@ struct xfs_rtgroup_geometry {
};
#define XFS_RTGROUP_GEOM_SICK_SUPER (1 << 0) /* superblock */
#define XFS_RTGROUP_GEOM_SICK_BITMAP (1 << 1) /* rtbitmap for this group */
+#define XFS_RTGROUP_GEOM_SICK_RMAPBT (1 << 2) /* reverse mappings */
#define XFS_IOC_RTGROUP_GEOMETRY _IOWR('X', 63, struct xfs_rtgroup_geometry)
diff --git a/libxfs/xfs_health.h b/libxfs/xfs_health.h
index 1e9938a417b..aeeb6276977 100644
--- a/libxfs/xfs_health.h
+++ b/libxfs/xfs_health.h
@@ -68,6 +68,7 @@ struct xfs_rtgroup;
#define XFS_SICK_RT_BITMAP (1 << 0) /* realtime bitmap */
#define XFS_SICK_RT_SUMMARY (1 << 1) /* realtime summary */
#define XFS_SICK_RT_SUPER (1 << 2) /* rt group superblock */
+#define XFS_SICK_RT_RMAPBT (1 << 3) /* reverse mappings */
/* Observable health issues for AG metadata. */
#define XFS_SICK_AG_SB (1 << 0) /* superblock */
@@ -113,7 +114,8 @@ struct xfs_rtgroup;
#define XFS_SICK_RT_PRIMARY (XFS_SICK_RT_BITMAP | \
XFS_SICK_RT_SUMMARY | \
- XFS_SICK_RT_SUPER)
+ XFS_SICK_RT_SUPER | \
+ XFS_SICK_RT_RMAPBT)
#define XFS_SICK_AG_PRIMARY (XFS_SICK_AG_SB | \
XFS_SICK_AG_AGF | \
diff --git a/libxfs/xfs_inode_fork.c b/libxfs/xfs_inode_fork.c
index 0e6cd5bacdb..127571527cf 100644
--- a/libxfs/xfs_inode_fork.c
+++ b/libxfs/xfs_inode_fork.c
@@ -264,8 +264,10 @@ xfs_iformat_data_fork(
case XFS_DINODE_FMT_BTREE:
return xfs_iformat_btree(ip, dip, XFS_DATA_FORK);
case XFS_DINODE_FMT_RMAP:
- if (!xfs_has_rtrmapbt(ip->i_mount))
+ if (!xfs_has_rtrmapbt(ip->i_mount)) {
+ xfs_inode_mark_sick(ip, XFS_SICK_INO_CORE);
return -EFSCORRUPTED;
+ }
return xfs_iformat_rtrmap(ip, dip);
default:
xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__,
diff --git a/libxfs/xfs_rtrmap_btree.c b/libxfs/xfs_rtrmap_btree.c
index 832a58cfe13..5a25791baa5 100644
--- a/libxfs/xfs_rtrmap_btree.c
+++ b/libxfs/xfs_rtrmap_btree.c
@@ -25,6 +25,7 @@
#include "xfs_rtgroup.h"
#include "xfs_bmap.h"
#include "xfs_imeta.h"
+#include "xfs_health.h"
static struct kmem_cache *xfs_rtrmapbt_cur_cache;
@@ -798,8 +799,10 @@ xfs_iformat_rtrmap(
level = be16_to_cpu(dfp->bb_level);
if (level > mp->m_rtrmap_maxlevels ||
- xfs_rtrmap_droot_space_calc(level, numrecs) > dsize)
+ xfs_rtrmap_droot_space_calc(level, numrecs) > dsize) {
+ xfs_inode_mark_sick(ip, XFS_SICK_INO_CORE);
return -EFSCORRUPTED;
+ }
xfs_iroot_alloc(ip, XFS_DATA_FORK,
xfs_rtrmap_broot_space_calc(mp, level, numrecs));
diff --git a/man/man2/ioctl_xfs_rtgroup_geometry.2 b/man/man2/ioctl_xfs_rtgroup_geometry.2
index ccd931d1e17..38753b93055 100644
--- a/man/man2/ioctl_xfs_rtgroup_geometry.2
+++ b/man/man2/ioctl_xfs_rtgroup_geometry.2
@@ -73,6 +73,9 @@ Realtime group superblock.
.TP
.B XFS_RTGROUP_GEOM_SICK_BITMAP
Realtime bitmap for this group.
+.TP
+.B XFS_RTGROUP_GEOM_SICK_RTRMAPBT
+Reverse mapping btree for this group.
.RE
.SH RETURN VALUE
On error, \-1 is returned, and
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 16/47] xfs: allow queued realtime intents to drain before scrubbing
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (14 preceding siblings ...)
2023-12-27 13:14 ` [PATCH 15/47] xfs: report realtime rmap btree corruption errors to the health system Darrick J. Wong
@ 2023-12-27 13:14 ` Darrick J. Wong
2023-12-27 13:14 ` [PATCH 17/47] xfs: scrub the realtime rmapbt Darrick J. Wong
` (30 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:14 UTC (permalink / raw)
To: cem, djwong; +Cc: Christoph Hellwig, linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
When a writer thread executes a chain of log intent items for the
realtime volume, the ILOCKs taken during each step are for each rt
metadata file, not the entire rt volume itself. Although scrub takes
all rt metadata ILOCKs, this isn't sufficient to guard against scrub
checking the rt volume while that writer thread is in the middle of
finishing a chain because there's no higher level locking primitive
guarding the realtime volume.
When there's a collision, cross-referencing between data structures
(e.g. rtrmapbt and rtrefcountbt) yields false corruption events; if
repair is running, this results in incorrect repairs, which is
catastrophic.
Fix this by adding to the mount structure the same drain that we use to
protect scrub against concurrent AG updates, but this time for the
realtime volume.
[Contains a few cleanups from hch]
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
include/xfs_mount.h | 12 ++++++++++++
libxfs/defer_item.c | 31 +++++++++++++------------------
libxfs/xfs_rtgroup.c | 2 ++
libxfs/xfs_rtgroup.h | 9 +++++++++
4 files changed, 36 insertions(+), 18 deletions(-)
diff --git a/include/xfs_mount.h b/include/xfs_mount.h
index 4e4da5bc4fa..07f9e33b8b2 100644
--- a/include/xfs_mount.h
+++ b/include/xfs_mount.h
@@ -333,6 +333,18 @@ struct xfs_defer_drain { /* empty */ };
static inline void xfs_perag_intent_hold(struct xfs_perag *pag) {}
static inline void xfs_perag_intent_rele(struct xfs_perag *pag) {}
+struct xfs_rtgroup;
+
+#define xfs_rtgroup_intent_get(mp, rgno) \
+ xfs_rtgroup_get((mp), xfs_rtb_to_rgno((mp), (rgno)))
+#define xfs_rtgroup_intent_put(rtg) xfs_rtgroup_put(rtg)
+
+static inline void xfs_rtgroup_intent_hold(struct xfs_rtgroup *rtg) { }
+static inline void xfs_rtgroup_intent_rele(struct xfs_rtgroup *rtg) { }
+
+#define xfs_drain_free(dr) ((void)0)
+#define xfs_drain_init(dr) ((void)0)
+
static inline void libxfs_buftarg_drain(struct xfs_buftarg *btp)
{
cache_purge(btp->bcache);
diff --git a/libxfs/defer_item.c b/libxfs/defer_item.c
index a82d23c17cf..e7270d02c4b 100644
--- a/libxfs/defer_item.c
+++ b/libxfs/defer_item.c
@@ -88,11 +88,8 @@ xfs_extent_free_defer_add(
struct xfs_mount *mp = tp->t_mountp;
if (xfs_efi_is_realtime(xefi)) {
- xfs_rgnumber_t rgno;
-
- rgno = xfs_rtb_to_rgno(mp, xefi->xefi_startblock);
- xefi->xefi_rtg = xfs_rtgroup_get(mp, rgno);
-
+ xefi->xefi_rtg = xfs_rtgroup_intent_get(mp,
+ xefi->xefi_startblock);
*dfpp = xfs_defer_add(tp, &xefi->xefi_list,
&xfs_rtextent_free_defer_type);
return;
@@ -204,7 +201,7 @@ xfs_rtextent_free_cancel_item(
{
struct xfs_extent_free_item *xefi = xefi_entry(item);
- xfs_rtgroup_put(xefi->xefi_rtg);
+ xfs_rtgroup_intent_put(xefi->xefi_rtg);
kmem_cache_free(xfs_extfree_item_cache, xefi);
}
@@ -338,13 +335,12 @@ xfs_rmap_defer_add(
* section updates.
*/
if (ri->ri_realtime) {
- xfs_rgnumber_t rgno;
-
- rgno = xfs_rtb_to_rgno(mp, ri->ri_bmap.br_startblock);
- ri->ri_rtg = xfs_rtgroup_get(mp, rgno);
+ ri->ri_rtg = xfs_rtgroup_intent_get(mp,
+ ri->ri_bmap.br_startblock);
xfs_defer_add(tp, &ri->ri_list, &xfs_rtrmap_update_defer_type);
} else {
- ri->ri_pag = xfs_perag_intent_get(mp, ri->ri_bmap.br_startblock);
+ ri->ri_pag = xfs_perag_intent_get(mp,
+ ri->ri_bmap.br_startblock);
xfs_defer_add(tp, &ri->ri_list, &xfs_rmap_update_defer_type);
}
}
@@ -445,7 +441,7 @@ xfs_rtrmap_update_cancel_item(
{
struct xfs_rmap_intent *ri = ri_entry(item);
- xfs_rtgroup_put(ri->ri_rtg);
+ xfs_rtgroup_intent_put(ri->ri_rtg);
kmem_cache_free(xfs_rmap_intent_cache, ri);
}
@@ -656,10 +652,8 @@ xfs_bmap_update_get_group(
{
if (xfs_ifork_is_realtime(bi->bi_owner, bi->bi_whichfork)) {
if (xfs_has_rtgroups(mp)) {
- xfs_rgnumber_t rgno;
-
- rgno = xfs_rtb_to_rgno(mp, bi->bi_bmap.br_startblock);
- bi->bi_rtg = xfs_rtgroup_get(mp, rgno);
+ bi->bi_rtg = xfs_rtgroup_intent_get(mp,
+ bi->bi_bmap.br_startblock);
} else {
bi->bi_rtg = NULL;
}
@@ -695,8 +689,9 @@ xfs_bmap_update_put_group(
struct xfs_bmap_intent *bi)
{
if (xfs_ifork_is_realtime(bi->bi_owner, bi->bi_whichfork)) {
- if (xfs_has_rtgroups(bi->bi_owner->i_mount))
- xfs_rtgroup_put(bi->bi_rtg);
+ if (xfs_has_rtgroups(bi->bi_owner->i_mount)) {
+ xfs_rtgroup_intent_put(bi->bi_rtg);
+ }
return;
}
diff --git a/libxfs/xfs_rtgroup.c b/libxfs/xfs_rtgroup.c
index 449cd57cf9e..1acf98f8c7e 100644
--- a/libxfs/xfs_rtgroup.c
+++ b/libxfs/xfs_rtgroup.c
@@ -159,6 +159,7 @@ xfs_initialize_rtgroups(
/* Place kernel structure only init below this point. */
spin_lock_init(&rtg->rtg_state_lock);
init_waitqueue_head(&rtg->rtg_active_wq);
+ xfs_defer_drain_init(&rtg->rtg_intents_drain);
#endif /* __KERNEL__ */
/* Active ref owned by mount indicates rtgroup is online. */
@@ -213,6 +214,7 @@ xfs_free_rtgroups(
spin_unlock(&mp->m_rtgroup_lock);
ASSERT(rtg);
XFS_IS_CORRUPT(mp, atomic_read(&rtg->rtg_ref) != 0);
+ xfs_defer_drain_free(&rtg->rtg_intents_drain);
/* drop the mount's active reference */
xfs_rtgroup_rele(rtg);
diff --git a/libxfs/xfs_rtgroup.h b/libxfs/xfs_rtgroup.h
index 559a5135820..9487c2e0047 100644
--- a/libxfs/xfs_rtgroup.h
+++ b/libxfs/xfs_rtgroup.h
@@ -39,6 +39,15 @@ struct xfs_rtgroup {
#ifdef __KERNEL__
/* -- kernel only structures below this line -- */
spinlock_t rtg_state_lock;
+
+ /*
+ * We use xfs_drain to track the number of deferred log intent items
+ * that have been queued (but not yet processed) so that waiters (e.g.
+ * scrub) will not lock resources when other threads are in the middle
+ * of processing a chain of intent items only to find momentary
+ * inconsistencies.
+ */
+ struct xfs_defer_drain rtg_intents_drain;
#endif /* __KERNEL__ */
};
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 17/47] xfs: scrub the realtime rmapbt
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (15 preceding siblings ...)
2023-12-27 13:14 ` [PATCH 16/47] xfs: allow queued realtime intents to drain before scrubbing Darrick J. Wong
@ 2023-12-27 13:14 ` Darrick J. Wong
2023-12-27 13:15 ` [PATCH 18/47] xfs: scrub the metadir path of rt rmap btree files Darrick J. Wong
` (29 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:14 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Check the realtime reverse mapping btree against the rtbitmap, and
modify the rtbitmap scrub to check against the rtrmapbt.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_fs.h | 3 ++-
man/man2/ioctl_xfs_scrub_metadata.2 | 8 ++++++--
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h
index 102b9273360..dcf048aae8c 100644
--- a/libxfs/xfs_fs.h
+++ b/libxfs/xfs_fs.h
@@ -737,9 +737,10 @@ struct xfs_scrub_metadata {
#define XFS_SCRUB_TYPE_METAPATH 29 /* metadata directory tree paths */
#define XFS_SCRUB_TYPE_RGSUPER 30 /* realtime superblock */
#define XFS_SCRUB_TYPE_RGBITMAP 31 /* realtime group bitmap */
+#define XFS_SCRUB_TYPE_RTRMAPBT 32 /* rtgroup reverse mapping btree */
/* Number of scrub subcommands. */
-#define XFS_SCRUB_TYPE_NR 32
+#define XFS_SCRUB_TYPE_NR 33
/*
* This special type code only applies to the vectored scrub implementation.
diff --git a/man/man2/ioctl_xfs_scrub_metadata.2 b/man/man2/ioctl_xfs_scrub_metadata.2
index dc439897c98..79875968d1c 100644
--- a/man/man2/ioctl_xfs_scrub_metadata.2
+++ b/man/man2/ioctl_xfs_scrub_metadata.2
@@ -98,9 +98,13 @@ The realtime allocation group number must be given in
must be zero.
.PP
-.TP
+.nf
.B XFS_SCRUB_TYPE_RGBITMAP
-Examine a given realtime allocation group's free space bitmap.
+.fi
+.TP
+.B XFS_SCRUB_TYPE_RTRMAPBT
+Examine a given realtime allocation group's free space bitmap or reverse
+mapping btree, respectively.
Records are checked for obviously incorrect values and cross-referenced
with other allocation group metadata records to ensure that there are no
conflicts.
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 18/47] xfs: scrub the metadir path of rt rmap btree files
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (16 preceding siblings ...)
2023-12-27 13:14 ` [PATCH 17/47] xfs: scrub the realtime rmapbt Darrick J. Wong
@ 2023-12-27 13:15 ` Darrick J. Wong
2023-12-27 13:15 ` [PATCH 19/47] xfs: online repair of the realtime rmap btree Darrick J. Wong
` (28 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:15 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Add a new XFS_SCRUB_METAPATH subtype so that we can scrub the metadata
directory tree path to the rmap btree file for each rt group.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libfrog/scrub.c | 5 +++++
libxfs/xfs_fs.h | 3 ++-
scrub/scrub.c | 3 +++
3 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/libfrog/scrub.c b/libfrog/scrub.c
index b22770d639c..8822fc0088c 100644
--- a/libfrog/scrub.c
+++ b/libfrog/scrub.c
@@ -197,6 +197,11 @@ const struct xfrog_scrub_descr xfrog_metapaths[XFS_SCRUB_METAPATH_NR] = {
.descr = "project quota metadir path",
.group = XFROG_SCRUB_GROUP_FS,
},
+ [XFS_SCRUB_METAPATH_RTRMAPBT] = {
+ .name = "rtrmapbt",
+ .descr = "rmap btree file metadir path",
+ .group = XFROG_SCRUB_GROUP_RTGROUP,
+ },
};
/* Invoke the scrub ioctl. Returns zero or negative error code. */
diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h
index dcf048aae8c..0bbdbfb0a8a 100644
--- a/libxfs/xfs_fs.h
+++ b/libxfs/xfs_fs.h
@@ -804,9 +804,10 @@ struct xfs_scrub_metadata {
#define XFS_SCRUB_METAPATH_USRQUOTA 2
#define XFS_SCRUB_METAPATH_GRPQUOTA 3
#define XFS_SCRUB_METAPATH_PRJQUOTA 4
+#define XFS_SCRUB_METAPATH_RTRMAPBT 5
/* Number of metapath sm_ino values */
-#define XFS_SCRUB_METAPATH_NR 5
+#define XFS_SCRUB_METAPATH_NR 6
/*
* ioctl limits
diff --git a/scrub/scrub.c b/scrub/scrub.c
index 8f9fde80263..f20910de855 100644
--- a/scrub/scrub.c
+++ b/scrub/scrub.c
@@ -66,6 +66,9 @@ format_metapath_descr(
(unsigned long long)vhead->svh_ino);
sc = &xfrog_metapaths[vhead->svh_ino];
+ if (sc->group == XFROG_SCRUB_GROUP_RTGROUP)
+ return snprintf(buf, buflen, _("rtgroup %u %s"),
+ vhead->svh_agno, _(sc->descr));
return snprintf(buf, buflen, "%s", _(sc->descr));
}
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 19/47] xfs: online repair of the realtime rmap btree
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (17 preceding siblings ...)
2023-12-27 13:15 ` [PATCH 18/47] xfs: scrub the metadir path of rt rmap btree files Darrick J. Wong
@ 2023-12-27 13:15 ` Darrick J. Wong
2023-12-27 13:15 ` [PATCH 20/47] xfs: create a shadow rmap btree during realtime rmap repair Darrick J. Wong
` (27 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:15 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Repair the realtime rmap btree while mounted.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_rtrmap_btree.c | 2 +-
libxfs/xfs_rtrmap_btree.h | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/libxfs/xfs_rtrmap_btree.c b/libxfs/xfs_rtrmap_btree.c
index 5a25791baa5..0393da8837a 100644
--- a/libxfs/xfs_rtrmap_btree.c
+++ b/libxfs/xfs_rtrmap_btree.c
@@ -703,7 +703,7 @@ xfs_rtrmapbt_create_path(
}
/* Calculate the rtrmap btree size for some records. */
-static unsigned long long
+unsigned long long
xfs_rtrmapbt_calc_size(
struct xfs_mount *mp,
unsigned long long len)
diff --git a/libxfs/xfs_rtrmap_btree.h b/libxfs/xfs_rtrmap_btree.h
index 108ab8c0aea..5aec719be05 100644
--- a/libxfs/xfs_rtrmap_btree.h
+++ b/libxfs/xfs_rtrmap_btree.h
@@ -202,4 +202,7 @@ struct xfs_imeta_update;
int xfs_rtrmapbt_create(struct xfs_imeta_update *upd, struct xfs_inode **ipp);
+unsigned long long xfs_rtrmapbt_calc_size(struct xfs_mount *mp,
+ unsigned long long len);
+
#endif /* __XFS_RTRMAP_BTREE_H__ */
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 20/47] xfs: create a shadow rmap btree during realtime rmap repair
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (18 preceding siblings ...)
2023-12-27 13:15 ` [PATCH 19/47] xfs: online repair of the realtime rmap btree Darrick J. Wong
@ 2023-12-27 13:15 ` Darrick J. Wong
2023-12-27 13:15 ` [PATCH 21/47] xfs: hook live realtime rmap operations during a repair operation Darrick J. Wong
` (26 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:15 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Create an in-memory btree of rmap records instead of an array. This
enables us to do live record collection instead of freezing the fs.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfbtree.c | 2 +
libxfs/xfs_btree.c | 2 +
libxfs/xfs_btree.h | 1
libxfs/xfs_rmap.c | 5 +-
libxfs/xfs_rtrmap_btree.c | 123 +++++++++++++++++++++++++++++++++++++++++++++
libxfs/xfs_rtrmap_btree.h | 9 +++
6 files changed, 141 insertions(+), 1 deletion(-)
diff --git a/libxfs/xfbtree.c b/libxfs/xfbtree.c
index b4762393b3a..cdc37561a62 100644
--- a/libxfs/xfbtree.c
+++ b/libxfs/xfbtree.c
@@ -253,6 +253,8 @@ xfbtree_dup_cursor(
if (cur->bc_mem.pag)
ncur->bc_mem.pag = xfs_perag_hold(cur->bc_mem.pag);
+ if (cur->bc_mem.rtg)
+ ncur->bc_mem.rtg = xfs_rtgroup_hold(cur->bc_mem.rtg);
return ncur;
}
diff --git a/libxfs/xfs_btree.c b/libxfs/xfs_btree.c
index f599dd17d30..450c48ceaf1 100644
--- a/libxfs/xfs_btree.c
+++ b/libxfs/xfs_btree.c
@@ -487,6 +487,8 @@ xfs_btree_del_cursor(
if (cur->bc_flags & XFS_BTREE_IN_XFILE) {
if (cur->bc_mem.pag)
xfs_perag_put(cur->bc_mem.pag);
+ if (cur->bc_mem.rtg)
+ xfs_rtgroup_put(cur->bc_mem.rtg);
}
kmem_cache_free(cur->bc_cache, cur);
}
diff --git a/libxfs/xfs_btree.h b/libxfs/xfs_btree.h
index 3559cf5d3a6..4753a5c8476 100644
--- a/libxfs/xfs_btree.h
+++ b/libxfs/xfs_btree.h
@@ -269,6 +269,7 @@ struct xfs_btree_cur_mem {
struct xfbtree *xfbtree;
struct xfs_buf *head_bp;
struct xfs_perag *pag;
+ struct xfs_rtgroup *rtg;
};
struct xfs_btree_level {
diff --git a/libxfs/xfs_rmap.c b/libxfs/xfs_rmap.c
index cf2968cbd7f..42713dd17f4 100644
--- a/libxfs/xfs_rmap.c
+++ b/libxfs/xfs_rmap.c
@@ -328,8 +328,11 @@ xfs_rmap_check_btrec(
struct xfs_btree_cur *cur,
const struct xfs_rmap_irec *irec)
{
- if (cur->bc_btnum == XFS_BTNUM_RTRMAP)
+ if (cur->bc_btnum == XFS_BTNUM_RTRMAP) {
+ if (cur->bc_flags & XFS_BTREE_IN_XFILE)
+ return xfs_rtrmap_check_irec(cur->bc_mem.rtg, irec);
return xfs_rtrmap_check_irec(cur->bc_ino.rtg, irec);
+ }
if (cur->bc_flags & XFS_BTREE_IN_XFILE)
return xfs_rmap_check_irec(cur->bc_mem.pag, irec);
diff --git a/libxfs/xfs_rtrmap_btree.c b/libxfs/xfs_rtrmap_btree.c
index 0393da8837a..b5adfe362a7 100644
--- a/libxfs/xfs_rtrmap_btree.c
+++ b/libxfs/xfs_rtrmap_btree.c
@@ -26,6 +26,9 @@
#include "xfs_bmap.h"
#include "xfs_imeta.h"
#include "xfs_health.h"
+#include "xfile.h"
+#include "xfbtree.h"
+#include "xfs_btree_mem.h"
static struct kmem_cache *xfs_rtrmapbt_cur_cache;
@@ -555,6 +558,126 @@ xfs_rtrmapbt_stage_cursor(
return cur;
}
+#ifdef CONFIG_XFS_BTREE_IN_XFILE
+/*
+ * Validate an in-memory realtime rmap btree block. Callers are allowed to
+ * generate an in-memory btree even if the ondisk feature is not enabled.
+ */
+static xfs_failaddr_t
+xfs_rtrmapbt_mem_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 (xfs_has_rmapbt(mp)) {
+ if (level >= mp->m_rtrmap_maxlevels)
+ return __this_address;
+ } else {
+ if (level >= xfs_rtrmapbt_maxlevels_ondisk())
+ return __this_address;
+ }
+
+ return xfbtree_lblock_verify(bp,
+ xfs_rtrmapbt_maxrecs(mp, xfo_to_b(1), level == 0));
+}
+
+static void
+xfs_rtrmapbt_mem_rw_verify(
+ struct xfs_buf *bp)
+{
+ xfs_failaddr_t fa = xfs_rtrmapbt_mem_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 xfs_rtrmapbt_mem_buf_ops = {
+ .name = "xfs_rtrmapbt_mem",
+ .magic = { 0, cpu_to_be32(XFS_RTRMAP_CRC_MAGIC) },
+ .verify_read = xfs_rtrmapbt_mem_rw_verify,
+ .verify_write = xfs_rtrmapbt_mem_rw_verify,
+ .verify_struct = xfs_rtrmapbt_mem_verify,
+};
+
+static const struct xfs_btree_ops xfs_rtrmapbt_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_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 = xfs_rtrmapbt_init_key_from_rec,
+ .init_high_key_from_rec = xfs_rtrmapbt_init_high_key_from_rec,
+ .init_rec_from_cur = xfs_rtrmapbt_init_rec_from_cur,
+ .init_ptr_from_cur = xfbtree_init_ptr_from_cur,
+ .key_diff = xfs_rtrmapbt_key_diff,
+ .buf_ops = &xfs_rtrmapbt_mem_buf_ops,
+ .diff_two_keys = xfs_rtrmapbt_diff_two_keys,
+ .keys_inorder = xfs_rtrmapbt_keys_inorder,
+ .recs_inorder = xfs_rtrmapbt_recs_inorder,
+ .keys_contiguous = xfs_rtrmapbt_keys_contiguous,
+};
+
+/* Create a cursor for an in-memory btree. */
+struct xfs_btree_cur *
+xfs_rtrmapbt_mem_cursor(
+ struct xfs_rtgroup *rtg,
+ struct xfs_trans *tp,
+ struct xfs_buf *head_bp,
+ struct xfbtree *xfbtree)
+{
+ struct xfs_btree_cur *cur;
+ struct xfs_mount *mp = rtg->rtg_mount;
+
+ /* Overlapping btree; 2 keys per pointer. */
+ cur = xfs_btree_alloc_cursor(mp, tp, XFS_BTNUM_RTRMAP,
+ &xfs_rtrmapbt_mem_ops, mp->m_rtrmap_maxlevels,
+ xfs_rtrmapbt_cur_cache);
+ cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_rmap_2);
+ cur->bc_mem.xfbtree = xfbtree;
+ cur->bc_mem.head_bp = head_bp;
+ cur->bc_nlevels = xfs_btree_mem_head_nlevels(head_bp);
+
+ cur->bc_mem.rtg = xfs_rtgroup_hold(rtg);
+ return cur;
+}
+
+int
+xfs_rtrmapbt_mem_create(
+ struct xfs_mount *mp,
+ xfs_rgnumber_t rgno,
+ struct xfs_buftarg *target,
+ struct xfbtree **xfbtreep)
+{
+ struct xfbtree_config cfg = {
+ .btree_ops = &xfs_rtrmapbt_mem_ops,
+ .target = target,
+ .flags = XFBTREE_DIRECT_MAP,
+ .owner = rgno,
+ };
+
+ return xfbtree_create(mp, &cfg, xfbtreep);
+}
+#endif /* CONFIG_XFS_BTREE_IN_XFILE */
+
/*
* Install a new rt reverse mapping btree root. Caller is responsible for
* invalidating and freeing the old btree blocks.
diff --git a/libxfs/xfs_rtrmap_btree.h b/libxfs/xfs_rtrmap_btree.h
index 5aec719be05..b0a8e8d89f9 100644
--- a/libxfs/xfs_rtrmap_btree.h
+++ b/libxfs/xfs_rtrmap_btree.h
@@ -205,4 +205,13 @@ int xfs_rtrmapbt_create(struct xfs_imeta_update *upd, struct xfs_inode **ipp);
unsigned long long xfs_rtrmapbt_calc_size(struct xfs_mount *mp,
unsigned long long len);
+#ifdef CONFIG_XFS_BTREE_IN_XFILE
+struct xfbtree;
+struct xfs_btree_cur *xfs_rtrmapbt_mem_cursor(struct xfs_rtgroup *rtg,
+ struct xfs_trans *tp, struct xfs_buf *mhead_bp,
+ struct xfbtree *xfbtree);
+int xfs_rtrmapbt_mem_create(struct xfs_mount *mp, xfs_rgnumber_t rgno,
+ struct xfs_buftarg *target, struct xfbtree **xfbtreep);
+#endif /* CONFIG_XFS_BTREE_IN_XFILE */
+
#endif /* __XFS_RTRMAP_BTREE_H__ */
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 21/47] xfs: hook live realtime rmap operations during a repair operation
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (19 preceding siblings ...)
2023-12-27 13:15 ` [PATCH 20/47] xfs: create a shadow rmap btree during realtime rmap repair Darrick J. Wong
@ 2023-12-27 13:15 ` Darrick J. Wong
2023-12-27 13:16 ` [PATCH 22/47] xfs_db: display the realtime rmap btree contents Darrick J. Wong
` (25 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:15 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Hook the regular realtime rmap code when an rtrmapbt repair operation is
running so that we can unlock the AGF buffer to scan the filesystem and
keep the in-memory btree up to date during the scan.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_rmap.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++---
libxfs/xfs_rmap.h | 6 +++++
libxfs/xfs_rtgroup.c | 1 +
libxfs/xfs_rtgroup.h | 3 +++
4 files changed, 63 insertions(+), 3 deletions(-)
diff --git a/libxfs/xfs_rmap.c b/libxfs/xfs_rmap.c
index 42713dd17f4..0056dc08662 100644
--- a/libxfs/xfs_rmap.c
+++ b/libxfs/xfs_rmap.c
@@ -919,8 +919,7 @@ xfs_rmap_update_hook(
.oinfo = *oinfo, /* struct copy */
};
- if (pag)
- xfs_hooks_call(&pag->pag_rmap_update_hooks, op, &p);
+ xfs_hooks_call(&pag->pag_rmap_update_hooks, op, &p);
}
}
@@ -945,6 +944,50 @@ xfs_rmap_hook_del(
# define xfs_rmap_update_hook(t, p, o, s, b, u, oi) do { } while (0)
#endif /* CONFIG_XFS_LIVE_HOOKS */
+# if defined(CONFIG_XFS_LIVE_HOOKS) && defined(CONFIG_XFS_RT)
+static inline void
+xfs_rtrmap_update_hook(
+ struct xfs_trans *tp,
+ struct xfs_rtgroup *rtg,
+ enum xfs_rmap_intent_type op,
+ xfs_rgblock_t startblock,
+ xfs_extlen_t blockcount,
+ bool unwritten,
+ const struct xfs_owner_info *oinfo)
+{
+ if (xfs_hooks_switched_on(&xfs_rmap_hooks_switch)) {
+ struct xfs_rmap_update_params p = {
+ .startblock = startblock,
+ .blockcount = blockcount,
+ .unwritten = unwritten,
+ .oinfo = *oinfo, /* struct copy */
+ };
+
+ xfs_hooks_call(&rtg->rtg_rmap_update_hooks, op, &p);
+ }
+}
+
+/* Call the specified function during a rt reverse mapping update. */
+int
+xfs_rtrmap_hook_add(
+ struct xfs_rtgroup *rtg,
+ struct xfs_rmap_hook *hook)
+{
+ return xfs_hooks_add(&rtg->rtg_rmap_update_hooks, &hook->update_hook);
+}
+
+/* Stop calling the specified function during a rt reverse mapping update. */
+void
+xfs_rtrmap_hook_del(
+ struct xfs_rtgroup *rtg,
+ struct xfs_rmap_hook *hook)
+{
+ xfs_hooks_del(&rtg->rtg_rmap_update_hooks, &hook->update_hook);
+}
+#else
+# define xfs_rtrmap_update_hook(t, r, o, s, b, u, oi) do { } while (0)
+#endif /* CONFIG_XFS_LIVE_HOOKS && CONFIG_XFS_RT */
+
/*
* Remove a reference to an extent in the rmap btree.
*/
@@ -2701,6 +2744,7 @@ xfs_rtrmap_finish_one(
xfs_rgnumber_t rgno;
xfs_rgblock_t bno;
bool unwritten;
+ int error;
trace_xfs_rmap_deferred(mp, ri);
@@ -2726,8 +2770,14 @@ xfs_rtrmap_finish_one(
unwritten = ri->ri_bmap.br_state == XFS_EXT_UNWRITTEN;
bno = xfs_rtb_to_rgbno(mp, ri->ri_bmap.br_startblock, &rgno);
- return __xfs_rmap_finish_intent(rcur, ri->ri_type, bno,
+ error = __xfs_rmap_finish_intent(rcur, ri->ri_type, bno,
ri->ri_bmap.br_blockcount, &oinfo, unwritten);
+ if (error)
+ return error;
+
+ xfs_rtrmap_update_hook(tp, ri->ri_rtg, ri->ri_type, bno,
+ ri->ri_bmap.br_blockcount, unwritten, &oinfo);
+ return 0;
}
/*
diff --git a/libxfs/xfs_rmap.h b/libxfs/xfs_rmap.h
index 3719fc4cbc2..9e19e657eef 100644
--- a/libxfs/xfs_rmap.h
+++ b/libxfs/xfs_rmap.h
@@ -275,6 +275,12 @@ void xfs_rmap_hook_enable(void);
int xfs_rmap_hook_add(struct xfs_perag *pag, struct xfs_rmap_hook *hook);
void xfs_rmap_hook_del(struct xfs_perag *pag, struct xfs_rmap_hook *hook);
+
+# ifdef CONFIG_XFS_RT
+int xfs_rtrmap_hook_add(struct xfs_rtgroup *rtg, struct xfs_rmap_hook *hook);
+void xfs_rtrmap_hook_del(struct xfs_rtgroup *rtg, struct xfs_rmap_hook *hook);
+# endif /* CONFIG_XFS_RT */
+
#endif
#endif /* __XFS_RMAP_H__ */
diff --git a/libxfs/xfs_rtgroup.c b/libxfs/xfs_rtgroup.c
index 1acf98f8c7e..03eb776ef8b 100644
--- a/libxfs/xfs_rtgroup.c
+++ b/libxfs/xfs_rtgroup.c
@@ -160,6 +160,7 @@ xfs_initialize_rtgroups(
spin_lock_init(&rtg->rtg_state_lock);
init_waitqueue_head(&rtg->rtg_active_wq);
xfs_defer_drain_init(&rtg->rtg_intents_drain);
+ xfs_hooks_init(&rtg->rtg_rmap_update_hooks);
#endif /* __KERNEL__ */
/* Active ref owned by mount indicates rtgroup is online. */
diff --git a/libxfs/xfs_rtgroup.h b/libxfs/xfs_rtgroup.h
index 9487c2e0047..3522527e553 100644
--- a/libxfs/xfs_rtgroup.h
+++ b/libxfs/xfs_rtgroup.h
@@ -48,6 +48,9 @@ struct xfs_rtgroup {
* inconsistencies.
*/
struct xfs_defer_drain rtg_intents_drain;
+
+ /* Hook to feed rt rmapbt updates to an active online repair. */
+ struct xfs_hooks rtg_rmap_update_hooks;
#endif /* __KERNEL__ */
};
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 22/47] xfs_db: display the realtime rmap btree contents
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (20 preceding siblings ...)
2023-12-27 13:15 ` [PATCH 21/47] xfs: hook live realtime rmap operations during a repair operation Darrick J. Wong
@ 2023-12-27 13:16 ` Darrick J. Wong
2023-12-27 13:16 ` [PATCH 23/47] xfs_db: support the realtime rmapbt Darrick J. Wong
` (24 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:16 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Implement all the code we need to dump rtrmapbt contents, starting
from the root inode.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
db/bmroot.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++
db/bmroot.h | 2 +
db/btblock.c | 100 +++++++++++++++++++++++++++++++
db/btblock.h | 5 ++
db/field.c | 11 +++
db/field.h | 5 ++
db/inode.c | 102 +++++++++++++++++++++++++++++++
db/inode.h | 3 +
db/type.c | 5 ++
db/type.h | 1
libxfs/libxfs_api_defs.h | 4 +
man/man8/xfs_db.8 | 60 ++++++++++++++++++-
12 files changed, 443 insertions(+), 4 deletions(-)
diff --git a/db/bmroot.c b/db/bmroot.c
index 7ef07da181e..19490bd2499 100644
--- a/db/bmroot.c
+++ b/db/bmroot.c
@@ -24,6 +24,13 @@ static int bmrootd_key_offset(void *obj, int startoff, int idx);
static int bmrootd_ptr_count(void *obj, int startoff);
static int bmrootd_ptr_offset(void *obj, int startoff, int idx);
+static int rtrmaproot_rec_count(void *obj, int startoff);
+static int rtrmaproot_rec_offset(void *obj, int startoff, int idx);
+static int rtrmaproot_key_count(void *obj, int startoff);
+static int rtrmaproot_key_offset(void *obj, int startoff, int idx);
+static int rtrmaproot_ptr_count(void *obj, int startoff);
+static int rtrmaproot_ptr_offset(void *obj, int startoff, int idx);
+
#define OFF(f) bitize(offsetof(xfs_bmdr_block_t, bb_ ## f))
const field_t bmroota_flds[] = {
{ "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE },
@@ -54,6 +61,20 @@ const field_t bmrootd_key_flds[] = {
{ NULL }
};
+/* realtime rmap btree root */
+const field_t rtrmaproot_flds[] = {
+ { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE },
+ { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE },
+ { "recs", FLDT_RTRMAPBTREC, rtrmaproot_rec_offset, rtrmaproot_rec_count,
+ FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE },
+ { "keys", FLDT_RTRMAPBTKEY, rtrmaproot_key_offset, rtrmaproot_key_count,
+ FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE },
+ { "ptrs", FLDT_RTRMAPBTPTR, rtrmaproot_ptr_offset, rtrmaproot_ptr_count,
+ FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_RTRMAPBT },
+ { NULL }
+};
+#undef OFF
+
static int
bmroota_key_count(
void *obj,
@@ -241,3 +262,131 @@ bmrootd_size(
dip = obj;
return bitize((int)XFS_DFORK_DSIZE(dip, mp));
}
+
+/* realtime rmap root */
+static int
+rtrmaproot_rec_count(
+ void *obj,
+ int startoff)
+{
+ struct xfs_rtrmap_root *block;
+#ifdef DEBUG
+ struct xfs_dinode *dip = obj;
+#endif
+
+ ASSERT(bitoffs(startoff) == 0);
+ ASSERT(obj == iocur_top->data);
+ block = (struct xfs_rtrmap_root *)((char *)obj + byteize(startoff));
+ ASSERT((char *)block == XFS_DFORK_DPTR(dip));
+ if (be16_to_cpu(block->bb_level) > 0)
+ return 0;
+ return be16_to_cpu(block->bb_numrecs);
+}
+
+static int
+rtrmaproot_rec_offset(
+ void *obj,
+ int startoff,
+ int idx)
+{
+ struct xfs_rtrmap_root *block;
+ struct xfs_rmap_rec *kp;
+
+ ASSERT(bitoffs(startoff) == 0);
+ ASSERT(obj == iocur_top->data);
+ block = (struct xfs_rtrmap_root *)((char *)obj + byteize(startoff));
+ ASSERT(be16_to_cpu(block->bb_level) == 0);
+ kp = xfs_rtrmap_droot_rec_addr(block, idx);
+ return bitize((int)((char *)kp - (char *)block));
+}
+
+static int
+rtrmaproot_key_count(
+ void *obj,
+ int startoff)
+{
+ struct xfs_rtrmap_root *block;
+#ifdef DEBUG
+ struct xfs_dinode *dip = obj;
+#endif
+
+ ASSERT(bitoffs(startoff) == 0);
+ ASSERT(obj == iocur_top->data);
+ block = (struct xfs_rtrmap_root *)((char *)obj + byteize(startoff));
+ ASSERT((char *)block == XFS_DFORK_DPTR(dip));
+ if (be16_to_cpu(block->bb_level) == 0)
+ return 0;
+ return be16_to_cpu(block->bb_numrecs);
+}
+
+static int
+rtrmaproot_key_offset(
+ void *obj,
+ int startoff,
+ int idx)
+{
+ struct xfs_rtrmap_root *block;
+ struct xfs_rmap_key *kp;
+
+ ASSERT(bitoffs(startoff) == 0);
+ ASSERT(obj == iocur_top->data);
+ block = (struct xfs_rtrmap_root *)((char *)obj + byteize(startoff));
+ ASSERT(be16_to_cpu(block->bb_level) > 0);
+ kp = xfs_rtrmap_droot_key_addr(block, idx);
+ return bitize((int)((char *)kp - (char *)block));
+}
+
+static int
+rtrmaproot_ptr_count(
+ void *obj,
+ int startoff)
+{
+ struct xfs_rtrmap_root *block;
+#ifdef DEBUG
+ struct xfs_dinode *dip = obj;
+#endif
+
+ ASSERT(bitoffs(startoff) == 0);
+ ASSERT(obj == iocur_top->data);
+ block = (struct xfs_rtrmap_root *)((char *)obj + byteize(startoff));
+ ASSERT((char *)block == XFS_DFORK_DPTR(dip));
+ if (be16_to_cpu(block->bb_level) == 0)
+ return 0;
+ return be16_to_cpu(block->bb_numrecs);
+}
+
+static int
+rtrmaproot_ptr_offset(
+ void *obj,
+ int startoff,
+ int idx)
+{
+ struct xfs_rtrmap_root *block;
+ xfs_rtrmap_ptr_t *pp;
+ struct xfs_dinode *dip;
+ int dmxr;
+
+ ASSERT(bitoffs(startoff) == 0);
+ ASSERT(obj == iocur_top->data);
+ dip = obj;
+ block = (struct xfs_rtrmap_root *)((char *)obj + byteize(startoff));
+ ASSERT(be16_to_cpu(block->bb_level) > 0);
+ dmxr = libxfs_rtrmapbt_droot_maxrecs(XFS_DFORK_DSIZE(dip, mp), false);
+ pp = xfs_rtrmap_droot_ptr_addr(block, idx, dmxr);
+ return bitize((int)((char *)pp - (char *)block));
+}
+
+int
+rtrmaproot_size(
+ void *obj,
+ int startoff,
+ int idx)
+{
+ struct xfs_dinode *dip;
+
+ ASSERT(bitoffs(startoff) == 0);
+ ASSERT(obj == iocur_top->data);
+ ASSERT(idx == 0);
+ dip = obj;
+ return bitize((int)XFS_DFORK_DSIZE(dip, mp));
+}
diff --git a/db/bmroot.h b/db/bmroot.h
index a1274cf6a94..a2c5cfb18f0 100644
--- a/db/bmroot.h
+++ b/db/bmroot.h
@@ -8,6 +8,8 @@ extern const struct field bmroota_flds[];
extern const struct field bmroota_key_flds[];
extern const struct field bmrootd_flds[];
extern const struct field bmrootd_key_flds[];
+extern const struct field rtrmaproot_flds[];
extern int bmroota_size(void *obj, int startoff, int idx);
extern int bmrootd_size(void *obj, int startoff, int idx);
+extern int rtrmaproot_size(void *obj, int startoff, int idx);
diff --git a/db/btblock.c b/db/btblock.c
index d5be6adb734..5cad166278d 100644
--- a/db/btblock.c
+++ b/db/btblock.c
@@ -92,6 +92,12 @@ static struct xfs_db_btree {
sizeof(struct xfs_rmap_rec),
sizeof(__be32),
},
+ { XFS_RTRMAP_CRC_MAGIC,
+ XFS_BTREE_LBLOCK_CRC_LEN,
+ 2 * sizeof(struct xfs_rmap_key),
+ sizeof(struct xfs_rmap_rec),
+ sizeof(__be64),
+ },
{ XFS_REFC_CRC_MAGIC,
XFS_BTREE_SBLOCK_CRC_LEN,
sizeof(struct xfs_refcount_key),
@@ -813,6 +819,100 @@ const field_t rmapbt_rec_flds[] = {
{ NULL }
};
+/* realtime RMAP btree blocks */
+const field_t rtrmapbt_crc_hfld[] = {
+ { "", FLDT_RTRMAPBT_CRC, OI(0), C1, 0, TYP_NONE },
+ { NULL }
+};
+
+#define OFF(f) bitize(offsetof(struct xfs_btree_block, bb_ ## f))
+const field_t rtrmapbt_crc_flds[] = {
+ { "magic", FLDT_UINT32X, OI(OFF(magic)), C1, 0, TYP_NONE },
+ { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE },
+ { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE },
+ { "leftsib", FLDT_DFSBNO, OI(OFF(u.l.bb_leftsib)), C1, 0, TYP_RTRMAPBT },
+ { "rightsib", FLDT_DFSBNO, OI(OFF(u.l.bb_rightsib)), C1, 0, TYP_RTRMAPBT },
+ { "bno", FLDT_DFSBNO, OI(OFF(u.l.bb_blkno)), C1, 0, TYP_RTRMAPBT },
+ { "lsn", FLDT_UINT64X, OI(OFF(u.l.bb_lsn)), C1, 0, TYP_NONE },
+ { "uuid", FLDT_UUID, OI(OFF(u.l.bb_uuid)), C1, 0, TYP_NONE },
+ { "owner", FLDT_INO, OI(OFF(u.l.bb_owner)), C1, 0, TYP_NONE },
+ { "crc", FLDT_CRC, OI(OFF(u.l.bb_crc)), C1, 0, TYP_NONE },
+ { "recs", FLDT_RTRMAPBTREC, btblock_rec_offset, btblock_rec_count,
+ FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE },
+ { "keys", FLDT_RTRMAPBTKEY, btblock_key_offset, btblock_key_count,
+ FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE },
+ { "ptrs", FLDT_RTRMAPBTPTR, btblock_ptr_offset, btblock_key_count,
+ FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_RTRMAPBT },
+ { NULL }
+};
+#undef OFF
+
+#define KOFF(f) bitize(offsetof(struct xfs_rmap_key, rm_ ## f))
+
+#define RTRMAPBK_STARTBLOCK_BITOFF 0
+#define RTRMAPBK_OWNER_BITOFF (RTRMAPBK_STARTBLOCK_BITOFF + RMAPBT_STARTBLOCK_BITLEN)
+#define RTRMAPBK_ATTRFLAG_BITOFF (RTRMAPBK_OWNER_BITOFF + RMAPBT_OWNER_BITLEN)
+#define RTRMAPBK_BMBTFLAG_BITOFF (RTRMAPBK_ATTRFLAG_BITOFF + RMAPBT_ATTRFLAG_BITLEN)
+#define RTRMAPBK_EXNTFLAG_BITOFF (RTRMAPBK_BMBTFLAG_BITOFF + RMAPBT_BMBTFLAG_BITLEN)
+#define RTRMAPBK_UNUSED_OFFSET_BITOFF (RTRMAPBK_EXNTFLAG_BITOFF + RMAPBT_EXNTFLAG_BITLEN)
+#define RTRMAPBK_OFFSET_BITOFF (RTRMAPBK_UNUSED_OFFSET_BITOFF + RMAPBT_UNUSED_OFFSET_BITLEN)
+
+#define HI_KOFF(f) bitize(sizeof(struct xfs_rmap_key) + offsetof(struct xfs_rmap_key, rm_ ## f))
+
+#define RTRMAPBK_STARTBLOCKHI_BITOFF (bitize(sizeof(struct xfs_rmap_key)))
+#define RTRMAPBK_OWNERHI_BITOFF (RTRMAPBK_STARTBLOCKHI_BITOFF + RMAPBT_STARTBLOCK_BITLEN)
+#define RTRMAPBK_ATTRFLAGHI_BITOFF (RTRMAPBK_OWNERHI_BITOFF + RMAPBT_OWNER_BITLEN)
+#define RTRMAPBK_BMBTFLAGHI_BITOFF (RTRMAPBK_ATTRFLAGHI_BITOFF + RMAPBT_ATTRFLAG_BITLEN)
+#define RTRMAPBK_EXNTFLAGHI_BITOFF (RTRMAPBK_BMBTFLAGHI_BITOFF + RMAPBT_BMBTFLAG_BITLEN)
+#define RTRMAPBK_UNUSED_OFFSETHI_BITOFF (RTRMAPBK_EXNTFLAGHI_BITOFF + RMAPBT_EXNTFLAG_BITLEN)
+#define RTRMAPBK_OFFSETHI_BITOFF (RTRMAPBK_UNUSED_OFFSETHI_BITOFF + RMAPBT_UNUSED_OFFSET_BITLEN)
+
+const field_t rtrmapbt_key_flds[] = {
+ { "startblock", FLDT_RGBLOCK, OI(KOFF(startblock)), C1, 0, TYP_DATA },
+ { "owner", FLDT_INT64D, OI(KOFF(owner)), C1, 0, TYP_NONE },
+ { "offset", FLDT_RFILEOFFD, OI(RTRMAPBK_OFFSET_BITOFF), C1, 0, TYP_NONE },
+ { "attrfork", FLDT_RATTRFORKFLG, OI(RTRMAPBK_ATTRFLAG_BITOFF), C1, 0,
+ TYP_NONE },
+ { "bmbtblock", FLDT_RBMBTFLG, OI(RTRMAPBK_BMBTFLAG_BITOFF), C1, 0,
+ TYP_NONE },
+ { "startblock_hi", FLDT_RGBLOCK, OI(HI_KOFF(startblock)), C1, 0, TYP_DATA },
+ { "owner_hi", FLDT_INT64D, OI(HI_KOFF(owner)), C1, 0, TYP_NONE },
+ { "offset_hi", FLDT_RFILEOFFD, OI(RTRMAPBK_OFFSETHI_BITOFF), C1, 0, TYP_NONE },
+ { "attrfork_hi", FLDT_RATTRFORKFLG, OI(RTRMAPBK_ATTRFLAGHI_BITOFF), C1, 0,
+ TYP_NONE },
+ { "bmbtblock_hi", FLDT_RBMBTFLG, OI(RTRMAPBK_BMBTFLAGHI_BITOFF), C1, 0,
+ TYP_NONE },
+ { NULL }
+};
+#undef HI_KOFF
+#undef KOFF
+
+#define ROFF(f) bitize(offsetof(struct xfs_rmap_rec, rm_ ## f))
+
+#define RTRMAPBT_STARTBLOCK_BITOFF 0
+#define RTRMAPBT_BLOCKCOUNT_BITOFF (RTRMAPBT_STARTBLOCK_BITOFF + RMAPBT_STARTBLOCK_BITLEN)
+#define RTRMAPBT_OWNER_BITOFF (RTRMAPBT_BLOCKCOUNT_BITOFF + RMAPBT_BLOCKCOUNT_BITLEN)
+#define RTRMAPBT_ATTRFLAG_BITOFF (RTRMAPBT_OWNER_BITOFF + RMAPBT_OWNER_BITLEN)
+#define RTRMAPBT_BMBTFLAG_BITOFF (RTRMAPBT_ATTRFLAG_BITOFF + RMAPBT_ATTRFLAG_BITLEN)
+#define RTRMAPBT_EXNTFLAG_BITOFF (RTRMAPBT_BMBTFLAG_BITOFF + RMAPBT_BMBTFLAG_BITLEN)
+#define RTRMAPBT_UNUSED_OFFSET_BITOFF (RTRMAPBT_EXNTFLAG_BITOFF + RMAPBT_EXNTFLAG_BITLEN)
+#define RTRMAPBT_OFFSET_BITOFF (RTRMAPBT_UNUSED_OFFSET_BITOFF + RMAPBT_UNUSED_OFFSET_BITLEN)
+
+const field_t rtrmapbt_rec_flds[] = {
+ { "startblock", FLDT_RGBLOCK, OI(RTRMAPBT_STARTBLOCK_BITOFF), C1, 0, TYP_DATA },
+ { "blockcount", FLDT_EXTLEN, OI(RTRMAPBT_BLOCKCOUNT_BITOFF), C1, 0, TYP_NONE },
+ { "owner", FLDT_INT64D, OI(RTRMAPBT_OWNER_BITOFF), C1, 0, TYP_NONE },
+ { "offset", FLDT_RFILEOFFD, OI(RTRMAPBT_OFFSET_BITOFF), C1, 0, TYP_NONE },
+ { "extentflag", FLDT_REXTFLG, OI(RTRMAPBT_EXNTFLAG_BITOFF), C1, 0,
+ TYP_NONE },
+ { "attrfork", FLDT_RATTRFORKFLG, OI(RTRMAPBT_ATTRFLAG_BITOFF), C1, 0,
+ TYP_NONE },
+ { "bmbtblock", FLDT_RBMBTFLG, OI(RTRMAPBT_BMBTFLAG_BITOFF), C1, 0,
+ TYP_NONE },
+ { NULL }
+};
+#undef ROFF
+
/* refcount btree blocks */
const field_t refcbt_crc_hfld[] = {
{ "", FLDT_REFCBT_CRC, OI(0), C1, 0, TYP_NONE },
diff --git a/db/btblock.h b/db/btblock.h
index 4168c9e2e15..b4013ea8073 100644
--- a/db/btblock.h
+++ b/db/btblock.h
@@ -53,6 +53,11 @@ extern const struct field rmapbt_crc_hfld[];
extern const struct field rmapbt_key_flds[];
extern const struct field rmapbt_rec_flds[];
+extern const struct field rtrmapbt_crc_flds[];
+extern const struct field rtrmapbt_crc_hfld[];
+extern const struct field rtrmapbt_key_flds[];
+extern const struct field rtrmapbt_rec_flds[];
+
extern const struct field refcbt_crc_flds[];
extern const struct field refcbt_crc_hfld[];
extern const struct field refcbt_key_flds[];
diff --git a/db/field.c b/db/field.c
index 4a6a4cf51c3..b3efbb5698d 100644
--- a/db/field.c
+++ b/db/field.c
@@ -184,6 +184,17 @@ const ftattr_t ftattrtab[] = {
{ FLDT_RMAPBTREC, "rmapbtrec", fp_sarray, (char *)rmapbt_rec_flds,
SI(bitsz(struct xfs_rmap_rec)), 0, NULL, rmapbt_rec_flds },
+ { FLDT_RTRMAPBT_CRC, "rtrmapbt", NULL, (char *)rtrmapbt_crc_flds, btblock_size,
+ FTARG_SIZE, NULL, rtrmapbt_crc_flds },
+ { FLDT_RTRMAPBTKEY, "rtrmapbtkey", fp_sarray, (char *)rtrmapbt_key_flds,
+ SI(bitize(2 * sizeof(struct xfs_rmap_key))), 0, NULL, rtrmapbt_key_flds },
+ { FLDT_RTRMAPBTPTR, "rtrmapbtptr", fp_num, "%llu",
+ SI(bitsz(xfs_rtrmap_ptr_t)), 0, fa_dfsbno, NULL },
+ { FLDT_RTRMAPBTREC, "rtrmapbtrec", fp_sarray, (char *)rtrmapbt_rec_flds,
+ SI(bitsz(struct xfs_rmap_rec)), 0, NULL, rtrmapbt_rec_flds },
+ { FLDT_RTRMAPROOT, "rtrmaproot", NULL, (char *)rtrmaproot_flds, rtrmaproot_size,
+ FTARG_SIZE, NULL, rtrmaproot_flds },
+
{ FLDT_REFCBT_CRC, "refcntbt", NULL, (char *)refcbt_crc_flds, btblock_size,
FTARG_SIZE, NULL, refcbt_crc_flds },
{ FLDT_REFCBTKEY, "refcntbtkey", fp_sarray, (char *)refcbt_key_flds,
diff --git a/db/field.h b/db/field.h
index e9c6142f282..db3e13d3927 100644
--- a/db/field.h
+++ b/db/field.h
@@ -83,6 +83,11 @@ typedef enum fldt {
FLDT_RMAPBTKEY,
FLDT_RMAPBTPTR,
FLDT_RMAPBTREC,
+ FLDT_RTRMAPBT_CRC,
+ FLDT_RTRMAPBTKEY,
+ FLDT_RTRMAPBTPTR,
+ FLDT_RTRMAPBTREC,
+ FLDT_RTRMAPROOT,
FLDT_REFCBT_CRC,
FLDT_REFCBTKEY,
FLDT_REFCBTPTR,
diff --git a/db/inode.c b/db/inode.c
index 16033c5ab79..6867f5c5427 100644
--- a/db/inode.c
+++ b/db/inode.c
@@ -17,6 +17,7 @@
#include "bit.h"
#include "output.h"
#include "init.h"
+#include "libfrog/bitmap.h"
static int inode_a_bmbt_count(void *obj, int startoff);
static int inode_a_bmx_count(void *obj, int startoff);
@@ -47,6 +48,7 @@ static int inode_u_muuid_count(void *obj, int startoff);
static int inode_u_sfdir2_count(void *obj, int startoff);
static int inode_u_sfdir3_count(void *obj, int startoff);
static int inode_u_symlink_count(void *obj, int startoff);
+static int inode_u_rtrmapbt_count(void *obj, int startoff);
static const cmdinfo_t inode_cmd =
{ "inode", NULL, inode_f, 0, 1, 1, "[inode#]",
@@ -230,6 +232,8 @@ const field_t inode_u_flds[] = {
{ "sfdir3", FLDT_DIR3SF, NULL, inode_u_sfdir3_count, FLD_COUNT, TYP_NONE },
{ "symlink", FLDT_CHARNS, NULL, inode_u_symlink_count, FLD_COUNT,
TYP_NONE },
+ { "rtrmapbt", FLDT_RTRMAPROOT, NULL, inode_u_rtrmapbt_count, FLD_COUNT,
+ TYP_NONE },
{ NULL }
};
@@ -243,7 +247,7 @@ const field_t inode_a_flds[] = {
};
static const char *dinode_fmt_name[] =
- { "dev", "local", "extents", "btree", "uuid" };
+ { "dev", "local", "extents", "btree", "uuid", "rmap" };
static const int dinode_fmt_name_size =
sizeof(dinode_fmt_name) / sizeof(dinode_fmt_name[0]);
@@ -633,9 +637,86 @@ inode_init(void)
add_command(&inode_cmd);
}
+static struct bitmap *rmap_inodes;
+
+static inline int
+set_rtgroup_rmap_inode(
+ struct xfs_mount *mp,
+ xfs_rgnumber_t rgno)
+{
+ struct xfs_imeta_path *path;
+ struct xfs_trans *tp;
+ xfs_ino_t rtino;
+ int error;
+
+ if (!xfs_has_rtrmapbt(mp))
+ return 0;
+
+ error = -libxfs_rtrmapbt_create_path(mp, rgno, &path);
+ if (error)
+ return error;
+
+ error = -libxfs_trans_alloc_empty(mp, &tp);
+ if (error)
+ goto out_path;
+
+ error = -libxfs_imeta_lookup(tp, path, &rtino);
+ if (error)
+ goto out_trans;
+
+ if (rtino == NULLFSINO) {
+ error = EFSCORRUPTED;
+ goto out_trans;
+ }
+
+ error = bitmap_set(rmap_inodes, rtino, 1);
+
+out_trans:
+ libxfs_trans_cancel(tp);
+out_path:
+ libxfs_imeta_free_path(path);
+ return error;
+}
+
+int
+init_rtmeta_inode_bitmaps(
+ struct xfs_mount *mp)
+{
+ xfs_rgnumber_t rgno;
+ int error;
+
+ if (rmap_inodes)
+ return 0;
+
+ error = bitmap_alloc(&rmap_inodes);
+ if (error)
+ return error;
+
+ for (rgno = 0; rgno < mp->m_sb.sb_rgcount; rgno++) {
+ int err2 = set_rtgroup_rmap_inode(mp, rgno);
+ if (err2 && !error)
+ error = err2;
+ }
+
+ return error;
+}
+
+bool is_rtrmap_inode(xfs_ino_t ino)
+{
+ return bitmap_test(rmap_inodes, ino, 1);
+}
+
typnm_t
inode_next_type(void)
{
+ int error;
+
+ error = init_rtmeta_inode_bitmaps(mp);
+ if (error) {
+ dbprintf(_("error %d setting up rt metadata inode bitmaps\n"),
+ error);
+ }
+
switch (iocur_top->mode & S_IFMT) {
case S_IFDIR:
return TYP_DIR2;
@@ -655,8 +736,9 @@ inode_next_type(void)
iocur_top->ino == mp->m_sb.sb_gquotino ||
iocur_top->ino == mp->m_sb.sb_pquotino)
return TYP_DQBLK;
- else
- return TYP_DATA;
+ else if (is_rtrmap_inode(iocur_top->ino))
+ return TYP_RTRMAPBT;
+ return TYP_DATA;
default:
return TYP_NONE;
}
@@ -790,6 +872,20 @@ inode_u_sfdir3_count(
xfs_has_ftype(mp);
}
+static int
+inode_u_rtrmapbt_count(
+ void *obj,
+ int startoff)
+{
+ struct xfs_dinode *dip;
+
+ ASSERT(bitoffs(startoff) == 0);
+ ASSERT(obj == iocur_top->data);
+ dip = obj;
+ ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
+ return dip->di_format == XFS_DINODE_FMT_RMAP;
+}
+
int
inode_u_size(
void *obj,
diff --git a/db/inode.h b/db/inode.h
index 31a2ebbba6a..a47b0575a15 100644
--- a/db/inode.h
+++ b/db/inode.h
@@ -23,3 +23,6 @@ extern int inode_size(void *obj, int startoff, int idx);
extern int inode_u_size(void *obj, int startoff, int idx);
extern void xfs_inode_set_crc(struct xfs_buf *);
extern void set_cur_inode(xfs_ino_t ino);
+
+int init_rtmeta_inode_bitmaps(struct xfs_mount *mp);
+bool is_rtrmap_inode(xfs_ino_t ino);
diff --git a/db/type.c b/db/type.c
index 2091b4ac8b1..1dfc33ffb44 100644
--- a/db/type.c
+++ b/db/type.c
@@ -51,6 +51,7 @@ static const typ_t __typtab[] = {
{ TYP_BNOBT, "bnobt", handle_struct, bnobt_hfld, NULL, TYP_F_NO_CRC_OFF },
{ TYP_CNTBT, "cntbt", handle_struct, cntbt_hfld, NULL, TYP_F_NO_CRC_OFF },
{ TYP_RMAPBT, NULL },
+ { TYP_RTRMAPBT, NULL },
{ TYP_REFCBT, NULL },
{ TYP_DATA, "data", handle_block, NULL, NULL, TYP_F_NO_CRC_OFF },
{ TYP_DIR2, "dir2", handle_struct, dir2_hfld, NULL, TYP_F_NO_CRC_OFF },
@@ -91,6 +92,8 @@ static const typ_t __typtab_crc[] = {
&xfs_cntbt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF },
{ TYP_RMAPBT, "rmapbt", handle_struct, rmapbt_crc_hfld,
&xfs_rmapbt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF },
+ { TYP_RTRMAPBT, "rtrmapbt", handle_struct, rtrmapbt_crc_hfld,
+ &xfs_rtrmapbt_buf_ops, XFS_BTREE_LBLOCK_CRC_OFF },
{ TYP_REFCBT, "refcntbt", handle_struct, refcbt_crc_hfld,
&xfs_refcountbt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF },
{ TYP_DATA, "data", handle_block, NULL, NULL, TYP_F_NO_CRC_OFF },
@@ -141,6 +144,8 @@ static const typ_t __typtab_spcrc[] = {
&xfs_cntbt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF },
{ TYP_RMAPBT, "rmapbt", handle_struct, rmapbt_crc_hfld,
&xfs_rmapbt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF },
+ { TYP_RTRMAPBT, "rtrmapbt", handle_struct, rtrmapbt_crc_hfld,
+ &xfs_rtrmapbt_buf_ops, XFS_BTREE_LBLOCK_CRC_OFF },
{ TYP_REFCBT, "refcntbt", handle_struct, refcbt_crc_hfld,
&xfs_refcountbt_buf_ops, XFS_BTREE_SBLOCK_CRC_OFF },
{ TYP_DATA, "data", handle_block, NULL, NULL, TYP_F_NO_CRC_OFF },
diff --git a/db/type.h b/db/type.h
index e7f0ecc1768..c98f3640202 100644
--- a/db/type.h
+++ b/db/type.h
@@ -20,6 +20,7 @@ typedef enum typnm
TYP_BNOBT,
TYP_CNTBT,
TYP_RMAPBT,
+ TYP_RTRMAPBT,
TYP_REFCBT,
TYP_DATA,
TYP_DIR2,
diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
index c5dad34f3d2..e961453052a 100644
--- a/libxfs/libxfs_api_defs.h
+++ b/libxfs/libxfs_api_defs.h
@@ -286,6 +286,10 @@
#define xfs_rtfree_extent libxfs_rtfree_extent
#define xfs_rtgroup_update_secondary_sbs libxfs_rtgroup_update_secondary_sbs
#define xfs_rtgroup_update_super libxfs_rtgroup_update_super
+#define xfs_rtrmapbt_create_path libxfs_rtrmapbt_create_path
+#define xfs_rtrmapbt_droot_maxrecs libxfs_rtrmapbt_droot_maxrecs
+#define xfs_rtrmapbt_maxrecs libxfs_rtrmapbt_maxrecs
+
#define xfs_sb_from_disk libxfs_sb_from_disk
#define xfs_sb_quota_from_disk libxfs_sb_quota_from_disk
#define xfs_sb_read_secondary libxfs_sb_read_secondary
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index d0115075888..0e20108fb51 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -1200,7 +1200,7 @@ The possible data types are:
.BR agf ", " agfl ", " agi ", " attr ", " bmapbta ", " bmapbtd ,
.BR bnobt ", " cntbt ", " data ", " dir ", " dir2 ", " dqblk ,
.BR inobt ", " inode ", " log ", " refcntbt ", " rmapbt ", " rtbitmap ,
-.BR rtsummary ", " sb ", " symlink " and " text .
+.BR rtsummary ", " sb ", " symlink ", " rtrmapbt ", and " text .
See the TYPES section below for more information on these data types.
.TP
.BI "timelimit [" OPTIONS ]
@@ -2348,6 +2348,64 @@ block number within the allocation group to the next level in the Btree.
.PD
.RE
.TP
+.B rtrmapbt
+There is one reverse mapping Btree for each realtime group.
+The
+.BR startblock " and "
+.B blockcount
+fields are 32 bits wide and record blocks within a realtime group.
+The root of this Btree is the reverse-mapping inode, which is recorded in the
+metadata directory.
+Blocks are linked to sibling left and right blocks at each level, as well as by
+pointers from parent to child blocks.
+Each block has the following fields:
+.RS 1.4i
+.PD 0
+.TP 1.2i
+.B magic
+RTRMAP block magic number, 0x4d415052 ('MAPR').
+.TP
+.B level
+level number of this block, 0 is a leaf.
+.TP
+.B numrecs
+number of data entries in the block.
+.TP
+.B leftsib
+left (logically lower) sibling block, 0 if none.
+.TP
+.B rightsib
+right (logically higher) sibling block, 0 if none.
+.TP
+.B recs
+[leaf blocks only] array of reference count records. Each record contains
+.BR startblock ,
+.BR blockcount ,
+.BR owner ,
+.BR offset ,
+.BR attr_fork ,
+.BR bmbt_block ,
+and
+.BR unwritten .
+.TP
+.B keys
+[non-leaf blocks only] array of double-key records. The first ("low") key
+contains the first value of each block in the level below this one. The second
+("high") key contains the largest key that can be used to identify any record
+in the subtree. Each record contains
+.BR startblock ,
+.BR owner ,
+.BR offset ,
+.BR attr_fork ,
+and
+.BR bmbt_block .
+.TP
+.B ptrs
+[non-leaf blocks only] array of child block pointers. Each pointer is a
+block number within the allocation group to the next level in the Btree.
+.PD
+.RE
+.TP
.B rtbitmap
If the filesystem has a realtime subvolume, then the
.B rbmino
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 23/47] xfs_db: support the realtime rmapbt
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (21 preceding siblings ...)
2023-12-27 13:16 ` [PATCH 22/47] xfs_db: display the realtime rmap btree contents Darrick J. Wong
@ 2023-12-27 13:16 ` Darrick J. Wong
2023-12-27 13:16 ` [PATCH 24/47] xfs_db: support rudimentary checks of the rtrmap btree Darrick J. Wong
` (23 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:16 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Wire up various parts of xfs_db for realtime rmap support.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
db/btblock.c | 3 ++
db/btdump.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++
db/btheight.c | 5 ++++
libxfs/libxfs_api_defs.h | 1 +
man/man8/xfs_db.8 | 3 +-
5 files changed, 75 insertions(+), 1 deletion(-)
diff --git a/db/btblock.c b/db/btblock.c
index 5cad166278d..70f6c3f6aed 100644
--- a/db/btblock.c
+++ b/db/btblock.c
@@ -147,6 +147,9 @@ block_to_bt(
case TYP_RMAPBT:
magic = crc ? XFS_RMAP_CRC_MAGIC : 0;
break;
+ case TYP_RTRMAPBT:
+ magic = crc ? XFS_RTRMAP_CRC_MAGIC : 0;
+ break;
case TYP_REFCBT:
magic = crc ? XFS_REFC_CRC_MAGIC : 0;
break;
diff --git a/db/btdump.c b/db/btdump.c
index 81642cde2b6..9c528e5a11a 100644
--- a/db/btdump.c
+++ b/db/btdump.c
@@ -441,6 +441,67 @@ dump_dabtree(
return ret;
}
+static bool
+is_btree_inode(void)
+{
+ struct xfs_dinode *dip;
+
+ dip = iocur_top->data;
+ return dip->di_format == XFS_DINODE_FMT_RMAP;
+}
+
+static int
+dump_btree_inode(
+ bool dump_node_blocks)
+{
+ char *prefix;
+ struct xfs_dinode *dip;
+ struct xfs_rtrmap_root *rtrmap;
+ int level;
+ int numrecs;
+ int ret;
+
+ dip = iocur_top->data;
+ switch (dip->di_format) {
+ case XFS_DINODE_FMT_RMAP:
+ prefix = "u3.rtrmapbt";
+ rtrmap = (struct xfs_rtrmap_root *)XFS_DFORK_DPTR(dip);
+ level = be16_to_cpu(rtrmap->bb_level);
+ numrecs = be16_to_cpu(rtrmap->bb_numrecs);
+ break;
+ default:
+ dbprintf("Unknown metadata inode type %u\n", dip->di_format);
+ return 0;
+ }
+
+ if (numrecs == 0)
+ return 0;
+ if (level > 0) {
+ if (dump_node_blocks) {
+ ret = eval("print %s.keys", prefix);
+ if (ret)
+ goto err;
+ ret = eval("print %s.ptrs", prefix);
+ if (ret)
+ goto err;
+ }
+ ret = eval("addr %s.ptrs[1]", prefix);
+ if (ret)
+ goto err;
+ ret = dump_btree_long(dump_node_blocks);
+ } else {
+ ret = eval("print %s.recs", prefix);
+ }
+ if (ret)
+ goto err;
+
+ ret = eval("pop");
+ return ret;
+err:
+ eval("pop");
+ return ret;
+}
+
static int
btdump_f(
int argc,
@@ -488,8 +549,11 @@ btdump_f(
return dump_btree_short(iflag);
case TYP_BMAPBTA:
case TYP_BMAPBTD:
+ case TYP_RTRMAPBT:
return dump_btree_long(iflag);
case TYP_INODE:
+ if (is_btree_inode())
+ return dump_btree_inode(iflag);
return dump_inode(iflag, aflag);
case TYP_ATTR:
return dump_dabtree(iflag, crc ? &attr3_print : &attr_print);
diff --git a/db/btheight.c b/db/btheight.c
index 6643489c82c..25ce3400334 100644
--- a/db/btheight.c
+++ b/db/btheight.c
@@ -53,6 +53,11 @@ struct btmap {
.maxlevels = libxfs_rmapbt_maxlevels_ondisk,
.maxrecs = libxfs_rmapbt_maxrecs,
},
+ {
+ .tag = "rtrmapbt",
+ .maxlevels = libxfs_rtrmapbt_maxlevels_ondisk,
+ .maxrecs = libxfs_rtrmapbt_maxrecs,
+ },
};
static void
diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
index e961453052a..4b2fbd7cac9 100644
--- a/libxfs/libxfs_api_defs.h
+++ b/libxfs/libxfs_api_defs.h
@@ -288,6 +288,7 @@
#define xfs_rtgroup_update_super libxfs_rtgroup_update_super
#define xfs_rtrmapbt_create_path libxfs_rtrmapbt_create_path
#define xfs_rtrmapbt_droot_maxrecs libxfs_rtrmapbt_droot_maxrecs
+#define xfs_rtrmapbt_maxlevels_ondisk libxfs_rtrmapbt_maxlevels_ondisk
#define xfs_rtrmapbt_maxrecs libxfs_rtrmapbt_maxrecs
#define xfs_sb_from_disk libxfs_sb_from_disk
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index 0e20108fb51..778e3f9dd70 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -454,8 +454,9 @@ The supported btree types are:
.IR finobt ,
.IR bmapbt ,
.IR refcountbt ,
+.IR rmapbt ,
and
-.IR rmapbt .
+.IR rtrmapbt .
The magic value
.I all
can be used to walk through all btree types.
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 24/47] xfs_db: support rudimentary checks of the rtrmap btree
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (22 preceding siblings ...)
2023-12-27 13:16 ` [PATCH 23/47] xfs_db: support the realtime rmapbt Darrick J. Wong
@ 2023-12-27 13:16 ` Darrick J. Wong
2023-12-27 13:17 ` [PATCH 25/47] xfs_db: copy the realtime rmap btree Darrick J. Wong
` (22 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:16 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Perform some fairly superficial checks of the rtrmap btree. We'll
do more sophisticated checks in xfs_repair, but provide enough of
a spot-check here that we can do simple things.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
db/check.c | 203 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
db/inode.c | 28 ++++++++
db/inode.h | 1
3 files changed, 226 insertions(+), 6 deletions(-)
diff --git a/db/check.c b/db/check.c
index d1c86206c08..351bb94a48e 100644
--- a/db/check.c
+++ b/db/check.c
@@ -20,6 +20,7 @@
#include "init.h"
#include "malloc.h"
#include "dir2.h"
+#include "inode.h"
typedef enum {
IS_USER_QUOTA, IS_PROJECT_QUOTA, IS_GROUP_QUOTA,
@@ -57,6 +58,7 @@ typedef enum {
DBM_RLDATA,
DBM_COWDATA,
DBM_RTSB,
+ DBM_BTRTRMAP,
DBM_NDBM
} dbm_t;
@@ -71,6 +73,7 @@ typedef struct inodata {
xfs_ino_t ino;
struct inodata *parent;
char *name;
+ xfs_rgnumber_t rgno; /* only if rtgroup metadata inode */
} inodata_t;
#define MIN_INODATA_HASH_SIZE 256
#define MAX_INODATA_HASH_SIZE 65536
@@ -189,6 +192,7 @@ static const char *typename[] = {
"rldata",
"cowdata",
"rtsb",
+ "btrtrmap",
NULL
};
@@ -341,6 +345,9 @@ static void process_rtbitmap(blkmap_t *blkmap);
static void process_rtsummary(blkmap_t *blkmap);
static xfs_ino_t process_sf_dir_v2(struct xfs_dinode *dip, int *dot,
int *dotdot, inodata_t *id);
+static void process_rtrmap(struct inodata *id,
+ struct xfs_dinode *dip,
+ xfs_rfsblock_t *toti);
static void quota_add(xfs_dqid_t *p, xfs_dqid_t *g, xfs_dqid_t *u,
int dq, xfs_qcnt_t bc, xfs_qcnt_t ic,
xfs_qcnt_t rc);
@@ -366,6 +373,12 @@ static void scanfunc_bmap(struct xfs_btree_block *block,
xfs_rfsblock_t *toti, xfs_extnum_t *nex,
blkmap_t **blkmapp, int isroot,
typnm_t btype);
+static void scanfunc_rtrmap(struct xfs_btree_block *block,
+ int level, dbm_t type, xfs_fsblock_t bno,
+ inodata_t *id, xfs_rfsblock_t *totd,
+ xfs_rfsblock_t *toti, xfs_extnum_t *nex,
+ blkmap_t **blkmapp, int isroot,
+ typnm_t btype);
static void scanfunc_bno(struct xfs_btree_block *block, int level,
xfs_agf_t *agf, xfs_agblock_t bno,
int isroot);
@@ -839,12 +852,21 @@ blockget_f(
xfs_agnumber_t agno;
int oldprefix;
int sbyell;
+ int error;
if (dbmap) {
dbprintf(_("already have block usage information\n"));
return 0;
}
+ error = init_rtmeta_inode_bitmaps(mp);
+ if (error) {
+ dbprintf(_("error %d setting up rt metadata inode bitmaps\n"),
+ error);
+ exitcode = 3;
+ return 0;
+ }
+
if (!init(argc, argv)) {
if (serious_error)
exitcode = 3;
@@ -1101,6 +1123,7 @@ blocktrash_f(
(1 << DBM_QUOTA) |
(1 << DBM_RTBITMAP) |
(1 << DBM_RTSUM) |
+ (1 << DBM_BTRTRMAP) |
(1 << DBM_SYMLINK) |
(1 << DBM_BTFINO) |
(1 << DBM_BTRMAP) |
@@ -2850,7 +2873,7 @@ process_inode(
0 /* type 15 unused */
};
static char *fmtnames[] = {
- "dev", "local", "extents", "btree", "uuid"
+ "dev", "local", "extents", "btree", "uuid", "rmap"
};
ino = XFS_AGINO_TO_INO(mp, be32_to_cpu(agf->agf_seqno), agino);
@@ -2916,11 +2939,20 @@ process_inode(
be32_to_cpu(dip->di_next_unlinked), ino);
error++;
}
- /*
- * di_mode is a 16-bit uint so no need to check the < 0 case
- */
+
+ /* Check that mode and data fork format match. */
mode = be16_to_cpu(dip->di_mode);
- if ((((mode & S_IFMT) >> 12) > 15) ||
+ if (is_rtrmap_inode(ino)) {
+ if (!S_ISREG(mode) || dip->di_format != XFS_DINODE_FMT_RMAP) {
+ if (v)
+ dbprintf(
+ _("bad format %d for rtrmap inode %lld type %#o\n"),
+ dip->di_format, (long long)ino,
+ mode & S_IFMT);
+ error++;
+ return;
+ }
+ } else if ((((mode & S_IFMT) >> 12) > 15) ||
(!(okfmts[(mode & S_IFMT) >> 12] & (1 << dip->di_format)))) {
if (v)
dbprintf(_("bad format %d for inode %lld type %#o\n"),
@@ -2993,6 +3025,9 @@ process_inode(
blkmap = blkmap_alloc(dnextents);
if (!xfs_has_metadir(mp))
addlink_inode(id);
+ } else if (is_rtrmap_inode(id->ino)) {
+ type = DBM_BTRTRMAP;
+ blkmap = blkmap_alloc(be32_to_cpu(dip->di_nextents));
}
else
type = DBM_DATA;
@@ -3024,6 +3059,10 @@ process_inode(
process_btinode(id, dip, type, &totdblocks, &totiblocks,
&nextents, &blkmap, XFS_DATA_FORK);
break;
+ case XFS_DINODE_FMT_RMAP:
+ id->rgno = rtgroup_for_rtrmap_ino(mp, id->ino);
+ process_rtrmap(id, dip, &totiblocks);
+ break;
}
if (dip->di_forkoff) {
sbversion |= XFS_SB_VERSION_ATTRBIT;
@@ -3049,6 +3088,7 @@ process_inode(
case DBM_RTBITMAP:
case DBM_RTSUM:
case DBM_SYMLINK:
+ case DBM_BTRTRMAP:
case DBM_UNKNOWN:
bc = totdblocks + totiblocks +
atotdblocks + atotiblocks;
@@ -3819,6 +3859,79 @@ process_rtsummary(
}
}
+static void
+process_rtrmap(
+ struct inodata *id,
+ struct xfs_dinode *dip,
+ xfs_rfsblock_t *toti)
+{
+ xfs_extnum_t nex = 0;
+ xfs_rfsblock_t totd = 0;
+ struct xfs_rtrmap_root *dib;
+ int whichfork = XFS_DATA_FORK;
+ int i;
+ int maxrecs;
+ xfs_rtrmap_ptr_t *pp;
+
+ if (id->rgno == NULLRGNUMBER) {
+ dbprintf(
+ _("rt group for rmap ino %lld not found\n"),
+ id->ino);
+ error++;
+ return;
+ }
+
+ dib = (struct xfs_rtrmap_root *)XFS_DFORK_PTR(dip, whichfork);
+ if (be16_to_cpu(dib->bb_level) >= mp->m_rtrmap_maxlevels) {
+ if (!sflag || id->ilist)
+ dbprintf(_("level for ino %lld rtrmap root too "
+ "large (%u)\n"),
+ id->ino,
+ be16_to_cpu(dib->bb_level));
+ error++;
+ return;
+ }
+ maxrecs = libxfs_rtrmapbt_droot_maxrecs(
+ XFS_DFORK_SIZE(dip, mp, whichfork),
+ dib->bb_level == 0);
+ if (be16_to_cpu(dib->bb_numrecs) > maxrecs) {
+ if (!sflag || id->ilist)
+ dbprintf(_("numrecs for ino %lld rtrmap root too "
+ "large (%u)\n"),
+ id->ino,
+ be16_to_cpu(dib->bb_numrecs));
+ error++;
+ return;
+ }
+ if (be16_to_cpu(dib->bb_level) == 0) {
+ struct xfs_rmap_rec *rp;
+ xfs_fsblock_t lastblock;
+
+ rp = xfs_rtrmap_droot_rec_addr(dib, 1);
+ lastblock = 0;
+ for (i = 0; i < be16_to_cpu(dib->bb_numrecs); i++) {
+ if (be32_to_cpu(rp[i].rm_startblock) < lastblock) {
+ dbprintf(_(
+ "out-of-order rtrmap btree record %d (%u %u) root\n"),
+ i, be32_to_cpu(rp[i].rm_startblock),
+ be32_to_cpu(rp[i].rm_startblock));
+ } else {
+ lastblock = be32_to_cpu(rp[i].rm_startblock) +
+ be32_to_cpu(rp[i].rm_blockcount);
+ }
+ }
+ return;
+ } else {
+ pp = xfs_rtrmap_droot_ptr_addr(dib, 1, maxrecs);
+ for (i = 0; i < be16_to_cpu(dib->bb_numrecs); i++)
+ scan_lbtree(get_unaligned_be64(&pp[i]),
+ be16_to_cpu(dib->bb_level),
+ scanfunc_rtrmap, DBM_BTRTRMAP,
+ id, &totd, toti,
+ &nex, NULL, 1, TYP_RTRMAPBT);
+ }
+}
+
static xfs_ino_t
process_sf_dir_v2(
struct xfs_dinode *dip,
@@ -4917,6 +5030,86 @@ scanfunc_rmap(
TYP_RMAPBT);
}
+static void
+scanfunc_rtrmap(
+ struct xfs_btree_block *block,
+ int level,
+ dbm_t type,
+ xfs_fsblock_t bno,
+ inodata_t *id,
+ xfs_rfsblock_t *totd,
+ xfs_rfsblock_t *toti,
+ xfs_extnum_t *nex,
+ blkmap_t **blkmapp,
+ int isroot,
+ typnm_t btype)
+{
+ xfs_agblock_t agbno;
+ xfs_agnumber_t agno;
+ int i;
+ xfs_rtrmap_ptr_t *pp;
+ struct xfs_rmap_rec *rp;
+ xfs_fsblock_t lastblock;
+
+ agno = XFS_FSB_TO_AGNO(mp, bno);
+ agbno = XFS_FSB_TO_AGBNO(mp, bno);
+ if (be32_to_cpu(block->bb_magic) != XFS_RTRMAP_CRC_MAGIC) {
+ dbprintf(_("bad magic # %#x in rtrmapbt block %u/%u\n"),
+ be32_to_cpu(block->bb_magic), agno, bno);
+ serious_error++;
+ return;
+ }
+ if (be16_to_cpu(block->bb_level) != level) {
+ if (!sflag)
+ dbprintf(_("expected level %d got %d in rtrmapbt block "
+ "%u/%u\n"),
+ level, be16_to_cpu(block->bb_level), agno, bno);
+ error++;
+ }
+ set_dbmap(agno, agbno, 1, type, agno, agbno);
+ set_inomap(agno, agbno, 1, id);
+ (*toti)++;
+ if (level == 0) {
+ if (be16_to_cpu(block->bb_numrecs) > mp->m_rtrmap_mxr[0] ||
+ (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_rtrmap_mnr[0])) {
+ dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
+ "rtrmapbt block %u/%u\n"),
+ be16_to_cpu(block->bb_numrecs), mp->m_rtrmap_mnr[0],
+ mp->m_rtrmap_mxr[0], agno, bno);
+ serious_error++;
+ return;
+ }
+ rp = xfs_rtrmap_rec_addr(block, 1);
+ lastblock = 0;
+ for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
+ if (be32_to_cpu(rp[i].rm_startblock) < lastblock) {
+ dbprintf(_(
+ "out-of-order rtrmap btree record %d (%u %u) block %u/%u l %llu\n"),
+ i, be32_to_cpu(rp[i].rm_startblock),
+ be32_to_cpu(rp[i].rm_blockcount),
+ agno, bno, lastblock);
+ } else {
+ lastblock = be32_to_cpu(rp[i].rm_startblock) +
+ be32_to_cpu(rp[i].rm_blockcount);
+ }
+ }
+ return;
+ }
+ if (be16_to_cpu(block->bb_numrecs) > mp->m_rtrmap_mxr[1] ||
+ (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_rtrmap_mnr[1])) {
+ dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in rtrmapbt "
+ "block %u/%u\n"),
+ be16_to_cpu(block->bb_numrecs), mp->m_rtrmap_mnr[1],
+ mp->m_rtrmap_mxr[1], agno, bno);
+ serious_error++;
+ return;
+ }
+ pp = xfs_rtrmap_ptr_addr(block, 1, mp->m_rtrmap_mxr[1]);
+ for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
+ scan_lbtree(be64_to_cpu(pp[i]), level, scanfunc_rtrmap, type, id,
+ totd, toti, nex, blkmapp, 0, btype);
+}
+
static void
scanfunc_refcnt(
struct xfs_btree_block *block,
diff --git a/db/inode.c b/db/inode.c
index 6867f5c5427..492a8f53ed0 100644
--- a/db/inode.c
+++ b/db/inode.c
@@ -637,7 +637,12 @@ inode_init(void)
add_command(&inode_cmd);
}
-static struct bitmap *rmap_inodes;
+struct rtgroup_inodes {
+ xfs_ino_t rmap_ino;
+};
+
+static struct rtgroup_inodes *rtgroup_inodes;
+static struct bitmap *rmap_inodes;
static inline int
set_rtgroup_rmap_inode(
@@ -670,6 +675,10 @@ set_rtgroup_rmap_inode(
}
error = bitmap_set(rmap_inodes, rtino, 1);
+ if (error)
+ goto out_trans;
+
+ rtgroup_inodes[rgno].rmap_ino = rtino;
out_trans:
libxfs_trans_cancel(tp);
@@ -688,6 +697,11 @@ init_rtmeta_inode_bitmaps(
if (rmap_inodes)
return 0;
+ rtgroup_inodes = calloc(mp->m_sb.sb_rgcount,
+ sizeof(struct rtgroup_inodes));
+ if (!rtgroup_inodes)
+ return ENOMEM;
+
error = bitmap_alloc(&rmap_inodes);
if (error)
return error;
@@ -706,6 +720,18 @@ bool is_rtrmap_inode(xfs_ino_t ino)
return bitmap_test(rmap_inodes, ino, 1);
}
+xfs_rgnumber_t rtgroup_for_rtrmap_ino(struct xfs_mount *mp, xfs_ino_t ino)
+{
+ unsigned int i;
+
+ for (i = 0; i < mp->m_sb.sb_rgcount; i++) {
+ if (rtgroup_inodes[i].rmap_ino == ino)
+ return i;
+ }
+
+ return NULLRGNUMBER;
+}
+
typnm_t
inode_next_type(void)
{
diff --git a/db/inode.h b/db/inode.h
index a47b0575a15..04e606abed3 100644
--- a/db/inode.h
+++ b/db/inode.h
@@ -26,3 +26,4 @@ extern void set_cur_inode(xfs_ino_t ino);
int init_rtmeta_inode_bitmaps(struct xfs_mount *mp);
bool is_rtrmap_inode(xfs_ino_t ino);
+xfs_rgnumber_t rtgroup_for_rtrmap_ino(struct xfs_mount *mp, xfs_ino_t ino);
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 25/47] xfs_db: copy the realtime rmap btree
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (23 preceding siblings ...)
2023-12-27 13:16 ` [PATCH 24/47] xfs_db: support rudimentary checks of the rtrmap btree Darrick J. Wong
@ 2023-12-27 13:17 ` Darrick J. Wong
2023-12-27 13:17 ` [PATCH 26/47] xfs_db: make fsmap query the realtime reverse mapping tree Darrick J. Wong
` (21 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:17 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Copy the realtime rmapbt when we're metadumping the filesystem.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
db/metadump.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 129 insertions(+)
diff --git a/db/metadump.c b/db/metadump.c
index ccf7b89ccd5..c6f6bf1ea17 100644
--- a/db/metadump.c
+++ b/db/metadump.c
@@ -589,6 +589,55 @@ copy_rmap_btree(
return scan_btree(agno, root, levels, TYP_RMAPBT, agf, scanfunc_rmapbt);
}
+static int
+scanfunc_rtrmapbt(
+ struct xfs_btree_block *block,
+ xfs_agnumber_t agno,
+ xfs_agblock_t agbno,
+ int level,
+ typnm_t btype,
+ void *arg)
+{
+ xfs_rtrmap_ptr_t *pp;
+ int i;
+ int numrecs;
+
+ if (level == 0)
+ return 1;
+
+ numrecs = be16_to_cpu(block->bb_numrecs);
+ if (numrecs > mp->m_rtrmap_mxr[1]) {
+ if (metadump.show_warnings)
+ print_warning("invalid numrecs (%u) in %s block %u/%u",
+ numrecs, typtab[btype].name, agno, agbno);
+ return 1;
+ }
+
+ pp = xfs_rtrmap_ptr_addr(block, 1, mp->m_rtrmap_mxr[1]);
+ for (i = 0; i < numrecs; i++) {
+ xfs_agnumber_t pagno;
+ xfs_agblock_t pbno;
+
+ pagno = XFS_FSB_TO_AGNO(mp, get_unaligned_be64(&pp[i]));
+ pbno = XFS_FSB_TO_AGBNO(mp, get_unaligned_be64(&pp[i]));
+
+ if (pbno == 0 || pbno > mp->m_sb.sb_agblocks ||
+ pagno > mp->m_sb.sb_agcount) {
+ if (metadump.show_warnings)
+ print_warning("invalid block number (%u/%u) "
+ "in inode %llu %s block %u/%u",
+ pagno, pbno,
+ (unsigned long long)metadump.cur_ino,
+ typtab[btype].name, agno, agbno);
+ continue;
+ }
+ if (!scan_btree(pagno, pbno, level, btype, arg,
+ scanfunc_rtrmapbt))
+ return 0;
+ }
+ return 1;
+}
+
static int
scanfunc_refcntbt(
struct xfs_btree_block *block,
@@ -2319,6 +2368,83 @@ process_exinode(
whichfork), nex, itype, is_meta);
}
+static int
+process_rtrmap(
+ struct xfs_dinode *dip,
+ typnm_t itype)
+{
+ struct xfs_rtrmap_root *dib;
+ int i;
+ xfs_rtrmap_ptr_t *pp;
+ int level;
+ int nrecs;
+ int maxrecs;
+ int whichfork;
+ typnm_t btype;
+
+ if (itype == TYP_ATTR && metadump.show_warnings) {
+ print_warning("ignoring rtrmapbt root in inode %llu attr fork",
+ (unsigned long long)metadump.cur_ino);
+ return 1;
+ }
+
+ whichfork = XFS_DATA_FORK;
+ btype = TYP_RTRMAPBT;
+
+ dib = (struct xfs_rtrmap_root *)XFS_DFORK_PTR(dip, whichfork);
+ level = be16_to_cpu(dib->bb_level);
+ nrecs = be16_to_cpu(dib->bb_numrecs);
+
+ if (level > mp->m_rtrmap_maxlevels) {
+ if (metadump.show_warnings)
+ print_warning("invalid level (%u) in inode %lld %s "
+ "root", level,
+ (unsigned long long)metadump.cur_ino,
+ typtab[btype].name);
+ return 1;
+ }
+
+ if (level == 0)
+ return 1;
+
+ maxrecs = libxfs_rtrmapbt_droot_maxrecs(
+ XFS_DFORK_SIZE(dip, mp, whichfork),
+ false);
+ if (nrecs > maxrecs) {
+ if (metadump.show_warnings)
+ print_warning("invalid numrecs (%u) in inode %lld %s "
+ "root", nrecs,
+ (unsigned long long)metadump.cur_ino,
+ typtab[btype].name);
+ return 1;
+ }
+
+ pp = xfs_rtrmap_droot_ptr_addr(dib, 1, maxrecs);
+ for (i = 0; i < nrecs; i++) {
+ xfs_agnumber_t ag;
+ xfs_agblock_t bno;
+
+ ag = XFS_FSB_TO_AGNO(mp, get_unaligned_be64(&pp[i]));
+ bno = XFS_FSB_TO_AGBNO(mp, get_unaligned_be64(&pp[i]));
+
+ if (bno == 0 || bno > mp->m_sb.sb_agblocks ||
+ ag > mp->m_sb.sb_agcount) {
+ if (metadump.show_warnings)
+ print_warning("invalid block number (%u/%u) "
+ "in inode %llu %s root", ag,
+ bno,
+ (unsigned long long)metadump.cur_ino,
+ typtab[btype].name);
+ continue;
+ }
+
+ if (!scan_btree(ag, bno, level, btype, &itype,
+ scanfunc_rtrmapbt))
+ return 0;
+ }
+ return 1;
+}
+
static int
process_inode_data(
struct xfs_dinode *dip,
@@ -2363,6 +2489,9 @@ process_inode_data(
case XFS_DINODE_FMT_BTREE:
return process_btinode(dip, itype);
+
+ case XFS_DINODE_FMT_RMAP:
+ return process_rtrmap(dip, itype);
}
return 1;
}
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 26/47] xfs_db: make fsmap query the realtime reverse mapping tree
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (24 preceding siblings ...)
2023-12-27 13:17 ` [PATCH 25/47] xfs_db: copy the realtime rmap btree Darrick J. Wong
@ 2023-12-27 13:17 ` Darrick J. Wong
2023-12-27 13:17 ` [PATCH 27/47] xfs_io: support scrubbing rtgroup metadata paths Darrick J. Wong
` (20 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:17 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Extend the 'fsmap' debugger command to support querying the realtime
rmap btree via a new -r argument.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
db/fsmap.c | 164 +++++++++++++++++++++++++++++++++++++++++++++-
libxfs/libxfs_api_defs.h | 2 +
2 files changed, 162 insertions(+), 4 deletions(-)
diff --git a/db/fsmap.c b/db/fsmap.c
index 7fd42df2a1c..363c159ec07 100644
--- a/db/fsmap.c
+++ b/db/fsmap.c
@@ -102,6 +102,149 @@ fsmap(
}
}
+static int
+fsmap_rt_fn(
+ struct xfs_btree_cur *cur,
+ const struct xfs_rmap_irec *rec,
+ void *priv)
+{
+ struct fsmap_info *info = priv;
+
+ dbprintf(_("%llu: %u/%u len %u owner %lld offset %llu bmbt %d attrfork %d extflag %d\n"),
+ info->nr, cur->bc_ino.rtg->rtg_rgno, rec->rm_startblock,
+ rec->rm_blockcount, rec->rm_owner, rec->rm_offset,
+ !!(rec->rm_flags & XFS_RMAP_BMBT_BLOCK),
+ !!(rec->rm_flags & XFS_RMAP_ATTR_FORK),
+ !!(rec->rm_flags & XFS_RMAP_UNWRITTEN));
+ info->nr++;
+
+ return 0;
+}
+
+static int
+fsmap_rtgroup(
+ struct xfs_rtgroup *rtg,
+ const struct xfs_rmap_irec *low,
+ const struct xfs_rmap_irec *high,
+ struct fsmap_info *info)
+{
+ struct xfs_mount *mp = rtg->rtg_mount;
+ struct xfs_trans *tp;
+ struct xfs_inode *ip;
+ struct xfs_imeta_path *path;
+ struct xfs_btree_cur *bt_cur;
+ xfs_ino_t ino;
+ int error;
+
+ error = -libxfs_rtrmapbt_create_path(mp, rtg->rtg_rgno, &path);
+ if (error) {
+ dbprintf(
+ _("Cannot create path to rtgroup %u rmap inode\n"),
+ rtg->rtg_rgno);
+ return error;
+ }
+
+ error = -libxfs_trans_alloc_empty(mp, &tp);
+ if (error) {
+ dbprintf(
+ _("Cannot alloc transaction to look up rtgroup %u rmap inode\n"),
+ rtg->rtg_rgno);
+ goto out_path;
+ }
+
+ error = -libxfs_imeta_lookup(tp, path, &ino);
+ if (ino == NULLFSINO)
+ error = ENOENT;
+ if (error) {
+ dbprintf(_("Cannot look up rtgroup %u rmap inode, error %d\n"),
+ rtg->rtg_rgno, error);
+ goto out_trans;
+ }
+
+ error = -libxfs_imeta_iget(tp, ino, XFS_DIR3_FT_REG_FILE, &ip);
+ if (error) {
+ dbprintf(_("Cannot load rtgroup %u rmap inode\n"),
+ rtg->rtg_rgno);
+ goto out_trans;
+ }
+
+ bt_cur = libxfs_rtrmapbt_init_cursor(mp, tp, rtg, ip);
+ if (!bt_cur) {
+ dbprintf(_("Not enough memory.\n"));
+ goto out_rele;
+ }
+
+ error = -libxfs_rmap_query_range(bt_cur, low, high, fsmap_rt_fn,
+ info);
+ if (error) {
+ dbprintf(_("Error %d while querying rt fsmap btree.\n"),
+ error);
+ goto out_cur;
+ }
+
+out_cur:
+ libxfs_btree_del_cursor(bt_cur, error);
+out_rele:
+ libxfs_imeta_irele(ip);
+out_trans:
+ libxfs_trans_cancel(tp);
+out_path:
+ libxfs_imeta_free_path(path);
+ return error;
+}
+
+static void
+fsmap_rt(
+ xfs_fsblock_t start_fsb,
+ xfs_fsblock_t end_fsb)
+{
+ struct fsmap_info info;
+ xfs_daddr_t eofs;
+ struct xfs_rmap_irec low;
+ struct xfs_rmap_irec high;
+ struct xfs_rtgroup *rtg;
+ xfs_rgnumber_t start_rg;
+ xfs_rgnumber_t end_rg;
+ int error;
+
+ if (mp->m_sb.sb_rblocks == 0)
+ return;
+
+ eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks);
+ if (XFS_FSB_TO_DADDR(mp, end_fsb) >= eofs)
+ end_fsb = XFS_DADDR_TO_FSB(mp, eofs - 1);
+
+ low.rm_startblock = xfs_rtb_to_rgbno(mp, start_fsb, &start_rg);
+ low.rm_owner = 0;
+ low.rm_offset = 0;
+ low.rm_flags = 0;
+ high.rm_startblock = -1U;
+ high.rm_owner = ULLONG_MAX;
+ high.rm_offset = ULLONG_MAX;
+ high.rm_flags = XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK |
+ XFS_RMAP_UNWRITTEN;
+
+ end_rg = xfs_rtb_to_rgno(mp, end_fsb);
+
+ info.nr = 0;
+ for_each_rtgroup_range(mp, start_rg, end_rg, rtg) {
+ xfs_rgnumber_t rgno;
+
+ if (rtg->rtg_rgno == end_rg)
+ high.rm_startblock = xfs_rtb_to_rgbno(mp, end_fsb,
+ &rgno);
+
+ error = fsmap_rtgroup(rtg, &low, &high, &info);
+ if (error) {
+ libxfs_rtgroup_put(rtg);
+ return;
+ }
+
+ if (rtg->rtg_rgno == start_rg)
+ low.rm_startblock = 0;
+ }
+}
+
static int
fsmap_f(
int argc,
@@ -111,14 +254,18 @@ fsmap_f(
int c;
xfs_fsblock_t start_fsb = 0;
xfs_fsblock_t end_fsb = NULLFSBLOCK;
+ bool isrt = false;
if (!xfs_has_rmapbt(mp)) {
dbprintf(_("Filesystem does not support reverse mapping btree.\n"));
return 0;
}
- while ((c = getopt(argc, argv, "")) != EOF) {
+ while ((c = getopt(argc, argv, "r")) != EOF) {
switch (c) {
+ case 'r':
+ isrt = true;
+ break;
default:
dbprintf(_("Bad option for fsmap command.\n"));
return 0;
@@ -141,14 +288,23 @@ fsmap_f(
}
}
- fsmap(start_fsb, end_fsb);
+ if (argc > optind + 2) {
+ exitcode = 1;
+ dbprintf(_("Too many arguments to fsmap.\n"));
+ return 0;
+ }
+
+ if (isrt)
+ fsmap_rt(start_fsb, end_fsb);
+ else
+ fsmap(start_fsb, end_fsb);
return 0;
}
static const cmdinfo_t fsmap_cmd =
- { "fsmap", NULL, fsmap_f, 0, 2, 0,
- N_("[start_fsb] [end_fsb]"),
+ { "fsmap", NULL, fsmap_f, 0, -1, 0,
+ N_("[-r] [start_fsb] [end_fsb]"),
N_("display reverse mapping(s)"), NULL };
void
diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
index 4b2fbd7cac9..85a4a131c75 100644
--- a/libxfs/libxfs_api_defs.h
+++ b/libxfs/libxfs_api_defs.h
@@ -284,11 +284,13 @@
#define xfs_rtsummary_wordcount libxfs_rtsummary_wordcount
#define xfs_rtfree_extent libxfs_rtfree_extent
+#define xfs_rtgroup_put libxfs_rtgroup_put
#define xfs_rtgroup_update_secondary_sbs libxfs_rtgroup_update_secondary_sbs
#define xfs_rtgroup_update_super libxfs_rtgroup_update_super
#define xfs_rtrmapbt_create_path libxfs_rtrmapbt_create_path
#define xfs_rtrmapbt_droot_maxrecs libxfs_rtrmapbt_droot_maxrecs
#define xfs_rtrmapbt_maxlevels_ondisk libxfs_rtrmapbt_maxlevels_ondisk
+#define xfs_rtrmapbt_init_cursor libxfs_rtrmapbt_init_cursor
#define xfs_rtrmapbt_maxrecs libxfs_rtrmapbt_maxrecs
#define xfs_sb_from_disk libxfs_sb_from_disk
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 27/47] xfs_io: support scrubbing rtgroup metadata paths
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (25 preceding siblings ...)
2023-12-27 13:17 ` [PATCH 26/47] xfs_db: make fsmap query the realtime reverse mapping tree Darrick J. Wong
@ 2023-12-27 13:17 ` Darrick J. Wong
2023-12-27 13:17 ` [PATCH 28/47] libfrog: enable scrubbng of the realtime rmap Darrick J. Wong
` (19 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:17 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Support scrubbing the metadata directory path of an rtgroup metadata
file.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
io/scrub.c | 41 +++++++++++++++++++++++++++++++++++------
man/man8/xfs_io.8 | 3 ++-
2 files changed, 37 insertions(+), 7 deletions(-)
diff --git a/io/scrub.c b/io/scrub.c
index e9254c7882a..72296cbe86a 100644
--- a/io/scrub.c
+++ b/io/scrub.c
@@ -136,21 +136,23 @@ parse_metapath(
int argc,
char **argv,
int optind,
- __u64 *ino)
+ __u64 *ino,
+ __u32 *group)
{
char *p;
unsigned long long control;
+ unsigned long control2 = 0;
int i;
- if (optind != argc - 1) {
+ if (optind != argc - 1 && optind != argc - 2) {
fprintf(stderr, _("Must specify metapath number.\n"));
return false;
}
for (i = 0; i < XFS_SCRUB_METAPATH_NR; i++) {
if (!strcmp(argv[optind], xfrog_metapaths[i].name)) {
- *ino = i;
- return true;
+ control = i;
+ goto find_group;
}
}
@@ -161,7 +163,32 @@ parse_metapath(
return false;
}
+find_group:
+ if (xfrog_metapaths[*ino].group == XFROG_SCRUB_GROUP_RTGROUP) {
+ if (optind == argc - 1) {
+ fprintf(stderr,
+_("%s: Metapath requires a group number.\n"),
+ xfrog_metapaths[*ino].name);
+ return false;
+ }
+ control2 = strtoul(argv[optind + 1], &p, 0);
+ if (*p != '\0') {
+ fprintf(stderr,
+ _("Bad group number '%s'.\n"),
+ argv[optind + 1]);
+ return false;
+ }
+ } else {
+ if (optind == argc - 2) {
+ fprintf(stderr,
+_("%s: Metapath does not take a second argument.\n"),
+ xfrog_metapaths[*ino].name);
+ return false;
+ }
+ }
+
*ino = control;
+ *group = control2;
return true;
}
@@ -237,7 +264,8 @@ parse_args(
switch (d->group) {
case XFROG_SCRUB_GROUP_METAPATH:
- if (!parse_metapath(argc, argv, optind, &meta->sm_ino)) {
+ if (!parse_metapath(argc, argv, optind, &meta->sm_ino,
+ &meta->sm_agno)) {
exitcode = 1;
return command_usage(cmdinfo);
}
@@ -587,7 +615,8 @@ scrubv_f(
switch (group) {
case XFROG_SCRUB_GROUP_METAPATH:
- if (!parse_metapath(argc, argv, optind, &vhead->svh_ino)) {
+ if (!parse_metapath(argc, argv, optind, &vhead->svh_ino,
+ &vhead->svh_agno)) {
exitcode = 1;
return command_usage(&scrubv_cmd);
}
diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8
index 6cf4b9e32e5..f94de0ce40f 100644
--- a/man/man8/xfs_io.8
+++ b/man/man8/xfs_io.8
@@ -1447,7 +1447,7 @@ Currently supported versions are 1 and 5.
.RE
.PD
.TP
-.BI "scrub " type " [ " agnumber " | " rgnumber " | " "ino" " " "gen" " | " metapath " ]"
+.BI "scrub " type " [ " agnumber " | " rgnumber " | " "ino" " " "gen" " | " metapath " [ " rgnumber " ] ]"
Scrub internal XFS filesystem metadata. The
.BI type
parameter specifies which type of metadata to scrub.
@@ -1456,6 +1456,7 @@ For realtime group metadata, one rtgroup number must be specified.
For file metadata, the scrub is applied to the open file unless the
inode number and generation number are specified.
For metapath, the name of a file or a raw number must be specified.
+If the metapath file is a per-rtgroup file, the group number must be specified.
.RE
.PD
.TP
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 28/47] libfrog: enable scrubbng of the realtime rmap
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (26 preceding siblings ...)
2023-12-27 13:17 ` [PATCH 27/47] xfs_io: support scrubbing rtgroup metadata paths Darrick J. Wong
@ 2023-12-27 13:17 ` Darrick J. Wong
2023-12-27 13:18 ` [PATCH 29/47] xfs_scrub: check rtrmapbt metadata directory connections Darrick J. Wong
` (18 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:17 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Add a new entry so that we can scrub the rtrmapbt.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libfrog/scrub.c | 5 +++++
scrub/repair.c | 1 +
2 files changed, 6 insertions(+)
diff --git a/libfrog/scrub.c b/libfrog/scrub.c
index 8822fc0088c..290ba0fb8bf 100644
--- a/libfrog/scrub.c
+++ b/libfrog/scrub.c
@@ -169,6 +169,11 @@ const struct xfrog_scrub_descr xfrog_scrubbers[XFS_SCRUB_TYPE_NR] = {
.descr = "realtime group bitmap",
.group = XFROG_SCRUB_GROUP_RTGROUP,
},
+ [XFS_SCRUB_TYPE_RTRMAPBT] = {
+ .name = "rtrmapbt",
+ .descr = "realtime reverse mapping btree",
+ .group = XFROG_SCRUB_GROUP_RTGROUP,
+ },
};
const struct xfrog_scrub_descr xfrog_metapaths[XFS_SCRUB_METAPATH_NR] = {
diff --git a/scrub/repair.c b/scrub/repair.c
index 43037a7c5e1..fee03f97701 100644
--- a/scrub/repair.c
+++ b/scrub/repair.c
@@ -532,6 +532,7 @@ repair_item_difficulty(
switch (scrub_type) {
case XFS_SCRUB_TYPE_RMAPBT:
+ case XFS_SCRUB_TYPE_RTRMAPBT:
ret |= REPAIR_DIFFICULTY_SECONDARY;
break;
case XFS_SCRUB_TYPE_SB:
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 29/47] xfs_scrub: check rtrmapbt metadata directory connections
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (27 preceding siblings ...)
2023-12-27 13:17 ` [PATCH 28/47] libfrog: enable scrubbng of the realtime rmap Darrick J. Wong
@ 2023-12-27 13:18 ` Darrick J. Wong
2023-12-27 13:18 ` [PATCH 30/47] xfs_scrub: retest metadata across scrub groups after a repair Darrick J. Wong
` (17 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:18 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Run the rt rmap btree metapath scrubber during phase 5 to ensure that
it's still connected to the metadir tree after we've pruned any bad
links.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
scrub/phase5.c | 24 ++++++++++++++++++++++--
scrub/scrub.h | 4 +++-
2 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/scrub/phase5.c b/scrub/phase5.c
index 3b8daf39ae6..6fd3c698270 100644
--- a/scrub/phase5.c
+++ b/scrub/phase5.c
@@ -743,6 +743,7 @@ static int
queue_metapath_scan(
struct workqueue *wq,
bool *abortedp,
+ xfs_rgnumber_t rgno,
uint64_t type)
{
struct fs_scan_item *item;
@@ -755,7 +756,7 @@ queue_metapath_scan(
str_liberror(ctx, ret, _("setting up metapath scan"));
return ret;
}
- scrub_item_init_metapath(&item->sri, type);
+ scrub_item_init_metapath(&item->sri, rgno, type);
scrub_item_schedule(&item->sri, XFS_SCRUB_TYPE_METAPATH);
item->abortedp = abortedp;
@@ -778,6 +779,7 @@ run_kernel_metadir_path_scrubbers(
const struct xfrog_scrub_descr *sc;
uint64_t type;
unsigned int nr_threads = scrub_nproc_workqueue(ctx);
+ xfs_rgnumber_t rgno;
bool aborted = false;
int ret, ret2;
@@ -797,7 +799,7 @@ run_kernel_metadir_path_scrubbers(
if (sc->group != XFROG_SCRUB_GROUP_FS)
continue;
- ret = queue_metapath_scan(&wq, &aborted, type);
+ ret = queue_metapath_scan(&wq, &aborted, 0, type);
if (ret) {
str_liberror(ctx, ret,
_("queueing metapath scrub work"));
@@ -805,6 +807,24 @@ run_kernel_metadir_path_scrubbers(
}
}
+ /* Scan all rtgroup metadata files */
+ for (rgno = 0;
+ rgno < ctx->mnt.fsgeom.rgcount && !aborted;
+ rgno++) {
+ for (type = 0; type < XFS_SCRUB_METAPATH_NR; type++) {
+ sc = &xfrog_metapaths[type];
+ if (sc->group != XFROG_SCRUB_GROUP_RTGROUP)
+ continue;
+
+ ret = queue_metapath_scan(&wq, &aborted, rgno, type);
+ if (ret) {
+ str_liberror(ctx, ret,
+ _("queueing metapath scrub work"));
+ goto wait;
+ }
+ }
+ }
+
wait:
ret2 = -workqueue_terminate(&wq);
if (ret2) {
diff --git a/scrub/scrub.h b/scrub/scrub.h
index bb94a11dcfc..24b5ad629c5 100644
--- a/scrub/scrub.h
+++ b/scrub/scrub.h
@@ -118,9 +118,11 @@ scrub_item_init_file(struct scrub_item *sri, const struct xfs_bulkstat *bstat)
}
static inline void
-scrub_item_init_metapath(struct scrub_item *sri, uint64_t metapath)
+scrub_item_init_metapath(struct scrub_item *sri, xfs_rgnumber_t rgno,
+ uint64_t metapath)
{
memset(sri, 0, sizeof(*sri));
+ sri->sri_agno = rgno;
sri->sri_ino = metapath;
}
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 30/47] xfs_scrub: retest metadata across scrub groups after a repair
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (28 preceding siblings ...)
2023-12-27 13:18 ` [PATCH 29/47] xfs_scrub: check rtrmapbt metadata directory connections Darrick J. Wong
@ 2023-12-27 13:18 ` Darrick J. Wong
2023-12-27 13:18 ` [PATCH 31/47] xfs_spaceman: report health status of the realtime rmap btree Darrick J. Wong
` (16 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:18 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Certain types of metadata have dependencies that cross scrub groups.
For example, after a repair the part of realtime bitmap corresponding to
a realtime group, we potentially need to rebuild the realtime summary to
reflect the new bitmap contents. The rtsummary is a separate scrub group
(metafiles) from the rgbitmap (rtgroup), which means that the rtsummary
repairs must be tracked by a separate scrub_item.
Create the necessary dependency table and code to make these kinds of
cross-group validations possible.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
scrub/phase4.c | 54 +++++++++++++++++++
scrub/repair.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
scrub/repair.h | 5 ++
3 files changed, 216 insertions(+), 1 deletion(-)
diff --git a/scrub/phase4.c b/scrub/phase4.c
index 88cb53aeac9..c58e4aaabda 100644
--- a/scrub/phase4.c
+++ b/scrub/phase4.c
@@ -42,6 +42,51 @@ struct repair_list_schedule {
bool made_progress;
};
+/*
+ * After a successful repair, schedule any additional revalidations needed in
+ * other scrub groups.
+ */
+static int
+revalidate_across_groups(
+ struct scrub_ctx *ctx,
+ const struct action_item *old_aitem,
+ struct repair_list_schedule *rls)
+{
+ struct action_list alist;
+ int error;
+
+ action_list_init(&alist);
+
+ error = action_item_schedule_revalidation(ctx, old_aitem, &alist);
+ if (error) {
+ rls->aborted = true;
+ return error;
+ }
+
+ if (action_list_empty(&alist))
+ return 0;
+
+ pthread_mutex_unlock(&rls->lock);
+ error = action_list_revalidate(ctx, &alist);
+ pthread_mutex_lock(&rls->lock);
+
+ /*
+ * Action items attached to @alist after the revalidation are either
+ * the result of finding new inconsistencies or an incomplete list
+ * after an operational error. In the first case we need these new
+ * items to be processed; in the second case, we're going to exit the
+ * process. Either way, pass the items back to the caller.
+ */
+ action_list_merge(&rls->requeue_list, &alist);
+
+ if (error) {
+ rls->aborted = true;
+ return error;
+ }
+
+ return 0;
+}
+
/* Try to repair as many things on our list as we can. */
static void
repair_list_worker(
@@ -89,9 +134,16 @@ repair_list_worker(
action_list_add(&rls->requeue_list, aitem);
break;
case TR_REPAIRED:
+ ret = revalidate_across_groups(ctx, aitem, rls);
+ if (ret) {
+ free(aitem);
+ break;
+ }
+
/*
* All repairs for this item completed. Free the item,
- * and remember that progress was made.
+ * and remember that progress was made, even if group
+ * revalidation uncovered more issues.
*/
rls->made_progress = true;
free(aitem);
diff --git a/scrub/repair.c b/scrub/repair.c
index fee03f97701..72533ab5b02 100644
--- a/scrub/repair.c
+++ b/scrub/repair.c
@@ -43,6 +43,15 @@ static const unsigned int repair_deps[XFS_SCRUB_TYPE_NR] = {
DEP(XFS_SCRUB_TYPE_PQUOTA),
[XFS_SCRUB_TYPE_RTSUM] = DEP(XFS_SCRUB_TYPE_RTBITMAP),
};
+
+/*
+ * Data dependencies that cross scrub groups. When we repair a metadata object
+ * of the given type (e.g. rtgroup bitmaps), we want to trigger a revalidation
+ * of the specified objects (e.g. rt summary file).
+ */
+static const unsigned int cross_group_recheck[XFS_SCRUB_TYPE_NR] = {
+ [XFS_SCRUB_TYPE_RGBITMAP] = DEP(XFS_SCRUB_TYPE_RTSUM),
+};
#undef DEP
/*
@@ -631,6 +640,16 @@ action_list_add(
list_add_tail(&aitem->list, &alist->list);
}
+/* Move an action item off of a list onto alist. */
+static void
+action_list_move(
+ struct action_list *alist,
+ struct action_item *aitem)
+{
+ list_del_init(&aitem->list);
+ action_list_add(alist, aitem);
+}
+
/*
* Try to repair a filesystem object and let the caller know what it should do
* with the action item. The caller must be able to requeue action items, so
@@ -894,3 +913,142 @@ repair_item_to_action_item(
*aitemp = aitem;
return 0;
}
+
+static int
+schedule_cross_group_recheck(
+ struct scrub_ctx *ctx,
+ unsigned int recheck_mask,
+ struct action_list *new_items)
+{
+ unsigned int scrub_type;
+
+ foreach_scrub_type(scrub_type) {
+ struct action_item *aitem;
+
+ if (!(recheck_mask & (1U << scrub_type)))
+ continue;
+
+ switch (xfrog_scrubbers[scrub_type].group) {
+ case XFROG_SCRUB_GROUP_FS:
+ /*
+ * XXX gcc fortify gets confused on the memset in
+ * scrub_item_init_fs if we hoist this allocation to a
+ * helper function.
+ */
+ aitem = malloc(sizeof(struct action_item));
+ if (!aitem) {
+ int error = errno;
+
+ str_liberror(ctx, error,
+ _("creating repair revalidation action item"));
+ return error;
+ }
+
+ INIT_LIST_HEAD(&aitem->list);
+ aitem->sri.sri_revalidate = true;
+
+ scrub_item_init_fs(&aitem->sri);
+ scrub_item_schedule(&aitem->sri, scrub_type);
+ action_list_add(new_items, aitem);
+ break;
+ default:
+ /* We don't support any other groups yet. */
+ assert(false);
+ continue;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * After a successful repair, schedule revalidation of metadata outside of this
+ * scrub item's group.
+ */
+int
+action_item_schedule_revalidation(
+ struct scrub_ctx *ctx,
+ const struct action_item *old_aitem,
+ struct action_list *new_repairs)
+{
+ struct action_list new_items;
+ struct action_item *aitem, *n;
+ unsigned int scrub_type;
+ int error = 0;
+
+ /* Find new scrub items to revalidate */
+ action_list_init(&new_items);
+ foreach_scrub_type(scrub_type) {
+ unsigned int mask;
+
+ if (!(old_aitem->sri.sri_selected & (1ULL << scrub_type)))
+ continue;
+ mask = cross_group_recheck[scrub_type];
+ if (!mask)
+ continue;
+
+ error = schedule_cross_group_recheck(ctx, mask, &new_items);
+ if (error)
+ goto bad;
+ }
+ if (action_list_empty(&new_items))
+ return 0;
+
+ /* Scrub them all, and move corrupted items to the caller's list */
+ list_for_each_entry_safe(aitem, n, &new_items.list, list) {
+ unsigned int bad;
+
+ error = scrub_item_check(ctx, &aitem->sri);
+ if (error)
+ goto bad;
+
+ bad = repair_item_count_needsrepair(&aitem->sri);
+ if (bad > 0) {
+ /*
+ * Uhoh, we found something else broken. Queue it for
+ * more repairs.
+ */
+ aitem->sri.sri_revalidate = false;
+ action_list_move(new_repairs, aitem);
+ }
+ }
+
+bad:
+ /* Delete anything that's still on the list. */
+ list_for_each_entry_safe(aitem, n, &new_items.list, list) {
+ list_del(&aitem->list);
+ free(aitem);
+ }
+
+ return error;
+}
+
+/*
+ * Revalidate all items scheduled for a recheck, and drop the ones that are
+ * clean.
+ */
+int
+action_list_revalidate(
+ struct scrub_ctx *ctx,
+ struct action_list *alist)
+{
+ struct action_item *aitem, *n;
+ int error;
+
+ list_for_each_entry_safe(aitem, n, &alist->list, list) {
+ error = scrub_item_check(ctx, &aitem->sri);
+ if (error)
+ return error;
+
+ if (repair_item_count_needsrepair(&aitem->sri) > 0) {
+ aitem->sri.sri_revalidate = false;
+ continue;
+ }
+
+ /* Metadata are clean, delete from list. */
+ list_del(&aitem->list);
+ free(aitem);
+ }
+
+ return 0;
+}
diff --git a/scrub/repair.h b/scrub/repair.h
index ec4aa381a82..96f621f124d 100644
--- a/scrub/repair.h
+++ b/scrub/repair.h
@@ -50,6 +50,11 @@ enum tryrepair_outcome {
int action_item_try_repair(struct scrub_ctx *ctx, struct action_item *aitem,
enum tryrepair_outcome *outcome);
+int action_item_schedule_revalidation(struct scrub_ctx *ctx,
+ const struct action_item *old_aitem,
+ struct action_list *new_items);
+int action_list_revalidate(struct scrub_ctx *sc, struct action_list *alist);
+
void repair_item_mustfix(struct scrub_item *sri, struct scrub_item *fix_now);
/* Primary metadata is corrupt */
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 31/47] xfs_spaceman: report health status of the realtime rmap btree
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (29 preceding siblings ...)
2023-12-27 13:18 ` [PATCH 30/47] xfs_scrub: retest metadata across scrub groups after a repair Darrick J. Wong
@ 2023-12-27 13:18 ` Darrick J. Wong
2023-12-27 13:18 ` [PATCH 32/47] libxfs: dirty buffers should be marked uptodate too Darrick J. Wong
` (15 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:18 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Add reporting of the rt rmap btree health to spaceman.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
spaceman/health.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/spaceman/health.c b/spaceman/health.c
index d9a18fcc3b4..fac81f4eda5 100644
--- a/spaceman/health.c
+++ b/spaceman/health.c
@@ -41,6 +41,11 @@ static bool has_reflink(const struct xfs_fsop_geom *g)
return g->flags & XFS_FSOP_GEOM_FLAGS_REFLINK;
}
+static bool has_rtrmapbt(const struct xfs_fsop_geom *g)
+{
+ return g->rtblocks > 0 && (g->flags & XFS_FSOP_GEOM_FLAGS_RMAPBT);
+}
+
struct flag_map {
unsigned int mask;
bool (*has_fn)(const struct xfs_fsop_geom *g);
@@ -145,6 +150,11 @@ static const struct flag_map rtgroup_flags[] = {
.mask = XFS_RTGROUP_GEOM_SICK_BITMAP,
.descr = "realtime bitmap",
},
+ {
+ .mask = XFS_RTGROUP_GEOM_SICK_RMAPBT,
+ .descr = "realtime reverse mappings btree",
+ .has_fn = has_rtrmapbt,
+ },
{0},
};
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 32/47] libxfs: dirty buffers should be marked uptodate too
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (30 preceding siblings ...)
2023-12-27 13:18 ` [PATCH 31/47] xfs_spaceman: report health status of the realtime rmap btree Darrick J. Wong
@ 2023-12-27 13:18 ` Darrick J. Wong
2023-12-27 13:19 ` [PATCH 33/47] xfs_repair: flag suspect long-format btree blocks Darrick J. Wong
` (14 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:18 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
I started fuzz-testing the realtime rmap feature with a very large
number of realtime allocation groups. There were so many rt groups that
repair had to rebuild /realtime in the metadata directory tree, and that
directory was big enough to spur the creation of a block format
directory.
Unfortunately, repair then walks both directory trees to look for
unconnceted files. This part of phase 6 emits CRC errors on the newly
created buffers for the /realtime directory, declares the directory to
be garbage, and moves all the rt rmap inodes to /lost+found, resulting
in a corrupt fs.
Poking around in gdb, I noticed that the buffer contents were indeed
zero, and that UPTODATE was not set. This was very strange, until I
added a watch on bp->b_flags to watch for accesses. It turns out that
xfs_repair's prefetch code will _get a buffer and zero the contents if
UPTODATE is not set.
The directory tree code in libxfs will also _get a buffer, initialize
it, and log it to the coordinating transaction, which in this case is
the transactions used to reconnect the rmap btree inodes to /realtime.
At no point does any of that code ever set UPTODATE on the buffer, which
is why prefetch zaps the contents.
Hence change both buffer dirtying functions to set UPTODATE, since a
dirty buffer is by definition at least as recent as whatever's on disk.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/rdwr.c | 2 +-
libxfs/trans.c | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c
index 17abced06c9..a3b30510926 100644
--- a/libxfs/rdwr.c
+++ b/libxfs/rdwr.c
@@ -959,7 +959,7 @@ libxfs_buf_mark_dirty(
*/
bp->b_error = 0;
bp->b_flags &= ~LIBXFS_B_STALE;
- bp->b_flags |= LIBXFS_B_DIRTY;
+ bp->b_flags |= LIBXFS_B_DIRTY | LIBXFS_B_UPTODATE;
}
/* Prepare a buffer to be sent to the MRU list. */
diff --git a/libxfs/trans.c b/libxfs/trans.c
index aab9923d9ad..3c5d6383e8c 100644
--- a/libxfs/trans.c
+++ b/libxfs/trans.c
@@ -716,6 +716,7 @@ libxfs_trans_dirty_buf(
ASSERT(bp->b_transp == tp);
ASSERT(bip != NULL);
+ bp->b_flags |= LIBXFS_B_UPTODATE;
tp->t_flags |= XFS_TRANS_DIRTY;
set_bit(XFS_LI_DIRTY, &bip->bli_item.li_flags);
}
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 33/47] xfs_repair: flag suspect long-format btree blocks
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (31 preceding siblings ...)
2023-12-27 13:18 ` [PATCH 32/47] libxfs: dirty buffers should be marked uptodate too Darrick J. Wong
@ 2023-12-27 13:19 ` Darrick J. Wong
2023-12-27 13:19 ` [PATCH 34/47] xfs_repair: use realtime rmap btree data to check block types Darrick J. Wong
` (13 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:19 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Pass a "suspect" counter through scan_lbtree just like we do for
short-format btree blocks, and increment its value when we encounter
blocks with bad CRCs or outright corruption. This makes it so that
repair actually catches bmbt blocks with bad crcs or other verifier
errors.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
repair/dinode.c | 2 +-
repair/scan.c | 15 ++++++++++++---
repair/scan.h | 3 +++
3 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/repair/dinode.c b/repair/dinode.c
index 31b3cd74139..a0071d5de88 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -872,7 +872,7 @@ _("bad bmap btree ptr 0x%" PRIx64 " in ino %" PRIu64 "\n"),
if (scan_lbtree(get_unaligned_be64(&pp[i]), level, scan_bmapbt,
type, whichfork, lino, tot, nex, blkmapp,
- &cursor, 1, check_dups, magic,
+ &cursor, 0, 1, check_dups, magic,
(void *)zap_metadata, &xfs_bmbt_buf_ops))
return(1);
/*
diff --git a/repair/scan.c b/repair/scan.c
index 1cd4d0ad2e1..2f8a3348ae1 100644
--- a/repair/scan.c
+++ b/repair/scan.c
@@ -136,6 +136,7 @@ scan_lbtree(
xfs_extnum_t *nex,
blkmap_t **blkmapp,
bmap_cursor_t *bm_cursor,
+ int suspect,
int isroot,
int check_dups,
int *dirty,
@@ -148,6 +149,7 @@ scan_lbtree(
xfs_extnum_t *nex,
blkmap_t **blkmapp,
bmap_cursor_t *bm_cursor,
+ int suspect,
int isroot,
int check_dups,
uint64_t magic,
@@ -167,6 +169,12 @@ scan_lbtree(
XFS_FSB_TO_AGBNO(mp, root));
return(1);
}
+ if (bp->b_error == -EFSBADCRC || bp->b_error == -EFSCORRUPTED) {
+ do_warn(_("btree block %d/%d is suspect, error %d\n"),
+ XFS_FSB_TO_AGNO(mp, root),
+ XFS_FSB_TO_AGBNO(mp, root), bp->b_error);
+ suspect++;
+ }
/*
* only check for bad CRC here - caller will determine if there
@@ -182,7 +190,7 @@ scan_lbtree(
err = (*func)(XFS_BUF_TO_BLOCK(bp), nlevels - 1,
type, whichfork, root, ino, tot, nex, blkmapp,
- bm_cursor, isroot, check_dups, &dirty,
+ bm_cursor, suspect, isroot, check_dups, &dirty,
magic, priv);
ASSERT(dirty == 0 || (dirty && !no_modify));
@@ -209,6 +217,7 @@ scan_bmapbt(
xfs_extnum_t *nex,
blkmap_t **blkmapp,
bmap_cursor_t *bm_cursor,
+ int suspect,
int isroot,
int check_dups,
int *dirty,
@@ -516,7 +525,7 @@ _("bad bmap btree ptr 0x%llx in ino %" PRIu64 "\n"),
err = scan_lbtree(be64_to_cpu(pp[i]), level, scan_bmapbt,
type, whichfork, ino, tot, nex, blkmapp,
- bm_cursor, 0, check_dups, magic, priv,
+ bm_cursor, suspect, 0, check_dups, magic, priv,
&xfs_bmbt_buf_ops);
if (err)
return(1);
@@ -584,7 +593,7 @@ _("bad fwd (right) sibling pointer (saw %" PRIu64 " should be NULLFSBLOCK)\n"
be64_to_cpu(pkey[numrecs - 1].br_startoff);
}
- return(0);
+ return suspect > 0 ? 1 : 0;
}
static void
diff --git a/repair/scan.h b/repair/scan.h
index 4da788becbe..aeaf9f1a7f4 100644
--- a/repair/scan.h
+++ b/repair/scan.h
@@ -23,6 +23,7 @@ int scan_lbtree(
xfs_extnum_t *nex,
struct blkmap **blkmapp,
bmap_cursor_t *bm_cursor,
+ int suspect,
int isroot,
int check_dups,
int *dirty,
@@ -35,6 +36,7 @@ int scan_lbtree(
xfs_extnum_t *nex,
struct blkmap **blkmapp,
bmap_cursor_t *bm_cursor,
+ int suspect,
int isroot,
int check_dups,
uint64_t magic,
@@ -52,6 +54,7 @@ int scan_bmapbt(
xfs_extnum_t *nex,
struct blkmap **blkmapp,
bmap_cursor_t *bm_cursor,
+ int suspect,
int isroot,
int check_dups,
int *dirty,
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 34/47] xfs_repair: use realtime rmap btree data to check block types
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (32 preceding siblings ...)
2023-12-27 13:19 ` [PATCH 33/47] xfs_repair: flag suspect long-format btree blocks Darrick J. Wong
@ 2023-12-27 13:19 ` Darrick J. Wong
2023-12-27 13:19 ` [PATCH 35/47] xfs_repair: create a new set of incore rmap information for rt groups Darrick J. Wong
` (12 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:19 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Use the realtime rmap btree to pre-populate the block type information
so that when repair iterates the primary metadata, we can confirm the
block type.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
repair/dinode.c | 163 +++++++++++++++++++++++
repair/scan.c | 390 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
repair/scan.h | 34 +++++
3 files changed, 577 insertions(+), 10 deletions(-)
diff --git a/repair/dinode.c b/repair/dinode.c
index a0071d5de88..23cec00ad9e 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -777,6 +777,153 @@ get_agino_buf(
* first, one utility routine for each type of inode
*/
+/*
+ * return 1 if inode should be cleared, 0 otherwise
+ */
+static int
+process_rtrmap(
+ struct xfs_mount *mp,
+ xfs_agnumber_t agno,
+ xfs_agino_t ino,
+ struct xfs_dinode *dip,
+ int type,
+ int *dirty,
+ xfs_rfsblock_t *tot,
+ uint64_t *nex,
+ blkmap_t **blkmapp,
+ int check_dups)
+{
+ struct xfs_rmap_irec oldkey;
+ struct xfs_rmap_irec key;
+ struct rmap_priv priv;
+ struct xfs_rtrmap_root *dib;
+ xfs_rtrmap_ptr_t *pp;
+ struct xfs_rmap_key *kp;
+ struct xfs_rmap_rec *rp;
+ char *forkname = get_forkname(XFS_DATA_FORK);
+ xfs_ino_t lino;
+ xfs_fsblock_t bno;
+ size_t droot_sz;
+ int i;
+ int level;
+ int numrecs;
+ int dmxr;
+ int suspect = 0;
+ int error;
+
+ /* We rebuild the rtrmapbt, so no need to process blocks again. */
+ if (check_dups) {
+ *tot = be64_to_cpu(dip->di_nblocks);
+ return 0;
+ }
+
+ lino = XFS_AGINO_TO_INO(mp, agno, ino);
+
+ /* This rmap btree inode must be a metadata inode. */
+ if (!(dip->di_flags2 & be64_to_cpu(XFS_DIFLAG2_METADIR))) {
+ do_warn(
+_("rtrmap inode %" PRIu64 " not flagged as metadata\n"),
+ lino);
+ return 1;
+ }
+
+ memset(&priv.high_key, 0xFF, sizeof(priv.high_key));
+ priv.high_key.rm_blockcount = 0;
+ priv.agcnts = NULL;
+ priv.last_rec.rm_owner = XFS_RMAP_OWN_UNKNOWN;
+
+ dib = (struct xfs_rtrmap_root *)XFS_DFORK_PTR(dip, XFS_DATA_FORK);
+ *tot = 0;
+ *nex = 0;
+
+ level = be16_to_cpu(dib->bb_level);
+ numrecs = be16_to_cpu(dib->bb_numrecs);
+
+ if (level > mp->m_rtrmap_maxlevels) {
+ do_warn(
+_("bad level %d in inode %" PRIu64 " rtrmap btree root block\n"),
+ level, lino);
+ return 1;
+ }
+
+ /*
+ * use rtroot/dfork_dsize since the root block is in the data fork
+ */
+ droot_sz = xfs_rtrmap_droot_space_calc(level, numrecs);
+ if (droot_sz > XFS_DFORK_SIZE(dip, mp, XFS_DATA_FORK)) {
+ do_warn(
+_("computed size of rtrmapbt root (%zu bytes) is greater than space in "
+ "inode %" PRIu64 " %s fork\n"),
+ droot_sz, lino, forkname);
+ return 1;
+ }
+
+ if (level == 0) {
+ rp = xfs_rtrmap_droot_rec_addr(dib, 1);
+ error = process_rtrmap_reclist(mp, rp, numrecs,
+ &priv.last_rec, NULL, "rtrmapbt root");
+ if (error) {
+ rmap_avoid_check();
+ return 1;
+ }
+ return 0;
+ }
+
+ dmxr = libxfs_rtrmapbt_droot_maxrecs(
+ XFS_DFORK_SIZE(dip, mp, XFS_DATA_FORK), false);
+ pp = xfs_rtrmap_droot_ptr_addr(dib, 1, dmxr);
+
+ /* check for in-order keys */
+ for (i = 0; i < numrecs; i++) {
+ kp = xfs_rtrmap_droot_key_addr(dib, i + 1);
+
+ key.rm_flags = 0;
+ key.rm_startblock = be32_to_cpu(kp->rm_startblock);
+ key.rm_owner = be64_to_cpu(kp->rm_owner);
+ if (libxfs_rmap_irec_offset_unpack(be64_to_cpu(kp->rm_offset),
+ &key)) {
+ /* Look for impossible flags. */
+ do_warn(
+_("invalid flags in key %u of rtrmap root ino %" PRIu64 "\n"),
+ i, lino);
+ suspect++;
+ continue;
+ }
+ if (i == 0) {
+ oldkey = key;
+ continue;
+ }
+ if (rmap_diffkeys(&oldkey, &key) > 0) {
+ do_warn(
+_("out of order key %u in rtrmap root ino %" PRIu64 "\n"),
+ i, lino);
+ suspect++;
+ continue;
+ }
+ oldkey = key;
+ }
+
+ /* probe keys */
+ for (i = 0; i < numrecs; i++) {
+ bno = get_unaligned_be64(&pp[i]);
+
+ if (!libxfs_verify_fsbno(mp, bno)) {
+ do_warn(
+_("bad rtrmap btree ptr 0x%" PRIx64 " in ino %" PRIu64 "\n"),
+ bno, lino);
+ return 1;
+ }
+
+ if (scan_lbtree(bno, level, scan_rtrmapbt,
+ type, XFS_DATA_FORK, lino, tot, nex, blkmapp,
+ NULL, 0, 1, check_dups, XFS_RTRMAP_CRC_MAGIC,
+ &priv, &xfs_rtrmapbt_buf_ops))
+ return 1;
+ }
+
+ return suspect ? 1 : 0;
+}
+
/*
* return 1 if inode should be cleared, 0 otherwise
*/
@@ -1553,7 +1700,7 @@ static int
check_dinode_mode_format(
struct xfs_dinode *dinoc)
{
- if (dinoc->di_format >= XFS_DINODE_FMT_UUID)
+ if (dinoc->di_format == XFS_DINODE_FMT_UUID)
return -1; /* FMT_UUID is not used */
switch (dinode_fmt(dinoc)) {
@@ -1568,8 +1715,13 @@ check_dinode_mode_format(
dinoc->di_format > XFS_DINODE_FMT_BTREE) ? -1 : 0;
case S_IFREG:
- return (dinoc->di_format < XFS_DINODE_FMT_EXTENTS ||
- dinoc->di_format > XFS_DINODE_FMT_BTREE) ? -1 : 0;
+ switch (dinoc->di_format) {
+ case XFS_DINODE_FMT_RMAP:
+ case XFS_DINODE_FMT_EXTENTS:
+ case XFS_DINODE_FMT_BTREE:
+ return 0;
+ }
+ return -1;
case S_IFLNK:
return (dinoc->di_format < XFS_DINODE_FMT_LOCAL ||
@@ -1983,6 +2135,10 @@ process_inode_data_fork(
totblocks, nextents, dblkmap, XFS_DATA_FORK,
check_dups, zap_metadata);
break;
+ case XFS_DINODE_FMT_RMAP:
+ err = process_rtrmap(mp, agno, ino, dino, type, dirty,
+ totblocks, nextents, dblkmap, check_dups);
+ break;
case XFS_DINODE_FMT_DEV:
err = 0;
break;
@@ -2042,6 +2198,7 @@ _("would have tried to rebuild inode %"PRIu64" data fork\n"),
XFS_DATA_FORK, 0, zap_metadata);
break;
case XFS_DINODE_FMT_DEV:
+ case XFS_DINODE_FMT_RMAP:
err = 0;
break;
default:
diff --git a/repair/scan.c b/repair/scan.c
index 2f8a3348ae1..27aeb341bf3 100644
--- a/repair/scan.c
+++ b/repair/scan.c
@@ -959,13 +959,6 @@ _("unknown block (%d,%d-%d) mismatch on %s tree, state - %d,%" PRIx64 "\n"),
}
}
-struct rmap_priv {
- struct aghdr_cnts *agcnts;
- struct xfs_rmap_irec high_key;
- struct xfs_rmap_irec last_rec;
- xfs_agblock_t nr_blocks;
-};
-
static bool
rmap_in_order(
xfs_agblock_t b,
@@ -1367,6 +1360,389 @@ _("out of order key %u in %s btree block (%u/%u)\n"),
rmap_avoid_check();
}
+int
+process_rtrmap_reclist(
+ struct xfs_mount *mp,
+ struct xfs_rmap_rec *rp,
+ int numrecs,
+ struct xfs_rmap_irec *last_rec,
+ struct xfs_rmap_irec *high_key,
+ const char *name)
+{
+ int suspect = 0;
+ int i;
+ struct xfs_rmap_irec oldkey;
+ struct xfs_rmap_irec key;
+
+ for (i = 0; i < numrecs; i++) {
+ xfs_rgblock_t b, end;
+ xfs_extlen_t len;
+ uint64_t owner, offset;
+
+ b = be32_to_cpu(rp[i].rm_startblock);
+ len = be32_to_cpu(rp[i].rm_blockcount);
+ owner = be64_to_cpu(rp[i].rm_owner);
+ offset = be64_to_cpu(rp[i].rm_offset);
+
+ key.rm_flags = 0;
+ key.rm_startblock = b;
+ key.rm_blockcount = len;
+ key.rm_owner = owner;
+ if (libxfs_rmap_irec_offset_unpack(offset, &key)) {
+ /* Look for impossible flags. */
+ do_warn(
+_("invalid flags in record %u of %s\n"),
+ i, name);
+ suspect++;
+ continue;
+ }
+
+
+ end = key.rm_startblock + key.rm_blockcount;
+
+ /* Make sure startblock & len make sense. */
+ if (b >= mp->m_sb.sb_rgblocks) {
+ do_warn(
+_("invalid start block %llu in record %u of %s\n"),
+ (unsigned long long)b, i, name);
+ suspect++;
+ continue;
+ }
+ if (len == 0 || end - 1 >= mp->m_sb.sb_rgblocks) {
+ do_warn(
+_("invalid length %llu in record %u of %s\n"),
+ (unsigned long long)len, i, name);
+ suspect++;
+ continue;
+ }
+
+ /* We only store file data and superblocks in the rtrmap. */
+ if (XFS_RMAP_NON_INODE_OWNER(owner) &&
+ owner != XFS_RMAP_OWN_FS) {
+ do_warn(
+_("invalid owner %lld in record %u of %s\n"),
+ (long long int)owner, i, name);
+ suspect++;
+ continue;
+ }
+
+ /* Look for impossible record field combinations. */
+ if (key.rm_flags & XFS_RMAP_KEY_FLAGS) {
+ do_warn(
+_("record %d cannot have attr fork/key flags in %s\n"),
+ i, name);
+ suspect++;
+ continue;
+ }
+
+ /* Check for out of order records. */
+ if (i == 0)
+ oldkey = key;
+ else {
+ if (rmap_diffkeys(&oldkey, &key) > 0)
+ do_warn(
+_("out-of-order record %d (%llu %"PRId64" %"PRIu64" %llu) in %s\n"),
+ i, (unsigned long long)b, owner, offset,
+ (unsigned long long)len, name);
+ else
+ oldkey = key;
+ }
+
+ /* Is this mergeable with the previous record? */
+ if (rmaps_are_mergeable(last_rec, &key)) {
+ do_warn(
+_("record %d in %s should be merged with previous record\n"),
+ i, name);
+ last_rec->rm_blockcount += key.rm_blockcount;
+ } else
+ *last_rec = key;
+
+ /* Check that we don't go past the high key. */
+ key.rm_startblock += key.rm_blockcount - 1;
+ key.rm_offset += key.rm_blockcount - 1;
+ key.rm_blockcount = 0;
+ if (high_key && rmap_diffkeys(&key, high_key) > 0) {
+ do_warn(
+_("record %d greater than high key of %s\n"),
+ i, name);
+ suspect++;
+ }
+ }
+
+ return suspect;
+}
+
+int
+scan_rtrmapbt(
+ struct xfs_btree_block *block,
+ int level,
+ int type,
+ int whichfork,
+ xfs_fsblock_t fsbno,
+ xfs_ino_t ino,
+ xfs_rfsblock_t *tot,
+ uint64_t *nex,
+ blkmap_t **blkmapp,
+ bmap_cursor_t *bm_cursor,
+ int suspect,
+ int isroot,
+ int check_dups,
+ int *dirty,
+ uint64_t magic,
+ void *priv)
+{
+ const char *name = "rtrmap";
+ char rootname[256];
+ int i;
+ xfs_rtrmap_ptr_t *pp;
+ struct xfs_rmap_rec *rp;
+ struct rmap_priv *rmap_priv = priv;
+ int hdr_errors = 0;
+ int numrecs;
+ int state;
+ struct xfs_rmap_key *kp;
+ struct xfs_rmap_irec oldkey;
+ struct xfs_rmap_irec key;
+ xfs_agnumber_t agno;
+ xfs_agblock_t agbno;
+ int error;
+
+ agno = XFS_FSB_TO_AGNO(mp, fsbno);
+ agbno = XFS_FSB_TO_AGBNO(mp, fsbno);
+
+ /* If anything here is bad, just bail. */
+ if (be32_to_cpu(block->bb_magic) != magic) {
+ do_warn(
+_("bad magic # %#x in inode %" PRIu64 " %s block %" PRIu64 "\n"),
+ be32_to_cpu(block->bb_magic), ino, name, fsbno);
+ return 1;
+ }
+ if (be16_to_cpu(block->bb_level) != level) {
+ do_warn(
+_("expected level %d got %d in inode %" PRIu64 ", %s block %" PRIu64 "\n"),
+ level, be16_to_cpu(block->bb_level),
+ ino, name, fsbno);
+ return(1);
+ }
+
+ /* verify owner */
+ if (be64_to_cpu(block->bb_u.l.bb_owner) != ino) {
+ do_warn(
+_("expected owner inode %" PRIu64 ", got %llu, %s block %" PRIu64 "\n"),
+ ino,
+ (unsigned long long)be64_to_cpu(block->bb_u.l.bb_owner),
+ name, fsbno);
+ return 1;
+ }
+ /* verify block number */
+ if (be64_to_cpu(block->bb_u.l.bb_blkno) !=
+ XFS_FSB_TO_DADDR(mp, fsbno)) {
+ do_warn(
+_("expected block %" PRIu64 ", got %llu, %s block %" PRIu64 "\n"),
+ XFS_FSB_TO_DADDR(mp, fsbno),
+ (unsigned long long)be64_to_cpu(block->bb_u.l.bb_blkno),
+ name, fsbno);
+ return 1;
+ }
+ /* verify uuid */
+ if (platform_uuid_compare(&block->bb_u.l.bb_uuid,
+ &mp->m_sb.sb_meta_uuid) != 0) {
+ do_warn(
+_("wrong FS UUID, %s block %" PRIu64 "\n"),
+ name, fsbno);
+ return 1;
+ }
+
+ /*
+ * Check for btree blocks multiply claimed. We're going to regenerate
+ * the rtrmap anyway, so mark the blocks as metadata so they get freed.
+ */
+ state = get_bmap(agno, agbno);
+ if (!(state == XR_E_UNKNOWN || state == XR_E_INUSE1)) {
+ do_warn(
+_("%s btree block claimed (state %d), agno %d, bno %d, suspect %d\n"),
+ name, state, agno, agbno, suspect);
+ suspect++;
+ goto out;
+ }
+ set_bmap(agno, agbno, XR_E_METADATA);
+
+ numrecs = be16_to_cpu(block->bb_numrecs);
+
+ /*
+ * All realtime rmap btree blocks are freed for a fully empty
+ * filesystem, thus they are counted towards the free data
+ * block counter. The root lives in an inode and is thus not
+ * counted.
+ */
+ (*tot)++;
+
+ if (level == 0) {
+ if (numrecs > mp->m_rtrmap_mxr[0]) {
+ numrecs = mp->m_rtrmap_mxr[0];
+ hdr_errors++;
+ }
+ if (isroot == 0 && numrecs < mp->m_rtrmap_mnr[0]) {
+ numrecs = mp->m_rtrmap_mnr[0];
+ hdr_errors++;
+ }
+
+ if (hdr_errors) {
+ do_warn(
+_("bad btree nrecs (%u, min=%u, max=%u) in bt%s block %u/%u\n"),
+ be16_to_cpu(block->bb_numrecs),
+ mp->m_rtrmap_mnr[0], mp->m_rtrmap_mxr[0],
+ name, agno, agbno);
+ suspect++;
+ }
+
+ rp = xfs_rtrmap_rec_addr(block, 1);
+ snprintf(rootname, 256, "%s btree block %u/%u", name, agno, agbno);
+ error = process_rtrmap_reclist(mp, rp, numrecs,
+ &rmap_priv->last_rec, &rmap_priv->high_key,
+ rootname);
+ if (error)
+ suspect++;
+ goto out;
+ }
+
+ /*
+ * interior record
+ */
+ pp = xfs_rtrmap_ptr_addr(block, 1, mp->m_rtrmap_mxr[1]);
+
+ if (numrecs > mp->m_rtrmap_mxr[1]) {
+ numrecs = mp->m_rtrmap_mxr[1];
+ hdr_errors++;
+ }
+ if (isroot == 0 && numrecs < mp->m_rtrmap_mnr[1]) {
+ numrecs = mp->m_rtrmap_mnr[1];
+ hdr_errors++;
+ }
+
+ /*
+ * don't pass bogus tree flag down further if this block
+ * looked ok. bail out if two levels in a row look bad.
+ */
+ if (hdr_errors) {
+ do_warn(
+_("bad btree nrecs (%u, min=%u, max=%u) in bt%s block %u/%u\n"),
+ be16_to_cpu(block->bb_numrecs),
+ mp->m_rtrmap_mnr[1], mp->m_rtrmap_mxr[1],
+ name, agno, agbno);
+ if (suspect)
+ goto out;
+ suspect++;
+ } else if (suspect) {
+ suspect = 0;
+ }
+
+ /* check the node's high keys */
+ for (i = 0; !isroot && i < numrecs; i++) {
+ kp = xfs_rtrmap_high_key_addr(block, i + 1);
+
+ key.rm_flags = 0;
+ key.rm_startblock = be32_to_cpu(kp->rm_startblock);
+ key.rm_owner = be64_to_cpu(kp->rm_owner);
+ if (libxfs_rmap_irec_offset_unpack(be64_to_cpu(kp->rm_offset),
+ &key)) {
+ /* Look for impossible flags. */
+ do_warn(
+_("invalid flags in key %u of %s btree block %u/%u\n"),
+ i, name, agno, agbno);
+ suspect++;
+ continue;
+ }
+ if (rmap_diffkeys(&key, &rmap_priv->high_key) > 0) {
+ do_warn(
+_("key %d greater than high key of block (%u/%u) in %s tree\n"),
+ i, agno, agbno, name);
+ suspect++;
+ }
+ }
+
+ /* check for in-order keys */
+ for (i = 0; i < numrecs; i++) {
+ kp = xfs_rtrmap_key_addr(block, i + 1);
+
+ key.rm_flags = 0;
+ key.rm_startblock = be32_to_cpu(kp->rm_startblock);
+ key.rm_owner = be64_to_cpu(kp->rm_owner);
+ if (libxfs_rmap_irec_offset_unpack(be64_to_cpu(kp->rm_offset),
+ &key)) {
+ /* Look for impossible flags. */
+ do_warn(
+_("invalid flags in key %u of %s btree block %u/%u\n"),
+ i, name, agno, agbno);
+ suspect++;
+ continue;
+ }
+ if (i == 0) {
+ oldkey = key;
+ continue;
+ }
+ if (rmap_diffkeys(&oldkey, &key) > 0) {
+ do_warn(
+_("out of order key %u in %s btree block (%u/%u)\n"),
+ i, name, agno, agbno);
+ suspect++;
+ }
+ oldkey = key;
+ }
+
+ for (i = 0; i < numrecs; i++) {
+ xfs_fsblock_t pbno = be64_to_cpu(pp[i]);
+
+ /*
+ * XXX - put sibling detection right here.
+ * we know our sibling chain is good. So as we go,
+ * we check the entry before and after each entry.
+ * If either of the entries references a different block,
+ * check the sibling pointer. If there's a sibling
+ * pointer mismatch, try and extract as much data
+ * as possible.
+ */
+ kp = xfs_rtrmap_high_key_addr(block, i + 1);
+ rmap_priv->high_key.rm_flags = 0;
+ rmap_priv->high_key.rm_startblock =
+ be32_to_cpu(kp->rm_startblock);
+ rmap_priv->high_key.rm_owner =
+ be64_to_cpu(kp->rm_owner);
+ if (libxfs_rmap_irec_offset_unpack(be64_to_cpu(kp->rm_offset),
+ &rmap_priv->high_key)) {
+ /* Look for impossible flags. */
+ do_warn(
+_("invalid flags in high key %u of %s btree block %u/%u\n"),
+ i, name, agno, agbno);
+ suspect++;
+ continue;
+ }
+
+ if (!libxfs_verify_fsbno(mp, pbno)) {
+ do_warn(
+_("bad %s btree ptr 0x%llx in ino %" PRIu64 "\n"),
+ name, (unsigned long long)pbno, ino);
+ return 1;
+ }
+
+ error = scan_lbtree(pbno, level, scan_rtrmapbt,
+ type, whichfork, ino, tot, nex, blkmapp,
+ bm_cursor, suspect, 0, check_dups, magic,
+ rmap_priv, &xfs_rtrmapbt_buf_ops);
+ if (error) {
+ suspect++;
+ goto out;
+ }
+ }
+
+out:
+ if (hdr_errors || suspect) {
+ rmap_avoid_check();
+ return 1;
+ }
+ return 0;
+}
+
struct refc_priv {
struct xfs_refcount_irec last_rec;
xfs_agblock_t nr_blocks;
diff --git a/repair/scan.h b/repair/scan.h
index aeaf9f1a7f4..a624c882734 100644
--- a/repair/scan.h
+++ b/repair/scan.h
@@ -66,4 +66,38 @@ scan_ags(
struct xfs_mount *mp,
int scan_threads);
+struct rmap_priv {
+ struct aghdr_cnts *agcnts;
+ struct xfs_rmap_irec high_key;
+ struct xfs_rmap_irec last_rec;
+ xfs_agblock_t nr_blocks;
+};
+
+int
+process_rtrmap_reclist(
+ struct xfs_mount *mp,
+ struct xfs_rmap_rec *rp,
+ int numrecs,
+ struct xfs_rmap_irec *last_rec,
+ struct xfs_rmap_irec *high_key,
+ const char *name);
+
+int scan_rtrmapbt(
+ struct xfs_btree_block *block,
+ int level,
+ int type,
+ int whichfork,
+ xfs_fsblock_t bno,
+ xfs_ino_t ino,
+ xfs_rfsblock_t *tot,
+ uint64_t *nex,
+ struct blkmap **blkmapp,
+ bmap_cursor_t *bm_cursor,
+ int suspect,
+ int isroot,
+ int check_dups,
+ int *dirty,
+ uint64_t magic,
+ void *priv);
+
#endif /* _XR_SCAN_H */
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 35/47] xfs_repair: create a new set of incore rmap information for rt groups
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (33 preceding siblings ...)
2023-12-27 13:19 ` [PATCH 34/47] xfs_repair: use realtime rmap btree data to check block types Darrick J. Wong
@ 2023-12-27 13:19 ` Darrick J. Wong
2023-12-27 13:19 ` [PATCH 36/47] xfs_repair: collect relatime reverse-mapping data for refcount/rmap tree rebuilding Darrick J. Wong
` (11 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:19 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Create a parallel set of "xfs_ag_rmap" structures to cache information
about reverse mappings for the realtime groups.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/libxfs_api_defs.h | 3 +
repair/agbtree.c | 5 +-
repair/dinode.c | 2 -
repair/rmap.c | 143 +++++++++++++++++++++++++++++++++++++---------
repair/rmap.h | 7 +-
5 files changed, 126 insertions(+), 34 deletions(-)
diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
index 85a4a131c75..e65b4d6fea5 100644
--- a/libxfs/libxfs_api_defs.h
+++ b/libxfs/libxfs_api_defs.h
@@ -284,6 +284,7 @@
#define xfs_rtsummary_wordcount libxfs_rtsummary_wordcount
#define xfs_rtfree_extent libxfs_rtfree_extent
+#define xfs_rtgroup_get libxfs_rtgroup_get
#define xfs_rtgroup_put libxfs_rtgroup_put
#define xfs_rtgroup_update_secondary_sbs libxfs_rtgroup_update_secondary_sbs
#define xfs_rtgroup_update_super libxfs_rtgroup_update_super
@@ -292,6 +293,8 @@
#define xfs_rtrmapbt_maxlevels_ondisk libxfs_rtrmapbt_maxlevels_ondisk
#define xfs_rtrmapbt_init_cursor libxfs_rtrmapbt_init_cursor
#define xfs_rtrmapbt_maxrecs libxfs_rtrmapbt_maxrecs
+#define xfs_rtrmapbt_mem_create libxfs_rtrmapbt_mem_create
+#define xfs_rtrmapbt_mem_cursor libxfs_rtrmapbt_mem_cursor
#define xfs_sb_from_disk libxfs_sb_from_disk
#define xfs_sb_quota_from_disk libxfs_sb_quota_from_disk
diff --git a/repair/agbtree.c b/repair/agbtree.c
index dccb15f9667..a401c80da38 100644
--- a/repair/agbtree.c
+++ b/repair/agbtree.c
@@ -645,7 +645,7 @@ init_rmapbt_cursor(
/* Compute how many blocks we'll need. */
error = -libxfs_btree_bload_compute_geometry(btr->cur, &btr->bload,
- rmap_record_count(sc->mp, agno));
+ rmap_record_count(sc->mp, false, agno));
if (error)
do_error(
_("Unable to compute rmap btree geometry, error %d.\n"), error);
@@ -662,7 +662,8 @@ build_rmap_tree(
{
int error;
- error = rmap_init_mem_cursor(sc->mp, NULL, agno, &btr->rmapbt_cursor);
+ error = rmap_init_mem_cursor(sc->mp, NULL, false, agno,
+ &btr->rmapbt_cursor);
if (error)
do_error(
_("Insufficient memory to construct rmap cursor.\n"));
diff --git a/repair/dinode.c b/repair/dinode.c
index 23cec00ad9e..41b44e6faad 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -657,7 +657,7 @@ _("illegal state %d in block map %" PRIu64 "\n"),
}
}
if (collect_rmaps && !zap_metadata) /* && !check_dups */
- rmap_add_rec(mp, ino, whichfork, &irec);
+ rmap_add_rec(mp, ino, whichfork, &irec, false);
*tot += irec.br_blockcount;
}
error = 0;
diff --git a/repair/rmap.c b/repair/rmap.c
index 265199d2117..aa47013baec 100644
--- a/repair/rmap.c
+++ b/repair/rmap.c
@@ -26,7 +26,7 @@
# define dbg_printf(f, a...)
#endif
-/* per-AG rmap object anchor */
+/* allocation group (AG or rtgroup) rmap object anchor */
struct xfs_ag_rmap {
struct xfbtree *ar_xfbtree; /* rmap observations */
struct xfs_slab *ar_agbtree_rmaps; /* rmaps for rebuilt ag btrees */
@@ -36,9 +36,17 @@ struct xfs_ag_rmap {
};
static struct xfs_ag_rmap *ag_rmaps;
+static struct xfs_ag_rmap *rg_rmaps;
bool rmapbt_suspect;
static bool refcbt_suspect;
+static struct xfs_ag_rmap *rmaps_for_group(bool isrt, unsigned int group)
+{
+ if (isrt)
+ return &rg_rmaps[group];
+ return &ag_rmaps[group];
+}
+
static inline int rmap_compare(const void *a, const void *b)
{
return libxfs_rmap_compare(a, b);
@@ -76,6 +84,44 @@ rmaps_destroy(
xfile_free_buftarg(target);
}
+/* Initialize the in-memory rmap btree for collecting realtime rmap records. */
+STATIC void
+rmaps_init_rt(
+ struct xfs_mount *mp,
+ xfs_rgnumber_t rgno,
+ struct xfs_ag_rmap *ag_rmap)
+{
+ struct xfs_buftarg *target;
+ char *descr;
+ unsigned long long maxbytes;
+ int error;
+
+ if (!xfs_has_realtime(mp))
+ return;
+
+ /*
+ * Each rtgroup rmap btree file can consume the entire data device,
+ * even if the metadata space reservation will be smaller than that.
+ */
+ maxbytes = XFS_FSB_TO_B(mp, mp->m_sb.sb_dblocks);
+ descr = kasprintf("xfs_repair (%s): rtgroup %u rmap records",
+ mp->m_fsname, rgno);
+ error = -xfile_alloc_buftarg(mp, descr, maxbytes, &target);
+ kfree(descr);
+ if (error)
+ goto nomem;
+
+ error = -libxfs_rtrmapbt_mem_create(mp, rgno, target,
+ &ag_rmap->ar_xfbtree);
+ if (error)
+ goto nomem;
+
+ return;
+nomem:
+ do_error(
+_("Insufficient memory while allocating realtime reverse mapping btree."));
+}
+
/* Initialize the in-memory rmap btree for collecting per-AG rmap records. */
STATIC void
rmaps_init_ag(
@@ -135,6 +181,13 @@ rmaps_init(
for (i = 0; i < mp->m_sb.sb_agcount; i++)
rmaps_init_ag(mp, i, &ag_rmaps[i]);
+
+ rg_rmaps = calloc(mp->m_sb.sb_rgcount, sizeof(struct xfs_ag_rmap));
+ if (!rg_rmaps)
+ do_error(_("couldn't allocate per-rtgroup reverse map roots\n"));
+
+ for (i = 0; i < mp->m_sb.sb_rgcount; i++)
+ rmaps_init_rt(mp, i, &rg_rmaps[i]);
}
/*
@@ -149,6 +202,11 @@ rmaps_free(
if (!rmap_needs_work(mp))
return;
+ for (i = 0; i < mp->m_sb.sb_rgcount; i++)
+ rmaps_destroy(mp, &rg_rmaps[i]);
+ free(rg_rmaps);
+ rg_rmaps = NULL;
+
for (i = 0; i < mp->m_sb.sb_agcount; i++)
rmaps_destroy(mp, &ag_rmaps[i]);
free(ag_rmaps);
@@ -184,26 +242,38 @@ int
rmap_init_mem_cursor(
struct xfs_mount *mp,
struct xfs_trans *tp,
+ bool isrt,
xfs_agnumber_t agno,
struct rmap_mem_cur *rmcur)
{
struct xfbtree *xfbt;
- struct xfs_perag *pag;
+ struct xfs_perag *pag = NULL;
+ struct xfs_rtgroup *rtg = NULL;
int error;
- xfbt = ag_rmaps[agno].ar_xfbtree;
+ xfbt = rmaps_for_group(isrt, agno)->ar_xfbtree;
error = -xfbtree_head_read_buf(xfbt, tp, &rmcur->mhead_bp);
if (error)
return error;
- pag = libxfs_perag_get(mp, agno);
- rmcur->mcur = libxfs_rmapbt_mem_cursor(pag, tp, rmcur->mhead_bp, xfbt);
+ if (isrt) {
+ rtg = libxfs_rtgroup_get(mp, agno);
+ rmcur->mcur = libxfs_rtrmapbt_mem_cursor(rtg, tp,
+ rmcur->mhead_bp, xfbt);
+ } else {
+ pag = libxfs_perag_get(mp, agno);
+ rmcur->mcur = libxfs_rmapbt_mem_cursor(pag, tp,
+ rmcur->mhead_bp, xfbt);
+ }
error = -libxfs_btree_goto_left_edge(rmcur->mcur);
if (error)
rmap_free_mem_cursor(tp, rmcur, error);
- libxfs_perag_put(pag);
+ if (pag)
+ libxfs_perag_put(pag);
+ if (rtg)
+ libxfs_rtgroup_put(rtg);
return error;
}
@@ -248,6 +318,7 @@ rmap_get_mem_rec(
static void
rmap_add_mem_rec(
struct xfs_mount *mp,
+ bool isrt,
xfs_agnumber_t agno,
struct xfs_rmap_irec *rmap)
{
@@ -256,12 +327,12 @@ rmap_add_mem_rec(
struct xfs_trans *tp;
int error;
- xfbt = ag_rmaps[agno].ar_xfbtree;
+ xfbt = rmaps_for_group(isrt, 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);
+ error = rmap_init_mem_cursor(mp, tp, isrt, agno, &rmcur);
if (error)
do_error(_("reading in-memory rmap btree head\n"));
@@ -286,7 +357,8 @@ rmap_add_rec(
struct xfs_mount *mp,
xfs_ino_t ino,
int whichfork,
- struct xfs_bmbt_irec *irec)
+ struct xfs_bmbt_irec *irec,
+ bool isrt)
{
struct xfs_rmap_irec rmap;
xfs_agnumber_t agno;
@@ -295,11 +367,19 @@ rmap_add_rec(
if (!rmap_needs_work(mp))
return;
- agno = XFS_FSB_TO_AGNO(mp, irec->br_startblock);
- agbno = XFS_FSB_TO_AGBNO(mp, irec->br_startblock);
- ASSERT(agno != NULLAGNUMBER);
- ASSERT(agno < mp->m_sb.sb_agcount);
- ASSERT(agbno + irec->br_blockcount <= mp->m_sb.sb_agblocks);
+ if (isrt) {
+ xfs_rgnumber_t rgno;
+
+ agbno = xfs_rtb_to_rgbno(mp, irec->br_startblock, &rgno);
+ agno = rgno;
+ ASSERT(agbno + irec->br_blockcount <= mp->m_sb.sb_rblocks);
+ } else {
+ agno = XFS_FSB_TO_AGNO(mp, irec->br_startblock);
+ agbno = XFS_FSB_TO_AGBNO(mp, irec->br_startblock);
+ ASSERT(agno != NULLAGNUMBER);
+ ASSERT(agno < mp->m_sb.sb_agcount);
+ ASSERT(agbno + irec->br_blockcount <= mp->m_sb.sb_agblocks);
+ }
ASSERT(ino != NULLFSINO);
ASSERT(whichfork == XFS_DATA_FORK || whichfork == XFS_ATTR_FORK);
@@ -313,7 +393,7 @@ rmap_add_rec(
if (irec->br_state == XFS_EXT_UNWRITTEN)
rmap.rm_flags |= XFS_RMAP_UNWRITTEN;
- rmap_add_mem_rec(mp, agno, &rmap);
+ rmap_add_mem_rec(mp, isrt, agno, &rmap);
}
/* add a raw rmap; these will be merged later */
@@ -340,7 +420,7 @@ __rmap_add_raw_rec(
rmap.rm_startblock = agbno;
rmap.rm_blockcount = len;
- rmap_add_mem_rec(mp, agno, &rmap);
+ rmap_add_mem_rec(mp, false, agno, &rmap);
}
/*
@@ -409,6 +489,7 @@ rmap_add_agbtree_mapping(
.rm_blockcount = len,
};
struct xfs_perag *pag;
+ struct xfs_ag_rmap *x;
if (!rmap_needs_work(mp))
return 0;
@@ -417,7 +498,8 @@ rmap_add_agbtree_mapping(
assert(libxfs_verify_agbext(pag, agbno, len));
libxfs_perag_put(pag);
- return slab_add(ag_rmaps[agno].ar_agbtree_rmaps, &rmap);
+ x = rmaps_for_group(false, agno);
+ return slab_add(x->ar_agbtree_rmaps, &rmap);
}
static int
@@ -533,7 +615,7 @@ rmap_commit_agbtree_mappings(
struct xfs_buf *agflbp = NULL;
struct xfs_trans *tp;
__be32 *agfl_bno, *b;
- struct xfs_ag_rmap *ag_rmap = &ag_rmaps[agno];
+ struct xfs_ag_rmap *ag_rmap = rmaps_for_group(false, agno);
struct bitmap *own_ag_bitmap = NULL;
int error = 0;
@@ -796,7 +878,7 @@ refcount_emit(
int error;
struct xfs_slab *rlslab;
- rlslab = ag_rmaps[agno].ar_refcount_items;
+ rlslab = rmaps_for_group(false, agno)->ar_refcount_items;
ASSERT(nr_rmaps > 0);
dbg_printf("REFL: agno=%u pblk=%u, len=%u -> refcount=%zu\n",
@@ -930,12 +1012,12 @@ compute_refcounts(
if (!xfs_has_reflink(mp))
return 0;
- if (ag_rmaps[agno].ar_xfbtree == NULL)
+ if (rmaps_for_group(false, agno)->ar_xfbtree == NULL)
return 0;
- nr_rmaps = rmap_record_count(mp, agno);
+ nr_rmaps = rmap_record_count(mp, false, agno);
- error = rmap_init_mem_cursor(mp, NULL, agno, &rmcur);
+ error = rmap_init_mem_cursor(mp, NULL, false, agno, &rmcur);
if (error)
return error;
@@ -1040,16 +1122,17 @@ count_btree_records(
uint64_t
rmap_record_count(
struct xfs_mount *mp,
+ bool isrt,
xfs_agnumber_t agno)
{
struct rmap_mem_cur rmcur;
uint64_t nr = 0;
int error;
- if (ag_rmaps[agno].ar_xfbtree == NULL)
+ if (rmaps_for_group(isrt, agno)->ar_xfbtree == NULL)
return 0;
- error = rmap_init_mem_cursor(mp, NULL, agno, &rmcur);
+ error = rmap_init_mem_cursor(mp, NULL, isrt, agno, &rmcur);
if (error)
do_error(_("%s while reading in-memory rmap btree\n"),
strerror(error));
@@ -1165,7 +1248,7 @@ rmaps_verify_btree(
}
/* Create cursors to rmap structures */
- error = rmap_init_mem_cursor(mp, NULL, agno, &rm_cur);
+ error = rmap_init_mem_cursor(mp, NULL, false, agno, &rm_cur);
if (error) {
do_warn(_("Not enough memory to check reverse mappings.\n"));
return;
@@ -1485,7 +1568,9 @@ refcount_record_count(
struct xfs_mount *mp,
xfs_agnumber_t agno)
{
- return slab_count(ag_rmaps[agno].ar_refcount_items);
+ struct xfs_ag_rmap *x = rmaps_for_group(false, agno);
+
+ return slab_count(x->ar_refcount_items);
}
/*
@@ -1496,7 +1581,9 @@ init_refcount_cursor(
xfs_agnumber_t agno,
struct xfs_slab_cursor **cur)
{
- return init_slab_cursor(ag_rmaps[agno].ar_refcount_items, NULL, cur);
+ struct xfs_ag_rmap *x = rmaps_for_group(false, agno);
+
+ return init_slab_cursor(x->ar_refcount_items, NULL, cur);
}
/*
@@ -1697,7 +1784,7 @@ rmap_store_agflcount(
if (!rmap_needs_work(mp))
return;
- ag_rmaps[agno].ar_flcount = count;
+ rmaps_for_group(false, agno)->ar_flcount = count;
}
/* Estimate the size of the ondisk rmapbt from the incore data. */
diff --git a/repair/rmap.h b/repair/rmap.h
index 50268b2f8ca..7a94ed6f90a 100644
--- a/repair/rmap.h
+++ b/repair/rmap.h
@@ -15,7 +15,7 @@ extern void rmaps_init(struct xfs_mount *);
extern void rmaps_free(struct xfs_mount *);
void rmap_add_rec(struct xfs_mount *mp, xfs_ino_t ino, int whichfork,
- struct xfs_bmbt_irec *irec);
+ struct xfs_bmbt_irec *irec, bool realtime);
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);
@@ -26,7 +26,8 @@ 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);
+uint64_t rmap_record_count(struct xfs_mount *mp, bool isrt,
+ xfs_agnumber_t agno);
extern void rmap_avoid_check(void);
void rmaps_verify_btree(struct xfs_mount *mp, xfs_agnumber_t agno);
@@ -57,7 +58,7 @@ struct rmap_mem_cur {
};
int rmap_init_mem_cursor(struct xfs_mount *mp, struct xfs_trans *tp,
- xfs_agnumber_t agno, struct rmap_mem_cur *rmcur);
+ bool isrt, xfs_agnumber_t agno, struct rmap_mem_cur *rmcur);
void rmap_free_mem_cursor(struct xfs_trans *tp, struct rmap_mem_cur *rmcur,
int error);
int rmap_get_mem_rec(struct rmap_mem_cur *rmcur, struct xfs_rmap_irec *irec);
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 36/47] xfs_repair: collect relatime reverse-mapping data for refcount/rmap tree rebuilding
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (34 preceding siblings ...)
2023-12-27 13:19 ` [PATCH 35/47] xfs_repair: create a new set of incore rmap information for rt groups Darrick J. Wong
@ 2023-12-27 13:19 ` Darrick J. Wong
2023-12-27 13:20 ` [PATCH 37/47] xfs_repair: refactor realtime inode check Darrick J. Wong
` (10 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:19 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Collect reverse-mapping data for realtime files so that we can later
check and rebuild the reference count tree and the reverse mapping
tree.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
repair/dinode.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/repair/dinode.c b/repair/dinode.c
index 41b44e6faad..d88bd80783c 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -350,6 +350,10 @@ _("inode %" PRIu64 " - bad rt extent overflows - start %" PRIu64 ", "
*/
*tot += irec->br_blockcount;
+ /* Record mapping data for the realtime rmap. */
+ if (collect_rmaps && !zap_metadata && !check_dups)
+ rmap_add_rec(mp, ino, XFS_DATA_FORK, irec, true);
+
return 0;
}
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 37/47] xfs_repair: refactor realtime inode check
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (35 preceding siblings ...)
2023-12-27 13:19 ` [PATCH 36/47] xfs_repair: collect relatime reverse-mapping data for refcount/rmap tree rebuilding Darrick J. Wong
@ 2023-12-27 13:20 ` Darrick J. Wong
2023-12-27 13:20 ` [PATCH 38/47] xfs_repair: find and mark the rtrmapbt inodes Darrick J. Wong
` (9 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:20 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Refactor the realtime bitmap and summary checks into a helper function.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
repair/dinode.c | 84 ++++++++++++++++++++++++++-----------------------------
1 file changed, 39 insertions(+), 45 deletions(-)
diff --git a/repair/dinode.c b/repair/dinode.c
index d88bd80783c..450f19eba4f 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -1736,6 +1736,39 @@ check_dinode_mode_format(
return 0; /* invalid modes are checked elsewhere */
}
+static int
+process_check_rt_inode(
+ struct xfs_mount *mp,
+ struct xfs_dinode *dinoc,
+ xfs_ino_t lino,
+ int *type,
+ int *dirty,
+ int expected_type,
+ const char *tag)
+{
+ xfs_extnum_t dnextents = xfs_dfork_data_extents(dinoc);
+
+ if (*type != expected_type) {
+ do_warn(
+_("%s inode %" PRIu64 " has bad type 0x%x, "),
+ tag, lino, dinode_fmt(dinoc));
+ if (!no_modify) {
+ do_warn(_("resetting to regular file\n"));
+ change_dinode_fmt(dinoc, S_IFREG);
+ *dirty = 1;
+ } else {
+ do_warn(_("would reset to regular file\n"));
+ }
+ }
+ if (mp->m_sb.sb_rblocks == 0 && dnextents != 0) {
+ do_warn(
+_("bad # of extents (%" PRIu64 ") for %s inode %" PRIu64 "\n"),
+ dnextents, tag, lino);
+ return 1;
+ }
+ return 0;
+}
+
/*
* If inode is a superblock inode, does type check to make sure is it valid.
* Returns 0 if it's valid, non-zero if it needs to be cleared.
@@ -1749,8 +1782,6 @@ process_check_sb_inodes(
int *type,
int *dirty)
{
- xfs_extnum_t dnextents;
-
if (lino == mp->m_sb.sb_rootino) {
if (*type != XR_INO_DIR) {
do_warn(_("root inode %" PRIu64 " has bad type 0x%x\n"),
@@ -1792,49 +1823,12 @@ process_check_sb_inodes(
}
return 0;
}
- dnextents = xfs_dfork_data_extents(dinoc);
- if (lino == mp->m_sb.sb_rsumino) {
- if (*type != XR_INO_RTSUM) {
- do_warn(
-_("realtime summary inode %" PRIu64 " has bad type 0x%x, "),
- lino, dinode_fmt(dinoc));
- if (!no_modify) {
- do_warn(_("resetting to regular file\n"));
- change_dinode_fmt(dinoc, S_IFREG);
- *dirty = 1;
- } else {
- do_warn(_("would reset to regular file\n"));
- }
- }
- if (mp->m_sb.sb_rblocks == 0 && dnextents != 0) {
- do_warn(
-_("bad # of extents (%" PRIu64 ") for realtime summary inode %" PRIu64 "\n"),
- dnextents, lino);
- return 1;
- }
- return 0;
- }
- if (lino == mp->m_sb.sb_rbmino) {
- if (*type != XR_INO_RTBITMAP) {
- do_warn(
-_("realtime bitmap inode %" PRIu64 " has bad type 0x%x, "),
- lino, dinode_fmt(dinoc));
- if (!no_modify) {
- do_warn(_("resetting to regular file\n"));
- change_dinode_fmt(dinoc, S_IFREG);
- *dirty = 1;
- } else {
- do_warn(_("would reset to regular file\n"));
- }
- }
- if (mp->m_sb.sb_rblocks == 0 && dnextents != 0) {
- do_warn(
-_("bad # of extents (%" PRIu64 ") for realtime bitmap inode %" PRIu64 "\n"),
- dnextents, lino);
- return 1;
- }
- return 0;
- }
+ if (lino == mp->m_sb.sb_rsumino)
+ return process_check_rt_inode(mp, dinoc, lino, type, dirty,
+ XR_INO_RTSUM, _("realtime summary"));
+ if (lino == mp->m_sb.sb_rbmino)
+ return process_check_rt_inode(mp, dinoc, lino, type, dirty,
+ XR_INO_RTBITMAP, _("realtime bitmap"));
return 0;
}
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 38/47] xfs_repair: find and mark the rtrmapbt inodes
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (36 preceding siblings ...)
2023-12-27 13:20 ` [PATCH 37/47] xfs_repair: refactor realtime inode check Darrick J. Wong
@ 2023-12-27 13:20 ` Darrick J. Wong
2023-12-27 13:20 ` [PATCH 39/47] xfs_repair: check existing realtime rmapbt entries against observed rmaps Darrick J. Wong
` (8 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:20 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Make sure that we find the realtime rmapbt inodes and mark them
appropriately, just in case we find a rogue inode claiming to be an
rtrmap, or garbage in the metadata directory tree.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
repair/dino_chunks.c | 13 +++++
repair/dinode.c | 42 ++++++++++++++++-
repair/dir2.c | 4 ++
repair/incore.h | 1
repair/rmap.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++-
repair/rmap.h | 5 ++
repair/scan.c | 8 ++-
7 files changed, 187 insertions(+), 9 deletions(-)
diff --git a/repair/dino_chunks.c b/repair/dino_chunks.c
index d132556d9dc..b7a5879bf4b 100644
--- a/repair/dino_chunks.c
+++ b/repair/dino_chunks.c
@@ -15,6 +15,8 @@
#include "versions.h"
#include "prefetch.h"
#include "progress.h"
+#include "slab.h"
+#include "rmap.h"
/*
* validates inode block or chunk, returns # of good inodes
@@ -1012,6 +1014,17 @@ process_inode_chunk(
_("would clear realtime summary inode %" PRIu64 "\n"),
ino);
}
+ } else if (is_rtrmap_inode(ino)) {
+ rmap_avoid_check(mp);
+ if (!no_modify) {
+ do_warn(
+ _("cleared realtime rmap inode %" PRIu64 "\n"),
+ ino);
+ } else {
+ do_warn(
+ _("would clear realtime rmap inode %" PRIu64 "\n"),
+ ino);
+ }
} else if (!no_modify) {
do_warn(_("cleared inode %" PRIu64 "\n"),
ino);
diff --git a/repair/dinode.c b/repair/dinode.c
index 450f19eba4f..e08b23a9454 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -153,6 +153,9 @@ clear_dinode(xfs_mount_t *mp, struct xfs_dinode *dino, xfs_ino_t ino_num)
clear_dinode_core(mp, dino, ino_num);
clear_dinode_unlinked(mp, dino);
+ if (is_rtrmap_inode(ino_num))
+ rmap_avoid_check(mp);
+
/* and clear the forks */
memset(XFS_DFORK_DPTR(dino), 0, XFS_LITINO(mp));
return;
@@ -823,13 +826,22 @@ process_rtrmap(
lino = XFS_AGINO_TO_INO(mp, agno, ino);
- /* This rmap btree inode must be a metadata inode. */
+ /*
+ * This rmap btree inode must be a metadata inode reachable via
+ * /realtime/$rgno.rmap in the metadata directory tree.
+ */
if (!(dip->di_flags2 & be64_to_cpu(XFS_DIFLAG2_METADIR))) {
do_warn(
_("rtrmap inode %" PRIu64 " not flagged as metadata\n"),
lino);
return 1;
}
+ if (type != XR_INO_RTRMAP) {
+ do_warn(
+_("rtrmap inode %" PRIu64 " was not found in the metadata directory tree\n"),
+ lino);
+ return 1;
+ }
memset(&priv.high_key, 0xFF, sizeof(priv.high_key));
priv.high_key.rm_blockcount = 0;
@@ -867,7 +879,7 @@ _("computed size of rtrmapbt root (%zu bytes) is greater than space in "
error = process_rtrmap_reclist(mp, rp, numrecs,
&priv.last_rec, NULL, "rtrmapbt root");
if (error) {
- rmap_avoid_check();
+ rmap_avoid_check(mp);
return 1;
}
return 0;
@@ -1829,6 +1841,9 @@ process_check_sb_inodes(
if (lino == mp->m_sb.sb_rbmino)
return process_check_rt_inode(mp, dinoc, lino, type, dirty,
XR_INO_RTBITMAP, _("realtime bitmap"));
+ if (is_rtrmap_inode(lino))
+ return process_check_rt_inode(mp, dinoc, lino, type, dirty,
+ XR_INO_RTRMAP, _("realtime rmap btree"));
return 0;
}
@@ -1926,6 +1941,18 @@ _("realtime summary inode %" PRIu64 " has bad size %" PRId64 " (should be %d)\n"
}
break;
+ case XR_INO_RTRMAP:
+ /*
+ * if we have no rmapbt, any inode claiming
+ * to be a real-time file is bogus
+ */
+ if (!xfs_has_rmapbt(mp)) {
+ do_warn(
+_("found inode %" PRIu64 " claiming to be a rtrmapbt file, but rmapbt is disabled\n"), lino);
+ return 1;
+ }
+ break;
+
default:
break;
}
@@ -1954,6 +1981,14 @@ _("bad attr fork offset %d in dev inode %" PRIu64 ", should be %d\n"),
return 1;
}
break;
+ case XFS_DINODE_FMT_RMAP:
+ if (!(xfs_has_metadir(mp) && xfs_has_parent(mp))) {
+ do_warn(
+_("metadata inode %" PRIu64 " type %d cannot have attr fork\n"),
+ lino, dino->di_format);
+ return 1;
+ }
+ fallthrough;
case XFS_DINODE_FMT_LOCAL:
case XFS_DINODE_FMT_EXTENTS:
case XFS_DINODE_FMT_BTREE:
@@ -3050,6 +3085,8 @@ _("bad (negative) size %" PRId64 " on inode %" PRIu64 "\n"),
type = XR_INO_GQUOTA;
else if (lino == mp->m_sb.sb_pquotino)
type = XR_INO_PQUOTA;
+ else if (is_rtrmap_inode(lino))
+ type = XR_INO_RTRMAP;
else
type = XR_INO_DATA;
break;
@@ -3155,6 +3192,7 @@ _("Bad CoW extent size %u on inode %" PRIu64 ", "),
case XR_INO_UQUOTA:
case XR_INO_GQUOTA:
case XR_INO_PQUOTA:
+ case XR_INO_RTRMAP:
/*
* This inode was recognized as being filesystem
* metadata, so preserve the inode and its contents for
diff --git a/repair/dir2.c b/repair/dir2.c
index a7f5018fba2..43229b3cd9b 100644
--- a/repair/dir2.c
+++ b/repair/dir2.c
@@ -15,6 +15,8 @@
#include "da_util.h"
#include "prefetch.h"
#include "progress.h"
+#include "slab.h"
+#include "rmap.h"
/*
* Known bad inode list. These are seen when the leaf and node
@@ -154,6 +156,8 @@ is_meta_ino(
reason = _("realtime bitmap");
else if (lino == mp->m_sb.sb_rsumino)
reason = _("realtime summary");
+ else if (is_rtrmap_inode(lino))
+ reason = _("realtime rmap");
else if (lino == mp->m_sb.sb_uquotino)
reason = _("user quota");
else if (lino == mp->m_sb.sb_gquotino)
diff --git a/repair/incore.h b/repair/incore.h
index 645cc5317c8..6ee7a662930 100644
--- a/repair/incore.h
+++ b/repair/incore.h
@@ -221,6 +221,7 @@ int count_bcnt_extents(xfs_agnumber_t);
#define XR_INO_UQUOTA 12 /* user quota inode */
#define XR_INO_GQUOTA 13 /* group quota inode */
#define XR_INO_PQUOTA 14 /* project quota inode */
+#define XR_INO_RTRMAP 15 /* realtime rmap */
/* inode allocation tree */
diff --git a/repair/rmap.c b/repair/rmap.c
index aa47013baec..b7e7fbe3f47 100644
--- a/repair/rmap.c
+++ b/repair/rmap.c
@@ -33,6 +33,12 @@ struct xfs_ag_rmap {
int ar_flcount; /* agfl entries from leftover */
/* agbt allocations */
struct xfs_slab *ar_refcount_items; /* refcount items, p4-5 */
+
+ /*
+ * inumber of the rmap btree for this rtgroup. This can be set to
+ * NULLFSINO to signal to phase 6 to link a new inode into the metadir.
+ */
+ xfs_ino_t rg_rmap_ino;
};
static struct xfs_ag_rmap *ag_rmaps;
@@ -40,6 +46,9 @@ static struct xfs_ag_rmap *rg_rmaps;
bool rmapbt_suspect;
static bool refcbt_suspect;
+/* Bitmap of rt group rmap inodes reachable via /realtime/$rgno.rmap. */
+static struct bitmap *rmap_inodes;
+
static struct xfs_ag_rmap *rmaps_for_group(bool isrt, unsigned int group)
{
if (isrt)
@@ -116,6 +125,7 @@ rmaps_init_rt(
if (error)
goto nomem;
+ ag_rmap->rg_rmap_ino = NULLFSINO;
return;
nomem:
do_error(
@@ -163,6 +173,90 @@ rmaps_init_ag(
_("Insufficient memory while allocating realtime reverse mapping btree."));
}
+static inline int
+set_rtgroup_rmap_inode(
+ struct xfs_mount *mp,
+ xfs_rgnumber_t rgno)
+{
+ struct xfs_imeta_path *path;
+ struct xfs_ag_rmap *ar = rmaps_for_group(true, rgno);
+ struct xfs_trans *tp;
+ xfs_ino_t ino;
+ int error;
+
+ if (!xfs_has_rtrmapbt(mp))
+ return 0;
+
+ error = -libxfs_rtrmapbt_create_path(mp, rgno, &path);
+ if (error)
+ return error;
+
+ error = -libxfs_trans_alloc_empty(mp, &tp);
+ if (error)
+ goto out_path;
+
+ error = -libxfs_imeta_lookup(tp, path, &ino);
+ if (error)
+ goto out_trans;
+
+ if (ino == NULLFSINO || bitmap_test(rmap_inodes, ino, 1)) {
+ error = EFSCORRUPTED;
+ goto out_trans;
+ }
+
+ error = bitmap_set(rmap_inodes, ino, 1);
+ if (error)
+ goto out_trans;
+
+ ar->rg_rmap_ino = ino;
+
+out_trans:
+ libxfs_trans_cancel(tp);
+out_path:
+ libxfs_imeta_free_path(path);
+ return error;
+}
+
+static void
+discover_rtgroup_inodes(
+ struct xfs_mount *mp)
+{
+ xfs_rgnumber_t rgno;
+ int error;
+
+ error = bitmap_alloc(&rmap_inodes);
+ if (error)
+ goto out;
+
+ for (rgno = 0; rgno < mp->m_sb.sb_rgcount; rgno++) {
+ int err2 = set_rtgroup_rmap_inode(mp, rgno);
+ if (err2 && !error)
+ error = err2;
+ }
+
+out:
+ if (error == EFSCORRUPTED)
+ do_warn(
+ _("corruption in metadata directory tree while discovering rt group inodes\n"));
+ if (error)
+ do_warn(
+ _("couldn't discover rt group inodes, err %d\n"),
+ error);
+}
+
+static inline void
+free_rtmeta_inode_bitmaps(void)
+{
+ bitmap_free(&rmap_inodes);
+}
+
+bool is_rtrmap_inode(xfs_ino_t ino)
+{
+ if (!rmap_inodes)
+ return false;
+ return bitmap_test(rmap_inodes, ino, 1);
+}
+
/*
* Initialize per-AG reverse map data.
*/
@@ -188,6 +282,8 @@ rmaps_init(
for (i = 0; i < mp->m_sb.sb_rgcount; i++)
rmaps_init_rt(mp, i, &rg_rmaps[i]);
+
+ discover_rtgroup_inodes(mp);
}
/*
@@ -202,6 +298,8 @@ rmaps_free(
if (!rmap_needs_work(mp))
return;
+ free_rtmeta_inode_bitmaps();
+
for (i = 0; i < mp->m_sb.sb_rgcount; i++)
rmaps_destroy(mp, &rg_rmaps[i]);
free(rg_rmaps);
@@ -1148,11 +1246,22 @@ rmap_record_count(
}
/*
- * Disable the refcount btree check.
+ * Disable the rmap btree check.
*/
void
-rmap_avoid_check(void)
+rmap_avoid_check(
+ struct xfs_mount *mp)
{
+ struct xfs_rtgroup *rtg;
+ xfs_rgnumber_t rgno;
+
+ for_each_rtgroup(mp, rgno, rtg) {
+ struct xfs_ag_rmap *ar = rmaps_for_group(true, rtg->rtg_rgno);
+
+ ar->rg_rmap_ino = NULLFSINO;
+ }
+
+ bitmap_clear(rmap_inodes, 0, XFS_MAXINUMBER);
rmapbt_suspect = true;
}
@@ -1831,3 +1940,13 @@ estimate_refcountbt_blocks(
return libxfs_refcountbt_calc_size(mp,
slab_count(x->ar_refcount_items));
}
+
+/* Retrieve the rtrmapbt inode number for a given rtgroup. */
+xfs_ino_t
+rtgroup_rmap_ino(
+ struct xfs_rtgroup *rtg)
+{
+ struct xfs_ag_rmap *ar = rmaps_for_group(true, rtg->rtg_rgno);
+
+ return ar->rg_rmap_ino;
+}
diff --git a/repair/rmap.h b/repair/rmap.h
index 7a94ed6f90a..dd55ba3cc29 100644
--- a/repair/rmap.h
+++ b/repair/rmap.h
@@ -28,7 +28,7 @@ int rmap_commit_agbtree_mappings(struct xfs_mount *mp, xfs_agnumber_t agno);
uint64_t rmap_record_count(struct xfs_mount *mp, bool isrt,
xfs_agnumber_t agno);
-extern void rmap_avoid_check(void);
+extern void rmap_avoid_check(struct xfs_mount *mp);
void rmaps_verify_btree(struct xfs_mount *mp, xfs_agnumber_t agno);
extern int64_t rmap_diffkeys(struct xfs_rmap_irec *kp1,
@@ -63,4 +63,7 @@ void rmap_free_mem_cursor(struct xfs_trans *tp, struct rmap_mem_cur *rmcur,
int error);
int rmap_get_mem_rec(struct rmap_mem_cur *rmcur, struct xfs_rmap_irec *irec);
+bool is_rtrmap_inode(xfs_ino_t ino);
+xfs_ino_t rtgroup_rmap_ino(struct xfs_rtgroup *rtg);
+
#endif /* RMAP_H_ */
diff --git a/repair/scan.c b/repair/scan.c
index 27aeb341bf3..2f414898078 100644
--- a/repair/scan.c
+++ b/repair/scan.c
@@ -1357,7 +1357,7 @@ _("out of order key %u in %s btree block (%u/%u)\n"),
out:
if (suspect)
- rmap_avoid_check();
+ rmap_avoid_check(mp);
}
int
@@ -1737,7 +1737,7 @@ _("bad %s btree ptr 0x%llx in ino %" PRIu64 "\n"),
out:
if (hdr_errors || suspect) {
- rmap_avoid_check();
+ rmap_avoid_check(mp);
return 1;
}
return 0;
@@ -2818,7 +2818,7 @@ validate_agf(
if (levels == 0 || levels > mp->m_rmap_maxlevels) {
do_warn(_("bad levels %u for rmapbt root, agno %d\n"),
levels, agno);
- rmap_avoid_check();
+ rmap_avoid_check(mp);
}
bno = be32_to_cpu(agf->agf_roots[XFS_BTNUM_RMAP]);
@@ -2833,7 +2833,7 @@ validate_agf(
} else {
do_warn(_("bad agbno %u for rmapbt root, agno %d\n"),
bno, agno);
- rmap_avoid_check();
+ rmap_avoid_check(mp);
}
}
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 39/47] xfs_repair: check existing realtime rmapbt entries against observed rmaps
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (37 preceding siblings ...)
2023-12-27 13:20 ` [PATCH 38/47] xfs_repair: find and mark the rtrmapbt inodes Darrick J. Wong
@ 2023-12-27 13:20 ` Darrick J. Wong
2023-12-27 13:20 ` [PATCH 40/47] xfs_repair: always check realtime file mappings against incore info Darrick J. Wong
` (7 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:20 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Once we've finished collecting reverse mapping observations from the
metadata scan, check those observations against the realtime rmap btree
(particularly if we're in -n mode) to detect rtrmapbt problems.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
repair/phase4.c | 12 +++
repair/rmap.c | 262 ++++++++++++++++++++++++++++++++++++++++++++-----------
repair/rmap.h | 2
3 files changed, 223 insertions(+), 53 deletions(-)
diff --git a/repair/phase4.c b/repair/phase4.c
index cfdea1460e5..b0cb805f30c 100644
--- a/repair/phase4.c
+++ b/repair/phase4.c
@@ -155,6 +155,16 @@ check_rmap_btrees(
rmaps_verify_btree(wq->wq_ctx, agno);
}
+static void
+check_rtrmap_btrees(
+ struct workqueue *wq,
+ xfs_agnumber_t agno,
+ void *arg)
+{
+ rmap_add_fixed_rtgroup_rec(wq->wq_ctx, agno);
+ rtrmaps_verify_btree(wq->wq_ctx, agno);
+}
+
static void
compute_ag_refcounts(
struct workqueue*wq,
@@ -207,6 +217,8 @@ process_rmap_data(
create_work_queue(&wq, mp, platform_nproc());
for (i = 0; i < mp->m_sb.sb_agcount; i++)
queue_work(&wq, check_rmap_btrees, i, NULL);
+ for (i = 0; i < mp->m_sb.sb_rgcount; i++)
+ queue_work(&wq, check_rtrmap_btrees, i, NULL);
destroy_work_queue(&wq);
if (!xfs_has_reflink(mp))
diff --git a/repair/rmap.c b/repair/rmap.c
index b7e7fbe3f47..5ac7188f12e 100644
--- a/repair/rmap.c
+++ b/repair/rmap.c
@@ -17,6 +17,7 @@
#include "libxfs/xfile.h"
#include "libxfs/xfbtree.h"
#include "rcbag.h"
+#include "prefetch.h"
#undef RMAP_DEBUG
@@ -682,6 +683,26 @@ rmap_add_fixed_ag_rec(
}
}
+/* Add this realtime group's fixed metadata to the incore data. */
+void
+rmap_add_fixed_rtgroup_rec(
+ struct xfs_mount *mp,
+ xfs_rgnumber_t rgno)
+{
+ struct xfs_rmap_irec rmap = {
+ .rm_startblock = 0,
+ .rm_blockcount = mp->m_sb.sb_rextsize,
+ .rm_owner = XFS_RMAP_OWN_FS,
+ .rm_offset = 0,
+ .rm_flags = 0,
+ };
+
+ if (!rmap_needs_work(mp))
+ return;
+
+ rmap_add_mem_rec(mp, true, rgno, &rmap);
+}
+
/*
* Copy the per-AG btree reverse-mapping data into the rmapbt.
*
@@ -1331,62 +1352,25 @@ rmap_is_good(
#undef NEXTP
#undef NEXTL
-/*
- * Compare the observed reverse mappings against what's in the ag btree.
- */
-void
-rmaps_verify_btree(
- struct xfs_mount *mp,
- xfs_agnumber_t agno)
+static int
+rmap_compare_records(
+ struct rmap_mem_cur *rm_cur,
+ struct xfs_btree_cur *bt_cur,
+ unsigned int group)
{
- struct rmap_mem_cur rm_cur;
struct xfs_rmap_irec rm_rec;
struct xfs_rmap_irec tmp;
- struct xfs_btree_cur *bt_cur = NULL;
- struct xfs_buf *agbp = NULL;
- struct xfs_perag *pag = NULL;
int have;
int error;
- if (!xfs_has_rmapbt(mp) || add_rmapbt)
- return;
- if (rmapbt_suspect) {
- if (no_modify && agno == 0)
- do_warn(_("would rebuild corrupt rmap btrees.\n"));
- return;
- }
-
- /* Create cursors to rmap structures */
- error = rmap_init_mem_cursor(mp, NULL, false, agno, &rm_cur);
- if (error) {
- do_warn(_("Not enough memory to check reverse mappings.\n"));
- return;
- }
-
- pag = libxfs_perag_get(mp, agno);
- error = -libxfs_alloc_read_agf(pag, NULL, 0, &agbp);
- if (error) {
- do_warn(_("Could not read AGF %u to check rmap btree.\n"),
- agno);
- goto err_pag;
- }
-
- /* Leave the per-ag data "uninitialized" since we rewrite it later */
- clear_bit(XFS_AGSTATE_AGF_INIT, &pag->pag_opstate);
-
- bt_cur = libxfs_rmapbt_init_cursor(mp, NULL, agbp, pag);
- if (!bt_cur) {
- do_warn(_("Not enough memory to check reverse mappings.\n"));
- goto err_agf;
- }
-
- while ((error = rmap_get_mem_rec(&rm_cur, &rm_rec)) == 1) {
+ 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);
- goto err_cur;
+ group,
+ rm_rec.rm_startblock);
+ return error;
}
/*
@@ -1401,15 +1385,15 @@ _("Could not read reverse-mapping record for (%u/%u).\n"),
if (error) {
do_warn(
_("Could not read reverse-mapping record for (%u/%u).\n"),
- agno, rm_rec.rm_startblock);
- goto err_cur;
+ group, rm_rec.rm_startblock);
+ return error;
}
}
if (!have) {
do_warn(
_("Missing reverse-mapping record for (%u/%u) %slen %u owner %"PRId64" \
%s%soff %"PRIu64"\n"),
- agno, rm_rec.rm_startblock,
+ group, rm_rec.rm_startblock,
(rm_rec.rm_flags & XFS_RMAP_UNWRITTEN) ?
_("unwritten ") : "",
rm_rec.rm_blockcount,
@@ -1422,12 +1406,12 @@ _("Missing reverse-mapping record for (%u/%u) %slen %u owner %"PRId64" \
continue;
}
- /* Compare each refcount observation against the btree's */
+ /* Compare each rmap observation against the btree's */
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"),
- agno, tmp.rm_startblock,
+ group, tmp.rm_startblock,
(tmp.rm_flags & XFS_RMAP_UNWRITTEN) ?
_("unwritten ") : "",
tmp.rm_blockcount,
@@ -1437,7 +1421,7 @@ _("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,
+ group, rm_rec.rm_startblock,
(rm_rec.rm_flags & XFS_RMAP_UNWRITTEN) ?
_("unwritten ") : "",
rm_rec.rm_blockcount,
@@ -1450,8 +1434,61 @@ _("Incorrect reverse-mapping: saw (%u/%u) %slen %u owner %"PRId64" %s%soff \
}
}
+ return error;
+}
+
+/*
+ * Compare the observed reverse mappings against what's in the ag btree.
+ */
+void
+rmaps_verify_btree(
+ struct xfs_mount *mp,
+ xfs_agnumber_t agno)
+{
+ struct rmap_mem_cur rm_cur;
+ struct xfs_btree_cur *bt_cur = NULL;
+ struct xfs_buf *agbp = NULL;
+ struct xfs_perag *pag = NULL;
+ int error;
+
+ if (!xfs_has_rmapbt(mp) || add_rmapbt)
+ return;
+ if (rmapbt_suspect) {
+ if (no_modify && agno == 0)
+ do_warn(_("would rebuild corrupt rmap btrees.\n"));
+ return;
+ }
+
+ /* Create cursors to rmap structures */
+ error = rmap_init_mem_cursor(mp, NULL, false, agno, &rm_cur);
+ if (error) {
+ do_warn(_("Not enough memory to check reverse mappings.\n"));
+ return;
+ }
+
+ pag = libxfs_perag_get(mp, agno);
+ error = -libxfs_alloc_read_agf(pag, NULL, 0, &agbp);
+ if (error) {
+ do_warn(_("Could not read AGF %u to check rmap btree.\n"),
+ agno);
+ goto err_pag;
+ }
+
+ /* Leave the per-ag data "uninitialized" since we rewrite it later */
+ clear_bit(XFS_AGSTATE_AGF_INIT, &pag->pag_opstate);
+
+ bt_cur = libxfs_rmapbt_init_cursor(mp, NULL, agbp, pag);
+ if (!bt_cur) {
+ do_warn(_("Not enough memory to check reverse mappings.\n"));
+ goto err_agf;
+ }
+
+ error = rmap_compare_records(&rm_cur, bt_cur, agno);
+ if (error)
+ goto err_cur;
+
err_cur:
- libxfs_btree_del_cursor(bt_cur, XFS_BTREE_NOERROR);
+ libxfs_btree_del_cursor(bt_cur, error);
err_agf:
libxfs_buf_relse(agbp);
err_pag:
@@ -1459,6 +1496,125 @@ _("Incorrect reverse-mapping: saw (%u/%u) %slen %u owner %"PRId64" %s%soff \
rmap_free_mem_cursor(NULL, &rm_cur, error);
}
+/*
+ * Thread-safe version of xfs_imeta_iget.
+ *
+ * In the kernel, xfs_imeta_iget requires a transaction so that the untrusted
+ * lookup will not livelock the mount process if the inobt contains a cycle.
+ * However, the userspace buffer cache only locks buffers if it's told to.
+ * That only happens when prefetch is enabled.
+ *
+ * Depending on allocation patterns, realtime metadata inodes can share the
+ * same inode cluster buffer. We don't want libxfs_trans_bjoin in racing iget
+ * calls to corrupt the incore buffer state, so we impose our own lock here.
+ * Evidently support orgs will sometimes use no-prefetch lockless mode as a
+ * last resort if repair gets stuck on a buffer lock elsewhere.
+ */
+static inline int
+threadsafe_imeta_iget(
+ struct xfs_mount *mp,
+ xfs_ino_t ino,
+ struct xfs_inode **ipp)
+{
+ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+ struct xfs_trans *tp;
+ int error;
+
+ error = -libxfs_trans_alloc_empty(mp, &tp);
+ if (error)
+ return error;
+
+ if (do_prefetch) {
+ error = -libxfs_imeta_iget(tp, ino, XFS_DIR3_FT_REG_FILE, ipp);
+ } else {
+ pthread_mutex_lock(&lock);
+ error = -libxfs_imeta_iget(tp, ino, XFS_DIR3_FT_REG_FILE, ipp);
+ pthread_mutex_unlock(&lock);
+ }
+ libxfs_trans_cancel(tp);
+
+ return error;
+}
+
+/*
+ * Compare the observed reverse mappings against what's in the rtgroup btree.
+ */
+void
+rtrmaps_verify_btree(
+ struct xfs_mount *mp,
+ xfs_rgnumber_t rgno)
+{
+ struct rmap_mem_cur rm_cur;
+ struct xfs_btree_cur *bt_cur = NULL;
+ struct xfs_rtgroup *rtg = NULL;
+ struct xfs_ag_rmap *ar = rmaps_for_group(true, rgno);
+ struct xfs_inode *ip = NULL;
+ int error;
+
+ if (!xfs_has_rmapbt(mp) || add_rmapbt)
+ return;
+ if (rmapbt_suspect) {
+ if (no_modify && rgno == 0)
+ do_warn(_("would rebuild corrupt rmap btrees.\n"));
+ return;
+ }
+
+ /* Create cursors to rmap structures */
+ error = rmap_init_mem_cursor(mp, NULL, true, rgno, &rm_cur);
+ if (error) {
+ do_warn(_("Not enough memory to check reverse mappings.\n"));
+ return;
+ }
+
+ rtg = libxfs_rtgroup_get(mp, rgno);
+ if (!rtg) {
+ do_warn(_("Could not load rtgroup %u.\n"), rgno);
+ goto err_rcur;
+ }
+
+ error = threadsafe_imeta_iget(mp, ar->rg_rmap_ino, &ip);
+ if (error) {
+ do_warn(
+_("Could not load rtgroup %u rmap inode, error %d.\n"),
+ rgno, error);
+ goto err_rtg;
+ }
+
+ if (ip->i_df.if_format != XFS_DINODE_FMT_RMAP) {
+ do_warn(
+_("rtgroup %u rmap inode has wrong format 0x%x, expected 0x%x\n"),
+ rgno, ip->i_df.if_format,
+ XFS_DINODE_FMT_RMAP);
+ goto err_ino;
+ }
+
+ if (xfs_inode_has_attr_fork(ip) &&
+ !(xfs_has_metadir(mp) && xfs_has_parent(mp))) {
+ do_warn(
+_("rtgroup %u rmap inode should not have extended attributes\n"), rgno);
+ goto err_ino;
+ }
+
+ bt_cur = libxfs_rtrmapbt_init_cursor(mp, NULL, rtg, ip);
+ if (!bt_cur) {
+ do_warn(_("Not enough memory to check reverse mappings.\n"));
+ goto err_ino;
+ }
+
+ error = rmap_compare_records(&rm_cur, bt_cur, rgno);
+ if (error)
+ goto err_cur;
+
+err_cur:
+ libxfs_btree_del_cursor(bt_cur, error);
+err_ino:
+ libxfs_imeta_irele(ip);
+err_rtg:
+ libxfs_rtgroup_put(rtg);
+err_rcur:
+ rmap_free_mem_cursor(NULL, &rm_cur, error);
+}
+
/*
* Compare the key fields of two rmap records -- positive if key1 > key2,
* negative if key1 < key2, and zero if equal.
diff --git a/repair/rmap.h b/repair/rmap.h
index dd55ba3cc29..dcd834ef242 100644
--- a/repair/rmap.h
+++ b/repair/rmap.h
@@ -21,6 +21,7 @@ void rmap_add_bmbt_rec(struct xfs_mount *mp, xfs_ino_t ino, int whichfork,
bool rmaps_are_mergeable(struct xfs_rmap_irec *r1, struct xfs_rmap_irec *r2);
void rmap_add_fixed_ag_rec(struct xfs_mount *mp, xfs_agnumber_t agno);
+void rmap_add_fixed_rtgroup_rec(struct xfs_mount *mp, xfs_rgnumber_t rgno);
int rmap_add_agbtree_mapping(struct xfs_mount *mp, xfs_agnumber_t agno,
xfs_agblock_t agbno, xfs_extlen_t len, uint64_t owner);
@@ -30,6 +31,7 @@ uint64_t rmap_record_count(struct xfs_mount *mp, bool isrt,
xfs_agnumber_t agno);
extern void rmap_avoid_check(struct xfs_mount *mp);
void rmaps_verify_btree(struct xfs_mount *mp, xfs_agnumber_t agno);
+void rtrmaps_verify_btree(struct xfs_mount *mp, xfs_rgnumber_t rgno);
extern int64_t rmap_diffkeys(struct xfs_rmap_irec *kp1,
struct xfs_rmap_irec *kp2);
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 40/47] xfs_repair: always check realtime file mappings against incore info
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (38 preceding siblings ...)
2023-12-27 13:20 ` [PATCH 39/47] xfs_repair: check existing realtime rmapbt entries against observed rmaps Darrick J. Wong
@ 2023-12-27 13:20 ` Darrick J. Wong
2023-12-27 13:21 ` [PATCH 41/47] xfs_repair: rebuild the realtime rmap btree Darrick J. Wong
` (6 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:20 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Curiously, the xfs_repair code that processes data fork mappings of
realtime files doesn't actually compare the mappings against the incore
state map during the !check_dups phase (aka phase 3). As a result, we
lose the opportunity to clear damaged realtime data forks before we get
to crosslinked file checking in phase 4, which results in ondisk
metadata errors calling do_error, which aborts repair.
Split the process_rt_rec_state code into two functions: one to check the
mapping, and another to update the incore state. The first one can be
called to help us decide if we're going to zap the fork, and the second
one updates the incore state if we decide to keep the fork. We already
do this for regular data files.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
repair/dinode.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 80 insertions(+), 8 deletions(-)
diff --git a/repair/dinode.c b/repair/dinode.c
index e08b23a9454..a6713a7bc6b 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -219,7 +219,7 @@ _("data fork in rt ino %" PRIu64 " claims dup rt extent,"
return 0;
}
-static int
+static void
process_rt_rec_state(
struct xfs_mount *mp,
xfs_ino_t ino,
@@ -263,11 +263,78 @@ _("data fork in rt inode %" PRIu64 " found invalid rt extent %"PRIu64" state %d
set_rtbmap(ext, zap_metadata ? XR_E_METADATA :
XR_E_INUSE);
break;
+ case XR_E_BAD_STATE:
+ do_error(
+_("bad state in rt extent map %" PRIu64 "\n"),
+ ext);
case XR_E_METADATA:
+ case XR_E_FS_MAP:
+ case XR_E_INO:
+ case XR_E_INUSE_FS:
+ break;
+ case XR_E_INUSE:
+ case XR_E_MULT:
+ set_rtbmap(ext, XR_E_MULT);
+ break;
+ case XR_E_FREE1:
+ default:
do_error(
+_("illegal state %d in rt extent %" PRIu64 "\n"),
+ state, ext);
+ }
+ b += mp->m_sb.sb_rextsize;
+ } while (b < irec->br_startblock + irec->br_blockcount);
+}
+
+/*
+ * Checks the realtime file's data mapping against in-core extent info, and
+ * complains if there are discrepancies. Returns 0 if good, 1 if bad.
+ */
+static int
+check_rt_rec_state(
+ struct xfs_mount *mp,
+ xfs_ino_t ino,
+ struct xfs_bmbt_irec *irec)
+{
+ xfs_fsblock_t b = irec->br_startblock;
+ xfs_rtblock_t ext;
+ int state;
+
+ do {
+ ext = (xfs_rtblock_t)b / mp->m_sb.sb_rextsize;
+ state = get_rtbmap(ext);
+
+ if ((b % mp->m_sb.sb_rextsize) != 0) {
+ /*
+ * We are midway through a partially written extent.
+ * If we don't find the state that gets set in the
+ * other clause of this loop body, then we have a
+ * partially *mapped* rt extent and should complain.
+ */
+ if (state != XR_E_INUSE && state != XR_E_FREE) {
+ do_warn(
+_("data fork in rt inode %" PRIu64 " found invalid rt extent %"PRIu64" state %d at rt block %"PRIu64"\n"),
+ ino, ext, state, b);
+ return 1;
+ }
+
+ b = roundup(b, mp->m_sb.sb_rextsize);
+ continue;
+ }
+
+ /*
+ * This is the start of an rt extent. Complain if there are
+ * conflicting states. We'll set the state elsewhere.
+ */
+ switch (state) {
+ case XR_E_FREE:
+ case XR_E_UNKNOWN:
+ break;
+ case XR_E_METADATA:
+ do_warn(
_("data fork in rt inode %" PRIu64 " found metadata file block %" PRIu64 " in rt bmap\n"),
ino, ext);
- break;
+ return 1;
case XR_E_BAD_STATE:
do_error(
_("bad state in rt extent map %" PRIu64 "\n"),
@@ -275,12 +342,12 @@ _("bad state in rt extent map %" PRIu64 "\n"),
case XR_E_FS_MAP:
case XR_E_INO:
case XR_E_INUSE_FS:
- do_error(
+ do_warn(
_("data fork in rt inode %" PRIu64 " found rt metadata extent %" PRIu64 " in rt bmap\n"),
ino, ext);
+ return 1;
case XR_E_INUSE:
case XR_E_MULT:
- set_rtbmap(ext, XR_E_MULT);
do_warn(
_("data fork in rt inode %" PRIu64 " claims used rt extent %" PRIu64 "\n"),
ino, b);
@@ -341,13 +408,18 @@ _("inode %" PRIu64 " - bad rt extent overflows - start %" PRIu64 ", "
return 1;
}
- if (check_dups)
- bad = process_rt_rec_dups(mp, ino, irec);
- else
- bad = process_rt_rec_state(mp, ino, zap_metadata, irec);
+ bad = check_rt_rec_state(mp, ino, irec);
if (bad)
return bad;
+ if (check_dups) {
+ bad = process_rt_rec_dups(mp, ino, irec);
+ if (bad)
+ return bad;
+ } else {
+ process_rt_rec_state(mp, ino, zap_metadata, irec);
+ }
+
/*
* bump up the block counter
*/
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 41/47] xfs_repair: rebuild the realtime rmap btree
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (39 preceding siblings ...)
2023-12-27 13:20 ` [PATCH 40/47] xfs_repair: always check realtime file mappings against incore info Darrick J. Wong
@ 2023-12-27 13:21 ` Darrick J. Wong
2023-12-27 13:21 ` [PATCH 42/47] xfs_repair: check for global free space concerns with default btree slack levels Darrick J. Wong
` (5 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:21 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Rebuild the realtime rmap btree file from the reverse mapping records we
gathered from walking the inodes.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/libxfs_api_defs.h | 5 +
repair/Makefile | 1
repair/bulkload.c | 41 +++++++
repair/bulkload.h | 2
repair/phase6.c | 155 +++++++++++++++++++++++++++
repair/rmap.c | 26 +++++
repair/rmap.h | 3 +
repair/rtrmap_repair.c | 261 ++++++++++++++++++++++++++++++++++++++++++++++
repair/xfs_repair.c | 8 +
9 files changed, 500 insertions(+), 2 deletions(-)
create mode 100644 repair/rtrmap_repair.c
diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
index e65b4d6fea5..b5bb6c39928 100644
--- a/libxfs/libxfs_api_defs.h
+++ b/libxfs/libxfs_api_defs.h
@@ -271,6 +271,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_extent libxfs_rmap_map_extent
#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
@@ -288,6 +289,9 @@
#define xfs_rtgroup_put libxfs_rtgroup_put
#define xfs_rtgroup_update_secondary_sbs libxfs_rtgroup_update_secondary_sbs
#define xfs_rtgroup_update_super libxfs_rtgroup_update_super
+#define xfs_rtrmapbt_calc_size libxfs_rtrmapbt_calc_size
+#define xfs_rtrmapbt_commit_staged_btree libxfs_rtrmapbt_commit_staged_btree
+#define xfs_rtrmapbt_create libxfs_rtrmapbt_create
#define xfs_rtrmapbt_create_path libxfs_rtrmapbt_create_path
#define xfs_rtrmapbt_droot_maxrecs libxfs_rtrmapbt_droot_maxrecs
#define xfs_rtrmapbt_maxlevels_ondisk libxfs_rtrmapbt_maxlevels_ondisk
@@ -295,6 +299,7 @@
#define xfs_rtrmapbt_maxrecs libxfs_rtrmapbt_maxrecs
#define xfs_rtrmapbt_mem_create libxfs_rtrmapbt_mem_create
#define xfs_rtrmapbt_mem_cursor libxfs_rtrmapbt_mem_cursor
+#define xfs_rtrmapbt_stage_cursor libxfs_rtrmapbt_stage_cursor
#define xfs_sb_from_disk libxfs_sb_from_disk
#define xfs_sb_quota_from_disk libxfs_sb_quota_from_disk
diff --git a/repair/Makefile b/repair/Makefile
index 1f72c811056..5bec8154829 100644
--- a/repair/Makefile
+++ b/repair/Makefile
@@ -75,6 +75,7 @@ CFILES = \
rcbag.c \
rmap.c \
rt.c \
+ rtrmap_repair.c \
sb.c \
scan.c \
slab.c \
diff --git a/repair/bulkload.c b/repair/bulkload.c
index e9c52afd23c..819639ae343 100644
--- a/repair/bulkload.c
+++ b/repair/bulkload.c
@@ -364,3 +364,44 @@ bulkload_estimate_ag_slack(
if (bload->node_slack < 0)
bload->node_slack = 2;
}
+
+/*
+ * Estimate proper slack values for a btree that's being reloaded.
+ *
+ * Under most circumstances, we'll take whatever default loading value the
+ * btree bulk loading code calculates for us. However, there are some
+ * exceptions to this rule:
+ *
+ * (1) If someone turned one of the debug knobs.
+ * (2) The FS has less than ~9% space free.
+ *
+ * Note that we actually use 3/32 for the comparison to avoid division.
+ */
+void
+bulkload_estimate_inode_slack(
+ struct xfs_mount *mp,
+ struct xfs_btree_bload *bload,
+ unsigned long long free)
+{
+ /*
+ * The global values are set to -1 (i.e. take the bload defaults)
+ * unless someone has set them otherwise, so we just pull the values
+ * here.
+ */
+ bload->leaf_slack = bload_leaf_slack;
+ bload->node_slack = bload_node_slack;
+
+ /* No further changes if there's more than 3/32ths space left. */
+ if (free >= ((mp->m_sb.sb_dblocks * 3) >> 5))
+ return;
+
+ /*
+ * We're low on space; load the btrees as tightly as possible. Leave
+ * a couple of open slots in each btree block so that we don't end up
+ * splitting the btrees like crazy right after mount.
+ */
+ if (bload->leaf_slack < 0)
+ bload->leaf_slack = 2;
+ if (bload->node_slack < 0)
+ bload->node_slack = 2;
+}
diff --git a/repair/bulkload.h b/repair/bulkload.h
index a88aafaa678..842121b1519 100644
--- a/repair/bulkload.h
+++ b/repair/bulkload.h
@@ -78,5 +78,7 @@ void bulkload_cancel(struct bulkload *bkl);
int bulkload_commit(struct bulkload *bkl);
void bulkload_estimate_ag_slack(struct repair_ctx *sc,
struct xfs_btree_bload *bload, unsigned int free);
+void bulkload_estimate_inode_slack(struct xfs_mount *mp,
+ struct xfs_btree_bload *bload, unsigned long long free);
#endif /* __XFS_REPAIR_BULKLOAD_H__ */
diff --git a/repair/phase6.c b/repair/phase6.c
index 63a2768d9c6..4c387557c31 100644
--- a/repair/phase6.c
+++ b/repair/phase6.c
@@ -19,6 +19,8 @@
#include "progress.h"
#include "versions.h"
#include "repair/pptr.h"
+#include "slab.h"
+#include "rmap.h"
static xfs_ino_t orphanage_ino;
@@ -1072,6 +1074,136 @@ mk_rsumino(
libxfs_irele(ip);
}
+static void
+ensure_rtgroup_rmapbt(
+ struct xfs_rtgroup *rtg,
+ xfs_filblks_t est_fdblocks)
+{
+ struct xfs_imeta_update upd;
+ struct xfs_mount *mp = rtg->rtg_mount;
+ struct xfs_imeta_path *path;
+ struct xfs_inode *ip;
+ xfs_ino_t ino;
+ int error;
+
+ if (!xfs_has_rtrmapbt(mp))
+ return;
+
+ ino = rtgroup_rmap_ino(rtg);
+ if (no_modify) {
+ if (ino == NULLFSINO)
+ do_warn(_("would reset rtgroup %u rmap btree\n"),
+ rtg->rtg_rgno);
+ return;
+ }
+
+ if (ino == NULLFSINO)
+ do_warn(_("resetting rtgroup %u rmap btree\n"),
+ rtg->rtg_rgno);
+
+ error = -libxfs_rtrmapbt_create_path(mp, rtg->rtg_rgno, &path);
+ if (error)
+ do_error(
+ _("Couldn't create rtgroup %u rmap file path, err %d\n"),
+ rtg->rtg_rgno, error);
+
+ error = ensure_imeta_dirpath(mp, path);
+ if (error)
+ do_error(
+ _("Couldn't create rtgroup %u metadata directory, error %d\n"),
+ rtg->rtg_rgno, error);
+
+ if (ino != NULLFSINO) {
+ struct xfs_trans *tp;
+
+ /*
+ * We're still hanging on to our old inode pointer, so grab it
+ * and reconnect it to the metadata directory tree. If it
+ * can't be grabbed, create a new rtrmap file.
+ */
+ error = -libxfs_trans_alloc_empty(mp, &tp);
+ if (error)
+ do_error(
+ _("Couldn't allocate transaction to iget rtgroup %u rmap inode 0x%llx, error %d\n"),
+ rtg->rtg_rgno, (unsigned long long)ino,
+ error);
+ error = -libxfs_imeta_iget(tp, ino, XFS_DIR3_FT_REG_FILE, &ip);
+ libxfs_trans_cancel(tp);
+ if (error) {
+ do_warn(
+ _("Couldn't iget rtgroup %u rmap inode 0x%llx, error %d\n"),
+ rtg->rtg_rgno, (unsigned long long)ino,
+ error);
+ goto zap;
+ }
+
+ /*
+ * Since we're reattaching this file to the metadata directory
+ * tree, try to remove all the parent pointers that might be
+ * attached.
+ */
+ try_erase_parent_ptrs(ip);
+
+ error = -libxfs_imeta_start_link(mp, path, ip, &upd);
+ if (error)
+ do_error(
+ _("Couldn't grab resources to reconnect rtgroup %u rmapbt, error %d\n"),
+ rtg->rtg_rgno, error);
+
+ error = -libxfs_imeta_link(&upd);
+ if (error)
+ do_error(
+ _("Failed to link rtgroup %u rmapbt inode 0x%llx, error %d\n"),
+ rtg->rtg_rgno,
+ (unsigned long long)ip->i_ino,
+ error);
+
+ /* Reset the link count to something sane. */
+ set_nlink(VFS_I(ip), 1);
+ ip->i_df.if_format = XFS_DINODE_FMT_RMAP;
+ libxfs_trans_log_inode(upd.tp, ip, XFS_ILOG_CORE);
+ } else {
+zap:
+ /*
+ * The rtrmap inode was bad or gone, so just make a new one
+ * and give our reference to the rtgroup structure.
+ */
+ error = -libxfs_imeta_start_create(mp, path, &upd);
+ if (error)
+ do_error(
+ _("Couldn't grab resources to recreate rtgroup %u rmapbt, error %d\n"),
+ rtg->rtg_rgno, error);
+
+ error = -libxfs_rtrmapbt_create(&upd, &ip);
+ if (error)
+ do_error(
+ _("Couldn't create rtgroup %u rmap inode, error %d\n"),
+ rtg->rtg_rgno, error);
+ }
+
+ /* Mark the inode in use. */
+ mark_ino_inuse(mp, ip->i_ino, S_IFREG, upd.dp->i_ino);
+ mark_ino_metadata(mp, ip->i_ino);
+
+ error = -libxfs_imeta_commit_update(&upd);
+ if (error)
+ do_error(
+ _("Couldn't commit new rtgroup %u rmap inode %llu, error %d\n"),
+ rtg->rtg_rgno,
+ (unsigned long long)ip->i_ino,
+ error);
+
+ /* Copy our incore rmap data to the ondisk rmap inode. */
+ error = populate_rtgroup_rmapbt(rtg, ip, est_fdblocks);
+ if (error)
+ do_error(
+ _("rtgroup %u rmap btree could not be rebuilt, error %d\n"),
+ rtg->rtg_rgno, error);
+
+ libxfs_imeta_free_path(path);
+ libxfs_imeta_irele(ip);
+}
+
/* Initialize a root directory. */
static int
init_fs_root_dir(
@@ -3838,6 +3970,27 @@ traverse_ags(
do_inode_prefetch(mp, ag_stride, traverse_function, false, true);
}
+static void
+reset_rt_metadata_inodes(
+ struct xfs_mount *mp)
+{
+ struct xfs_rtgroup *rtg;
+ xfs_filblks_t metadata_blocks = 0;
+ xfs_filblks_t est_fdblocks = 0;
+ xfs_rgnumber_t rgno;
+
+ /* Estimate how much free space will be left after building btrees */
+ for_each_rtgroup(mp, rgno, rtg) {
+ metadata_blocks += estimate_rtrmapbt_blocks(rtg);
+ }
+ if (mp->m_sb.sb_fdblocks > metadata_blocks)
+ est_fdblocks = mp->m_sb.sb_fdblocks - metadata_blocks;
+
+ for_each_rtgroup(mp, rgno, rtg) {
+ ensure_rtgroup_rmapbt(rtg, est_fdblocks);
+ }
+}
+
void
phase6(xfs_mount_t *mp)
{
@@ -3903,6 +4056,8 @@ phase6(xfs_mount_t *mp)
}
}
+ reset_rt_metadata_inodes(mp);
+
if (!no_modify) {
do_log(
_(" - resetting contents of realtime bitmap and summary inodes\n"));
diff --git a/repair/rmap.c b/repair/rmap.c
index 5ac7188f12e..1312a0dde34 100644
--- a/repair/rmap.c
+++ b/repair/rmap.c
@@ -2106,3 +2106,29 @@ rtgroup_rmap_ino(
return ar->rg_rmap_ino;
}
+
+/* Estimate the size of the ondisk rtrmapbt from the incore tree. */
+xfs_filblks_t
+estimate_rtrmapbt_blocks(
+ struct xfs_rtgroup *rtg)
+{
+ struct xfs_mount *mp = rtg->rtg_mount;
+ struct xfs_ag_rmap *x;
+ unsigned long long nr_recs;
+
+ if (!rmap_needs_work(mp) || !xfs_has_rtrmapbt(mp))
+ return 0;
+
+ x = &rg_rmaps[rtg->rtg_rgno];
+ if (!x->ar_xfbtree)
+ return 0;
+
+ /*
+ * Overestimate the amount of space needed by pretending that every
+ * byte in the incore tree is used to store rtrmapbt records. This
+ * means we can use SEEK_DATA/HOLE on the xfile, which is faster than
+ * walking the entire btree.
+ */
+ nr_recs = xfbtree_bytes(x->ar_xfbtree) / sizeof(struct xfs_rmap_rec);
+ return libxfs_rtrmapbt_calc_size(mp, nr_recs);
+}
diff --git a/repair/rmap.h b/repair/rmap.h
index dcd834ef242..1f99606a455 100644
--- a/repair/rmap.h
+++ b/repair/rmap.h
@@ -67,5 +67,8 @@ int rmap_get_mem_rec(struct rmap_mem_cur *rmcur, struct xfs_rmap_irec *irec);
bool is_rtrmap_inode(xfs_ino_t ino);
xfs_ino_t rtgroup_rmap_ino(struct xfs_rtgroup *rtg);
+int populate_rtgroup_rmapbt(struct xfs_rtgroup *rtg, struct xfs_inode *ip,
+ xfs_filblks_t fdblocks);
+xfs_filblks_t estimate_rtrmapbt_blocks(struct xfs_rtgroup *rtg);
#endif /* RMAP_H_ */
diff --git a/repair/rtrmap_repair.c b/repair/rtrmap_repair.c
new file mode 100644
index 00000000000..1c9df17d205
--- /dev/null
+++ b/repair/rtrmap_repair.c
@@ -0,0 +1,261 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019-2024 Oracle. All Rights Reserved.
+ * Author: Darrick J. Wong <djwong@kernel.org>
+ */
+#include <libxfs.h>
+#include "btree.h"
+#include "err_protos.h"
+#include "libxlog.h"
+#include "incore.h"
+#include "globals.h"
+#include "dinode.h"
+#include "slab.h"
+#include "rmap.h"
+#include "bulkload.h"
+
+/* Ported routines from fs/xfs/scrub/rtrmap_repair.c */
+
+/*
+ * Realtime Reverse Mapping (RTRMAPBT) Repair
+ * ==========================================
+ *
+ * Gather all the rmap records for the inode and fork we're fixing, reset the
+ * incore fork, then recreate the btree.
+ */
+struct xrep_rtrmap {
+ struct rmap_mem_cur btree_cursor;
+
+ /* New fork. */
+ struct bulkload new_fork_info;
+ struct xfs_btree_bload rtrmap_bload;
+
+ struct repair_ctx *sc;
+ struct xfs_rtgroup *rtg;
+
+ /* Estimated free space after building all rt btrees */
+ xfs_filblks_t est_fdblocks;
+};
+
+/* Retrieve rtrmapbt data for bulk load. */
+STATIC int
+xrep_rtrmap_get_records(
+ struct xfs_btree_cur *cur,
+ unsigned int idx,
+ struct xfs_btree_block *block,
+ unsigned int nr_wanted,
+ void *priv)
+{
+ struct xrep_rtrmap *rr = priv;
+ union xfs_btree_rec *block_rec;
+ unsigned int loaded;
+ int ret;
+
+ for (loaded = 0; loaded < nr_wanted; loaded++, idx++) {
+ ret = rmap_get_mem_rec(&rr->btree_cursor, &cur->bc_rec.r);
+ if (ret < 0)
+ return ret;
+ if (ret == 0)
+ do_error(
+ _("ran out of records while rebuilding rt rmap btree\n"));
+
+ block_rec = libxfs_btree_rec_addr(cur, idx, block);
+ cur->bc_ops->init_rec_from_cur(cur, block_rec);
+ }
+
+ return loaded;
+}
+
+/* Feed one of the new btree blocks to the bulk loader. */
+STATIC int
+xrep_rtrmap_claim_block(
+ struct xfs_btree_cur *cur,
+ union xfs_btree_ptr *ptr,
+ void *priv)
+{
+ struct xrep_rtrmap *rr = priv;
+
+ return bulkload_claim_block(cur, &rr->new_fork_info, ptr);
+}
+
+/* Figure out how much space we need to create the incore btree root block. */
+STATIC size_t
+xrep_rtrmap_iroot_size(
+ struct xfs_btree_cur *cur,
+ unsigned int level,
+ unsigned int nr_this_level,
+ void *priv)
+{
+ return xfs_rtrmap_broot_space_calc(cur->bc_mp, level, nr_this_level);
+}
+
+/* Reserve new btree blocks and bulk load all the rtrmap records. */
+STATIC int
+xrep_rtrmap_btree_load(
+ struct xrep_rtrmap *rr,
+ struct xfs_btree_cur *rtrmap_cur)
+{
+ struct repair_ctx *sc = rr->sc;
+ int error;
+
+ rr->rtrmap_bload.get_records = xrep_rtrmap_get_records;
+ rr->rtrmap_bload.claim_block = xrep_rtrmap_claim_block;
+ rr->rtrmap_bload.iroot_size = xrep_rtrmap_iroot_size;
+ bulkload_estimate_inode_slack(sc->mp, &rr->rtrmap_bload,
+ rr->est_fdblocks);
+
+ /* Compute how many blocks we'll need. */
+ error = -libxfs_btree_bload_compute_geometry(rtrmap_cur,
+ &rr->rtrmap_bload,
+ rmap_record_count(sc->mp, true, rr->rtg->rtg_rgno));
+ if (error)
+ return error;
+
+ /*
+ * Guess how many blocks we're going to need to rebuild an entire rtrmap
+ * from the number of extents we found, and pump up our transaction to
+ * have sufficient block reservation.
+ */
+ error = -libxfs_trans_reserve_more(sc->tp, rr->rtrmap_bload.nr_blocks,
+ 0);
+ if (error)
+ return error;
+
+ /*
+ * Reserve the space we'll need for the new btree. Drop the cursor
+ * while we do this because that can roll the transaction and cursors
+ * can't handle that.
+ */
+ error = bulkload_alloc_file_blocks(&rr->new_fork_info,
+ rr->rtrmap_bload.nr_blocks);
+ if (error)
+ return error;
+
+ /* Add all observed rtrmap records. */
+ error = rmap_init_mem_cursor(rr->sc->mp, sc->tp, true,
+ rr->rtg->rtg_rgno, &rr->btree_cursor);
+ if (error)
+ return error;
+ error = -libxfs_btree_bload(rtrmap_cur, &rr->rtrmap_bload, rr);
+ rmap_free_mem_cursor(sc->tp, &rr->btree_cursor, error);
+ return error;
+}
+
+/* Update the inode counters. */
+STATIC int
+xrep_rtrmap_reset_counters(
+ struct xrep_rtrmap *rr)
+{
+ struct repair_ctx *sc = rr->sc;
+
+ /*
+ * Update the inode block counts to reflect the btree we just
+ * generated.
+ */
+ sc->ip->i_nblocks = rr->new_fork_info.ifake.if_blocks;
+ libxfs_trans_log_inode(sc->tp, sc->ip, XFS_ILOG_CORE);
+
+ /* Quotas don't exist so we're done. */
+ return 0;
+}
+
+/*
+ * Use the collected rmap information to stage a new rt rmap btree. If this is
+ * successful we'll return with the new btree root information logged to the
+ * repair transaction but not yet committed.
+ */
+static int
+xrep_rtrmap_build_new_tree(
+ struct xrep_rtrmap *rr)
+{
+ struct xfs_owner_info oinfo;
+ struct xfs_btree_cur *cur;
+ struct repair_ctx *sc = rr->sc;
+ struct xbtree_ifakeroot *ifake = &rr->new_fork_info.ifake;
+ int error;
+
+ /*
+ * Prepare to construct the new fork by initializing the new btree
+ * structure and creating a fake ifork in the ifakeroot structure.
+ */
+ libxfs_rmap_ino_bmbt_owner(&oinfo, sc->ip->i_ino, XFS_DATA_FORK);
+ bulkload_init_inode(&rr->new_fork_info, sc, XFS_DATA_FORK, &oinfo);
+ cur = libxfs_rtrmapbt_stage_cursor(sc->mp, rr->rtg, sc->ip, ifake);
+
+ /*
+ * Figure out the size and format of the new fork, then fill it with
+ * all the rtrmap records we've found. Join the inode to the
+ * transaction so that we can roll the transaction while holding the
+ * inode locked.
+ */
+ libxfs_trans_ijoin(sc->tp, sc->ip, 0);
+ ifake->if_fork->if_format = XFS_DINODE_FMT_RMAP;
+ error = xrep_rtrmap_btree_load(rr, cur);
+ if (error)
+ goto err_cur;
+
+ /*
+ * Install the new fork in the inode. After this point the old mapping
+ * data are no longer accessible and the new tree is live. We delete
+ * the cursor immediately after committing the staged root because the
+ * staged fork might be in extents format.
+ */
+ libxfs_rtrmapbt_commit_staged_btree(cur, sc->tp);
+ libxfs_btree_del_cursor(cur, 0);
+
+ /* Reset the inode counters now that we've changed the fork. */
+ error = xrep_rtrmap_reset_counters(rr);
+ if (error)
+ goto err_newbt;
+
+ /* Dispose of any unused blocks and the accounting infomation. */
+ error = bulkload_commit(&rr->new_fork_info);
+ if (error)
+ return error;
+
+ return -libxfs_trans_roll_inode(&sc->tp, sc->ip);
+err_cur:
+ if (cur)
+ libxfs_btree_del_cursor(cur, error);
+err_newbt:
+ bulkload_cancel(&rr->new_fork_info);
+ return error;
+}
+
+/* Store the realtime reverse-mappings in the rtrmapbt. */
+int
+populate_rtgroup_rmapbt(
+ struct xfs_rtgroup *rtg,
+ struct xfs_inode *ip,
+ xfs_filblks_t est_fdblocks)
+{
+ struct repair_ctx sc = {
+ .mp = rtg->rtg_mount,
+ .ip = ip,
+ };
+ struct xrep_rtrmap rr = {
+ .sc = &sc,
+ .rtg = rtg,
+ .est_fdblocks = est_fdblocks,
+ };
+ struct xfs_mount *mp = rtg->rtg_mount;
+ int error;
+
+ if (!xfs_has_rtrmapbt(mp))
+ return 0;
+
+ error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0,
+ &sc.tp);
+ if (error)
+ return error;
+
+ error = xrep_rtrmap_build_new_tree(&rr);
+ if (error)
+ goto out_cancel;
+
+ return -libxfs_trans_commit(sc.tp);
+
+out_cancel:
+ libxfs_trans_cancel(sc.tp);
+ return error;
+}
diff --git a/repair/xfs_repair.c b/repair/xfs_repair.c
index e3701f91470..88d23dbc8ec 100644
--- a/repair/xfs_repair.c
+++ b/repair/xfs_repair.c
@@ -1425,13 +1425,17 @@ main(int argc, char **argv)
rcbagbt_destroy_cur_cache();
/*
- * Done with the block usage maps, toss them...
+ * Done with the block usage maps, toss them. Realtime metadata aren't
+ * rebuilt until phase 6, so we have to keep them around.
*/
- rmaps_free(mp);
+ if (mp->m_sb.sb_rblocks == 0)
+ rmaps_free(mp);
free_bmaps(mp);
if (!bad_ino_btree) {
phase6(mp);
+ if (mp->m_sb.sb_rblocks != 0)
+ rmaps_free(mp);
phase_end(mp, 6);
phase7(mp, phase2_threads);
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 42/47] xfs_repair: check for global free space concerns with default btree slack levels
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (40 preceding siblings ...)
2023-12-27 13:21 ` [PATCH 41/47] xfs_repair: rebuild the realtime rmap btree Darrick J. Wong
@ 2023-12-27 13:21 ` Darrick J. Wong
2023-12-27 13:21 ` [PATCH 43/47] xfs_repair: rebuild the bmap btree for realtime files Darrick J. Wong
` (4 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:21 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
It's possible that before repair was started, the filesystem might have
been nearly full, and its metadata btree blocks could all have been
nearly full. If we then rebuild the btrees with blocks that are only
75% full, that expansion might be enough to run out of free space. The
solution to this is to pack the new blocks completely full if we fear
running out of space.
Previously, we only had to check and decide that on a per-AG basis.
However, now that XFS can have filesystems with metadata btrees rooted
in inodes, we have a global free space concern because there might be
enough space in each AG to regenerate the AG btrees at 75%, but that
might not leave enough space to regenerate the inode btrees, even if we
fill those blocks to 100%.
Hence we need to precompute the worst case space usage for all btrees in
the filesystem and compare /that/ against the global free space to
decide if we're going to pack the btrees maximally to conserve space.
That decision can override the per-AG determination.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
repair/globals.c | 6 +++
repair/globals.h | 2 +
repair/phase5.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
repair/phase6.c | 16 +++++--
4 files changed, 131 insertions(+), 9 deletions(-)
diff --git a/repair/globals.c b/repair/globals.c
index b121d6e2d6d..92ebe5fab8a 100644
--- a/repair/globals.c
+++ b/repair/globals.c
@@ -133,3 +133,9 @@ int thread_count;
/* If nonzero, simulate failure after this phase. */
int fail_after_phase;
+
+/*
+ * Do we think we're going to be so low on disk space that we need to pack
+ * all rebuilt btree blocks completely full to avoid running out of space?
+ */
+bool need_packed_btrees;
diff --git a/repair/globals.h b/repair/globals.h
index f5dcc11f410..2e11f35a0e4 100644
--- a/repair/globals.h
+++ b/repair/globals.h
@@ -180,4 +180,6 @@ extern int fail_after_phase;
extern struct libxfs_init x;
+extern bool need_packed_btrees;
+
#endif /* _XFS_REPAIR_GLOBAL_H */
diff --git a/repair/phase5.c b/repair/phase5.c
index 74594d53a87..5e1dff0aadd 100644
--- a/repair/phase5.c
+++ b/repair/phase5.c
@@ -479,11 +479,14 @@ _("unable to rebuild AG %u. Not enough free space in on-disk AG.\n"),
/*
* Estimate the number of free blocks in this AG after rebuilding
- * all btrees.
+ * all btrees, unless we already decided that we need to pack all
+ * btree blocks maximally.
*/
- total_btblocks = estimate_agbtree_blocks(pag, num_extents);
- if (num_freeblocks > total_btblocks)
- est_agfreeblocks = num_freeblocks - total_btblocks;
+ if (!need_packed_btrees) {
+ total_btblocks = estimate_agbtree_blocks(pag, num_extents);
+ if (num_freeblocks > total_btblocks)
+ est_agfreeblocks = num_freeblocks - total_btblocks;
+ }
init_ino_cursors(&sc, pag, est_agfreeblocks, &sb_icount_ag[agno],
&sb_ifree_ag[agno], &btr_ino, &btr_fino);
@@ -631,6 +634,109 @@ check_rtmetadata(
check_rtsummary(mp);
}
+/*
+ * Estimate the amount of free space used by the perag metadata without
+ * building the incore tree. This is only necessary if realtime btrees are
+ * enabled.
+ */
+static xfs_extlen_t
+estimate_agbtree_blocks_early(
+ struct xfs_perag *pag,
+ unsigned int *num_freeblocks)
+{
+ struct xfs_mount *mp = pag->pag_mount;
+ xfs_agblock_t agbno;
+ xfs_agblock_t ag_end;
+ xfs_extlen_t extent_len;
+ xfs_extlen_t blen;
+ unsigned int num_extents = 0;
+ int bstate;
+ bool in_extent = false;
+
+ /* Find the number of free space extents. */
+ ag_end = libxfs_ag_block_count(mp, pag->pag_agno);
+ for (agbno = 0; agbno < ag_end; agbno += blen) {
+ bstate = get_bmap_ext(pag->pag_agno, agbno, ag_end, &blen);
+ if (bstate < XR_E_INUSE) {
+ if (!in_extent) {
+ /*
+ * found the start of a free extent
+ */
+ in_extent = true;
+ num_extents++;
+ extent_len = blen;
+ } else {
+ extent_len += blen;
+ }
+ } else {
+ if (in_extent) {
+ /*
+ * free extent ends here
+ */
+ in_extent = false;
+ *num_freeblocks += extent_len;
+ }
+ }
+ }
+ if (in_extent)
+ *num_freeblocks += extent_len;
+
+ return estimate_agbtree_blocks(pag, num_extents);
+}
+
+/*
+ * Decide if we need to pack every new btree block completely full to conserve
+ * disk space. Normally we rebuild btree blocks to be 75% full, but we don't
+ * want to start rebuilding AG btrees that way only to discover that there
+ * isn't enough space left in the data volume to rebuild inode-based btrees.
+ */
+static bool
+are_packed_btrees_needed(
+ struct xfs_mount *mp)
+{
+ struct xfs_perag *pag;
+ struct xfs_rtgroup *rtg;
+ xfs_agnumber_t agno;
+ xfs_rgnumber_t rgno;
+ unsigned long long metadata_blocks = 0;
+ unsigned long long fdblocks = 0;
+
+ /*
+ * If we don't have inode-based metadata, we can let the AG btrees
+ * pack as needed; there are no global space concerns here.
+ */
+ if (!xfs_has_rtrmapbt(mp))
+ return false;
+
+ for_each_perag(mp, agno, pag) {
+ unsigned int ag_fdblocks = 0;
+
+ metadata_blocks += estimate_agbtree_blocks_early(pag,
+ &ag_fdblocks);
+ fdblocks += ag_fdblocks;
+ }
+
+ for_each_rtgroup(mp, rgno, rtg) {
+ metadata_blocks += estimate_rtrmapbt_blocks(rtg);
+ }
+
+ /*
+ * If we think we'll have more metadata blocks than free space, then
+ * pack the btree blocks.
+ */
+ if (metadata_blocks > fdblocks)
+ return true;
+
+ /*
+ * If the amount of free space after building btrees is less than 9%
+ * of the data volume, pack the btree blocks.
+ */
+ fdblocks -= metadata_blocks;
+ if (fdblocks < ((mp->m_sb.sb_dblocks * 3) >> 5))
+ return true;
+ return false;
+}
+
void
phase5(xfs_mount_t *mp)
{
@@ -682,6 +788,8 @@ phase5(xfs_mount_t *mp)
if (error)
do_error(_("cannot alloc lost block bitmap\n"));
+ need_packed_btrees = are_packed_btrees_needed(mp);
+
for_each_perag(mp, agno, pag)
phase5_func(mp, pag, lost_blocks);
diff --git a/repair/phase6.c b/repair/phase6.c
index 4c387557c31..ab5c22ffbb0 100644
--- a/repair/phase6.c
+++ b/repair/phase6.c
@@ -3979,12 +3979,18 @@ reset_rt_metadata_inodes(
xfs_filblks_t est_fdblocks = 0;
xfs_rgnumber_t rgno;
- /* Estimate how much free space will be left after building btrees */
- for_each_rtgroup(mp, rgno, rtg) {
- metadata_blocks += estimate_rtrmapbt_blocks(rtg);
+ /*
+ * Estimate how much free space will be left after building btrees
+ * unless we already decided that we needed to pack all new blocks
+ * maximally.
+ */
+ if (!need_packed_btrees) {
+ for_each_rtgroup(mp, rgno, rtg) {
+ metadata_blocks += estimate_rtrmapbt_blocks(rtg);
+ }
+ if (mp->m_sb.sb_fdblocks > metadata_blocks)
+ est_fdblocks = mp->m_sb.sb_fdblocks - metadata_blocks;
}
- if (mp->m_sb.sb_fdblocks > metadata_blocks)
- est_fdblocks = mp->m_sb.sb_fdblocks - metadata_blocks;
for_each_rtgroup(mp, rgno, rtg) {
ensure_rtgroup_rmapbt(rtg, est_fdblocks);
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 43/47] xfs_repair: rebuild the bmap btree for realtime files
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (41 preceding siblings ...)
2023-12-27 13:21 ` [PATCH 42/47] xfs_repair: check for global free space concerns with default btree slack levels Darrick J. Wong
@ 2023-12-27 13:21 ` Darrick J. Wong
2023-12-27 13:21 ` [PATCH 44/47] xfs_repair: reserve per-AG space while rebuilding rt metadata Darrick J. Wong
` (3 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:21 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Use the realtime rmap btree information to rebuild an inode's data fork
when appropriate.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
repair/bmap_repair.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 127 insertions(+), 4 deletions(-)
diff --git a/repair/bmap_repair.c b/repair/bmap_repair.c
index dfd1405cca2..5d4da861322 100644
--- a/repair/bmap_repair.c
+++ b/repair/bmap_repair.c
@@ -212,6 +212,122 @@ xrep_bmap_scan_ag(
return error;
}
+/* Check for any obvious errors or conflicts in the file mapping. */
+STATIC int
+xrep_bmap_check_rtfork_rmap(
+ struct repair_ctx *sc,
+ struct xfs_btree_cur *cur,
+ const struct xfs_rmap_irec *rec)
+{
+ /* xattr extents are never stored on realtime devices */
+ if (rec->rm_flags & XFS_RMAP_ATTR_FORK)
+ return EFSCORRUPTED;
+
+ /* bmbt blocks are never stored on realtime devices */
+ if (rec->rm_flags & XFS_RMAP_BMBT_BLOCK)
+ return EFSCORRUPTED;
+
+ /* Data extents for non-rt files are never stored on the rt device. */
+ if (!XFS_IS_REALTIME_INODE(sc->ip))
+ return EFSCORRUPTED;
+
+ /* Check the file offsets and physical extents. */
+ if (!xfs_verify_fileext(sc->mp, rec->rm_offset, rec->rm_blockcount))
+ return EFSCORRUPTED;
+
+ /* Check that this fits in the rt volume. */
+ if (!xfs_verify_rgbext(cur->bc_ino.rtg, rec->rm_startblock,
+ rec->rm_blockcount))
+ return EFSCORRUPTED;
+
+ return 0;
+}
+
+/* Record realtime extents that belong to this inode's fork. */
+STATIC int
+xrep_bmap_walk_rtrmap(
+ struct xfs_btree_cur *cur,
+ const struct xfs_rmap_irec *rec,
+ void *priv)
+{
+ struct xrep_bmap *rb = priv;
+ int error = 0;
+
+ /* Skip extents which are not owned by this inode and fork. */
+ if (rec->rm_owner != rb->sc->ip->i_ino)
+ return 0;
+
+ error = xrep_bmap_check_rtfork_rmap(rb->sc, cur, rec);
+ if (error)
+ return error;
+
+ /*
+ * Record all blocks allocated to this file even if the extent isn't
+ * for the fork we're rebuilding so that we can reset di_nblocks later.
+ */
+ rb->nblocks += rec->rm_blockcount;
+
+ /* If this rmap isn't for the fork we want, we're done. */
+ if (rb->whichfork == XFS_DATA_FORK &&
+ (rec->rm_flags & XFS_RMAP_ATTR_FORK))
+ return 0;
+ if (rb->whichfork == XFS_ATTR_FORK &&
+ !(rec->rm_flags & XFS_RMAP_ATTR_FORK))
+ return 0;
+
+ return xrep_bmap_from_rmap(rb, rec->rm_offset, rec->rm_startblock,
+ rec->rm_blockcount,
+ rec->rm_flags & XFS_RMAP_UNWRITTEN);
+}
+
+/*
+ * Scan the realtime reverse mappings to build the new extent map. The rt rmap
+ * inodes must be loaded from disk explicitly here, since we have not yet
+ * validated the metadata directory tree but do not wish to throw away user
+ * data unnecessarily.
+ */
+STATIC int
+xrep_bmap_scan_rt(
+ struct xrep_bmap *rb,
+ struct xfs_rtgroup *rtg)
+{
+ struct repair_ctx *sc = rb->sc;
+ struct xfs_mount *mp = sc->mp;
+ struct xfs_btree_cur *cur;
+ struct xfs_inode *ip;
+ struct xfs_imeta_path *path;
+ xfs_ino_t ino;
+ int error;
+
+ error = -libxfs_rtrmapbt_create_path(mp, rtg->rtg_rgno, &path);
+ if (error)
+ return error;
+
+ error = -libxfs_imeta_lookup(sc->tp, path, &ino);
+ if (error)
+ goto out_path;
+
+ if (ino == NULLFSINO) {
+ error = EFSCORRUPTED;
+ goto out_path;
+ }
+
+ error = -libxfs_imeta_iget(sc->tp, ino, XFS_DIR3_FT_REG_FILE, &ip);
+ if (error)
+ goto out_path;
+
+ cur = libxfs_rtrmapbt_init_cursor(mp, sc->tp, rtg, ip);
+ error = -libxfs_rmap_query_all(cur, xrep_bmap_walk_rtrmap, rb);
+ if (error)
+ goto out_cur;
+out_cur:
+ libxfs_btree_del_cursor(cur, error);
+ libxfs_imeta_irele(ip);
+out_path:
+ libxfs_imeta_free_path(path);
+ return error;
+}
+
/*
* Collect block mappings for this fork of this inode and decide if we have
* enough space to rebuild. Caller is responsible for cleaning up the list if
@@ -222,9 +338,20 @@ xrep_bmap_find_mappings(
struct xrep_bmap *rb)
{
struct xfs_perag *pag;
+ struct xfs_rtgroup *rtg;
xfs_agnumber_t agno;
+ xfs_rgnumber_t rgno;
int error;
+ /* Iterate the rtrmaps for extents. */
+ for_each_rtgroup(rb->sc->mp, rgno, rtg) {
+ error = xrep_bmap_scan_rt(rb, rtg);
+ if (error) {
+ libxfs_rtgroup_put(rtg);
+ return error;
+ }
+ }
+
/* Iterate the rmaps for extents. */
for_each_perag(rb->sc->mp, agno, pag) {
error = xrep_bmap_scan_ag(rb, pag);
@@ -572,10 +699,6 @@ xrep_bmap_check_inputs(
return EINVAL;
}
- /* Don't know how to rebuild realtime data forks. */
- if (XFS_IS_REALTIME_INODE(sc->ip))
- return EOPNOTSUPP;
-
return 0;
}
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 44/47] xfs_repair: reserve per-AG space while rebuilding rt metadata
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (42 preceding siblings ...)
2023-12-27 13:21 ` [PATCH 43/47] xfs_repair: rebuild the bmap btree for realtime files Darrick J. Wong
@ 2023-12-27 13:21 ` Darrick J. Wong
2023-12-27 13:22 ` [PATCH 45/47] xfs_repair: allow sysadmins to add realtime reverse mapping indexes Darrick J. Wong
` (2 subsequent siblings)
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:21 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Realtime metadata btrees can consume quite a bit of space on a full
filesystem. Since the metadata are just regular files, we need to
make the per-AG reservations to avoid overfilling any of the AGs while
rebuilding metadata. This avoids the situation where a filesystem comes
straight from repair and immediately trips over not having enough space
in an AG.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
include/libxfs.h | 1 +
repair/phase6.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 48 insertions(+)
diff --git a/include/libxfs.h b/include/libxfs.h
index 3ab93158cf7..72f38938f69 100644
--- a/include/libxfs.h
+++ b/include/libxfs.h
@@ -94,6 +94,7 @@ struct iomap;
#include "xfs_rtbitmap.h"
#include "xfs_rtgroup.h"
#include "xfs_rtrmap_btree.h"
+#include "xfs_ag_resv.h"
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
diff --git a/repair/phase6.c b/repair/phase6.c
index ab5c22ffbb0..fd862362f1d 100644
--- a/repair/phase6.c
+++ b/repair/phase6.c
@@ -3997,10 +3997,43 @@ reset_rt_metadata_inodes(
}
}
+static int
+reserve_ag_blocks(
+ struct xfs_mount *mp)
+{
+ struct xfs_perag *pag;
+ xfs_agnumber_t agno;
+ int error = 0;
+ int err2;
+
+ mp->m_finobt_nores = false;
+
+ for_each_perag(mp, agno, pag) {
+ err2 = -libxfs_ag_resv_init(pag, NULL);
+ if (err2 && !error)
+ error = err2;
+ }
+
+ return error;
+}
+
+static void
+unreserve_ag_blocks(
+ struct xfs_mount *mp)
+{
+ struct xfs_perag *pag;
+ xfs_agnumber_t agno;
+
+ for_each_perag(mp, agno, pag)
+ libxfs_ag_resv_free(pag);
+}
+
void
phase6(xfs_mount_t *mp)
{
ino_tree_node_t *irec;
+ bool reserve_perag;
+ int error;
int i;
parent_ptr_init(mp);
@@ -4040,6 +4073,17 @@ phase6(xfs_mount_t *mp)
do_warn(_("would reinitialize metadata root directory\n"));
}
+ reserve_perag = xfs_has_realtime(mp) && !no_modify;
+ if (reserve_perag) {
+ error = reserve_ag_blocks(mp);
+ if (error) {
+ if (error != ENOSPC)
+ do_warn(
+ _("could not reserve per-AG space to rebuild realtime metadata"));
+ reserve_perag = false;
+ }
+ }
+
if (need_rbmino) {
if (!no_modify) {
if (need_rbmino > 0)
@@ -4078,6 +4122,9 @@ _(" - resetting contents of realtime bitmap and summary inodes\n"));
}
}
+ if (reserve_perag)
+ unreserve_ag_blocks(mp);
+
reattach_metadir_quota_inodes(mp);
mark_standalone_inodes(mp);
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 45/47] xfs_repair: allow sysadmins to add realtime reverse mapping indexes
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (43 preceding siblings ...)
2023-12-27 13:21 ` [PATCH 44/47] xfs_repair: reserve per-AG space while rebuilding rt metadata Darrick J. Wong
@ 2023-12-27 13:22 ` Darrick J. Wong
2023-12-27 13:22 ` [PATCH 46/47] xfs_logprint: report realtime RUIs Darrick J. Wong
2023-12-27 13:22 ` [PATCH 47/47] mkfs: create the realtime rmap inode Darrick J. Wong
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:22 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Allow the sysadmin to use xfs_repair to upgrade an existing filesystem
to support the reverse mapping btree index for realtime volumes. This
is needed for online fsck.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/libxfs_api_defs.h | 4 ++
repair/phase2.c | 100 ++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 99 insertions(+), 5 deletions(-)
diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
index b5bb6c39928..cfa8c474160 100644
--- a/libxfs/libxfs_api_defs.h
+++ b/libxfs/libxfs_api_defs.h
@@ -63,6 +63,7 @@
#define xfs_btree_bload libxfs_btree_bload
#define xfs_btree_bload_compute_geometry libxfs_btree_bload_compute_geometry
#define xfs_btree_calc_size libxfs_btree_calc_size
+#define xfs_btree_compute_maxlevels libxfs_btree_compute_maxlevels
#define xfs_btree_decrement libxfs_btree_decrement
#define xfs_btree_del_cursor libxfs_btree_del_cursor
#define xfs_btree_delete libxfs_btree_delete
@@ -190,6 +191,8 @@
#define xfs_imeta_link_space_res libxfs_imeta_link_space_res
#define xfs_imeta_lookup libxfs_imeta_lookup
#define xfs_imeta_mount libxfs_imeta_mount
+#define xfs_imeta_resv_free_inode libxfs_imeta_resv_free_inode
+#define xfs_imeta_resv_init_inode libxfs_imeta_resv_init_inode
#define xfs_imeta_set_iflag libxfs_imeta_set_iflag
#define xfs_imeta_start_create libxfs_imeta_start_create
#define xfs_imeta_start_link libxfs_imeta_start_link
@@ -289,6 +292,7 @@
#define xfs_rtgroup_put libxfs_rtgroup_put
#define xfs_rtgroup_update_secondary_sbs libxfs_rtgroup_update_secondary_sbs
#define xfs_rtgroup_update_super libxfs_rtgroup_update_super
+#define xfs_rtrmapbt_calc_reserves libxfs_rtrmapbt_calc_reserves
#define xfs_rtrmapbt_calc_size libxfs_rtrmapbt_calc_size
#define xfs_rtrmapbt_commit_staged_btree libxfs_rtrmapbt_commit_staged_btree
#define xfs_rtrmapbt_create libxfs_rtrmapbt_create
diff --git a/repair/phase2.c b/repair/phase2.c
index 4cb0d7946bf..22458aee4cd 100644
--- a/repair/phase2.c
+++ b/repair/phase2.c
@@ -250,9 +250,8 @@ set_rmapbt(
exit(0);
}
- if (xfs_has_realtime(mp)) {
- printf(
- _("Reverse mapping btree feature not supported with realtime.\n"));
+ if (xfs_has_realtime(mp) && !xfs_has_rtgroups(mp)) {
+ printf(_("Reverse mapping btree requires realtime groups.\n"));
exit(0);
}
@@ -265,6 +264,11 @@ set_rmapbt(
printf(_("Adding reverse mapping btrees to filesystem.\n"));
new_sb->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_RMAPBT;
new_sb->sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR;
+
+ /* Quota counts will be wrong once we add the rmap inodes. */
+ if (xfs_has_realtime(mp))
+ quotacheck_skip();
+
return true;
}
@@ -450,6 +454,63 @@ check_free_space(
return avail > GIGABYTES(10, mp->m_sb.sb_blocklog);
}
+/*
+ * Reserve space to handle rt rmap btree expansion.
+ *
+ * If the rmap inode for this group already exists, we assume that we're adding
+ * some other feature. Note that we have not validated the metadata directory
+ * tree, so we must perform the lookup by hand and abort the upgrade if there
+ * are errors. Otherwise, the amount of space needed to handle a new maximally
+ * sized rmap btree is added to @new_resv.
+ */
+static int
+reserve_rtrmap_inode(
+ struct xfs_rtgroup *rtg,
+ xfs_rfsblock_t *new_resv)
+{
+ struct xfs_mount *mp = rtg->rtg_mount;
+ struct xfs_trans *tp;
+ struct xfs_imeta_path *path;
+ xfs_ino_t ino;
+ xfs_filblks_t ask;
+ int error;
+
+ if (!xfs_has_rtrmapbt(mp))
+ return 0;
+
+ error = -libxfs_rtrmapbt_create_path(mp, rtg->rtg_rgno, &path);
+ if (error)
+ return error;
+
+ error = -libxfs_trans_alloc_empty(mp, &tp);
+ if (error)
+ goto out_path;
+
+ ask = libxfs_rtrmapbt_calc_reserves(mp);
+
+ error = -libxfs_imeta_lookup(tp, path, &ino);
+ if (error)
+ goto out_trans;
+
+ if (ino == NULLFSINO) {
+ *new_resv += ask;
+ goto out_trans;
+ }
+
+ error = -libxfs_imeta_iget(tp, ino, XFS_DIR3_FT_REG_FILE,
+ &rtg->rtg_rmapip);
+ if (error)
+ goto out_trans;
+
+ error = -libxfs_imeta_resv_init_inode(rtg->rtg_rmapip, ask);
+
+out_trans:
+ libxfs_trans_cancel(tp);
+out_path:
+ libxfs_imeta_free_path(path);
+ return error;
+}
+
static void
check_fs_free_space(
struct xfs_mount *mp,
@@ -457,7 +518,10 @@ check_fs_free_space(
struct xfs_sb *new_sb)
{
struct xfs_perag *pag;
+ struct xfs_rtgroup *rtg;
+ xfs_rfsblock_t new_resv = 0;
xfs_agnumber_t agno;
+ xfs_rgnumber_t rgno;
int error;
/* Make sure we have enough space for per-AG reservations. */
@@ -533,6 +597,21 @@ check_fs_free_space(
libxfs_trans_cancel(tp);
}
+ /* Realtime metadata btree inodes */
+ for_each_rtgroup(mp, rgno, rtg) {
+ error = reserve_rtrmap_inode(rtg, &new_resv);
+ if (error == ENOSPC) {
+ printf(
+_("Not enough free space would remain for rtgroup %u rmap inode.\n"),
+ rtg->rtg_rgno);
+ exit(0);
+ }
+ if (error)
+ do_error(
+_("Error %d while checking rtgroup %u rmap inode space reservation.\n"),
+ error, rtg->rtg_rgno);
+ }
+
/*
* If we're adding parent pointers, we need at least 25% free since
* scanning the entire filesystem to guesstimate the overhead is
@@ -548,13 +627,24 @@ check_fs_free_space(
/*
* Would the post-upgrade filesystem have enough free space on the data
- * device after making per-AG reservations?
+ * device after making per-AG reservations and reserving rt metadata
+ * inode blocks?
*/
- if (!check_free_space(mp, mp->m_sb.sb_fdblocks, mp->m_sb.sb_dblocks)) {
+ if (new_resv > mp->m_sb.sb_fdblocks ||
+ !check_free_space(mp, mp->m_sb.sb_fdblocks, mp->m_sb.sb_dblocks)) {
printf(_("Filesystem will be low on space after upgrade.\n"));
exit(1);
}
+ /* Unreserve the realtime metadata reservations. */
+ for_each_rtgroup(mp, rgno, rtg) {
+ if (rtg->rtg_rmapip) {
+ libxfs_imeta_resv_free_inode(rtg->rtg_rmapip);
+ libxfs_imeta_irele(rtg->rtg_rmapip);
+ rtg->rtg_rmapip = NULL;
+ }
+ }
+
/*
* Release the per-AG reservations and mark the per-AG structure as
* uninitialized so that we don't trip over stale cached counters
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 46/47] xfs_logprint: report realtime RUIs
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (44 preceding siblings ...)
2023-12-27 13:22 ` [PATCH 45/47] xfs_repair: allow sysadmins to add realtime reverse mapping indexes Darrick J. Wong
@ 2023-12-27 13:22 ` Darrick J. Wong
2023-12-27 13:22 ` [PATCH 47/47] mkfs: create the realtime rmap inode Darrick J. Wong
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:22 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Decode the RUI format just enough to report if an RUI targets the
realtime device or not.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
logprint/log_misc.c | 2 ++
logprint/log_print_all.c | 8 ++++++++
logprint/log_redo.c | 24 +++++++++++++++++++-----
3 files changed, 29 insertions(+), 5 deletions(-)
diff --git a/logprint/log_misc.c b/logprint/log_misc.c
index 9d63f376390..3661b595c53 100644
--- a/logprint/log_misc.c
+++ b/logprint/log_misc.c
@@ -1021,12 +1021,14 @@ xlog_print_record(
be32_to_cpu(op_head->oh_len));
break;
}
+ case XFS_LI_RUI_RT:
case XFS_LI_RUI: {
skip = xlog_print_trans_rui(&ptr,
be32_to_cpu(op_head->oh_len),
continued);
break;
}
+ case XFS_LI_RUD_RT:
case XFS_LI_RUD: {
skip = xlog_print_trans_rud(&ptr,
be32_to_cpu(op_head->oh_len));
diff --git a/logprint/log_print_all.c b/logprint/log_print_all.c
index d030efa9efb..e67e2c57f26 100644
--- a/logprint/log_print_all.c
+++ b/logprint/log_print_all.c
@@ -424,9 +424,11 @@ xlog_recover_print_logitem(
case XFS_LI_ATTRI:
xlog_recover_print_attri(item);
break;
+ case XFS_LI_RUD_RT:
case XFS_LI_RUD:
xlog_recover_print_rud(item);
break;
+ case XFS_LI_RUI_RT:
case XFS_LI_RUI:
xlog_recover_print_rui(item);
break;
@@ -500,6 +502,12 @@ xlog_recover_print_item(
case XFS_LI_RUI:
printf("RUI");
break;
+ case XFS_LI_RUD_RT:
+ printf("RUD_RT");
+ break;
+ case XFS_LI_RUI_RT:
+ printf("RUI_RT");
+ break;
case XFS_LI_CUD:
printf("CUD");
break;
diff --git a/logprint/log_redo.c b/logprint/log_redo.c
index 0cc3cd4ba28..ae6f311f19b 100644
--- a/logprint/log_redo.c
+++ b/logprint/log_redo.c
@@ -274,6 +274,7 @@ xlog_print_trans_rui(
uint src_len,
int continued)
{
+ const char *item_name = "RUI?";
struct xfs_rui_log_format *src_f, *f = NULL;
uint dst_len;
uint nextents;
@@ -318,8 +319,14 @@ xlog_print_trans_rui(
goto error;
}
- printf(_("RUI: #regs: %d num_extents: %d id: 0x%llx\n"),
- f->rui_size, f->rui_nextents, (unsigned long long)f->rui_id);
+ switch (f->rui_type) {
+ case XFS_LI_RUI: item_name = "RUI"; break;
+ case XFS_LI_RUI_RT: item_name = "RUI_RT"; break;
+ }
+
+ printf(_("%s: #regs: %d num_extents: %d id: 0x%llx\n"),
+ item_name, f->rui_size, f->rui_nextents,
+ (unsigned long long)f->rui_id);
if (continued) {
printf(_("RUI extent data skipped (CONTINUE set, no space)\n"));
@@ -359,6 +366,7 @@ xlog_print_trans_rud(
char **ptr,
uint len)
{
+ const char *item_name = "RUD?";
struct xfs_rud_log_format *f;
struct xfs_rud_log_format lbuf;
@@ -371,11 +379,17 @@ xlog_print_trans_rud(
*/
memmove(&lbuf, *ptr, min(core_size, len));
f = &lbuf;
+
+ switch (f->rud_type) {
+ case XFS_LI_RUD: item_name = "RUD"; break;
+ case XFS_LI_RUD_RT: item_name = "RUD_RT"; break;
+ }
+
*ptr += len;
if (len >= core_size) {
- printf(_("RUD: #regs: %d id: 0x%llx\n"),
- f->rud_size,
- (unsigned long long)f->rud_rui_id);
+ printf(_("%s: #regs: %d id: 0x%llx\n"),
+ item_name, f->rud_size,
+ (unsigned long long)f->rud_rui_id);
/* don't print extents as they are not used */
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 47/47] mkfs: create the realtime rmap inode
2023-12-31 19:54 ` [PATCHSET v2.0 12/17] xfsprogs: realtime reverse-mapping support Darrick J. Wong
` (45 preceding siblings ...)
2023-12-27 13:22 ` [PATCH 46/47] xfs_logprint: report realtime RUIs Darrick J. Wong
@ 2023-12-27 13:22 ` Darrick J. Wong
46 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:22 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Create a realtime rmapbt inode if we format the fs with realtime
and rmap.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/init.c | 7 ----
mkfs/proto.c | 56 ++++++++++++++++++++++++++++++++++
mkfs/xfs_mkfs.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 141 insertions(+), 12 deletions(-)
diff --git a/libxfs/init.c b/libxfs/init.c
index ba0b9a87f2d..18bd2116c50 100644
--- a/libxfs/init.c
+++ b/libxfs/init.c
@@ -307,13 +307,6 @@ rtmount_init(
return -1;
}
- if (xfs_has_rmapbt(mp)) {
- fprintf(stderr,
- _("%s: Reverse mapping btree not compatible with realtime device. Please try a newer xfsprogs.\n"),
- progname);
- return -1;
- }
-
if (mp->m_rtdev_targp->bt_bdev == 0 && !xfs_is_debugger(mp)) {
fprintf(stderr, _("%s: filesystem has a realtime subvolume\n"),
progname);
diff --git a/mkfs/proto.c b/mkfs/proto.c
index 5239f9ec413..d575d9c511e 100644
--- a/mkfs/proto.c
+++ b/mkfs/proto.c
@@ -852,6 +852,54 @@ rtsummary_create(
mp->m_rsumip = rsumip;
}
+/* Create the realtime rmap btree inode. */
+static void
+rtrmapbt_create(
+ struct xfs_rtgroup *rtg)
+{
+ struct xfs_imeta_update upd;
+ struct xfs_rmap_irec rmap = {
+ .rm_startblock = 0,
+ .rm_blockcount = rtg->rtg_mount->m_sb.sb_rextsize,
+ .rm_owner = XFS_RMAP_OWN_FS,
+ .rm_offset = 0,
+ .rm_flags = 0,
+ };
+ struct xfs_mount *mp = rtg->rtg_mount;
+ struct xfs_imeta_path *path;
+ struct xfs_btree_cur *cur;
+ int error;
+
+ error = -libxfs_rtrmapbt_create_path(mp, rtg->rtg_rgno, &path);
+ if (error)
+ fail( _("rtrmap inode path creation failed"), error);
+
+ error = -libxfs_imeta_ensure_dirpath(mp, path);
+ if (error)
+ fail(_("rtgroup directory allocation failed"), error);
+
+ error = -libxfs_imeta_start_create(mp, path, &upd);
+ if (error)
+ res_failed(error);
+
+ error = -libxfs_rtrmapbt_create(&upd, &rtg->rtg_rmapip);
+ if (error)
+ fail(_("rtrmap inode creation failed"), error);
+
+ /* Adding an rmap for the rtgroup super should fit in the data fork */
+ cur = libxfs_rtrmapbt_init_cursor(mp, upd.tp, rtg, rtg->rtg_rmapip);
+ error = -libxfs_rmap_map_raw(cur, &rmap);
+ libxfs_btree_del_cursor(cur, error);
+ if (error)
+ fail(_("rtrmapbt initialization failed"), error);
+
+ error = -libxfs_imeta_commit_update(&upd);
+ if (error)
+ fail(_("rtrmapbt commit failed"), error);
+
+ libxfs_imeta_free_path(path);
+}
+
/* Initialize block headers of rt free space files. */
static int
init_rtblock_headers(
@@ -1084,9 +1132,17 @@ static void
rtinit(
struct xfs_mount *mp)
{
+ struct xfs_rtgroup *rtg;
+ xfs_rgnumber_t rgno;
+
rtbitmap_create(mp);
rtsummary_create(mp);
+ for_each_rtgroup(mp, rgno, rtg) {
+ if (xfs_has_rtrmapbt(mp))
+ rtrmapbt_create(rtg);
+ }
+
rtbitmap_init(mp);
rtsummary_init(mp);
if (xfs_has_rtgroups(mp))
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 66532b8c9b6..162546cd1e8 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -2474,12 +2474,18 @@ _("reflink not supported with realtime devices\n"));
}
cli->sb_feat.reflink = false;
- if (cli->sb_feat.rmapbt && cli_opt_set(&mopts, M_RMAPBT)) {
- fprintf(stderr,
-_("rmapbt not supported with realtime devices\n"));
- usage();
+ if (!cli->sb_feat.rtgroups && cli->sb_feat.rmapbt) {
+ if (cli_opt_set(&mopts, M_RMAPBT) &&
+ cli_opt_set(&ropts, R_RTGROUPS)) {
+ fprintf(stderr,
+_("rmapbt not supported on realtime devices without rtgroups feature\n"));
+ usage();
+ } else if (cli_opt_set(&mopts, M_RMAPBT)) {
+ cli->sb_feat.rtgroups = true;
+ } else {
+ cli->sb_feat.rmapbt = false;
+ }
}
- cli->sb_feat.rmapbt = false;
}
if ((cli->fsx.fsx_xflags & FS_XFLAG_COWEXTSIZE) &&
@@ -4553,6 +4559,77 @@ cfgfile_parse(
cli->cfgfile);
}
+static inline void
+prealloc_fail(
+ struct xfs_mount *mp,
+ int error,
+ xfs_filblks_t ask,
+ const char *tag)
+{
+ if (error == ENOSPC)
+ fprintf(stderr,
+ _("%s: cannot handle expansion of %s; need %llu free blocks, have %llu\n"),
+ progname, tag, (unsigned long long)ask,
+ (unsigned long long)mp->m_sb.sb_fdblocks);
+ else
+ fprintf(stderr,
+ _("%s: error %d while checking free space for %s\n"),
+ progname, error, tag);
+ exit(1);
+}
+
+/*
+ * Make sure there's enough space on the data device to handle realtime
+ * metadata btree expansions.
+ */
+static void
+check_rt_meta_prealloc(
+ struct xfs_mount *mp)
+{
+ struct xfs_perag *pag;
+ struct xfs_rtgroup *rtg;
+ xfs_agnumber_t agno;
+ xfs_rgnumber_t rgno;
+ xfs_filblks_t ask;
+ int error;
+
+ /*
+ * First create all the per-AG reservations, since they take from the
+ * free block count. Each AG should start with enough free space for
+ * the per-AG reservation.
+ */
+ mp->m_finobt_nores = false;
+
+ for_each_perag(mp, agno, pag) {
+ error = -libxfs_ag_resv_init(pag, NULL);
+ if (error && error != ENOSPC) {
+ fprintf(stderr,
+ _("%s: error %d while checking AG free space for realtime metadata\n"),
+ progname, error);
+ exit(1);
+ }
+ }
+
+ /* Realtime metadata btree inode */
+ for_each_rtgroup(mp, rgno, rtg) {
+ ask = libxfs_rtrmapbt_calc_reserves(mp);
+ error = -libxfs_imeta_resv_init_inode(rtg->rtg_rmapip, ask);
+ if (error)
+ prealloc_fail(mp, error, ask, _("realtime rmap btree"));
+ }
+
+ /* Unreserve the realtime metadata reservations. */
+ for_each_rtgroup(mp, rgno, rtg) {
+ libxfs_imeta_resv_free_inode(rtg->rtg_rmapip);
+ }
+
+ /* Unreserve the per-AG reservations. */
+ for_each_perag(mp, agno, pag)
+ libxfs_ag_resv_free(pag);
+
+ mp->m_finobt_nores = false;
+}
+
int
main(
int argc,
@@ -4922,6 +4999,9 @@ main(
*/
check_root_ino(mp);
+ /* Make sure we can handle space preallocations of rt metadata btrees */
+ check_rt_meta_prealloc(mp);
+
/*
* Re-write multiple secondary superblocks with rootinode field set
*/
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 1/4] libxfs: resync libxfs_alloc_file_space interface with the kernel
2023-12-31 19:55 ` [PATCHSET v2.0 13/17] xfsprogs: file write utility refactoring Darrick J. Wong
@ 2023-12-27 13:23 ` Darrick J. Wong
2023-12-27 13:23 ` [PATCH 2/4] mkfs: use libxfs_alloc_file_space for rtinit Darrick J. Wong
` (2 subsequent siblings)
3 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:23 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Make the userspace xfs_alloc_file_space behave (more or less) like the
kernel version, at least as far as the interface goes.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
include/libxfs.h | 4 +-
libxfs/util.c | 143 ++++++++++++++++++++++++++++++++++++------------------
mkfs/proto.c | 2 -
3 files changed, 99 insertions(+), 50 deletions(-)
diff --git a/include/libxfs.h b/include/libxfs.h
index 72f38938f69..1fc8bc0e97b 100644
--- a/include/libxfs.h
+++ b/include/libxfs.h
@@ -174,8 +174,8 @@ extern int libxfs_log_header(char *, uuid_t *, int, int, int, xfs_lsn_t,
/* Shared utility routines */
-extern int libxfs_alloc_file_space (struct xfs_inode *, xfs_off_t,
- xfs_off_t, int, int);
+extern int libxfs_alloc_file_space(struct xfs_inode *ip, xfs_off_t offset,
+ xfs_off_t len, uint32_t bmapi_flags);
/* XXX: this is messy and needs fixing */
#ifndef __LIBXFS_INTERNAL_XFS_H__
diff --git a/libxfs/util.c b/libxfs/util.c
index 76e49b8637c..aec7798a814 100644
--- a/libxfs/util.c
+++ b/libxfs/util.c
@@ -179,78 +179,127 @@ libxfs_mod_incore_sb(
*/
int
libxfs_alloc_file_space(
- xfs_inode_t *ip,
- xfs_off_t offset,
- xfs_off_t len,
- int alloc_type,
- int attr_flags)
+ struct xfs_inode *ip,
+ xfs_off_t offset,
+ xfs_off_t len,
+ uint32_t bmapi_flags)
{
- xfs_mount_t *mp;
- xfs_off_t count;
- xfs_filblks_t datablocks;
- xfs_filblks_t allocated_fsb;
- xfs_filblks_t allocatesize_fsb;
- xfs_bmbt_irec_t *imapp;
- xfs_bmbt_irec_t imaps[1];
- int reccount;
- uint resblks;
- xfs_fileoff_t startoffset_fsb;
- xfs_trans_t *tp;
- int xfs_bmapi_flags;
- int error;
+ xfs_mount_t *mp = ip->i_mount;
+ xfs_off_t count;
+ xfs_filblks_t allocatesize_fsb;
+ xfs_extlen_t extsz, temp;
+ xfs_fileoff_t startoffset_fsb;
+ xfs_fileoff_t endoffset_fsb;
+ int rt;
+ xfs_trans_t *tp;
+ xfs_bmbt_irec_t imaps[1], *imapp;
+ int error;
if (len <= 0)
return -EINVAL;
+ rt = XFS_IS_REALTIME_INODE(ip);
+ extsz = xfs_get_extsz_hint(ip);
+
count = len;
- error = 0;
imapp = &imaps[0];
- reccount = 1;
- xfs_bmapi_flags = alloc_type ? XFS_BMAPI_PREALLOC : 0;
- mp = ip->i_mount;
- startoffset_fsb = XFS_B_TO_FSBT(mp, offset);
- allocatesize_fsb = XFS_B_TO_FSB(mp, count);
+ startoffset_fsb = XFS_B_TO_FSBT(mp, offset);
+ endoffset_fsb = XFS_B_TO_FSB(mp, offset + count);
+ allocatesize_fsb = endoffset_fsb - startoffset_fsb;
- /* allocate file space until done or until there is an error */
+ /*
+ * Allocate file space until done or until there is an error
+ */
while (allocatesize_fsb && !error) {
- datablocks = allocatesize_fsb;
+ xfs_fileoff_t s, e;
+ unsigned int dblocks, rblocks, resblks;
+ int nimaps = 1;
- resblks = (uint)XFS_DIOSTRAT_SPACE_RES(mp, datablocks);
- error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks,
- 0, 0, &tp);
/*
- * Check for running out of space
+ * Determine space reservations for data/realtime.
*/
- if (error) {
- ASSERT(error == -ENOSPC);
+ if (unlikely(extsz)) {
+ s = startoffset_fsb;
+ do_div(s, extsz);
+ s *= extsz;
+ e = startoffset_fsb + allocatesize_fsb;
+ div_u64_rem(startoffset_fsb, extsz, &temp);
+ if (temp)
+ e += temp;
+ div_u64_rem(e, extsz, &temp);
+ if (temp)
+ e += extsz - temp;
+ } else {
+ s = 0;
+ e = allocatesize_fsb;
+ }
+
+ /*
+ * The transaction reservation is limited to a 32-bit block
+ * count, hence we need to limit the number of blocks we are
+ * trying to reserve to avoid an overflow. We can't allocate
+ * more than @nimaps extents, and an extent is limited on disk
+ * to XFS_BMBT_MAX_EXTLEN (21 bits), so use that to enforce the
+ * limit.
+ */
+ resblks = min_t(xfs_fileoff_t, (e - s),
+ (XFS_MAX_BMBT_EXTLEN * nimaps));
+ if (unlikely(rt)) {
+ dblocks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
+ rblocks = resblks;
+ } else {
+ dblocks = XFS_DIOSTRAT_SPACE_RES(mp, resblks);
+ rblocks = 0;
+ }
+
+ error = xfs_trans_alloc_inode(ip, &M_RES(mp)->tr_write,
+ dblocks, rblocks, false, &tp);
+ if (error)
break;
- }
- xfs_trans_ijoin(tp, ip, 0);
- error = xfs_bmapi_write(tp, ip, startoffset_fsb, allocatesize_fsb,
- xfs_bmapi_flags, 0, imapp, &reccount);
+ error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK,
+ XFS_IEXT_ADD_NOSPLIT_CNT);
+ if (error == -EFBIG)
+ error = xfs_iext_count_upgrade(tp, ip,
+ XFS_IEXT_ADD_NOSPLIT_CNT);
+ if (error)
+ goto error;
+ error = xfs_bmapi_write(tp, ip, startoffset_fsb,
+ allocatesize_fsb, bmapi_flags, 0, imapp,
+ &nimaps);
if (error)
- goto error0;
+ goto error;
+
+ ip->i_diflags |= XFS_DIFLAG_PREALLOC;
+ xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
- /*
- * Complete the transaction
- */
error = xfs_trans_commit(tp);
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
if (error)
break;
- allocated_fsb = imapp->br_blockcount;
- if (reccount == 0)
- return -ENOSPC;
-
- startoffset_fsb += allocated_fsb;
- allocatesize_fsb -= allocated_fsb;
+ /*
+ * If xfs_bmapi_write finds a delalloc extent at the requested
+ * range, it tries to convert the entire delalloc extent to a
+ * real allocation.
+ * If the allocator cannot find a single free extent large
+ * enough to cover the start block of the requested range,
+ * xfs_bmapi_write will return 0 but leave *nimaps set to 0.
+ * In that case we simply need to keep looping with the same
+ * startoffset_fsb.
+ */
+ if (nimaps) {
+ startoffset_fsb += imapp->br_blockcount;
+ allocatesize_fsb -= imapp->br_blockcount;
+ }
}
+
return error;
-error0: /* Cancel bmap, cancel trans */
+error:
xfs_trans_cancel(tp);
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
return error;
}
diff --git a/mkfs/proto.c b/mkfs/proto.c
index d575d9c511e..5b632d31215 100644
--- a/mkfs/proto.c
+++ b/mkfs/proto.c
@@ -205,7 +205,7 @@ rsvfile(
int error;
xfs_trans_t *tp;
- error = -libxfs_alloc_file_space(ip, 0, llen, 1, 0);
+ error = -libxfs_alloc_file_space(ip, 0, llen, XFS_BMAPI_PREALLOC);
if (error) {
fail(_("error reserving space for a file"), error);
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 2/4] mkfs: use libxfs_alloc_file_space for rtinit
2023-12-31 19:55 ` [PATCHSET v2.0 13/17] xfsprogs: file write utility refactoring Darrick J. Wong
2023-12-27 13:23 ` [PATCH 1/4] libxfs: resync libxfs_alloc_file_space interface with the kernel Darrick J. Wong
@ 2023-12-27 13:23 ` Darrick J. Wong
2023-12-27 13:23 ` [PATCH 3/4] xfs_repair: use libxfs_alloc_file_space to reallocate rt metadata Darrick J. Wong
2023-12-27 13:23 ` [PATCH 4/4] mkfs: use file write helper to populate files Darrick J. Wong
3 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:23 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Since xfs_bmapi_write can now zero newly allocated blocks, use it to
initialize the realtime inodes instead of open coding this.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
mkfs/proto.c | 80 +++++++++-------------------------------------------------
1 file changed, 12 insertions(+), 68 deletions(-)
diff --git a/mkfs/proto.c b/mkfs/proto.c
index 5b632d31215..83888572395 100644
--- a/mkfs/proto.c
+++ b/mkfs/proto.c
@@ -949,43 +949,14 @@ static void
rtbitmap_init(
struct xfs_mount *mp)
{
- struct xfs_bmbt_irec map[XFS_BMAP_MAX_NMAP];
- struct xfs_trans *tp;
- struct xfs_bmbt_irec *ep;
- xfs_fileoff_t bno;
- uint blocks;
- int i;
- int nmap;
int error;
- blocks = mp->m_sb.sb_rbmblocks +
- XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1;
- error = -libxfs_trans_alloc_rollable(mp, blocks, &tp);
+ error = -libxfs_alloc_file_space(mp->m_rbmip, 0,
+ mp->m_sb.sb_rbmblocks << mp->m_sb.sb_blocklog,
+ XFS_BMAPI_ZERO);
if (error)
- res_failed(error);
-
- libxfs_trans_ijoin(tp, mp->m_rbmip, 0);
- bno = 0;
- while (bno < mp->m_sb.sb_rbmblocks) {
- nmap = XFS_BMAP_MAX_NMAP;
- error = -libxfs_bmapi_write(tp, mp->m_rbmip, bno,
- (xfs_extlen_t)(mp->m_sb.sb_rbmblocks - bno),
- 0, mp->m_sb.sb_rbmblocks, map, &nmap);
- if (error)
- fail(_("Allocation of the realtime bitmap failed"),
- error);
-
- for (i = 0, ep = map; i < nmap; i++, ep++) {
- libxfs_device_zero(mp->m_ddev_targp,
- XFS_FSB_TO_DADDR(mp, ep->br_startblock),
- XFS_FSB_TO_BB(mp, ep->br_blockcount));
- bno += ep->br_blockcount;
- }
- }
-
- error = -libxfs_trans_commit(tp);
- if (error)
- fail(_("Block allocation of the realtime bitmap inode failed"),
+ fail(
+ _("Block allocation of the realtime bitmap inode failed"),
error);
if (xfs_has_rtgroups(mp)) {
@@ -1001,43 +972,13 @@ static void
rtsummary_init(
struct xfs_mount *mp)
{
- struct xfs_bmbt_irec map[XFS_BMAP_MAX_NMAP];
- struct xfs_trans *tp;
- struct xfs_bmbt_irec *ep;
- xfs_fileoff_t bno;
- xfs_extlen_t nsumblocks;
- uint blocks;
- int i;
- int nmap;
int error;
- nsumblocks = mp->m_rsumsize >> mp->m_sb.sb_blocklog;
- blocks = nsumblocks + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1;
- error = -libxfs_trans_alloc_rollable(mp, blocks, &tp);
+ error = -libxfs_alloc_file_space(mp->m_rsumip, 0, mp->m_rsumsize,
+ XFS_BMAPI_ZERO);
if (error)
- res_failed(error);
- libxfs_trans_ijoin(tp, mp->m_rsumip, 0);
-
- bno = 0;
- while (bno < nsumblocks) {
- nmap = XFS_BMAP_MAX_NMAP;
- error = -libxfs_bmapi_write(tp, mp->m_rsumip, bno,
- (xfs_extlen_t)(nsumblocks - bno),
- 0, nsumblocks, map, &nmap);
- if (error)
- fail(_("Allocation of the realtime summary failed"),
- error);
-
- for (i = 0, ep = map; i < nmap; i++, ep++) {
- libxfs_device_zero(mp->m_ddev_targp,
- XFS_FSB_TO_DADDR(mp, ep->br_startblock),
- XFS_FSB_TO_BB(mp, ep->br_blockcount));
- bno += ep->br_blockcount;
- }
- }
- error = -libxfs_trans_commit(tp);
- if (error)
- fail(_("Block allocation of the realtime summary inode failed"),
+ fail(
+ _("Block allocation of the realtime summary inode failed"),
error);
if (xfs_has_rtgroups(mp)) {
@@ -1143,6 +1084,9 @@ rtinit(
rtrmapbt_create(rtg);
}
+ if (mp->m_sb.sb_rbmblocks == 0)
+ return;
+
rtbitmap_init(mp);
rtsummary_init(mp);
if (xfs_has_rtgroups(mp))
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 3/4] xfs_repair: use libxfs_alloc_file_space to reallocate rt metadata
2023-12-31 19:55 ` [PATCHSET v2.0 13/17] xfsprogs: file write utility refactoring Darrick J. Wong
2023-12-27 13:23 ` [PATCH 1/4] libxfs: resync libxfs_alloc_file_space interface with the kernel Darrick J. Wong
2023-12-27 13:23 ` [PATCH 2/4] mkfs: use libxfs_alloc_file_space for rtinit Darrick J. Wong
@ 2023-12-27 13:23 ` Darrick J. Wong
2023-12-27 13:23 ` [PATCH 4/4] mkfs: use file write helper to populate files Darrick J. Wong
3 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:23 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Now that libxfs_alloc_file_space can allocate and zero blocks, use it to
repair the realtime metadata instead of open-coding all this.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
repair/phase6.c | 76 +++++++------------------------------------------------
1 file changed, 10 insertions(+), 66 deletions(-)
diff --git a/repair/phase6.c b/repair/phase6.c
index fd862362f1d..c9974623d12 100644
--- a/repair/phase6.c
+++ b/repair/phase6.c
@@ -736,15 +736,9 @@ mk_rbmino(
struct xfs_mount *mp)
{
struct xfs_imeta_update upd = { };
- struct xfs_trans *tp = NULL;
struct xfs_inode *ip = NULL;
- struct xfs_bmbt_irec *ep;
int i;
- int nmap;
int error;
- xfs_fileoff_t bno;
- struct xfs_bmbt_irec map[XFS_BMAP_MAX_NMAP];
- uint blocks;
/* Reset the realtime bitmap inode. */
if (!xfs_has_metadir(mp)) {
@@ -779,36 +773,15 @@ mk_rbmino(
* then allocate blocks for file and fill with zeroes (stolen
* from mkfs)
*/
- blocks = mp->m_sb.sb_rbmblocks +
- XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1;
- error = -libxfs_trans_alloc_rollable(mp, blocks, &tp);
- if (error)
- res_failed(error);
-
- libxfs_trans_ijoin(tp, ip, 0);
- bno = 0;
- while (bno < mp->m_sb.sb_rbmblocks) {
- nmap = XFS_BMAP_MAX_NMAP;
- error = -libxfs_bmapi_write(tp, ip, bno,
- (xfs_extlen_t)(mp->m_sb.sb_rbmblocks - bno),
- 0, mp->m_sb.sb_rbmblocks, map, &nmap);
+ if (mp->m_sb.sb_rbmblocks) {
+ error = -libxfs_alloc_file_space(ip, 0,
+ mp->m_sb.sb_rbmblocks << mp->m_sb.sb_blocklog,
+ XFS_BMAPI_ZERO);
if (error) {
do_error(
- _("couldn't allocate realtime bitmap, error = %d\n"),
+ _("allocation of the realtime bitmap failed, error = %d\n"),
error);
}
- for (i = 0, ep = map; i < nmap; i++, ep++) {
- libxfs_device_zero(mp->m_ddev_targp,
- XFS_FSB_TO_DADDR(mp, ep->br_startblock),
- XFS_FSB_TO_BB(mp, ep->br_blockcount));
- bno += ep->br_blockcount;
- }
- }
- error = -libxfs_trans_commit(tp);
- if (error) {
- do_error(
- _("allocation of the realtime bitmap failed, error = %d\n"),
- error);
}
libxfs_irele(ip);
}
@@ -996,16 +969,9 @@ mk_rsumino(
struct xfs_mount *mp)
{
struct xfs_imeta_update upd = { };
- struct xfs_trans *tp = NULL;
struct xfs_inode *ip = NULL;
- struct xfs_bmbt_irec *ep;
int i;
- int nmap;
int error;
- int nsumblocks;
- xfs_fileoff_t bno;
- struct xfs_bmbt_irec map[XFS_BMAP_MAX_NMAP];
- uint blocks;
/* Reset the realtime summary inode. */
if (!xfs_has_metadir(mp)) {
@@ -1040,36 +1006,14 @@ mk_rsumino(
* then allocate blocks for file and fill with zeroes (stolen
* from mkfs)
*/
- nsumblocks = mp->m_rsumsize >> mp->m_sb.sb_blocklog;
- blocks = nsumblocks + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1;
- error = -libxfs_trans_alloc_rollable(mp, blocks, &tp);
- if (error)
- res_failed(error);
-
- libxfs_trans_ijoin(tp, ip, 0);
- bno = 0;
- while (bno < nsumblocks) {
- nmap = XFS_BMAP_MAX_NMAP;
- error = -libxfs_bmapi_write(tp, ip, bno,
- (xfs_extlen_t)(nsumblocks - bno),
- 0, nsumblocks, map, &nmap);
+ if (mp->m_rsumsize) {
+ error = -libxfs_alloc_file_space(ip, 0, mp->m_rsumsize,
+ XFS_BMAPI_ZERO);
if (error) {
do_error(
- _("couldn't allocate realtime summary inode, error = %d\n"),
- error);
- }
- for (i = 0, ep = map; i < nmap; i++, ep++) {
- libxfs_device_zero(mp->m_ddev_targp,
- XFS_FSB_TO_DADDR(mp, ep->br_startblock),
- XFS_FSB_TO_BB(mp, ep->br_blockcount));
- bno += ep->br_blockcount;
- }
- }
- error = -libxfs_trans_commit(tp);
- if (error) {
- do_error(
_("allocation of the realtime summary ino failed, error = %d\n"),
- error);
+ error);
+ }
}
libxfs_irele(ip);
}
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 4/4] mkfs: use file write helper to populate files
2023-12-31 19:55 ` [PATCHSET v2.0 13/17] xfsprogs: file write utility refactoring Darrick J. Wong
` (2 preceding siblings ...)
2023-12-27 13:23 ` [PATCH 3/4] xfs_repair: use libxfs_alloc_file_space to reallocate rt metadata Darrick J. Wong
@ 2023-12-27 13:23 ` Darrick J. Wong
3 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:23 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Use the file write helper to write files into the filesystem.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
include/libxfs.h | 2 ++
libxfs/util.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
mkfs/proto.c | 26 ++++----------------
3 files changed, 76 insertions(+), 21 deletions(-)
diff --git a/include/libxfs.h b/include/libxfs.h
index 1fc8bc0e97b..46003fe641d 100644
--- a/include/libxfs.h
+++ b/include/libxfs.h
@@ -176,6 +176,8 @@ extern int libxfs_log_header(char *, uuid_t *, int, int, int, xfs_lsn_t,
extern int libxfs_alloc_file_space(struct xfs_inode *ip, xfs_off_t offset,
xfs_off_t len, uint32_t bmapi_flags);
+extern int libxfs_file_write(struct xfs_trans *tp, struct xfs_inode *ip,
+ void *buf, size_t len, bool logit);
/* XXX: this is messy and needs fixing */
#ifndef __LIBXFS_INTERNAL_XFS_H__
diff --git a/libxfs/util.c b/libxfs/util.c
index aec7798a814..f2be9dbf4a2 100644
--- a/libxfs/util.c
+++ b/libxfs/util.c
@@ -537,3 +537,72 @@ get_random_u32(void)
return ret;
}
#endif
+
+/*
+ * Write a buffer to a file on the data device. We assume there are no holes
+ * and no unwritten extents.
+ */
+int
+libxfs_file_write(
+ struct xfs_trans *tp,
+ struct xfs_inode *ip,
+ void *buf,
+ size_t len,
+ bool logit)
+{
+ struct xfs_bmbt_irec map;
+ struct xfs_mount *mp = ip->i_mount;
+ struct xfs_buf *bp;
+ xfs_fileoff_t bno = 0;
+ xfs_fileoff_t end_bno = XFS_B_TO_FSB(mp, len);
+ size_t count;
+ size_t bcount;
+ int nmap;
+ int error = 0;
+
+ /* Write up to 1MB at a time. */
+ while (bno < end_bno) {
+ xfs_filblks_t maplen;
+
+ maplen = min(end_bno - bno, XFS_B_TO_FSBT(mp, 1048576));
+ nmap = 1;
+ error = libxfs_bmapi_read(ip, bno, maplen, &map, &nmap, 0);
+ if (error)
+ return error;
+ if (nmap != 1)
+ return -ENOSPC;
+
+ if (map.br_startblock == HOLESTARTBLOCK ||
+ map.br_state == XFS_EXT_UNWRITTEN)
+ return -EINVAL;
+
+ error = libxfs_trans_get_buf(tp, mp->m_dev,
+ XFS_FSB_TO_DADDR(mp, map.br_startblock),
+ XFS_FSB_TO_BB(mp, map.br_blockcount),
+ 0, &bp);
+ if (error)
+ break;
+ bp->b_ops = NULL;
+
+ count = min(len, XFS_FSB_TO_B(mp, map.br_blockcount));
+ memmove(bp->b_addr, buf, count);
+ bcount = BBTOB(bp->b_length);
+ if (count < bcount)
+ memset((char *)bp->b_addr + count, 0, bcount - count);
+
+ if (tp) {
+ libxfs_trans_log_buf(tp, bp, 0, bcount - 1);
+ } else {
+ libxfs_buf_mark_dirty(bp);
+ libxfs_buf_relse(bp);
+ }
+ if (error)
+ break;
+
+ buf += count;
+ len -= count;
+ bno += map.br_blockcount;
+ }
+
+ return error;
+}
diff --git a/mkfs/proto.c b/mkfs/proto.c
index 83888572395..436f9ac82b2 100644
--- a/mkfs/proto.c
+++ b/mkfs/proto.c
@@ -270,16 +270,12 @@ writefile(
{
struct xfs_bmbt_irec map;
struct xfs_mount *mp;
- struct xfs_buf *bp;
- xfs_daddr_t d;
xfs_extlen_t nb;
int nmap;
int error;
mp = ip->i_mount;
if (len > 0) {
- int bcount;
-
nb = XFS_B_TO_FSB(mp, len);
nmap = 1;
error = -libxfs_bmapi_write(tp, ip, 0, nb, 0, nb, &map, &nmap);
@@ -289,30 +285,18 @@ writefile(
progname);
exit(1);
}
- if (error) {
+ if (error)
fail(_("error allocating space for a file"), error);
- }
if (nmap != 1) {
fprintf(stderr,
_("%s: cannot allocate space for file\n"),
progname);
exit(1);
}
- d = XFS_FSB_TO_DADDR(mp, map.br_startblock);
- error = -libxfs_trans_get_buf(NULL, mp->m_dev, d,
- nb << mp->m_blkbb_log, 0, &bp);
- if (error) {
- fprintf(stderr,
- _("%s: cannot allocate buffer for file\n"),
- progname);
- exit(1);
- }
- memmove(bp->b_addr, buf, len);
- bcount = BBTOB(bp->b_length);
- if (len < bcount)
- memset((char *)bp->b_addr + len, 0, bcount - len);
- libxfs_buf_mark_dirty(bp);
- libxfs_buf_relse(bp);
+
+ error = -libxfs_file_write(tp, ip, buf, len, false);
+ if (error)
+ fail(_("error writing file"), error);
}
ip->i_disk_size = len;
}
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 1/9] xfs: give refcount btree cursor error tracepoints their own class
2023-12-31 19:55 ` [PATCHSET v2.0 14/17] xfsprogs: refcount log intent cleanups Darrick J. Wong
@ 2023-12-27 13:24 ` Darrick J. Wong
2023-12-27 13:24 ` [PATCH 2/9] xfs: create specialized classes for refcount tracepoints Darrick J. Wong
` (7 subsequent siblings)
8 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:24 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Convert all the refcount tracepoints to use the btree error tracepoint
class.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_refcount.c | 42 ++++++++++++++----------------------------
1 file changed, 14 insertions(+), 28 deletions(-)
diff --git a/libxfs/xfs_refcount.c b/libxfs/xfs_refcount.c
index 0e8daab9986..9bb7acbdc6f 100644
--- a/libxfs/xfs_refcount.c
+++ b/libxfs/xfs_refcount.c
@@ -210,8 +210,7 @@ xfs_refcount_update(
error = xfs_btree_update(cur, &rec);
if (error)
- trace_xfs_refcount_update_error(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, error, _RET_IP_);
+ trace_xfs_refcount_update_error(cur, error, _RET_IP_);
return error;
}
@@ -246,8 +245,7 @@ xfs_refcount_insert(
out_error:
if (error)
- trace_xfs_refcount_insert_error(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, error, _RET_IP_);
+ trace_xfs_refcount_insert_error(cur, error, _RET_IP_);
return error;
}
@@ -287,8 +285,7 @@ xfs_refcount_delete(
&found_rec);
out_error:
if (error)
- trace_xfs_refcount_delete_error(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, error, _RET_IP_);
+ trace_xfs_refcount_delete_error(cur, error, _RET_IP_);
return error;
}
@@ -437,8 +434,7 @@ xfs_refcount_split_extent(
return error;
out_error:
- trace_xfs_refcount_split_extent_error(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, error, _RET_IP_);
+ trace_xfs_refcount_split_extent_error(cur, error, _RET_IP_);
return error;
}
@@ -521,8 +517,7 @@ xfs_refcount_merge_center_extents(
return error;
out_error:
- trace_xfs_refcount_merge_center_extents_error(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, error, _RET_IP_);
+ trace_xfs_refcount_merge_center_extents_error(cur, error, _RET_IP_);
return error;
}
@@ -588,8 +583,7 @@ xfs_refcount_merge_left_extent(
return error;
out_error:
- trace_xfs_refcount_merge_left_extent_error(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, error, _RET_IP_);
+ trace_xfs_refcount_merge_left_extent_error(cur, error, _RET_IP_);
return error;
}
@@ -657,8 +651,7 @@ xfs_refcount_merge_right_extent(
return error;
out_error:
- trace_xfs_refcount_merge_right_extent_error(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, error, _RET_IP_);
+ trace_xfs_refcount_merge_right_extent_error(cur, error, _RET_IP_);
return error;
}
@@ -752,8 +745,7 @@ xfs_refcount_find_left_extents(
return error;
out_error:
- trace_xfs_refcount_find_left_extent_error(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, error, _RET_IP_);
+ trace_xfs_refcount_find_left_extent_error(cur, error, _RET_IP_);
return error;
}
@@ -847,8 +839,7 @@ xfs_refcount_find_right_extents(
return error;
out_error:
- trace_xfs_refcount_find_right_extent_error(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, error, _RET_IP_);
+ trace_xfs_refcount_find_right_extent_error(cur, error, _RET_IP_);
return error;
}
@@ -1253,8 +1244,7 @@ xfs_refcount_adjust_extents(
return error;
out_error:
- trace_xfs_refcount_modify_extent_error(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, error, _RET_IP_);
+ trace_xfs_refcount_modify_extent_error(cur, error, _RET_IP_);
return error;
}
@@ -1314,8 +1304,7 @@ xfs_refcount_adjust(
return 0;
out_error:
- trace_xfs_refcount_adjust_error(cur->bc_mp, cur->bc_ag.pag->pag_agno,
- error, _RET_IP_);
+ trace_xfs_refcount_adjust_error(cur, error, _RET_IP_);
return error;
}
@@ -1629,8 +1618,7 @@ xfs_refcount_find_shared(
out_error:
if (error)
- trace_xfs_refcount_find_shared_error(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, error, _RET_IP_);
+ trace_xfs_refcount_find_shared_error(cur, error, _RET_IP_);
return error;
}
@@ -1785,8 +1773,7 @@ xfs_refcount_adjust_cow_extents(
return error;
out_error:
- trace_xfs_refcount_modify_extent_error(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, error, _RET_IP_);
+ trace_xfs_refcount_modify_extent_error(cur, error, _RET_IP_);
return error;
}
@@ -1832,8 +1819,7 @@ xfs_refcount_adjust_cow(
return 0;
out_error:
- trace_xfs_refcount_adjust_cow_error(cur->bc_mp, cur->bc_ag.pag->pag_agno,
- error, _RET_IP_);
+ trace_xfs_refcount_adjust_cow_error(cur, error, _RET_IP_);
return error;
}
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 2/9] xfs: create specialized classes for refcount tracepoints
2023-12-31 19:55 ` [PATCHSET v2.0 14/17] xfsprogs: refcount log intent cleanups Darrick J. Wong
2023-12-27 13:24 ` [PATCH 1/9] xfs: give refcount btree cursor error tracepoints their own class Darrick J. Wong
@ 2023-12-27 13:24 ` Darrick J. Wong
2023-12-27 13:24 ` [PATCH 3/9] xfs: prepare refcount btree tracepoints for widening Darrick J. Wong
` (6 subsequent siblings)
8 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:24 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
The only user of the "ag" tracepoint event classes is the refcount
btree, so rename them to make that obvious and make them take the btree
cursor to simplify the arguments. This will save us a lot of trouble
later on.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_refcount.c | 24 +++++++++---------------
1 file changed, 9 insertions(+), 15 deletions(-)
diff --git a/libxfs/xfs_refcount.c b/libxfs/xfs_refcount.c
index 9bb7acbdc6f..67c9895efb3 100644
--- a/libxfs/xfs_refcount.c
+++ b/libxfs/xfs_refcount.c
@@ -50,7 +50,7 @@ xfs_refcount_lookup_le(
xfs_agblock_t bno,
int *stat)
{
- trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno,
+ trace_xfs_refcount_lookup(cur,
xfs_refcount_encode_startblock(bno, domain),
XFS_LOOKUP_LE);
cur->bc_rec.rc.rc_startblock = bno;
@@ -70,7 +70,7 @@ xfs_refcount_lookup_ge(
xfs_agblock_t bno,
int *stat)
{
- trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno,
+ trace_xfs_refcount_lookup(cur,
xfs_refcount_encode_startblock(bno, domain),
XFS_LOOKUP_GE);
cur->bc_rec.rc.rc_startblock = bno;
@@ -90,7 +90,7 @@ xfs_refcount_lookup_eq(
xfs_agblock_t bno,
int *stat)
{
- trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno,
+ trace_xfs_refcount_lookup(cur,
xfs_refcount_encode_startblock(bno, domain),
XFS_LOOKUP_LE);
cur->bc_rec.rc.rc_startblock = bno;
@@ -1261,11 +1261,9 @@ xfs_refcount_adjust(
int error;
if (adj == XFS_REFCOUNT_ADJUST_INCREASE)
- trace_xfs_refcount_increase(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, *agbno, *aglen);
+ trace_xfs_refcount_increase(cur, *agbno, *aglen);
else
- trace_xfs_refcount_decrease(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, *agbno, *aglen);
+ trace_xfs_refcount_decrease(cur, *agbno, *aglen);
/*
* Ensure that no rcextents cross the boundary of the adjustment range.
@@ -1525,8 +1523,7 @@ xfs_refcount_find_shared(
int have;
int error;
- trace_xfs_refcount_find_shared(cur->bc_mp, cur->bc_ag.pag->pag_agno,
- agbno, aglen);
+ trace_xfs_refcount_find_shared(cur, agbno, aglen);
/* By default, skip the whole range */
*fbno = NULLAGBLOCK;
@@ -1613,8 +1610,7 @@ xfs_refcount_find_shared(
}
done:
- trace_xfs_refcount_find_shared_result(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, *fbno, *flen);
+ trace_xfs_refcount_find_shared_result(cur, *fbno, *flen);
out_error:
if (error)
@@ -1832,8 +1828,7 @@ __xfs_refcount_cow_alloc(
xfs_agblock_t agbno,
xfs_extlen_t aglen)
{
- trace_xfs_refcount_cow_increase(rcur->bc_mp, rcur->bc_ag.pag->pag_agno,
- agbno, aglen);
+ trace_xfs_refcount_cow_increase(rcur, agbno, aglen);
/* Add refcount btree reservation */
return xfs_refcount_adjust_cow(rcur, agbno, aglen,
@@ -1849,8 +1844,7 @@ __xfs_refcount_cow_free(
xfs_agblock_t agbno,
xfs_extlen_t aglen)
{
- trace_xfs_refcount_cow_decrease(rcur->bc_mp, rcur->bc_ag.pag->pag_agno,
- agbno, aglen);
+ trace_xfs_refcount_cow_decrease(rcur, agbno, aglen);
/* Remove refcount btree reservation */
return xfs_refcount_adjust_cow(rcur, agbno, aglen,
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 3/9] xfs: prepare refcount btree tracepoints for widening
2023-12-31 19:55 ` [PATCHSET v2.0 14/17] xfsprogs: refcount log intent cleanups Darrick J. Wong
2023-12-27 13:24 ` [PATCH 1/9] xfs: give refcount btree cursor error tracepoints their own class Darrick J. Wong
2023-12-27 13:24 ` [PATCH 2/9] xfs: create specialized classes for refcount tracepoints Darrick J. Wong
@ 2023-12-27 13:24 ` Darrick J. Wong
2023-12-27 13:24 ` [PATCH 4/9] xfs: clean up refcount log intent item tracepoint callsites Darrick J. Wong
` (5 subsequent siblings)
8 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:24 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Prepare the rest of refcount btree tracepoints for use with realtime
reflink by making them take the btree cursor object as a parameter.
This will save us a lot of trouble later on.
Remove the xfs_refcount_recover_extent tracepoint since it's already
covered by other refcount tracepoints.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_refcount.c | 42 +++++++++++++++---------------------------
1 file changed, 15 insertions(+), 27 deletions(-)
diff --git a/libxfs/xfs_refcount.c b/libxfs/xfs_refcount.c
index 67c9895efb3..18b04c38cdd 100644
--- a/libxfs/xfs_refcount.c
+++ b/libxfs/xfs_refcount.c
@@ -182,7 +182,7 @@ xfs_refcount_get_rec(
if (fa)
return xfs_refcount_complain_bad_rec(cur, fa, irec);
- trace_xfs_refcount_get(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec);
+ trace_xfs_refcount_get(cur, irec);
return 0;
}
@@ -200,7 +200,7 @@ xfs_refcount_update(
uint32_t start;
int error;
- trace_xfs_refcount_update(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec);
+ trace_xfs_refcount_update(cur, irec);
start = xfs_refcount_encode_startblock(irec->rc_startblock,
irec->rc_domain);
@@ -227,7 +227,7 @@ xfs_refcount_insert(
{
int error;
- trace_xfs_refcount_insert(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec);
+ trace_xfs_refcount_insert(cur, irec);
cur->bc_rec.rc.rc_startblock = irec->rc_startblock;
cur->bc_rec.rc.rc_blockcount = irec->rc_blockcount;
@@ -272,7 +272,7 @@ xfs_refcount_delete(
error = -EFSCORRUPTED;
goto out_error;
}
- trace_xfs_refcount_delete(cur->bc_mp, cur->bc_ag.pag->pag_agno, &irec);
+ trace_xfs_refcount_delete(cur, &irec);
error = xfs_btree_delete(cur, i);
if (XFS_IS_CORRUPT(cur->bc_mp, *i != 1)) {
xfs_btree_mark_sick(cur);
@@ -409,8 +409,7 @@ xfs_refcount_split_extent(
return 0;
*shape_changed = true;
- trace_xfs_refcount_split_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno,
- &rcext, agbno);
+ trace_xfs_refcount_split_extent(cur, &rcext, agbno);
/* Establish the right extent. */
tmp = rcext;
@@ -453,8 +452,7 @@ xfs_refcount_merge_center_extents(
int error;
int found_rec;
- trace_xfs_refcount_merge_center_extents(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, left, center, right);
+ trace_xfs_refcount_merge_center_extents(cur, left, center, right);
ASSERT(left->rc_domain == center->rc_domain);
ASSERT(right->rc_domain == center->rc_domain);
@@ -535,8 +533,7 @@ xfs_refcount_merge_left_extent(
int error;
int found_rec;
- trace_xfs_refcount_merge_left_extent(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, left, cleft);
+ trace_xfs_refcount_merge_left_extent(cur, left, cleft);
ASSERT(left->rc_domain == cleft->rc_domain);
@@ -600,8 +597,7 @@ xfs_refcount_merge_right_extent(
int error;
int found_rec;
- trace_xfs_refcount_merge_right_extent(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, cright, right);
+ trace_xfs_refcount_merge_right_extent(cur, cright, right);
ASSERT(right->rc_domain == cright->rc_domain);
@@ -740,8 +736,7 @@ xfs_refcount_find_left_extents(
cleft->rc_refcount = 1;
cleft->rc_domain = domain;
}
- trace_xfs_refcount_find_left_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno,
- left, cleft, agbno);
+ trace_xfs_refcount_find_left_extent(cur, left, cleft, agbno);
return error;
out_error:
@@ -834,8 +829,8 @@ xfs_refcount_find_right_extents(
cright->rc_refcount = 1;
cright->rc_domain = domain;
}
- trace_xfs_refcount_find_right_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno,
- cright, right, agbno + aglen);
+ trace_xfs_refcount_find_right_extent(cur, cright, right,
+ agbno + aglen);
return error;
out_error:
@@ -1138,8 +1133,7 @@ xfs_refcount_adjust_extents(
tmp.rc_refcount = 1 + adj;
tmp.rc_domain = XFS_REFC_DOMAIN_SHARED;
- trace_xfs_refcount_modify_extent(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, &tmp);
+ trace_xfs_refcount_modify_extent(cur, &tmp);
/*
* Either cover the hole (increment) or
@@ -1204,8 +1198,7 @@ xfs_refcount_adjust_extents(
if (ext.rc_refcount == MAXREFCOUNT)
goto skip;
ext.rc_refcount += adj;
- trace_xfs_refcount_modify_extent(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, &ext);
+ trace_xfs_refcount_modify_extent(cur, &ext);
cur->bc_ag.refc.nr_ops++;
if (ext.rc_refcount > 1) {
error = xfs_refcount_update(cur, &ext);
@@ -1720,8 +1713,7 @@ xfs_refcount_adjust_cow_extents(
tmp.rc_refcount = 1;
tmp.rc_domain = XFS_REFC_DOMAIN_COW;
- trace_xfs_refcount_modify_extent(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, &tmp);
+ trace_xfs_refcount_modify_extent(cur, &tmp);
error = xfs_refcount_insert(cur, &tmp,
&found_tmp);
@@ -1752,8 +1744,7 @@ xfs_refcount_adjust_cow_extents(
}
ext.rc_refcount = 0;
- trace_xfs_refcount_modify_extent(cur->bc_mp,
- cur->bc_ag.pag->pag_agno, &ext);
+ trace_xfs_refcount_modify_extent(cur, &ext);
error = xfs_refcount_delete(cur, &found_rec);
if (error)
goto out_error;
@@ -1987,9 +1978,6 @@ xfs_refcount_recover_cow_leftovers(
if (error)
goto out_free;
- trace_xfs_refcount_recover_extent(mp, pag->pag_agno,
- &rr->rr_rrec);
-
/* Free the orphan record */
fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno,
rr->rr_rrec.rc_startblock);
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 4/9] xfs: clean up refcount log intent item tracepoint callsites
2023-12-31 19:55 ` [PATCHSET v2.0 14/17] xfsprogs: refcount log intent cleanups Darrick J. Wong
` (2 preceding siblings ...)
2023-12-27 13:24 ` [PATCH 3/9] xfs: prepare refcount btree tracepoints for widening Darrick J. Wong
@ 2023-12-27 13:24 ` Darrick J. Wong
2023-12-27 13:25 ` [PATCH 5/9] xfs: add a ci_entry helper Darrick J. Wong
` (4 subsequent siblings)
8 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:24 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Pass the incore refcount intent structure to the tracepoints instead of
open-coding the argument passing.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_refcount.c | 14 ++++----------
libxfs/xfs_refcount.h | 6 ++++++
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/libxfs/xfs_refcount.c b/libxfs/xfs_refcount.c
index 18b04c38cdd..3ae68ea22e3 100644
--- a/libxfs/xfs_refcount.c
+++ b/libxfs/xfs_refcount.c
@@ -1366,9 +1366,7 @@ xfs_refcount_finish_one(
bno = XFS_FSB_TO_AGBNO(mp, ri->ri_startblock);
- trace_xfs_refcount_deferred(mp, XFS_FSB_TO_AGNO(mp, ri->ri_startblock),
- ri->ri_type, XFS_FSB_TO_AGBNO(mp, ri->ri_startblock),
- ri->ri_blockcount);
+ trace_xfs_refcount_deferred(mp, ri);
if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_REFCOUNT_FINISH_ONE))
return -EIO;
@@ -1431,8 +1429,7 @@ xfs_refcount_finish_one(
return -EFSCORRUPTED;
}
if (!error && ri->ri_blockcount > 0)
- trace_xfs_refcount_finish_one_leftover(mp, ri->ri_pag->pag_agno,
- ri->ri_type, bno, ri->ri_blockcount);
+ trace_xfs_refcount_finish_one_leftover(mp, ri);
return error;
}
@@ -1448,11 +1445,6 @@ __xfs_refcount_add(
{
struct xfs_refcount_intent *ri;
- trace_xfs_refcount_defer(tp->t_mountp,
- XFS_FSB_TO_AGNO(tp->t_mountp, startblock),
- type, XFS_FSB_TO_AGBNO(tp->t_mountp, startblock),
- blockcount);
-
ri = kmem_cache_alloc(xfs_refcount_intent_cache,
GFP_NOFS | __GFP_NOFAIL);
INIT_LIST_HEAD(&ri->ri_list);
@@ -1460,6 +1452,8 @@ __xfs_refcount_add(
ri->ri_startblock = startblock;
ri->ri_blockcount = blockcount;
+ trace_xfs_refcount_defer(tp->t_mountp, ri);
+
xfs_refcount_update_get_group(tp->t_mountp, ri);
xfs_defer_add(tp, &ri->ri_list, &xfs_refcount_update_defer_type);
}
diff --git a/libxfs/xfs_refcount.h b/libxfs/xfs_refcount.h
index 9b56768a590..01a20621192 100644
--- a/libxfs/xfs_refcount.h
+++ b/libxfs/xfs_refcount.h
@@ -48,6 +48,12 @@ enum xfs_refcount_intent_type {
XFS_REFCOUNT_FREE_COW,
};
+#define XFS_REFCOUNT_INTENT_STRINGS \
+ { XFS_REFCOUNT_INCREASE, "incr" }, \
+ { XFS_REFCOUNT_DECREASE, "decr" }, \
+ { XFS_REFCOUNT_ALLOC_COW, "alloc_cow" }, \
+ { XFS_REFCOUNT_FREE_COW, "free_cow" }
+
struct xfs_refcount_intent {
struct list_head ri_list;
struct xfs_perag *ri_pag;
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 5/9] xfs: add a ci_entry helper
2023-12-31 19:55 ` [PATCHSET v2.0 14/17] xfsprogs: refcount log intent cleanups Darrick J. Wong
` (3 preceding siblings ...)
2023-12-27 13:24 ` [PATCH 4/9] xfs: clean up refcount log intent item tracepoint callsites Darrick J. Wong
@ 2023-12-27 13:25 ` Darrick J. Wong
2023-12-27 13:25 ` [PATCH 6/9] xfs: reuse xfs_refcount_update_cancel_item Darrick J. Wong
` (3 subsequent siblings)
8 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:25 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Add a helper to translate from the item list head to the
refcount_intent_item structure and use it so shorten assignments and
avoid the need for extra local variables.
Inspired-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/defer_item.c | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/libxfs/defer_item.c b/libxfs/defer_item.c
index e7270d02c4b..471e4f6867d 100644
--- a/libxfs/defer_item.c
+++ b/libxfs/defer_item.c
@@ -485,6 +485,11 @@ const struct xfs_defer_op_type xfs_rtrmap_update_defer_type = {
/* Reference Counting */
+static inline struct xfs_refcount_intent *ci_entry(const struct list_head *e)
+{
+ return list_entry(e, struct xfs_refcount_intent, ri_list);
+}
+
/* Sort refcount intents by AG. */
static int
xfs_refcount_update_diff_items(
@@ -492,11 +497,8 @@ xfs_refcount_update_diff_items(
const struct list_head *a,
const struct list_head *b)
{
- const struct xfs_refcount_intent *ra;
- const struct xfs_refcount_intent *rb;
-
- ra = container_of(a, struct xfs_refcount_intent, ri_list);
- rb = container_of(b, struct xfs_refcount_intent, ri_list);
+ struct xfs_refcount_intent *ra = ci_entry(a);
+ struct xfs_refcount_intent *rb = ci_entry(b);
return ra->ri_pag->pag_agno - rb->ri_pag->pag_agno;
}
@@ -551,10 +553,9 @@ xfs_refcount_update_finish_item(
struct list_head *item,
struct xfs_btree_cur **state)
{
- struct xfs_refcount_intent *ri;
+ struct xfs_refcount_intent *ri = ci_entry(item);
int error;
- ri = container_of(item, struct xfs_refcount_intent, ri_list);
error = xfs_refcount_finish_one(tp, ri, state);
/* Did we run out of reservation? Requeue what we didn't finish. */
@@ -581,9 +582,7 @@ STATIC void
xfs_refcount_update_cancel_item(
struct list_head *item)
{
- struct xfs_refcount_intent *ri;
-
- ri = container_of(item, struct xfs_refcount_intent, ri_list);
+ struct xfs_refcount_intent *ri = ci_entry(item);
xfs_refcount_update_put_group(ri);
kmem_cache_free(xfs_refcount_intent_cache, ri);
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 6/9] xfs: reuse xfs_refcount_update_cancel_item
2023-12-31 19:55 ` [PATCHSET v2.0 14/17] xfsprogs: refcount log intent cleanups Darrick J. Wong
` (4 preceding siblings ...)
2023-12-27 13:25 ` [PATCH 5/9] xfs: add a ci_entry helper Darrick J. Wong
@ 2023-12-27 13:25 ` Darrick J. Wong
2023-12-27 13:25 ` [PATCH 7/9] xfs: don't bother calling xfs_refcount_finish_one_cleanup in xfs_refcount_finish_one Darrick J. Wong
` (2 subsequent siblings)
8 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:25 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Reuse xfs_refcount_update_cancel_item to put the AG/RTG and free the
item in a few places that currently open code the logic.
Inspired-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/defer_item.c | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/libxfs/defer_item.c b/libxfs/defer_item.c
index 471e4f6867d..e056c3b449b 100644
--- a/libxfs/defer_item.c
+++ b/libxfs/defer_item.c
@@ -545,6 +545,17 @@ xfs_refcount_update_put_group(
xfs_perag_intent_put(ri->ri_pag);
}
+/* Cancel a deferred refcount update. */
+STATIC void
+xfs_refcount_update_cancel_item(
+ struct list_head *item)
+{
+ struct xfs_refcount_intent *ri = ci_entry(item);
+
+ xfs_refcount_update_put_group(ri);
+ kmem_cache_free(xfs_refcount_intent_cache, ri);
+}
+
/* Process a deferred refcount update. */
STATIC int
xfs_refcount_update_finish_item(
@@ -565,8 +576,7 @@ xfs_refcount_update_finish_item(
return -EAGAIN;
}
- xfs_refcount_update_put_group(ri);
- kmem_cache_free(xfs_refcount_intent_cache, ri);
+ xfs_refcount_update_cancel_item(item);
return error;
}
@@ -577,17 +587,6 @@ xfs_refcount_update_abort_intent(
{
}
-/* Cancel a deferred refcount update. */
-STATIC void
-xfs_refcount_update_cancel_item(
- struct list_head *item)
-{
- struct xfs_refcount_intent *ri = ci_entry(item);
-
- xfs_refcount_update_put_group(ri);
- kmem_cache_free(xfs_refcount_intent_cache, ri);
-}
-
const struct xfs_defer_op_type xfs_refcount_update_defer_type = {
.name = "refcount",
.create_intent = xfs_refcount_update_create_intent,
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 7/9] xfs: don't bother calling xfs_refcount_finish_one_cleanup in xfs_refcount_finish_one
2023-12-31 19:55 ` [PATCHSET v2.0 14/17] xfsprogs: refcount log intent cleanups Darrick J. Wong
` (5 preceding siblings ...)
2023-12-27 13:25 ` [PATCH 6/9] xfs: reuse xfs_refcount_update_cancel_item Darrick J. Wong
@ 2023-12-27 13:25 ` Darrick J. Wong
2023-12-27 13:25 ` [PATCH 8/9] xfs: simplify usage of the rcur local variable " Darrick J. Wong
2023-12-27 13:26 ` [PATCH 9/9] xfs: move xfs_refcount_update_defer_add to xfs_refcount_item.c Darrick J. Wong
8 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:25 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
In xfs_refcount_finish_one we know the cursor is non-zero when calling
xfs_refcount_finish_one_cleanup and we pass a 0 error variable. This
means xfs_refcount_finish_one_cleanup is just doing a
xfs_btree_del_cursor.
Open code that and move xfs_refcount_finish_one_cleanup to
fs/xfs/xfs_refcount_item.c.
Inspired-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/defer_item.c | 17 +++++++++++++++++
libxfs/xfs_refcount.c | 19 +------------------
libxfs/xfs_refcount.h | 2 --
3 files changed, 18 insertions(+), 20 deletions(-)
diff --git a/libxfs/defer_item.c b/libxfs/defer_item.c
index e056c3b449b..58a18c7876d 100644
--- a/libxfs/defer_item.c
+++ b/libxfs/defer_item.c
@@ -587,6 +587,23 @@ xfs_refcount_update_abort_intent(
{
}
+/* Clean up after calling xfs_refcount_finish_one. */
+STATIC void
+xfs_refcount_finish_one_cleanup(
+ struct xfs_trans *tp,
+ struct xfs_btree_cur *rcur,
+ int error)
+{
+ struct xfs_buf *agbp;
+
+ if (rcur == NULL)
+ return;
+ agbp = rcur->bc_ag.agbp;
+ xfs_btree_del_cursor(rcur, error);
+ if (error)
+ xfs_trans_brelse(tp, agbp);
+}
+
const struct xfs_defer_op_type xfs_refcount_update_defer_type = {
.name = "refcount",
.create_intent = xfs_refcount_update_create_intent,
diff --git a/libxfs/xfs_refcount.c b/libxfs/xfs_refcount.c
index 3ae68ea22e3..635bbf7f99d 100644
--- a/libxfs/xfs_refcount.c
+++ b/libxfs/xfs_refcount.c
@@ -1299,23 +1299,6 @@ xfs_refcount_adjust(
return error;
}
-/* Clean up after calling xfs_refcount_finish_one. */
-void
-xfs_refcount_finish_one_cleanup(
- struct xfs_trans *tp,
- struct xfs_btree_cur *rcur,
- int error)
-{
- struct xfs_buf *agbp;
-
- if (rcur == NULL)
- return;
- agbp = rcur->bc_ag.agbp;
- xfs_btree_del_cursor(rcur, error);
- if (error)
- xfs_trans_brelse(tp, agbp);
-}
-
/*
* Set up a continuation a deferred refcount operation by updating the intent.
* Checks to make sure we're not going to run off the end of the AG.
@@ -1379,7 +1362,7 @@ xfs_refcount_finish_one(
if (rcur != NULL && rcur->bc_ag.pag != ri->ri_pag) {
nr_ops = rcur->bc_ag.refc.nr_ops;
shape_changes = rcur->bc_ag.refc.shape_changes;
- xfs_refcount_finish_one_cleanup(tp, rcur, 0);
+ xfs_btree_del_cursor(rcur, 0);
rcur = NULL;
*pcur = NULL;
}
diff --git a/libxfs/xfs_refcount.h b/libxfs/xfs_refcount.h
index 01a20621192..c94b8f71d40 100644
--- a/libxfs/xfs_refcount.h
+++ b/libxfs/xfs_refcount.h
@@ -82,8 +82,6 @@ void xfs_refcount_increase_extent(struct xfs_trans *tp,
void xfs_refcount_decrease_extent(struct xfs_trans *tp,
struct xfs_bmbt_irec *irec);
-extern void xfs_refcount_finish_one_cleanup(struct xfs_trans *tp,
- struct xfs_btree_cur *rcur, int error);
extern int xfs_refcount_finish_one(struct xfs_trans *tp,
struct xfs_refcount_intent *ri, struct xfs_btree_cur **pcur);
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 8/9] xfs: simplify usage of the rcur local variable in xfs_refcount_finish_one
2023-12-31 19:55 ` [PATCHSET v2.0 14/17] xfsprogs: refcount log intent cleanups Darrick J. Wong
` (6 preceding siblings ...)
2023-12-27 13:25 ` [PATCH 7/9] xfs: don't bother calling xfs_refcount_finish_one_cleanup in xfs_refcount_finish_one Darrick J. Wong
@ 2023-12-27 13:25 ` Darrick J. Wong
2023-12-27 13:26 ` [PATCH 9/9] xfs: move xfs_refcount_update_defer_add to xfs_refcount_item.c Darrick J. Wong
8 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:25 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Only update rcur when we know the final *pcur value.
Inspired-by: Christoph Hellwig <hch@lst.de>
[djwong: don't leave the caller with a dangling ref]
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_refcount.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/libxfs/xfs_refcount.c b/libxfs/xfs_refcount.c
index 635bbf7f99d..5cd279786ce 100644
--- a/libxfs/xfs_refcount.c
+++ b/libxfs/xfs_refcount.c
@@ -1340,7 +1340,7 @@ xfs_refcount_finish_one(
struct xfs_btree_cur **pcur)
{
struct xfs_mount *mp = tp->t_mountp;
- struct xfs_btree_cur *rcur;
+ struct xfs_btree_cur *rcur = *pcur;
struct xfs_buf *agbp = NULL;
int error = 0;
xfs_agblock_t bno;
@@ -1358,7 +1358,6 @@ xfs_refcount_finish_one(
* If we haven't gotten a cursor or the cursor AG doesn't match
* the startblock, get one now.
*/
- rcur = *pcur;
if (rcur != NULL && rcur->bc_ag.pag != ri->ri_pag) {
nr_ops = rcur->bc_ag.refc.nr_ops;
shape_changes = rcur->bc_ag.refc.shape_changes;
@@ -1372,11 +1371,11 @@ xfs_refcount_finish_one(
if (error)
return error;
- rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, ri->ri_pag);
+ *pcur = rcur = xfs_refcountbt_init_cursor(mp, tp, agbp,
+ ri->ri_pag);
rcur->bc_ag.refc.nr_ops = nr_ops;
rcur->bc_ag.refc.shape_changes = shape_changes;
}
- *pcur = rcur;
switch (ri->ri_type) {
case XFS_REFCOUNT_INCREASE:
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 9/9] xfs: move xfs_refcount_update_defer_add to xfs_refcount_item.c
2023-12-31 19:55 ` [PATCHSET v2.0 14/17] xfsprogs: refcount log intent cleanups Darrick J. Wong
` (7 preceding siblings ...)
2023-12-27 13:25 ` [PATCH 8/9] xfs: simplify usage of the rcur local variable " Darrick J. Wong
@ 2023-12-27 13:26 ` Darrick J. Wong
8 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:26 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Move the code that adds the incore xfs_refcount_update_item deferred
work data to a transaction live with the CUI log item code. This means
that the refcount code no longer has to know about the inner workings of
the CUI log items.
As a consequence, we can get rid of the _{get,put}_group helpers.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/defer_item.c | 21 +++++++++------------
libxfs/defer_item.h | 5 +++++
libxfs/xfs_refcount.c | 6 ++----
libxfs/xfs_refcount.h | 3 ---
4 files changed, 16 insertions(+), 19 deletions(-)
diff --git a/libxfs/defer_item.c b/libxfs/defer_item.c
index 58a18c7876d..3956a38b414 100644
--- a/libxfs/defer_item.c
+++ b/libxfs/defer_item.c
@@ -528,21 +528,18 @@ xfs_refcount_update_create_done(
return NULL;
}
-/* Take an active ref to the AG containing the space we're refcounting. */
+/* Add this deferred CUI to the transaction. */
void
-xfs_refcount_update_get_group(
- struct xfs_mount *mp,
+xfs_refcount_defer_add(
+ struct xfs_trans *tp,
struct xfs_refcount_intent *ri)
{
+ struct xfs_mount *mp = tp->t_mountp;
+
+ trace_xfs_refcount_defer(mp, ri);
+
ri->ri_pag = xfs_perag_intent_get(mp, ri->ri_startblock);
-}
-
-/* Release an active AG ref after finishing refcounting work. */
-static inline void
-xfs_refcount_update_put_group(
- struct xfs_refcount_intent *ri)
-{
- xfs_perag_intent_put(ri->ri_pag);
+ xfs_defer_add(tp, &ri->ri_list, &xfs_refcount_update_defer_type);
}
/* Cancel a deferred refcount update. */
@@ -552,7 +549,7 @@ xfs_refcount_update_cancel_item(
{
struct xfs_refcount_intent *ri = ci_entry(item);
- xfs_refcount_update_put_group(ri);
+ xfs_perag_intent_put(ri->ri_pag);
kmem_cache_free(xfs_refcount_intent_cache, ri);
}
diff --git a/libxfs/defer_item.h b/libxfs/defer_item.h
index 3ef31ad0aec..bbb4587b97f 100644
--- a/libxfs/defer_item.h
+++ b/libxfs/defer_item.h
@@ -24,4 +24,9 @@ struct xfs_rmap_intent;
void xfs_rmap_defer_add(struct xfs_trans *tp, struct xfs_rmap_intent *ri);
+struct xfs_refcount_intent;
+
+void xfs_refcount_defer_add(struct xfs_trans *tp,
+ struct xfs_refcount_intent *ri);
+
#endif /* __LIBXFS_DEFER_ITEM_H_ */
diff --git a/libxfs/xfs_refcount.c b/libxfs/xfs_refcount.c
index 5cd279786ce..b094d9a41f6 100644
--- a/libxfs/xfs_refcount.c
+++ b/libxfs/xfs_refcount.c
@@ -23,6 +23,7 @@
#include "xfs_rmap.h"
#include "xfs_ag.h"
#include "xfs_health.h"
+#include "defer_item.h"
struct kmem_cache *xfs_refcount_intent_cache;
@@ -1434,10 +1435,7 @@ __xfs_refcount_add(
ri->ri_startblock = startblock;
ri->ri_blockcount = blockcount;
- trace_xfs_refcount_defer(tp->t_mountp, ri);
-
- xfs_refcount_update_get_group(tp->t_mountp, ri);
- xfs_defer_add(tp, &ri->ri_list, &xfs_refcount_update_defer_type);
+ xfs_refcount_defer_add(tp, ri);
}
/*
diff --git a/libxfs/xfs_refcount.h b/libxfs/xfs_refcount.h
index c94b8f71d40..68acb0b1b4a 100644
--- a/libxfs/xfs_refcount.h
+++ b/libxfs/xfs_refcount.h
@@ -74,9 +74,6 @@ xfs_refcount_check_domain(
return true;
}
-void xfs_refcount_update_get_group(struct xfs_mount *mp,
- struct xfs_refcount_intent *ri);
-
void xfs_refcount_increase_extent(struct xfs_trans *tp,
struct xfs_bmbt_irec *irec);
void xfs_refcount_decrease_extent(struct xfs_trans *tp,
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 01/42] xfs: introduce realtime refcount btree definitions
2023-12-31 19:55 ` [PATCHSET v2.0 15/17] xfsprogs: reflink on the realtime device Darrick J. Wong
@ 2023-12-27 13:26 ` Darrick J. Wong
2023-12-27 13:26 ` [PATCH 02/42] xfs: namespace the maximum length/refcount symbols Darrick J. Wong
` (40 subsequent siblings)
41 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:26 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Add new realtime refcount btree definitions. The realtime refcount btree
will be rooted from a hidden inode, but has its own shape and therefore
needs to have most of its own separate types.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_btree.h | 1 +
libxfs/xfs_format.h | 6 ++++++
libxfs/xfs_types.h | 5 +++--
3 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/libxfs/xfs_btree.h b/libxfs/xfs_btree.h
index 4753a5c8476..f58240adda6 100644
--- a/libxfs/xfs_btree.h
+++ b/libxfs/xfs_btree.h
@@ -65,6 +65,7 @@ union xfs_btree_rec {
#define XFS_BTNUM_REFC ((xfs_btnum_t)XFS_BTNUM_REFCi)
#define XFS_BTNUM_RCBAG ((xfs_btnum_t)XFS_BTNUM_RCBAGi)
#define XFS_BTNUM_RTRMAP ((xfs_btnum_t)XFS_BTNUM_RTRMAPi)
+#define XFS_BTNUM_RTREFC ((xfs_btnum_t)XFS_BTNUM_RTREFCi)
struct xfs_btree_ops;
uint32_t xfs_btree_magic(struct xfs_mount *mp, const struct xfs_btree_ops *ops);
diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
index 1c1910256a9..0dc169fde2e 100644
--- a/libxfs/xfs_format.h
+++ b/libxfs/xfs_format.h
@@ -1815,6 +1815,12 @@ struct xfs_refcount_key {
/* btree pointer type */
typedef __be32 xfs_refcount_ptr_t;
+/*
+ * Realtime Reference Count btree format definitions
+ *
+ * This is a btree for reference count records for realtime volumes
+ */
+#define XFS_RTREFC_CRC_MAGIC 0x52434e54 /* 'RCNT' */
/*
* BMAP Btree format definitions
diff --git a/libxfs/xfs_types.h b/libxfs/xfs_types.h
index b3edc57dc65..4147ba288ec 100644
--- a/libxfs/xfs_types.h
+++ b/libxfs/xfs_types.h
@@ -126,7 +126,7 @@ 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_RCBAGi,
- XFS_BTNUM_RTRMAPi, XFS_BTNUM_MAX
+ XFS_BTNUM_RTRMAPi, XFS_BTNUM_RTREFCi, XFS_BTNUM_MAX
} xfs_btnum_t;
#define XFS_BTNUM_STRINGS \
@@ -138,7 +138,8 @@ typedef enum {
{ XFS_BTNUM_FINOi, "finobt" }, \
{ XFS_BTNUM_REFCi, "refcbt" }, \
{ XFS_BTNUM_RCBAGi, "rcbagbt" }, \
- { XFS_BTNUM_RTRMAPi, "rtrmapbt" }
+ { XFS_BTNUM_RTRMAPi, "rtrmapbt" }, \
+ { XFS_BTNUM_RTREFCi, "rtrefcbt" }
struct xfs_name {
const unsigned char *name;
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 02/42] xfs: namespace the maximum length/refcount symbols
2023-12-31 19:55 ` [PATCHSET v2.0 15/17] xfsprogs: reflink on the realtime device Darrick J. Wong
2023-12-27 13:26 ` [PATCH 01/42] xfs: introduce realtime refcount btree definitions Darrick J. Wong
@ 2023-12-27 13:26 ` Darrick J. Wong
2023-12-27 13:26 ` [PATCH 03/42] xfs: define the on-disk realtime refcount btree format Darrick J. Wong
` (39 subsequent siblings)
41 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:26 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Actually namespace these variables properly, so that readers can tell
that this is an XFS symbol, and that it's for the refcount
functionality.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_format.h | 4 ++--
libxfs/xfs_refcount.c | 18 +++++++++---------
repair/rmap.c | 4 ++--
repair/scan.c | 2 +-
4 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
index 0dc169fde2e..473bdc2a1ad 100644
--- a/libxfs/xfs_format.h
+++ b/libxfs/xfs_format.h
@@ -1809,8 +1809,8 @@ struct xfs_refcount_key {
__be32 rc_startblock; /* starting block number */
};
-#define MAXREFCOUNT ((xfs_nlink_t)~0U)
-#define MAXREFCEXTLEN ((xfs_extlen_t)~0U)
+#define XFS_REFC_REFCOUNT_MAX ((xfs_nlink_t)~0U)
+#define XFS_REFC_LEN_MAX ((xfs_extlen_t)~0U)
/* btree pointer type */
typedef __be32 xfs_refcount_ptr_t;
diff --git a/libxfs/xfs_refcount.c b/libxfs/xfs_refcount.c
index b094d9a41f6..e98d5ea6ca2 100644
--- a/libxfs/xfs_refcount.c
+++ b/libxfs/xfs_refcount.c
@@ -127,7 +127,7 @@ xfs_refcount_check_irec(
struct xfs_perag *pag,
const struct xfs_refcount_irec *irec)
{
- if (irec->rc_blockcount == 0 || irec->rc_blockcount > MAXREFCEXTLEN)
+ if (irec->rc_blockcount == 0 || irec->rc_blockcount > XFS_REFC_LEN_MAX)
return __this_address;
if (!xfs_refcount_check_domain(irec))
@@ -137,7 +137,7 @@ xfs_refcount_check_irec(
if (!xfs_verify_agbext(pag, irec->rc_startblock, irec->rc_blockcount))
return __this_address;
- if (irec->rc_refcount == 0 || irec->rc_refcount > MAXREFCOUNT)
+ if (irec->rc_refcount == 0 || irec->rc_refcount > XFS_REFC_REFCOUNT_MAX)
return __this_address;
return NULL;
@@ -852,9 +852,9 @@ xfs_refc_merge_refcount(
const struct xfs_refcount_irec *irec,
enum xfs_refc_adjust_op adjust)
{
- /* Once a record hits MAXREFCOUNT, it is pinned there forever */
- if (irec->rc_refcount == MAXREFCOUNT)
- return MAXREFCOUNT;
+ /* Once a record hits XFS_REFC_REFCOUNT_MAX, it is pinned forever */
+ if (irec->rc_refcount == XFS_REFC_REFCOUNT_MAX)
+ return XFS_REFC_REFCOUNT_MAX;
return irec->rc_refcount + adjust;
}
@@ -897,7 +897,7 @@ xfs_refc_want_merge_center(
* hence we need to catch u32 addition overflows here.
*/
ulen += cleft->rc_blockcount + right->rc_blockcount;
- if (ulen >= MAXREFCEXTLEN)
+ if (ulen >= XFS_REFC_LEN_MAX)
return false;
*ulenp = ulen;
@@ -932,7 +932,7 @@ xfs_refc_want_merge_left(
* hence we need to catch u32 addition overflows here.
*/
ulen += cleft->rc_blockcount;
- if (ulen >= MAXREFCEXTLEN)
+ if (ulen >= XFS_REFC_LEN_MAX)
return false;
return true;
@@ -966,7 +966,7 @@ xfs_refc_want_merge_right(
* hence we need to catch u32 addition overflows here.
*/
ulen += cright->rc_blockcount;
- if (ulen >= MAXREFCEXTLEN)
+ if (ulen >= XFS_REFC_LEN_MAX)
return false;
return true;
@@ -1196,7 +1196,7 @@ xfs_refcount_adjust_extents(
* Adjust the reference count and either update the tree
* (incr) or free the blocks (decr).
*/
- if (ext.rc_refcount == MAXREFCOUNT)
+ if (ext.rc_refcount == XFS_REFC_REFCOUNT_MAX)
goto skip;
ext.rc_refcount += adj;
trace_xfs_refcount_modify_extent(cur, &ext);
diff --git a/repair/rmap.c b/repair/rmap.c
index 1312a0dde34..6fd537f533f 100644
--- a/repair/rmap.c
+++ b/repair/rmap.c
@@ -1004,8 +1004,8 @@ refcount_emit(
agno, agbno, len, nr_rmaps);
rlrec.rc_startblock = agbno;
rlrec.rc_blockcount = len;
- if (nr_rmaps > MAXREFCOUNT)
- nr_rmaps = MAXREFCOUNT;
+ if (nr_rmaps > XFS_REFC_REFCOUNT_MAX)
+ nr_rmaps = XFS_REFC_REFCOUNT_MAX;
rlrec.rc_refcount = nr_rmaps;
rlrec.rc_domain = XFS_REFC_DOMAIN_SHARED;
diff --git a/repair/scan.c b/repair/scan.c
index 2f414898078..ba634af8bb1 100644
--- a/repair/scan.c
+++ b/repair/scan.c
@@ -1895,7 +1895,7 @@ _("extent (%u/%u) len %u claimed, state is %d\n"),
break;
}
}
- } else if (nr < 2 || nr > MAXREFCOUNT) {
+ } else if (nr < 2 || nr > XFS_REFC_REFCOUNT_MAX) {
do_warn(
_("invalid reference count %u in record %u of %s btree block %u/%u\n"),
nr, i, name, agno, bno);
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 03/42] xfs: define the on-disk realtime refcount btree format
2023-12-31 19:55 ` [PATCHSET v2.0 15/17] xfsprogs: reflink on the realtime device Darrick J. Wong
2023-12-27 13:26 ` [PATCH 01/42] xfs: introduce realtime refcount btree definitions Darrick J. Wong
2023-12-27 13:26 ` [PATCH 02/42] xfs: namespace the maximum length/refcount symbols Darrick J. Wong
@ 2023-12-27 13:26 ` Darrick J. Wong
2023-12-27 13:27 ` [PATCH 04/42] xfs: realtime refcount btree transaction reservations Darrick J. Wong
` (38 subsequent siblings)
41 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:26 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Start filling out the rtrefcount btree implementation. Start with the
on-disk btree format; add everything needed to read, write and
manipulate refcount btree blocks. This prepares the way for connecting
the btree operations implementation.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
include/libxfs.h | 1
include/xfs_mount.h | 9 +
libxfs/Makefile | 2
libxfs/init.c | 6 +
libxfs/xfs_btree.c | 5 +
libxfs/xfs_btree.h | 11 +
libxfs/xfs_format.h | 3
libxfs/xfs_ondisk.h | 1
libxfs/xfs_rtrefcount_btree.c | 310 +++++++++++++++++++++++++++++++++++++++++
libxfs/xfs_rtrefcount_btree.h | 71 +++++++++
libxfs/xfs_sb.c | 8 +
libxfs/xfs_shared.h | 2
12 files changed, 424 insertions(+), 5 deletions(-)
create mode 100644 libxfs/xfs_rtrefcount_btree.c
create mode 100644 libxfs/xfs_rtrefcount_btree.h
diff --git a/include/libxfs.h b/include/libxfs.h
index 46003fe641d..83cee8a6e4c 100644
--- a/include/libxfs.h
+++ b/include/libxfs.h
@@ -83,6 +83,7 @@ struct iomap;
#include "xfs_rmap_btree.h"
#include "xfs_rmap.h"
#include "xfs_refcount_btree.h"
+#include "xfs_rtrefcount_btree.h"
#include "xfs_refcount.h"
#include "xfs_btree_staging.h"
#include "xfs_rtbitmap.h"
diff --git a/include/xfs_mount.h b/include/xfs_mount.h
index 07f9e33b8b2..916da55793b 100644
--- a/include/xfs_mount.h
+++ b/include/xfs_mount.h
@@ -96,11 +96,14 @@ typedef struct xfs_mount {
uint m_rtrmap_mnr[2]; /* min rtrmap btree records */
uint m_refc_mxr[2]; /* max refc btree records */
uint m_refc_mnr[2]; /* min refc btree records */
+ unsigned int m_rtrefc_mxr[2]; /* max rtrefc btree records */
+ unsigned int m_rtrefc_mnr[2]; /* min rtrefc btree records */
uint m_alloc_maxlevels; /* max alloc btree levels */
uint m_bm_maxlevels[2]; /* max bmap btree levels */
uint m_rmap_maxlevels; /* max rmap btree levels */
uint m_rtrmap_maxlevels; /* max rtrmap btree level */
uint m_refc_maxlevels; /* max refc btree levels */
+ unsigned int m_rtrefc_maxlevels; /* max rtrefc btree level */
unsigned int m_agbtree_maxlevels; /* max level of all AG btrees */
unsigned int m_rtbtree_maxlevels; /* max level of all rt btrees */
xfs_extlen_t m_ag_prealloc_blocks; /* reserved ag blocks */
@@ -242,6 +245,12 @@ static inline bool xfs_has_rtrmapbt(struct xfs_mount *mp)
xfs_has_rmapbt(mp);
}
+static inline bool xfs_has_rtreflink(struct xfs_mount *mp)
+{
+ return xfs_has_metadir(mp) && xfs_has_realtime(mp) &&
+ xfs_has_reflink(mp);
+}
+
/* Kernel mount features that we don't support */
#define __XFS_UNSUPP_FEAT(name) \
static inline bool xfs_has_ ## name (struct xfs_mount *mp) \
diff --git a/libxfs/Makefile b/libxfs/Makefile
index 0b3e8c896bd..6faeca34562 100644
--- a/libxfs/Makefile
+++ b/libxfs/Makefile
@@ -59,6 +59,7 @@ HFILES = \
xfs_quota_defs.h \
xfs_refcount.h \
xfs_refcount_btree.h \
+ xfs_rtrefcount_btree.h \
xfs_rmap.h \
xfs_rmap_btree.h \
xfs_rtbitmap.h \
@@ -118,6 +119,7 @@ CFILES = cache.c \
xfs_parent.c \
xfs_refcount.c \
xfs_refcount_btree.c \
+ xfs_rtrefcount_btree.c \
xfs_rmap.c \
xfs_rmap_btree.c \
xfs_rtbitmap.c \
diff --git a/libxfs/init.c b/libxfs/init.c
index 18bd2116c50..36b4b486145 100644
--- a/libxfs/init.c
+++ b/libxfs/init.c
@@ -650,7 +650,10 @@ static inline void
xfs_rtbtree_compute_maxlevels(
struct xfs_mount *mp)
{
- mp->m_rtbtree_maxlevels = mp->m_rtrmap_maxlevels;
+ unsigned int levels;
+
+ levels = max(mp->m_rtrmap_maxlevels, mp->m_rtrefc_maxlevels);
+ mp->m_rtbtree_maxlevels = levels;
}
/* Compute maximum possible height of all btrees. */
@@ -668,6 +671,7 @@ libxfs_compute_all_maxlevels(
xfs_rmapbt_compute_maxlevels(mp);
xfs_rtrmapbt_compute_maxlevels(mp);
xfs_refcountbt_compute_maxlevels(mp);
+ xfs_rtrefcountbt_compute_maxlevels(mp);
xfs_agbtree_compute_maxlevels(mp);
xfs_rtbtree_compute_maxlevels(mp);
diff --git a/libxfs/xfs_btree.c b/libxfs/xfs_btree.c
index 450c48ceaf1..ebb409e4280 100644
--- a/libxfs/xfs_btree.c
+++ b/libxfs/xfs_btree.c
@@ -33,6 +33,7 @@
#include "xfs_bmap.h"
#include "xfs_rmap.h"
#include "xfs_imeta.h"
+#include "xfs_rtrefcount_btree.h"
/*
* Btree magic numbers.
@@ -5534,6 +5535,9 @@ xfs_btree_init_cur_caches(void)
if (error)
goto err;
error = xfs_rtrmapbt_init_cur_cache();
+ if (error)
+ goto err;
+ error = xfs_rtrefcountbt_init_cur_cache();
if (error)
goto err;
@@ -5553,6 +5557,7 @@ xfs_btree_destroy_cur_caches(void)
xfs_rmapbt_destroy_cur_cache();
xfs_refcountbt_destroy_cur_cache();
xfs_rtrmapbt_destroy_cur_cache();
+ xfs_rtrefcountbt_destroy_cur_cache();
}
/* Move the btree cursor before the first record. */
diff --git a/libxfs/xfs_btree.h b/libxfs/xfs_btree.h
index f58240adda6..64e37a0ffb7 100644
--- a/libxfs/xfs_btree.h
+++ b/libxfs/xfs_btree.h
@@ -229,6 +229,11 @@ union xfs_btree_irec {
struct xfs_refcount_irec rc;
};
+struct xbtree_refc {
+ unsigned int nr_ops; /* # record updates */
+ unsigned int shape_changes; /* # of extent splits */
+};
+
/* Per-AG btree information. */
struct xfs_btree_cur_ag {
struct xfs_perag *pag;
@@ -237,10 +242,7 @@ struct xfs_btree_cur_ag {
struct xbtree_afakeroot *afake; /* for staging cursor */
};
union {
- struct {
- unsigned int nr_ops; /* # record updates */
- unsigned int shape_changes; /* # of extent splits */
- } refc;
+ struct xbtree_refc refc;
struct {
bool active; /* allocation cursor state */
} abt;
@@ -261,6 +263,7 @@ struct xfs_btree_cur_ino {
/* For extent swap, ignore owner check in verifier */
#define XFS_BTCUR_BMBT_INVALID_OWNER (1 << 1)
+ struct xbtree_refc refc;
};
/* In-memory btree information */
diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
index 473bdc2a1ad..c938b814c43 100644
--- a/libxfs/xfs_format.h
+++ b/libxfs/xfs_format.h
@@ -1822,6 +1822,9 @@ typedef __be32 xfs_refcount_ptr_t;
*/
#define XFS_RTREFC_CRC_MAGIC 0x52434e54 /* 'RCNT' */
+/* inode-rooted btree pointer type */
+typedef __be64 xfs_rtrefcount_ptr_t;
+
/*
* BMAP Btree format definitions
*
diff --git a/libxfs/xfs_ondisk.h b/libxfs/xfs_ondisk.h
index 102a3574fc6..242b6831256 100644
--- a/libxfs/xfs_ondisk.h
+++ b/libxfs/xfs_ondisk.h
@@ -79,6 +79,7 @@ xfs_check_ondisk_structs(void)
XFS_CHECK_STRUCT_SIZE(struct xfs_rtbuf_blkinfo, 48);
XFS_CHECK_STRUCT_SIZE(xfs_rtrmap_ptr_t, 8);
XFS_CHECK_STRUCT_SIZE(struct xfs_rtrmap_root, 4);
+ XFS_CHECK_STRUCT_SIZE(xfs_rtrefcount_ptr_t, 8);
/*
* m68k has problems with xfs_attr_leaf_name_remote_t, but we pad it to
diff --git a/libxfs/xfs_rtrefcount_btree.c b/libxfs/xfs_rtrefcount_btree.c
new file mode 100644
index 00000000000..e0db4cbf34c
--- /dev/null
+++ b/libxfs/xfs_rtrefcount_btree.c
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2021-2024 Oracle. All Rights Reserved.
+ * Author: Darrick J. Wong <djwong@kernel.org>
+ */
+#include "libxfs_priv.h"
+#include "xfs_fs.h"
+#include "xfs_shared.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_bit.h"
+#include "xfs_sb.h"
+#include "xfs_mount.h"
+#include "xfs_defer.h"
+#include "xfs_inode.h"
+#include "xfs_trans.h"
+#include "xfs_alloc.h"
+#include "xfs_btree.h"
+#include "xfs_btree_staging.h"
+#include "xfs_rtrefcount_btree.h"
+#include "xfs_trace.h"
+#include "xfs_cksum.h"
+#include "xfs_rtgroup.h"
+#include "xfs_rtbitmap.h"
+
+static struct kmem_cache *xfs_rtrefcountbt_cur_cache;
+
+/*
+ * Realtime Reference Count btree.
+ *
+ * This is a btree used to track the owner(s) of a given extent in the realtime
+ * device. See the comments in xfs_refcount_btree.c for more information.
+ *
+ * This tree is basically the same as the regular refcount btree except that
+ * it's rooted in an inode.
+ */
+
+static struct xfs_btree_cur *
+xfs_rtrefcountbt_dup_cursor(
+ struct xfs_btree_cur *cur)
+{
+ struct xfs_btree_cur *new;
+
+ new = xfs_rtrefcountbt_init_cursor(cur->bc_mp, cur->bc_tp,
+ cur->bc_ino.rtg, cur->bc_ino.ip);
+
+ /* Copy the flags values since init cursor doesn't get them. */
+ new->bc_ino.flags = cur->bc_ino.flags;
+
+ return new;
+}
+
+static xfs_failaddr_t
+xfs_rtrefcountbt_verify(
+ struct xfs_buf *bp)
+{
+ struct xfs_mount *mp = bp->b_target->bt_mount;
+ struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
+ xfs_failaddr_t fa;
+ int level;
+
+ if (!xfs_verify_magic(bp, block->bb_magic))
+ return __this_address;
+
+ if (!xfs_has_reflink(mp))
+ 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 > mp->m_rtrefc_maxlevels)
+ return __this_address;
+
+ return xfs_btree_lblock_verify(bp, mp->m_rtrefc_mxr[level != 0]);
+}
+
+static void
+xfs_rtrefcountbt_read_verify(
+ struct xfs_buf *bp)
+{
+ xfs_failaddr_t fa;
+
+ if (!xfs_btree_lblock_verify_crc(bp))
+ xfs_verifier_error(bp, -EFSBADCRC, __this_address);
+ else {
+ fa = xfs_rtrefcountbt_verify(bp);
+ if (fa)
+ xfs_verifier_error(bp, -EFSCORRUPTED, fa);
+ }
+
+ if (bp->b_error)
+ trace_xfs_btree_corrupt(bp, _RET_IP_);
+}
+
+static void
+xfs_rtrefcountbt_write_verify(
+ struct xfs_buf *bp)
+{
+ xfs_failaddr_t fa;
+
+ fa = xfs_rtrefcountbt_verify(bp);
+ if (fa) {
+ trace_xfs_btree_corrupt(bp, _RET_IP_);
+ xfs_verifier_error(bp, -EFSCORRUPTED, fa);
+ return;
+ }
+ xfs_btree_lblock_calc_crc(bp);
+
+}
+
+const struct xfs_buf_ops xfs_rtrefcountbt_buf_ops = {
+ .name = "xfs_rtrefcountbt",
+ .magic = { 0, cpu_to_be32(XFS_RTREFC_CRC_MAGIC) },
+ .verify_read = xfs_rtrefcountbt_read_verify,
+ .verify_write = xfs_rtrefcountbt_write_verify,
+ .verify_struct = xfs_rtrefcountbt_verify,
+};
+
+const struct xfs_btree_ops xfs_rtrefcountbt_ops = {
+ .rec_len = sizeof(struct xfs_refcount_rec),
+ .key_len = sizeof(struct xfs_refcount_key),
+ .lru_refs = XFS_REFC_BTREE_REF,
+ .geom_flags = XFS_BTREE_LONG_PTRS | XFS_BTREE_ROOT_IN_INODE |
+ XFS_BTREE_CRC_BLOCKS | XFS_BTREE_IROOT_RECORDS,
+
+ .dup_cursor = xfs_rtrefcountbt_dup_cursor,
+ .buf_ops = &xfs_rtrefcountbt_buf_ops,
+};
+
+/* Initialize a new rt refcount btree cursor. */
+static struct xfs_btree_cur *
+xfs_rtrefcountbt_init_common(
+ struct xfs_mount *mp,
+ struct xfs_trans *tp,
+ struct xfs_rtgroup *rtg,
+ struct xfs_inode *ip)
+{
+ struct xfs_btree_cur *cur;
+
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
+
+ cur = xfs_btree_alloc_cursor(mp, tp, XFS_BTNUM_RTREFC,
+ &xfs_rtrefcountbt_ops, mp->m_rtrefc_maxlevels,
+ xfs_rtrefcountbt_cur_cache);
+ cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_refcbt_2);
+
+ cur->bc_ino.ip = ip;
+ cur->bc_ino.allocated = 0;
+ cur->bc_ino.flags = 0;
+ cur->bc_ino.refc.nr_ops = 0;
+ cur->bc_ino.refc.shape_changes = 0;
+
+ cur->bc_ino.rtg = xfs_rtgroup_hold(rtg);
+ return cur;
+}
+
+/* Allocate a new rt refcount btree cursor. */
+struct xfs_btree_cur *
+xfs_rtrefcountbt_init_cursor(
+ struct xfs_mount *mp,
+ struct xfs_trans *tp,
+ struct xfs_rtgroup *rtg,
+ struct xfs_inode *ip)
+{
+ struct xfs_btree_cur *cur;
+ struct xfs_ifork *ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK);
+
+ cur = xfs_rtrefcountbt_init_common(mp, tp, rtg, ip);
+ cur->bc_nlevels = be16_to_cpu(ifp->if_broot->bb_level) + 1;
+ cur->bc_ino.forksize = xfs_inode_fork_size(ip, XFS_DATA_FORK);
+ cur->bc_ino.whichfork = XFS_DATA_FORK;
+ return cur;
+}
+
+/* Create a new rt reverse mapping btree cursor with a fake root for staging. */
+struct xfs_btree_cur *
+xfs_rtrefcountbt_stage_cursor(
+ struct xfs_mount *mp,
+ struct xfs_rtgroup *rtg,
+ struct xfs_inode *ip,
+ struct xbtree_ifakeroot *ifake)
+{
+ struct xfs_btree_cur *cur;
+
+ cur = xfs_rtrefcountbt_init_common(mp, NULL, rtg, ip);
+ cur->bc_nlevels = ifake->if_levels;
+ cur->bc_ino.forksize = ifake->if_fork_size;
+ cur->bc_ino.whichfork = -1;
+ xfs_btree_stage_ifakeroot(cur, ifake, NULL);
+ return cur;
+}
+
+/*
+ * Install a new rt reverse mapping btree root. Caller is responsible for
+ * invalidating and freeing the old btree blocks.
+ */
+void
+xfs_rtrefcountbt_commit_staged_btree(
+ struct xfs_btree_cur *cur,
+ struct xfs_trans *tp)
+{
+ struct xbtree_ifakeroot *ifake = cur->bc_ino.ifake;
+ struct xfs_ifork *ifp;
+ int flags = XFS_ILOG_CORE | XFS_ILOG_DBROOT;
+
+ ASSERT(cur->bc_flags & XFS_BTREE_STAGING);
+
+ /*
+ * Free any resources hanging off the real fork, then shallow-copy the
+ * staging fork's contents into the real fork to transfer everything
+ * we just built.
+ */
+ ifp = xfs_ifork_ptr(cur->bc_ino.ip, XFS_DATA_FORK);
+ xfs_idestroy_fork(ifp);
+ memcpy(ifp, ifake->if_fork, sizeof(struct xfs_ifork));
+
+ xfs_trans_log_inode(tp, cur->bc_ino.ip, flags);
+ xfs_btree_commit_ifakeroot(cur, tp, XFS_DATA_FORK,
+ &xfs_rtrefcountbt_ops);
+}
+
+/* Calculate number of records in a realtime refcount btree block. */
+static inline unsigned int
+xfs_rtrefcountbt_block_maxrecs(
+ unsigned int blocklen,
+ bool leaf)
+{
+
+ if (leaf)
+ return blocklen / sizeof(struct xfs_refcount_rec);
+ return blocklen / (sizeof(struct xfs_refcount_key) +
+ sizeof(xfs_rtrefcount_ptr_t));
+}
+
+/*
+ * Calculate number of records in an refcount btree block.
+ */
+unsigned int
+xfs_rtrefcountbt_maxrecs(
+ struct xfs_mount *mp,
+ unsigned int blocklen,
+ bool leaf)
+{
+ blocklen -= XFS_RTREFCOUNT_BLOCK_LEN;
+ return xfs_rtrefcountbt_block_maxrecs(blocklen, leaf);
+}
+
+/* Compute the max possible height for realtime refcount btrees. */
+unsigned int
+xfs_rtrefcountbt_maxlevels_ondisk(void)
+{
+ unsigned int minrecs[2];
+ unsigned int blocklen;
+
+ blocklen = XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_LBLOCK_CRC_LEN;
+
+ minrecs[0] = xfs_rtrefcountbt_block_maxrecs(blocklen, true) / 2;
+ minrecs[1] = xfs_rtrefcountbt_block_maxrecs(blocklen, false) / 2;
+
+ /* We need at most one record for every block in an rt group. */
+ return xfs_btree_compute_maxlevels(minrecs, XFS_MAX_RGBLOCKS);
+}
+
+int __init
+xfs_rtrefcountbt_init_cur_cache(void)
+{
+ xfs_rtrefcountbt_cur_cache = kmem_cache_create("xfs_rtrefcountbt_cur",
+ xfs_btree_cur_sizeof(
+ xfs_rtrefcountbt_maxlevels_ondisk()),
+ 0, 0, NULL);
+
+ if (!xfs_rtrefcountbt_cur_cache)
+ return -ENOMEM;
+ return 0;
+}
+
+void
+xfs_rtrefcountbt_destroy_cur_cache(void)
+{
+ kmem_cache_destroy(xfs_rtrefcountbt_cur_cache);
+ xfs_rtrefcountbt_cur_cache = NULL;
+}
+
+/* Compute the maximum height of a realtime refcount btree. */
+void
+xfs_rtrefcountbt_compute_maxlevels(
+ struct xfs_mount *mp)
+{
+ unsigned int d_maxlevels, r_maxlevels;
+
+ if (!xfs_has_rtreflink(mp)) {
+ mp->m_rtrefc_maxlevels = 0;
+ return;
+ }
+
+ /*
+ * The realtime refcountbt lives on the data device, which means that
+ * its maximum height is constrained by the size of the data device and
+ * the height required to store one refcount record for each rtextent
+ * in an rt group.
+ */
+ d_maxlevels = xfs_btree_space_to_height(mp->m_rtrefc_mnr,
+ mp->m_sb.sb_dblocks);
+ r_maxlevels = xfs_btree_compute_maxlevels(mp->m_rtrefc_mnr,
+ xfs_rtb_to_rtx(mp, mp->m_sb.sb_rgblocks));
+
+ /* Add one level to handle the inode root level. */
+ mp->m_rtrefc_maxlevels = min(d_maxlevels, r_maxlevels) + 1;
+}
diff --git a/libxfs/xfs_rtrefcount_btree.h b/libxfs/xfs_rtrefcount_btree.h
new file mode 100644
index 00000000000..6d23ab3a9ad
--- /dev/null
+++ b/libxfs/xfs_rtrefcount_btree.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2021-2024 Oracle. All Rights Reserved.
+ * Author: Darrick J. Wong <djwong@kernel.org>
+ */
+#ifndef __XFS_RTREFCOUNT_BTREE_H__
+#define __XFS_RTREFCOUNT_BTREE_H__
+
+struct xfs_buf;
+struct xfs_btree_cur;
+struct xfs_mount;
+struct xbtree_ifakeroot;
+struct xfs_rtgroup;
+
+/* refcounts only exist on crc enabled filesystems */
+#define XFS_RTREFCOUNT_BLOCK_LEN XFS_BTREE_LBLOCK_CRC_LEN
+
+struct xfs_btree_cur *xfs_rtrefcountbt_init_cursor(struct xfs_mount *mp,
+ struct xfs_trans *tp, struct xfs_rtgroup *rtg,
+ struct xfs_inode *ip);
+struct xfs_btree_cur *xfs_rtrefcountbt_stage_cursor(struct xfs_mount *mp,
+ struct xfs_rtgroup *rtg, struct xfs_inode *ip,
+ struct xbtree_ifakeroot *ifake);
+void xfs_rtrefcountbt_commit_staged_btree(struct xfs_btree_cur *cur,
+ struct xfs_trans *tp);
+unsigned int xfs_rtrefcountbt_maxrecs(struct xfs_mount *mp,
+ unsigned int blocklen, bool leaf);
+void xfs_rtrefcountbt_compute_maxlevels(struct xfs_mount *mp);
+
+/*
+ * Addresses of records, keys, and pointers within an incore rtrefcountbt block.
+ *
+ * (note that some of these may appear unused, but they are used in userspace)
+ */
+static inline struct xfs_refcount_rec *
+xfs_rtrefcount_rec_addr(
+ struct xfs_btree_block *block,
+ unsigned int index)
+{
+ return (struct xfs_refcount_rec *)
+ ((char *)block + XFS_RTREFCOUNT_BLOCK_LEN +
+ (index - 1) * sizeof(struct xfs_refcount_rec));
+}
+
+static inline struct xfs_refcount_key *
+xfs_rtrefcount_key_addr(
+ struct xfs_btree_block *block,
+ unsigned int index)
+{
+ return (struct xfs_refcount_key *)
+ ((char *)block + XFS_RTREFCOUNT_BLOCK_LEN +
+ (index - 1) * sizeof(struct xfs_refcount_key));
+}
+
+static inline xfs_rtrefcount_ptr_t *
+xfs_rtrefcount_ptr_addr(
+ struct xfs_btree_block *block,
+ unsigned int index,
+ unsigned int maxrecs)
+{
+ return (xfs_rtrefcount_ptr_t *)
+ ((char *)block + XFS_RTREFCOUNT_BLOCK_LEN +
+ maxrecs * sizeof(struct xfs_refcount_key) +
+ (index - 1) * sizeof(xfs_rtrefcount_ptr_t));
+}
+
+unsigned int xfs_rtrefcountbt_maxlevels_ondisk(void);
+int __init xfs_rtrefcountbt_init_cur_cache(void);
+void xfs_rtrefcountbt_destroy_cur_cache(void);
+
+#endif /* __XFS_RTREFCOUNT_BTREE_H__ */
diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c
index 891b71190d5..4e3b481327c 100644
--- a/libxfs/xfs_sb.c
+++ b/libxfs/xfs_sb.c
@@ -27,6 +27,7 @@
#include "xfs_swapext.h"
#include "xfs_rtgroup.h"
#include "xfs_rtrmap_btree.h"
+#include "xfs_rtrefcount_btree.h"
/*
* Physical superblock buffer manipulations. Shared with libxfs in userspace.
@@ -1134,6 +1135,13 @@ xfs_sb_mount_common(
mp->m_refc_mnr[0] = mp->m_refc_mxr[0] / 2;
mp->m_refc_mnr[1] = mp->m_refc_mxr[1] / 2;
+ mp->m_rtrefc_mxr[0] = xfs_rtrefcountbt_maxrecs(mp, sbp->sb_blocksize,
+ true);
+ mp->m_rtrefc_mxr[1] = xfs_rtrefcountbt_maxrecs(mp, sbp->sb_blocksize,
+ false);
+ mp->m_rtrefc_mnr[0] = mp->m_rtrefc_mxr[0] / 2;
+ mp->m_rtrefc_mnr[1] = mp->m_rtrefc_mxr[1] / 2;
+
mp->m_bsize = XFS_FSB_TO_BB(mp, 1);
mp->m_alloc_set_aside = xfs_alloc_set_aside(mp);
mp->m_ag_max_usable = xfs_alloc_ag_max_usable(mp);
diff --git a/libxfs/xfs_shared.h b/libxfs/xfs_shared.h
index adb742267c9..3a7f92a9ac7 100644
--- a/libxfs/xfs_shared.h
+++ b/libxfs/xfs_shared.h
@@ -42,6 +42,7 @@ extern const struct xfs_buf_ops xfs_rtbitmap_buf_ops;
extern const struct xfs_buf_ops xfs_rtsummary_buf_ops;
extern const struct xfs_buf_ops xfs_rtbuf_ops;
extern const struct xfs_buf_ops xfs_rtsb_buf_ops;
+extern const struct xfs_buf_ops xfs_rtrefcountbt_buf_ops;
extern const struct xfs_buf_ops xfs_rtrmapbt_buf_ops;
extern const struct xfs_buf_ops xfs_sb_buf_ops;
extern const struct xfs_buf_ops xfs_sb_quiet_buf_ops;
@@ -56,6 +57,7 @@ extern const struct xfs_btree_ops xfs_bmbt_ops;
extern const struct xfs_btree_ops xfs_refcountbt_ops;
extern const struct xfs_btree_ops xfs_rmapbt_ops;
extern const struct xfs_btree_ops xfs_rtrmapbt_ops;
+extern const struct xfs_btree_ops xfs_rtrefcountbt_ops;
/* log size calculation functions */
int xfs_log_calc_unit_res(struct xfs_mount *mp, int unit_bytes);
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 04/42] xfs: realtime refcount btree transaction reservations
2023-12-31 19:55 ` [PATCHSET v2.0 15/17] xfsprogs: reflink on the realtime device Darrick J. Wong
` (2 preceding siblings ...)
2023-12-27 13:26 ` [PATCH 03/42] xfs: define the on-disk realtime refcount btree format Darrick J. Wong
@ 2023-12-27 13:27 ` Darrick J. Wong
2023-12-27 13:27 ` [PATCH 05/42] xfs: add realtime refcount btree operations Darrick J. Wong
` (37 subsequent siblings)
41 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:27 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Make sure that there's enough log reservation to handle mapping
and unmapping realtime extents. We have to reserve enough space
to handle a split in the rtrefcountbt to add the record and a second
split in the regular refcountbt to record the rtrefcountbt split.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_trans_resv.c | 25 ++++++++++++++++++++++---
1 file changed, 22 insertions(+), 3 deletions(-)
diff --git a/libxfs/xfs_trans_resv.c b/libxfs/xfs_trans_resv.c
index 18efae57975..2fd942c42e7 100644
--- a/libxfs/xfs_trans_resv.c
+++ b/libxfs/xfs_trans_resv.c
@@ -90,6 +90,14 @@ xfs_refcountbt_block_count(
return num_ops * (2 * mp->m_refc_maxlevels - 1);
}
+static unsigned int
+xfs_rtrefcountbt_block_count(
+ struct xfs_mount *mp,
+ unsigned int num_ops)
+{
+ return num_ops * (2 * mp->m_rtrefc_maxlevels - 1);
+}
+
/*
* Logging inodes is really tricksy. They are logged in memory format,
* which means that what we write into the log doesn't directly translate into
@@ -257,10 +265,13 @@ xfs_rtalloc_block_count(
* Compute the log reservation required to handle the refcount update
* transaction. Refcount updates are always done via deferred log items.
*
- * This is calculated as:
+ * This is calculated as the max of:
* Data device refcount updates (t1):
* the agfs of the ags containing the blocks: nr_ops * sector size
* the refcount btrees: nr_ops * 1 trees * (2 * max depth - 1) * block size
+ * Realtime refcount updates (t2);
+ * the rt refcount inode
+ * the rtrefcount btrees: nr_ops * 1 trees * (2 * max depth - 1) * block size
*/
static unsigned int
xfs_calc_refcountbt_reservation(
@@ -268,12 +279,20 @@ xfs_calc_refcountbt_reservation(
unsigned int nr_ops)
{
unsigned int blksz = XFS_FSB_TO_B(mp, 1);
+ unsigned int t1, t2 = 0;
if (!xfs_has_reflink(mp))
return 0;
- return xfs_calc_buf_res(nr_ops, mp->m_sb.sb_sectsize) +
- xfs_calc_buf_res(xfs_refcountbt_block_count(mp, nr_ops), blksz);
+ t1 = xfs_calc_buf_res(nr_ops, mp->m_sb.sb_sectsize) +
+ xfs_calc_buf_res(xfs_refcountbt_block_count(mp, nr_ops), blksz);
+
+ if (xfs_has_realtime(mp))
+ t2 = xfs_calc_inode_res(mp, 1) +
+ xfs_calc_buf_res(xfs_rtrefcountbt_block_count(mp, nr_ops),
+ blksz);
+
+ return max(t1, t2);
}
/*
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 05/42] xfs: add realtime refcount btree operations
2023-12-31 19:55 ` [PATCHSET v2.0 15/17] xfsprogs: reflink on the realtime device Darrick J. Wong
` (3 preceding siblings ...)
2023-12-27 13:27 ` [PATCH 04/42] xfs: realtime refcount btree transaction reservations Darrick J. Wong
@ 2023-12-27 13:27 ` Darrick J. Wong
2023-12-27 13:27 ` [PATCH 06/42] xfs: prepare refcount functions to deal with rtrefcountbt Darrick J. Wong
` (36 subsequent siblings)
41 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:27 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Implement the generic btree operations needed to manipulate rtrefcount
btree blocks. This is different from the regular refcountbt in that we
allocate space from the filesystem at large, and are neither constrained
to the free space nor any particular AG.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_rtrefcount_btree.c | 148 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 148 insertions(+)
diff --git a/libxfs/xfs_rtrefcount_btree.c b/libxfs/xfs_rtrefcount_btree.c
index e0db4cbf34c..fb4944d570f 100644
--- a/libxfs/xfs_rtrefcount_btree.c
+++ b/libxfs/xfs_rtrefcount_btree.c
@@ -19,6 +19,7 @@
#include "xfs_btree.h"
#include "xfs_btree_staging.h"
#include "xfs_rtrefcount_btree.h"
+#include "xfs_refcount.h"
#include "xfs_trace.h"
#include "xfs_cksum.h"
#include "xfs_rtgroup.h"
@@ -51,6 +52,106 @@ xfs_rtrefcountbt_dup_cursor(
return new;
}
+STATIC int
+xfs_rtrefcountbt_get_minrecs(
+ struct xfs_btree_cur *cur,
+ int level)
+{
+ if (level == cur->bc_nlevels - 1) {
+ struct xfs_ifork *ifp = xfs_btree_ifork_ptr(cur);
+
+ return xfs_rtrefcountbt_maxrecs(cur->bc_mp, ifp->if_broot_bytes,
+ level == 0) / 2;
+ }
+
+ return cur->bc_mp->m_rtrefc_mnr[level != 0];
+}
+
+STATIC int
+xfs_rtrefcountbt_get_maxrecs(
+ struct xfs_btree_cur *cur,
+ int level)
+{
+ if (level == cur->bc_nlevels - 1) {
+ struct xfs_ifork *ifp = xfs_btree_ifork_ptr(cur);
+
+ return xfs_rtrefcountbt_maxrecs(cur->bc_mp, ifp->if_broot_bytes,
+ level == 0);
+ }
+
+ return cur->bc_mp->m_rtrefc_mxr[level != 0];
+}
+
+STATIC void
+xfs_rtrefcountbt_init_key_from_rec(
+ union xfs_btree_key *key,
+ const union xfs_btree_rec *rec)
+{
+ key->refc.rc_startblock = rec->refc.rc_startblock;
+}
+
+STATIC void
+xfs_rtrefcountbt_init_high_key_from_rec(
+ union xfs_btree_key *key,
+ const union xfs_btree_rec *rec)
+{
+ __u32 x;
+
+ x = be32_to_cpu(rec->refc.rc_startblock);
+ x += be32_to_cpu(rec->refc.rc_blockcount) - 1;
+ key->refc.rc_startblock = cpu_to_be32(x);
+}
+
+STATIC void
+xfs_rtrefcountbt_init_rec_from_cur(
+ struct xfs_btree_cur *cur,
+ union xfs_btree_rec *rec)
+{
+ const struct xfs_refcount_irec *irec = &cur->bc_rec.rc;
+ uint32_t start;
+
+ start = xfs_refcount_encode_startblock(irec->rc_startblock,
+ irec->rc_domain);
+ rec->refc.rc_startblock = cpu_to_be32(start);
+ rec->refc.rc_blockcount = cpu_to_be32(cur->bc_rec.rc.rc_blockcount);
+ rec->refc.rc_refcount = cpu_to_be32(cur->bc_rec.rc.rc_refcount);
+}
+
+STATIC void
+xfs_rtrefcountbt_init_ptr_from_cur(
+ struct xfs_btree_cur *cur,
+ union xfs_btree_ptr *ptr)
+{
+ ptr->l = 0;
+}
+
+STATIC int64_t
+xfs_rtrefcountbt_key_diff(
+ struct xfs_btree_cur *cur,
+ const union xfs_btree_key *key)
+{
+ const struct xfs_refcount_key *kp = &key->refc;
+ const struct xfs_refcount_irec *irec = &cur->bc_rec.rc;
+ uint32_t start;
+
+ start = xfs_refcount_encode_startblock(irec->rc_startblock,
+ irec->rc_domain);
+ return (int64_t)be32_to_cpu(kp->rc_startblock) - start;
+}
+
+STATIC int64_t
+xfs_rtrefcountbt_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)
+{
+ ASSERT(!mask || mask->refc.rc_startblock);
+
+ return (int64_t)be32_to_cpu(k1->refc.rc_startblock) -
+ be32_to_cpu(k2->refc.rc_startblock);
+}
+
static xfs_failaddr_t
xfs_rtrefcountbt_verify(
struct xfs_buf *bp)
@@ -117,6 +218,40 @@ const struct xfs_buf_ops xfs_rtrefcountbt_buf_ops = {
.verify_struct = xfs_rtrefcountbt_verify,
};
+STATIC int
+xfs_rtrefcountbt_keys_inorder(
+ struct xfs_btree_cur *cur,
+ const union xfs_btree_key *k1,
+ const union xfs_btree_key *k2)
+{
+ return be32_to_cpu(k1->refc.rc_startblock) <
+ be32_to_cpu(k2->refc.rc_startblock);
+}
+
+STATIC int
+xfs_rtrefcountbt_recs_inorder(
+ struct xfs_btree_cur *cur,
+ const union xfs_btree_rec *r1,
+ const union xfs_btree_rec *r2)
+{
+ return be32_to_cpu(r1->refc.rc_startblock) +
+ be32_to_cpu(r1->refc.rc_blockcount) <=
+ be32_to_cpu(r2->refc.rc_startblock);
+}
+
+STATIC enum xbtree_key_contig
+xfs_rtrefcountbt_keys_contiguous(
+ struct xfs_btree_cur *cur,
+ const union xfs_btree_key *key1,
+ const union xfs_btree_key *key2,
+ const union xfs_btree_key *mask)
+{
+ ASSERT(!mask || mask->refc.rc_startblock);
+
+ return xbtree_key_contig(be32_to_cpu(key1->refc.rc_startblock),
+ be32_to_cpu(key2->refc.rc_startblock));
+}
+
const struct xfs_btree_ops xfs_rtrefcountbt_ops = {
.rec_len = sizeof(struct xfs_refcount_rec),
.key_len = sizeof(struct xfs_refcount_key),
@@ -125,7 +260,20 @@ const struct xfs_btree_ops xfs_rtrefcountbt_ops = {
XFS_BTREE_CRC_BLOCKS | XFS_BTREE_IROOT_RECORDS,
.dup_cursor = xfs_rtrefcountbt_dup_cursor,
+ .alloc_block = xfs_btree_alloc_imeta_block,
+ .free_block = xfs_btree_free_imeta_block,
+ .get_minrecs = xfs_rtrefcountbt_get_minrecs,
+ .get_maxrecs = xfs_rtrefcountbt_get_maxrecs,
+ .init_key_from_rec = xfs_rtrefcountbt_init_key_from_rec,
+ .init_high_key_from_rec = xfs_rtrefcountbt_init_high_key_from_rec,
+ .init_rec_from_cur = xfs_rtrefcountbt_init_rec_from_cur,
+ .init_ptr_from_cur = xfs_rtrefcountbt_init_ptr_from_cur,
+ .key_diff = xfs_rtrefcountbt_key_diff,
.buf_ops = &xfs_rtrefcountbt_buf_ops,
+ .diff_two_keys = xfs_rtrefcountbt_diff_two_keys,
+ .keys_inorder = xfs_rtrefcountbt_keys_inorder,
+ .recs_inorder = xfs_rtrefcountbt_recs_inorder,
+ .keys_contiguous = xfs_rtrefcountbt_keys_contiguous,
};
/* Initialize a new rt refcount btree cursor. */
^ permalink raw reply related [flat|nested] 632+ messages in thread
* [PATCH 06/42] xfs: prepare refcount functions to deal with rtrefcountbt
2023-12-31 19:55 ` [PATCHSET v2.0 15/17] xfsprogs: reflink on the realtime device Darrick J. Wong
` (4 preceding siblings ...)
2023-12-27 13:27 ` [PATCH 05/42] xfs: add realtime refcount btree operations Darrick J. Wong
@ 2023-12-27 13:27 ` Darrick J. Wong
2023-12-27 13:27 ` [PATCH 07/42] xfs: add a realtime flag to the refcount update log redo items Darrick J. Wong
` (35 subsequent siblings)
41 siblings, 0 replies; 632+ messages in thread
From: Darrick J. Wong @ 2023-12-27 13:27 UTC (permalink / raw)
To: cem, djwong; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Prepare the high-level refcount functions to deal with the new realtime
refcountbt and its slightly different conventions. Provide the ability
to talk to either refcountbt or rtrefcountbt formats from the same high
level code.
Note that we leave the _recover_cow_leftovers functions for a separate
patch so that we can convert it all at once.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
libxfs/xfs_refcount.c | 93 ++++++++++++++++++++++++++++++++++++++++---------
libxfs/xfs_refcount.h | 3 ++
2 files changed, 78 insertions(+), 18 deletions(-)
diff --git a/libxfs/xfs_refcount.c b/libxfs/xfs_refcount.c
index e98d5ea6ca2..2202d9cfb37 100644
--- a/libxfs/xfs_refcount.c
+++ b/libxfs/xfs_refcount.c
@@ -24,6 +24,7 @@
#include "xfs_ag.h"
#include "xfs_health.h"
#include "defer_item.h"
+#include "xfs_rtgroup.h"
struct kmem_cache *xfs_refcount_intent_cache;
@@ -40,6 +41,16 @@ STATIC int __xfs_refcount_cow_alloc(struct xfs_btree_cur *rcur,
STATIC int __xfs_refcount_cow_free(struct xfs_btree_cur *rcur,
xfs_agblock_t agbno, xfs_extlen_t aglen);
+/* Return the maximum startblock number of the refcountbt. */
+static inline xfs_agblock_t
+xrefc_max_startblock(
+ struct xfs_btree_cur *cur)
+{
+ if (cur->bc_btnum == XFS_BTNUM_RTREFC)
+ return cur->bc_mp->m_sb.sb_rgblocks;
+ return cur->bc_mp->m_sb.sb_agblocks;
+}
+
/*
* Look up the first record less than or equal to [bno, len] in the btree
* given by cur.
@@ -143,6 +154,37 @@ xfs_refcount_check_irec(
return NULL;
}
+xfs_failaddr_t
+xfs_rtrefcount_check_irec(
+ struct xfs_rtgroup *rtg,
+ const struct xfs_refcount_irec *irec)
+{
+ if (irec->rc_blockcount == 0 || irec->rc_blockcount > XFS_REFC_LEN_MAX)
+ return __this_address;
+
+ if (!xfs_refcount_check_domain(irec))
+ return __this_address;
+
+ /* check for valid extent range, including overflow */
+ if (!xfs_verify_rgbext(rtg, irec->rc_startblock, irec->rc_blockcount))
+ return __this_address;
+
+ if (irec->rc_refcount == 0 || irec->rc_refcount > XFS_REFC_REFCOUNT_MAX)
+ return __this_address;
+
+ return NULL;
+}
+
+static inline xfs_failaddr_t
+xfs_refcount_check_btrec(
+ struct xfs_btree_cur *cur,
+ const struct xfs_refcount_irec *irec)
+{
+ if (cur->bc_btnum == XFS_BTNUM_RTREFC)
+ return xfs_rtrefcount_check_irec(cur->bc_ino.rtg, irec);
+ return xfs_refcount_check_irec(cur->bc_ag.pag, irec);
+}
+
static inline int
xfs_refcount_complain_bad_rec(
struct xfs_btree_cur *cur,
@@ -151,9 +193,15 @@ xfs_refcount_complain_bad_rec(
{
struct xfs_mount *mp = cur->bc_mp;
- xfs_warn(mp,
+ if (cur->bc_btnum == XFS_BTNUM_RTREFC) {
+ xfs_warn(mp,
+ "RT Refcount BTree record corruption in rtgroup %u detected at %pS!",
+ cur->bc_ino.rtg->rtg_rgno, fa);
+ } else {
+ xfs_warn(mp,
"Refcount BTree record corruption in AG %d