aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_qm.c
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2012-11-27 21:01:02 -0500
committerBen Myers <bpm@sgi.com>2012-11-29 15:24:03 -0500
commitb870553cdecb26d5291af09602352b763e323df2 (patch)
tree4d7cfd6b3485d7e204003abc084245dc9a4e2ab5 /fs/xfs/xfs_qm.c
parent437a255aa23766666aec78af63be4c253faa8d57 (diff)
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: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_qm.c')
-rw-r--r--fs/xfs/xfs_qm.c15
1 files changed, 7 insertions, 8 deletions
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index e6a0af0ba007..60eff4763156 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -1456,7 +1456,7 @@ xfs_qm_dqreclaim_one(
1456 int error; 1456 int error;
1457 1457
1458 if (!xfs_dqlock_nowait(dqp)) 1458 if (!xfs_dqlock_nowait(dqp))
1459 goto out_busy; 1459 goto out_move_tail;
1460 1460
1461 /* 1461 /*
1462 * This dquot has acquired a reference in the meantime remove it from 1462 * This dquot has acquired a reference in the meantime remove it from
@@ -1479,7 +1479,7 @@ xfs_qm_dqreclaim_one(
1479 * getting flushed to disk, we don't want to reclaim it. 1479 * getting flushed to disk, we don't want to reclaim it.
1480 */ 1480 */
1481 if (!xfs_dqflock_nowait(dqp)) 1481 if (!xfs_dqflock_nowait(dqp))
1482 goto out_busy; 1482 goto out_unlock_move_tail;
1483 1483
1484 if (XFS_DQ_IS_DIRTY(dqp)) { 1484 if (XFS_DQ_IS_DIRTY(dqp)) {
1485 struct xfs_buf *bp = NULL; 1485 struct xfs_buf *bp = NULL;
@@ -1490,7 +1490,7 @@ xfs_qm_dqreclaim_one(
1490 if (error) { 1490 if (error) {
1491 xfs_warn(mp, "%s: dquot %p flush failed", 1491 xfs_warn(mp, "%s: dquot %p flush failed",
1492 __func__, dqp); 1492 __func__, dqp);
1493 goto out_busy; 1493 goto out_unlock_move_tail;
1494 } 1494 }
1495 1495
1496 xfs_buf_delwri_queue(bp, buffer_list); 1496 xfs_buf_delwri_queue(bp, buffer_list);
@@ -1499,7 +1499,7 @@ xfs_qm_dqreclaim_one(
1499 * Give the dquot another try on the freelist, as the 1499 * Give the dquot another try on the freelist, as the
1500 * flushing will take some time. 1500 * flushing will take some time.
1501 */ 1501 */
1502 goto out_busy; 1502 goto out_unlock_move_tail;
1503 } 1503 }
1504 xfs_dqfunlock(dqp); 1504 xfs_dqfunlock(dqp);
1505 1505
@@ -1518,14 +1518,13 @@ xfs_qm_dqreclaim_one(
1518 XFS_STATS_INC(xs_qm_dqreclaims); 1518 XFS_STATS_INC(xs_qm_dqreclaims);
1519 return; 1519 return;
1520 1520
1521out_busy:
1522 xfs_dqunlock(dqp);
1523
1524 /* 1521 /*
1525 * Move the dquot to the tail of the list so that we don't spin on it. 1522 * Move the dquot to the tail of the list so that we don't spin on it.
1526 */ 1523 */
1524out_unlock_move_tail:
1525 xfs_dqunlock(dqp);
1526out_move_tail:
1527 list_move_tail(&dqp->q_lru, &qi->qi_lru_list); 1527 list_move_tail(&dqp->q_lru, &qi->qi_lru_list);
1528
1529 trace_xfs_dqreclaim_busy(dqp); 1528 trace_xfs_dqreclaim_busy(dqp);
1530 XFS_STATS_INC(xs_qm_dqreclaim_misses); 1529 XFS_STATS_INC(xs_qm_dqreclaim_misses);
1531} 1530}