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

Commit b870553c authored by Dave Chinner's avatar Dave Chinner Committed by Ben Myers
Browse files

xfs: fix stray dquot unlock when reclaiming dquots



When we fail to get a dquot lock during reclaim, we jump to an error
handler that unlocks the dquot. This is wrong as we didn't lock the
dquot, and unlocking it means who-ever is holding the lock has had
it silently taken away, and hence it results in a lock imbalance.

Found by inspection while modifying the code for the numa-lru
patchset. This fixes a random hang I've been seeing on xfstest 232
for the past several months.

cc: <stable@vger.kernel.org>
Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarBen Myers <bpm@sgi.com>
parent 437a255a
Loading
Loading
Loading
Loading
+7 −8
Original line number Diff line number Diff line
@@ -1456,7 +1456,7 @@ xfs_qm_dqreclaim_one(
	int			error;

	if (!xfs_dqlock_nowait(dqp))
		goto out_busy;
		goto out_move_tail;

	/*
	 * This dquot has acquired a reference in the meantime remove it from
@@ -1479,7 +1479,7 @@ xfs_qm_dqreclaim_one(
	 * getting flushed to disk, we don't want to reclaim it.
	 */
	if (!xfs_dqflock_nowait(dqp))
		goto out_busy;
		goto out_unlock_move_tail;

	if (XFS_DQ_IS_DIRTY(dqp)) {
		struct xfs_buf	*bp = NULL;
@@ -1490,7 +1490,7 @@ xfs_qm_dqreclaim_one(
		if (error) {
			xfs_warn(mp, "%s: dquot %p flush failed",
				 __func__, dqp);
			goto out_busy;
			goto out_unlock_move_tail;
		}

		xfs_buf_delwri_queue(bp, buffer_list);
@@ -1499,7 +1499,7 @@ xfs_qm_dqreclaim_one(
		 * Give the dquot another try on the freelist, as the
		 * flushing will take some time.
		 */
		goto out_busy;
		goto out_unlock_move_tail;
	}
	xfs_dqfunlock(dqp);

@@ -1518,14 +1518,13 @@ xfs_qm_dqreclaim_one(
	XFS_STATS_INC(xs_qm_dqreclaims);
	return;

out_busy:
	xfs_dqunlock(dqp);

	/*
	 * Move the dquot to the tail of the list so that we don't spin on it.
	 */
out_unlock_move_tail:
	xfs_dqunlock(dqp);
out_move_tail:
	list_move_tail(&dqp->q_lru, &qi->qi_lru_list);

	trace_xfs_dqreclaim_busy(dqp);
	XFS_STATS_INC(xs_qm_dqreclaim_misses);
}