summaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_qm.c
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2012-11-28 13:01:02 +1100
committerBen Myers <bpm@sgi.com>2012-11-29 14:24:03 -0600
commitb870553cdecb26d5291af09602352b763e323df2 (patch)
tree4d7cfd6b3485d7e204003abc084245dc9a4e2ab5 /fs/xfs/xfs_qm.c
parent437a255aa23766666aec78af63be4c253faa8d57 (diff)
downloadlinux-b870553cdecb26d5291af09602352b763e323df2.tar.gz
linux-b870553cdecb26d5291af09602352b763e323df2.tar.bz2
linux-b870553cdecb26d5291af09602352b763e323df2.zip
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(
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);
}