From: Darrick J. Wong <djwong@xxxxxxxxxx> Update the new metadata inode transaction reservations to handle metadata directories if that feature is enabled. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> --- libxfs/xfs_log_rlimit.c | 9 ++++++ libxfs/xfs_trans_resv.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/libxfs/xfs_log_rlimit.c b/libxfs/xfs_log_rlimit.c index cba24493f86..84ebdbddd0a 100644 --- a/libxfs/xfs_log_rlimit.c +++ b/libxfs/xfs_log_rlimit.c @@ -48,6 +48,15 @@ xfs_log_calc_trans_resv_for_minlogblocks( { unsigned int rmap_maxlevels = mp->m_rmap_maxlevels; + /* + * The metadata directory tree feature drops the oversized minimum log + * size computations introduced by the original reflink code. + */ + if (xfs_has_metadir(mp)) { + xfs_trans_resv_calc(mp, resv); + return; + } + /* * In the early days of rmap+reflink, we always set the rmap maxlevels * to 9 even if the AG was small enough that it would never grow to diff --git a/libxfs/xfs_trans_resv.c b/libxfs/xfs_trans_resv.c index 00bdcb1d550..67008bb4b72 100644 --- a/libxfs/xfs_trans_resv.c +++ b/libxfs/xfs_trans_resv.c @@ -908,6 +908,56 @@ xfs_calc_sb_reservation( return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); } +/* + * Metadata inode creation needs enough space to create or mkdir a directory, + * plus logging the superblock. + */ +static unsigned int +xfs_calc_imeta_create_resv( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + unsigned int ret; + + ret = xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); + ret += resp->tr_create.tr_logres; + return ret; +} + +/* Metadata inode creation needs enough rounds to create or mkdir a directory */ +static int +xfs_calc_imeta_create_count( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + return resp->tr_create.tr_logcount; +} + +/* + * Metadata inode unlink needs enough space to remove a file plus logging the + * superblock. + */ +static unsigned int +xfs_calc_imeta_unlink_resv( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + unsigned int ret; + + ret = xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); + ret += resp->tr_remove.tr_logres; + return ret; +} + +/* Metadata inode creation needs enough rounds to remove a file. */ +static int +xfs_calc_imeta_unlink_count( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + return resp->tr_remove.tr_logcount; +} + void xfs_trans_resv_calc( struct xfs_mount *mp, @@ -1026,6 +1076,20 @@ xfs_trans_resv_calc( resp->tr_qm_dqalloc.tr_logcount += logcount_adj; /* metadata inode creation and unlink */ - resp->tr_imeta_create = resp->tr_create; - resp->tr_imeta_unlink = resp->tr_remove; + if (xfs_has_metadir(mp)) { + resp->tr_imeta_create.tr_logres = + xfs_calc_imeta_create_resv(mp, resp); + resp->tr_imeta_create.tr_logcount = + xfs_calc_imeta_create_count(mp, resp); + resp->tr_imeta_create.tr_logflags |= XFS_TRANS_PERM_LOG_RES; + + resp->tr_imeta_unlink.tr_logres = + xfs_calc_imeta_unlink_resv(mp, resp); + resp->tr_imeta_unlink.tr_logcount = + xfs_calc_imeta_unlink_count(mp, resp); + resp->tr_imeta_unlink.tr_logflags |= XFS_TRANS_PERM_LOG_RES; + } else { + resp->tr_imeta_create = resp->tr_create; + resp->tr_imeta_unlink = resp->tr_remove; + } }