From: Darrick J. Wong <djwong@xxxxxxxxxx> Create a realtime rmapbt inode if we format the fs with realtime and rmap. Signed-off-by: "Darrick J. Wong" <djwong@xxxxxxxxxx> --- libxfs/init.c | 7 ---- libxfs/libxfs_api_defs.h | 3 ++ mkfs/proto.c | 29 +++++++++++++++ mkfs/xfs_mkfs.c | 87 +++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 114 insertions(+), 12 deletions(-) diff --git a/libxfs/init.c b/libxfs/init.c index 02a4cfdf38b198..f92805620c33f1 100644 --- a/libxfs/init.c +++ b/libxfs/init.c @@ -312,13 +312,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/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index 193b1eeaa7537e..df24f36f0d2874 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -224,6 +224,8 @@ #define xfs_metafile_iget libxfs_metafile_iget #define xfs_trans_metafile_iget libxfs_trans_metafile_iget +#define xfs_metafile_resv_free libxfs_metafile_resv_free +#define xfs_metafile_resv_init libxfs_metafile_resv_init #define xfs_metafile_set_iflag libxfs_metafile_set_iflag #define xfs_metadir_cancel libxfs_metadir_cancel #define xfs_metadir_commit libxfs_metadir_commit @@ -324,6 +326,7 @@ #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_init_rtsb libxfs_rtrmapbt_init_rtsb #define xfs_rtrmapbt_maxrecs libxfs_rtrmapbt_maxrecs #define xfs_rtrmapbt_mem_init libxfs_rtrmapbt_mem_init #define xfs_rtrmapbt_mem_cursor libxfs_rtrmapbt_mem_cursor diff --git a/mkfs/proto.c b/mkfs/proto.c index 60e5c7d02713d0..2c453480271666 100644 --- a/mkfs/proto.c +++ b/mkfs/proto.c @@ -1095,6 +1095,28 @@ rtinit_nogroups( } } +static int +init_rtrmap_for_rtsb( + struct xfs_rtgroup *rtg) +{ + struct xfs_mount *mp = rtg_mount(rtg); + struct xfs_trans *tp; + int error; + + error = -libxfs_trans_alloc_inode(rtg_rmap(rtg), + &M_RES(mp)->tr_itruncate, 0, 0, false, &tp); + if (error) + return error; + + error = -libxfs_rtrmapbt_init_rtsb(mp, rtg, tp); + if (error) { + libxfs_trans_cancel(tp); + return error; + } + + return -libxfs_trans_commit(tp); +} + static void rtinit_groups( struct xfs_mount *mp) @@ -1115,6 +1137,13 @@ rtinit_groups( error); } + if (xfs_has_rtsb(mp) && xfs_has_rtrmapbt(mp) && + rtg_rgno(rtg) == 0) { + error = init_rtrmap_for_rtsb(rtg); + if (error) + fail(_("rtrmap rtsb init failed"), error); + } + rtfreesp_init(rtg); } } diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index f5556fcc4040ed..c8042261328171 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -2678,12 +2678,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.metadir && cli->sb_feat.rmapbt) { + if (cli_opt_set(&mopts, M_RMAPBT) && + cli_opt_set(&mopts, M_METADIR)) { + fprintf(stderr, +_("rmapbt not supported on realtime devices without metadir feature\n")); + usage(); + } else if (cli_opt_set(&mopts, M_RMAPBT)) { + cli->sb_feat.metadir = true; + } else { + cli->sb_feat.rmapbt = false; + } } - cli->sb_feat.rmapbt = false; } if ((cli->fsx.fsx_xflags & FS_XFLAG_COWEXTSIZE) && @@ -5006,6 +5012,74 @@ write_rtsb( libxfs_buf_relse(sb_bp); } +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 = NULL; + struct xfs_rtgroup *rtg = NULL; + 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; + + while ((pag = xfs_perag_next(mp, 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 */ + while ((rtg = xfs_rtgroup_next(mp, rtg))) { + ask = libxfs_rtrmapbt_calc_reserves(mp); + error = -libxfs_metafile_resv_init(rtg_rmap(rtg), ask); + if (error) + prealloc_fail(mp, error, ask, _("realtime rmap btree")); + } + + /* Unreserve the realtime metadata reservations. */ + while ((rtg = xfs_rtgroup_next(mp, rtg))) + libxfs_metafile_resv_free(rtg_rmap(rtg)); + + /* Unreserve the per-AG reservations. */ + while ((pag = xfs_perag_next(mp, pag))) + libxfs_ag_resv_free(pag); + + mp->m_finobt_nores = false; +} + int main( int argc, @@ -5343,6 +5417,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 */