@@ -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
@@ -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;
+ }
}