Commit f103df76 authored by Allison Henderson's avatar Allison Henderson Committed by Darrick J. Wong
Browse files

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: default avatarAllison Henderson <allison.henderson@oracle.com>
Reviewed-by: default avatarDarrick J. Wong <djwong@kernel.org>
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 7560c937
Loading
Loading
Loading
Loading
+41 −0
Original line number Diff line number Diff line
@@ -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)
{
+1 −0
Original line number Diff line number Diff line
@@ -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 *);

+1 −1
Original line number Diff line number Diff line
@@ -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];
};
+10 −5
Original line number Diff line number Diff line
@@ -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);
		}
	}
}