xfs: Increase XFS_QM_TRANS_MAXDQS to 5
authorAllison Henderson <allison.henderson@oracle.com>
Mon, 15 Apr 2024 21:55:12 +0000 (14:55 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Mon, 15 Apr 2024 21:59:01 +0000 (14:59 -0700)
With parent pointers enabled, a rename operation can update up to 5
inodes: src_dp, target_dp, src_ip, target_ip and wip.  This causes
their dquots to a be attached to the transaction chain, so we need
to increase XFS_QM_TRANS_MAXDQS.  This patch also add a helper
function xfs_dqlockn to lock an arbitrary number of dquots.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/xfs/xfs_dquot.c
fs/xfs/xfs_dquot.h
fs/xfs/xfs_qm.h
fs/xfs/xfs_trans_dquot.c

index c98cb468c35780e3045da25de62612637b0867a8..13aba84bd64afbd99b4f4eff9ddfac01b7e7a960 100644 (file)
@@ -1371,6 +1371,47 @@ xfs_dqlock2(
        }
 }
 
+static int
+xfs_dqtrx_cmp(
+       const void              *a,
+       const void              *b)
+{
+       const struct xfs_dqtrx  *qa = a;
+       const struct xfs_dqtrx  *qb = b;
+
+       if (qa->qt_dquot->q_id > qb->qt_dquot->q_id)
+               return 1;
+       if (qa->qt_dquot->q_id < qb->qt_dquot->q_id)
+               return -1;
+       return 0;
+}
+
+void
+xfs_dqlockn(
+       struct xfs_dqtrx        *q)
+{
+       unsigned int            i;
+
+       BUILD_BUG_ON(XFS_QM_TRANS_MAXDQS > MAX_LOCKDEP_SUBCLASSES);
+
+       /* Sort in order of dquot id, do not allow duplicates */
+       for (i = 0; i < XFS_QM_TRANS_MAXDQS && q[i].qt_dquot != NULL; i++) {
+               unsigned int    j;
+
+               for (j = 0; j < i; j++)
+                       ASSERT(q[i].qt_dquot != q[j].qt_dquot);
+       }
+       if (i == 0)
+               return;
+
+       sort(q, i, sizeof(struct xfs_dqtrx), xfs_dqtrx_cmp, NULL);
+
+       mutex_lock(&q[0].qt_dquot->q_qlock);
+       for (i = 1; i < XFS_QM_TRANS_MAXDQS && q[i].qt_dquot != NULL; i++)
+               mutex_lock_nested(&q[i].qt_dquot->q_qlock,
+                               XFS_QLOCK_NESTED + i - 1);
+}
+
 int __init
 xfs_qm_init(void)
 {
index 956272d9b302fc027ebcda6e980cd0d8b77c87d2..677bb2dc9ac9131667f9e17d20a4e790d1f85d94 100644 (file)
@@ -223,6 +223,7 @@ int         xfs_qm_dqget_uncached(struct xfs_mount *mp,
 void           xfs_qm_dqput(struct xfs_dquot *dqp);
 
 void           xfs_dqlock2(struct xfs_dquot *, struct xfs_dquot *);
+void           xfs_dqlockn(struct xfs_dqtrx *q);
 
 void           xfs_dquot_set_prealloc_limits(struct xfs_dquot *);
 
index f5993012bf98feb0d269e5047238b7a33cbc75d8..6e09dfcd13e254f3545d2b2de7ab9b9a9c690a47 100644 (file)
@@ -136,7 +136,7 @@ enum {
        XFS_QM_TRANS_PRJ,
        XFS_QM_TRANS_DQTYPES
 };
-#define XFS_QM_TRANS_MAXDQS            2
+#define XFS_QM_TRANS_MAXDQS            5
 struct xfs_dquot_acct {
        struct xfs_dqtrx        dqs[XFS_QM_TRANS_DQTYPES][XFS_QM_TRANS_MAXDQS];
 };
index 577b535a595cbafe38e255f9d1144c95a6ec6a30..b368e13424c4f474962c9551a2f5dc561b9cd5e1 100644 (file)
@@ -379,24 +379,29 @@ xfs_trans_mod_dquot(
 
 /*
  * Given an array of dqtrx structures, lock all the dquots associated and join
- * them to the transaction, provided they have been modified.  We know that the
- * highest number of dquots of one type - usr, grp and prj - involved in a
- * transaction is 3 so we don't need to make this very generic.
+ * them to the transaction, provided they have been modified.
  */
 STATIC void
 xfs_trans_dqlockedjoin(
        struct xfs_trans        *tp,
        struct xfs_dqtrx        *q)
 {
+       unsigned int            i;
        ASSERT(q[0].qt_dquot != NULL);
        if (q[1].qt_dquot == NULL) {
                xfs_dqlock(q[0].qt_dquot);
                xfs_trans_dqjoin(tp, q[0].qt_dquot);
-       } else {
-               ASSERT(XFS_QM_TRANS_MAXDQS == 2);
+       } else if (q[2].qt_dquot == NULL) {
                xfs_dqlock2(q[0].qt_dquot, q[1].qt_dquot);
                xfs_trans_dqjoin(tp, q[0].qt_dquot);
                xfs_trans_dqjoin(tp, q[1].qt_dquot);
+       } else {
+               xfs_dqlockn(q);
+               for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) {
+                       if (q[i].qt_dquot == NULL)
+                               break;
+                       xfs_trans_dqjoin(tp, q[i].qt_dquot);
+               }
        }
 }