提交 b870553c 编写于 作者: D Dave Chinner 提交者: Ben Myers

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: NDave Chinner <dchinner@redhat.com>
Reviewed-by: NChristoph Hellwig <hch@lst.de>
Signed-off-by: NBen Myers <bpm@sgi.com>
上级 437a255a
...@@ -1456,7 +1456,7 @@ xfs_qm_dqreclaim_one( ...@@ -1456,7 +1456,7 @@ xfs_qm_dqreclaim_one(
int error; int error;
if (!xfs_dqlock_nowait(dqp)) if (!xfs_dqlock_nowait(dqp))
goto out_busy; goto out_move_tail;
/* /*
* This dquot has acquired a reference in the meantime remove it from * This dquot has acquired a reference in the meantime remove it from
...@@ -1479,7 +1479,7 @@ xfs_qm_dqreclaim_one( ...@@ -1479,7 +1479,7 @@ xfs_qm_dqreclaim_one(
* getting flushed to disk, we don't want to reclaim it. * getting flushed to disk, we don't want to reclaim it.
*/ */
if (!xfs_dqflock_nowait(dqp)) if (!xfs_dqflock_nowait(dqp))
goto out_busy; goto out_unlock_move_tail;
if (XFS_DQ_IS_DIRTY(dqp)) { if (XFS_DQ_IS_DIRTY(dqp)) {
struct xfs_buf *bp = NULL; struct xfs_buf *bp = NULL;
...@@ -1490,7 +1490,7 @@ xfs_qm_dqreclaim_one( ...@@ -1490,7 +1490,7 @@ xfs_qm_dqreclaim_one(
if (error) { if (error) {
xfs_warn(mp, "%s: dquot %p flush failed", xfs_warn(mp, "%s: dquot %p flush failed",
__func__, dqp); __func__, dqp);
goto out_busy; goto out_unlock_move_tail;
} }
xfs_buf_delwri_queue(bp, buffer_list); xfs_buf_delwri_queue(bp, buffer_list);
...@@ -1499,7 +1499,7 @@ xfs_qm_dqreclaim_one( ...@@ -1499,7 +1499,7 @@ xfs_qm_dqreclaim_one(
* Give the dquot another try on the freelist, as the * Give the dquot another try on the freelist, as the
* flushing will take some time. * flushing will take some time.
*/ */
goto out_busy; goto out_unlock_move_tail;
} }
xfs_dqfunlock(dqp); xfs_dqfunlock(dqp);
...@@ -1518,14 +1518,13 @@ xfs_qm_dqreclaim_one( ...@@ -1518,14 +1518,13 @@ xfs_qm_dqreclaim_one(
XFS_STATS_INC(xs_qm_dqreclaims); XFS_STATS_INC(xs_qm_dqreclaims);
return; return;
out_busy:
xfs_dqunlock(dqp);
/* /*
* Move the dquot to the tail of the list so that we don't spin on it. * 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); list_move_tail(&dqp->q_lru, &qi->qi_lru_list);
trace_xfs_dqreclaim_busy(dqp); trace_xfs_dqreclaim_busy(dqp);
XFS_STATS_INC(xs_qm_dqreclaim_misses); XFS_STATS_INC(xs_qm_dqreclaim_misses);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册