| From b870553cdecb26d5291af09602352b763e323df2 Mon Sep 17 00:00:00 2001 |
| From: Dave Chinner <dchinner@redhat.com> |
| Date: Wed, 28 Nov 2012 13:01:02 +1100 |
| Subject: xfs: fix stray dquot unlock when reclaiming dquots |
| |
| From: Dave Chinner <dchinner@redhat.com> |
| |
| commit b870553cdecb26d5291af09602352b763e323df2 upstream. |
| |
| 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. |
| |
| Signed-off-by: Dave Chinner <dchinner@redhat.com> |
| Reviewed-by: Christoph Hellwig <hch@lst.de> |
| Signed-off-by: Ben Myers <bpm@sgi.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/xfs/xfs_qm.c | 15 +++++++-------- |
| 1 file changed, 7 insertions(+), 8 deletions(-) |
| |
| --- a/fs/xfs/xfs_qm.c |
| +++ b/fs/xfs/xfs_qm.c |
| @@ -1453,7 +1453,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 |
| @@ -1476,7 +1476,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; |
| @@ -1487,7 +1487,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); |
| @@ -1496,7 +1496,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); |
| |
| @@ -1515,14 +1515,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); |
| } |