From: Darrick J. Wong <djwong@xxxxxxxxxx> If we're adding enough space to the realtime section to require the creation of new realtime groups, create the rt rmap btree inode before we start adding the space. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> --- fs/xfs/xfs_rtalloc.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 2 deletions(-) diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c index ac6580bda2052..f6b23439b674d 100644 --- a/fs/xfs/xfs_rtalloc.c +++ b/fs/xfs/xfs_rtalloc.c @@ -24,8 +24,11 @@ #include "xfs_health.h" #include "xfs_da_format.h" #include "xfs_imeta.h" +#include "xfs_imeta_utils.h" #include "xfs_rtgroup.h" #include "xfs_error.h" +#include "xfs_btree.h" +#include "xfs_rmap.h" #include "xfs_rtrmap_btree.h" #include "xfs_trace.h" @@ -1017,6 +1020,74 @@ xfs_growfs_rt_init_primary( return 0; } +/* Add a metadata inode for a realtime rmap btree. */ +static int +xfs_growfsrt_create_rtrmap( + struct xfs_rtgroup *rtg) +{ + struct xfs_mount *mp = rtg->rtg_mount; + struct xfs_imeta_update upd; + 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, + }; + struct xfs_btree_cur *cur; + struct xfs_imeta_path *path; + struct xfs_inode *ip = NULL; + int error; + + if (!xfs_has_rtrmapbt(mp) || rtg->rtg_rmapip) + return 0; + + error = xfs_rtrmapbt_create_path(mp, rtg->rtg_rgno, &path); + if (error) + return error; + + error = xfs_imeta_ensure_dirpath(mp, path); + if (error) + goto out_path; + + error = xfs_imeta_start_create(mp, path, &upd); + if (error) + goto out_path; + + error = xfs_rtrmapbt_create(&upd, &ip); + if (error) + goto out_cancel; + + lockdep_set_class(&ip->i_lock.mr_lock, &xfs_rrmapip_key); + + /* Rmap the rtgroup superblock; this had better fit in the data fork. */ + cur = xfs_rtrmapbt_init_cursor(mp, upd.tp, rtg, ip); + error = xfs_rmap_map_raw(cur, &rmap); + xfs_btree_del_cursor(cur, error); + if (error) + goto out_cancel; + + error = xfs_imeta_commit_update(&upd); + if (error) + goto out_path; + + xfs_imeta_free_path(path); + xfs_finish_inode_setup(ip); + rtg->rtg_rmapip = ip; + return 0; + +out_cancel: + xfs_imeta_cancel_update(&upd, error); + /* Have to finish setting up the inode to ensure it's deleted. */ + if (ip) { + xfs_finish_inode_setup(ip); + xfs_irele(ip); + } +out_path: + xfs_imeta_free_path(path); + return error; +} + /* * Check that changes to the realtime geometry won't affect the minimum * log size, which would cause the fs to become unusable. @@ -1122,7 +1193,9 @@ xfs_growfs_rt( return -EINVAL; /* Unsupported realtime features. */ - if (xfs_has_rmapbt(mp) || xfs_has_reflink(mp) || xfs_has_quota(mp)) + if (!xfs_has_rtgroups(mp) && xfs_has_rmapbt(mp)) + return -EOPNOTSUPP; + if (xfs_has_reflink(mp) || xfs_has_quota(mp)) return -EOPNOTSUPP; nrblocks = in->newblocks; @@ -1261,10 +1334,21 @@ xfs_growfs_rt( /* recompute growfsrt reservation from new rsumsize */ xfs_trans_resv_calc(nmp, &nmp->m_resv); - if (xfs_has_rtgroups(mp)) + if (xfs_has_rtgroups(mp)) { + xfs_rgnumber_t rgno = last_rgno; + nsbp->sb_rgcount = howmany_64(nsbp->sb_rblocks, nsbp->sb_rgblocks); + for_each_rtgroup_range(mp, rgno, nsbp->sb_rgcount, rtg) { + error = xfs_growfsrt_create_rtrmap(rtg); + if (error) { + xfs_rtgroup_rele(rtg); + break; + } + } + } + /* * Start a transaction, get the log reservation. */