xfs: Increase XFS_QM_TRANS_MAXDQS to 5

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>
This commit is contained in:
Allison Henderson 2024-04-15 14:55:12 -07:00 committed by Darrick J. Wong
parent 7560c937b4
commit f103df7635
4 changed files with 53 additions and 6 deletions

View 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)
{

View 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 *);

View 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];
};

View 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);
}
}
}