Merge tag 'printk-for-5.19-fixup' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / fs / xfs / libxfs / xfs_log_rlimit.c
index 67798ff..9975b93 100644 (file)
@@ -14,6 +14,7 @@
 #include "xfs_trans_space.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
+#include "xfs_trace.h"
 
 /*
  * Calculate the maximum length in bytes that would be required for a local
@@ -36,6 +37,65 @@ xfs_log_calc_max_attrsetm_res(
                M_RES(mp)->tr_attrsetrt.tr_logres * nblks;
 }
 
+/*
+ * Compute an alternate set of log reservation sizes for use exclusively with
+ * minimum log size calculations.
+ */
+static void
+xfs_log_calc_trans_resv_for_minlogblocks(
+       struct xfs_mount        *mp,
+       struct xfs_trans_resv   *resv)
+{
+       unsigned int            rmap_maxlevels = mp->m_rmap_maxlevels;
+
+       /*
+        * 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
+        * that height.  Transaction reservation sizes influence the minimum
+        * log size calculation, which influences the size of the log that mkfs
+        * creates.  Use the old value here to ensure that newly formatted
+        * small filesystems will mount on older kernels.
+        */
+       if (xfs_has_rmapbt(mp) && xfs_has_reflink(mp))
+               mp->m_rmap_maxlevels = XFS_OLD_REFLINK_RMAP_MAXLEVELS;
+
+       xfs_trans_resv_calc(mp, resv);
+
+       if (xfs_has_reflink(mp)) {
+               /*
+                * In the early days of reflink, typical log operation counts
+                * were greatly overestimated.
+                */
+               resv->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT_REFLINK;
+               resv->tr_itruncate.tr_logcount =
+                               XFS_ITRUNCATE_LOG_COUNT_REFLINK;
+               resv->tr_qm_dqalloc.tr_logcount = XFS_WRITE_LOG_COUNT_REFLINK;
+       } else if (xfs_has_rmapbt(mp)) {
+               /*
+                * In the early days of non-reflink rmap, the impact of rmapbt
+                * updates on log counts were not taken into account at all.
+                */
+               resv->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT;
+               resv->tr_itruncate.tr_logcount = XFS_ITRUNCATE_LOG_COUNT;
+               resv->tr_qm_dqalloc.tr_logcount = XFS_WRITE_LOG_COUNT;
+       }
+
+       /*
+        * In the early days of reflink, we did not use deferred refcount
+        * update log items, so log reservations must be recomputed using the
+        * old calculations.
+        */
+       resv->tr_write.tr_logres =
+                       xfs_calc_write_reservation_minlogsize(mp);
+       resv->tr_itruncate.tr_logres =
+                       xfs_calc_itruncate_reservation_minlogsize(mp);
+       resv->tr_qm_dqalloc.tr_logres =
+                       xfs_calc_qm_dqalloc_reservation_minlogsize(mp);
+
+       /* Put everything back the way it was.  This goes at the end. */
+       mp->m_rmap_maxlevels = rmap_maxlevels;
+}
+
 /*
  * Iterate over the log space reservation table to figure out and return
  * the maximum one in terms of the pre-calculated values which were done
@@ -46,19 +106,25 @@ xfs_log_get_max_trans_res(
        struct xfs_mount        *mp,
        struct xfs_trans_res    *max_resp)
 {
+       struct xfs_trans_resv   resv = {};
        struct xfs_trans_res    *resp;
        struct xfs_trans_res    *end_resp;
+       unsigned int            i;
        int                     log_space = 0;
        int                     attr_space;
 
        attr_space = xfs_log_calc_max_attrsetm_res(mp);
 
-       resp = (struct xfs_trans_res *)M_RES(mp);
-       end_resp = (struct xfs_trans_res *)(M_RES(mp) + 1);
-       for (; resp < end_resp; resp++) {
+       xfs_log_calc_trans_resv_for_minlogblocks(mp, &resv);
+
+       resp = (struct xfs_trans_res *)&resv;
+       end_resp = (struct xfs_trans_res *)(&resv + 1);
+       for (i = 0; resp < end_resp; i++, resp++) {
                int             tmp = resp->tr_logcount > 1 ?
                                      resp->tr_logres * resp->tr_logcount :
                                      resp->tr_logres;
+
+               trace_xfs_trans_resv_calc_minlogsize(mp, i, resp);
                if (log_space < tmp) {
                        log_space = tmp;
                        *max_resp = *resp;              /* struct copy */
@@ -66,9 +132,10 @@ xfs_log_get_max_trans_res(
        }
 
        if (attr_space > log_space) {
-               *max_resp = M_RES(mp)->tr_attrsetm;     /* struct copy */
+               *max_resp = resv.tr_attrsetm;   /* struct copy */
                max_resp->tr_logres = attr_space;
        }
+       trace_xfs_log_get_max_trans_res(mp, max_resp);
 }
 
 /*