Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit be7ffc38 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Ben Myers
Browse files

xfs: implement lazy removal for the dquot freelist



Do not remove dquots from the freelist when we grab a reference to them in
xfs_qm_dqlookup, but leave them on the freelist util scanning notices that
they have a reference.  This speeds up the lookup fastpath, and greatly
simplifies the lock ordering constraints.  Note that the same scheme is
used by the VFS inode and dentry caches.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
Signed-off-by: default avatarBen Myers <bpm@sgi.com>
parent 80a376bf
Loading
Loading
Loading
Loading
+18 −49
Original line number Diff line number Diff line
@@ -722,58 +722,25 @@ xfs_qm_dqlookup(
		 * dqlock to look at the id field of the dquot, since the
		 * id can't be modified without the hashlock anyway.
		 */
		if (be32_to_cpu(dqp->q_core.d_id) == id && dqp->q_mount == mp) {
			trace_xfs_dqlookup_found(dqp);

			/*
			 * All in core dquots must be on the dqlist of mp
			 */
			ASSERT(!list_empty(&dqp->q_mplist));
		if (be32_to_cpu(dqp->q_core.d_id) != id || dqp->q_mount != mp)
			continue;

			xfs_dqlock(dqp);
			if (dqp->q_nrefs == 0) {
				ASSERT(!list_empty(&dqp->q_freelist));
				if (!mutex_trylock(&xfs_Gqm->qm_dqfrlist_lock)) {
					trace_xfs_dqlookup_want(dqp);
		trace_xfs_dqlookup_found(dqp);

					/*
					 * We may have raced with dqreclaim_one()
					 * (and lost). So, flag that we don't
					 * want the dquot to be reclaimed.
					 */
					dqp->dq_flags |= XFS_DQ_WANT;
					xfs_dqunlock(dqp);
					mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
		xfs_dqlock(dqp);
					dqp->dq_flags &= ~(XFS_DQ_WANT);
				}

				if (dqp->q_nrefs == 0) {
					/* take it off the freelist */
					trace_xfs_dqlookup_freelist(dqp);
					list_del_init(&dqp->q_freelist);
					xfs_Gqm->qm_dqfrlist_cnt--;
				}
		XFS_DQHOLD(dqp);
				mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
			} else {
				XFS_DQHOLD(dqp);
			}

		/*
		 * move the dquot to the front of the hashchain
		 */
			ASSERT(mutex_is_locked(&qh->qh_lock));
		list_move(&dqp->q_hashlist, &qh->qh_list);
		trace_xfs_dqlookup_done(dqp);
		*O_dqpp = dqp;
		return 0;
	}
	}

	*O_dqpp = NULL;
	ASSERT(mutex_is_locked(&qh->qh_lock));
	return (1);
	return 1;
}

/*
@@ -1033,8 +1000,10 @@ xfs_qm_dqput(
		if (--dqp->q_nrefs == 0) {
			trace_xfs_dqput_free(dqp);

			if (list_empty(&dqp->q_freelist)) {
				list_add_tail(&dqp->q_freelist, &xfs_Gqm->qm_dqfrlist);
				xfs_Gqm->qm_dqfrlist_cnt++;
			}

			/*
			 * If we just added a udquot to the freelist, then
+11 −11
Original line number Diff line number Diff line
@@ -517,13 +517,12 @@ xfs_qm_dqpurge_int(
	 * get them off mplist and hashlist, but leave them on freelist.
	 */
	list_for_each_entry_safe(dqp, n, &q->qi_dqlist, q_mplist) {
		/*
		 * It's OK to look at the type without taking dqlock here.
		 * We're holding the mplist lock here, and that's needed for
		 * a dqreclaim.
		 */
		if ((dqp->dq_flags & dqtype) == 0)
		xfs_dqlock(dqp);
		if ((dqp->dq_flags & dqtype) == 0) {
			xfs_dqunlock(dqp);
			continue;
		}
		xfs_dqunlock(dqp);

		if (!mutex_trylock(&dqp->q_hash->qh_lock)) {
			nrecl = q->qi_dqreclaims;
@@ -1692,14 +1691,15 @@ xfs_qm_dqreclaim_one(void)
		xfs_dqlock(dqp);

		/*
		 * We are racing with dqlookup here. Naturally we don't
		 * want to reclaim a dquot that lookup wants. We release the
		 * freelist lock and start over, so that lookup will grab
		 * both the dquot and the freelistlock.
		 * This dquot has already been grabbed by dqlookup.
		 * Remove it from the freelist and try again.
		 */
		if (dqp->dq_flags & XFS_DQ_WANT) {
		if (dqp->q_nrefs) {
			trace_xfs_dqreclaim_want(dqp);
			XQM_STATS_INC(xqmstats.xs_qm_dqwants);

			list_del_init(&dqp->q_freelist);
			xfs_Gqm->qm_dqfrlist_cnt--;
			restarts++;
			startagain = 1;
			goto dqunlock;
+1 −3
Original line number Diff line number Diff line
@@ -87,7 +87,6 @@ typedef struct xfs_dqblk {
#define XFS_DQ_PROJ		0x0002		/* project quota */
#define XFS_DQ_GROUP		0x0004		/* a group quota */
#define XFS_DQ_DIRTY		0x0008		/* dquot is dirty */
#define XFS_DQ_WANT		0x0010		/* for lookup/reclaim race */

#define XFS_DQ_ALLTYPES		(XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP)

@@ -95,8 +94,7 @@ typedef struct xfs_dqblk {
	{ XFS_DQ_USER,		"USER" }, \
	{ XFS_DQ_PROJ,		"PROJ" }, \
	{ XFS_DQ_GROUP,		"GROUP" }, \
	{ XFS_DQ_DIRTY,		"DIRTY" }, \
	{ XFS_DQ_WANT,		"WANT" }
	{ XFS_DQ_DIRTY,		"DIRTY" }

/*
 * In the worst case, when both user and group quotas are on,
+0 −2
Original line number Diff line number Diff line
@@ -743,8 +743,6 @@ DEFINE_DQUOT_EVENT(xfs_dqtobp_read);
DEFINE_DQUOT_EVENT(xfs_dqread);
DEFINE_DQUOT_EVENT(xfs_dqread_fail);
DEFINE_DQUOT_EVENT(xfs_dqlookup_found);
DEFINE_DQUOT_EVENT(xfs_dqlookup_want);
DEFINE_DQUOT_EVENT(xfs_dqlookup_freelist);
DEFINE_DQUOT_EVENT(xfs_dqlookup_done);
DEFINE_DQUOT_EVENT(xfs_dqget_hit);
DEFINE_DQUOT_EVENT(xfs_dqget_miss);