aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_qm.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2011-12-06 16:58:18 -0500
committerBen Myers <bpm@sgi.com>2011-12-14 17:32:21 -0500
commit92678554abfc2a2f2727ad168da87d8d434ac904 (patch)
tree082b395f587dca7903c083e8e10529be1890dc4e /fs/xfs/xfs_qm.c
parentbe7ffc38a80a78e6b68d0f51fae8e8d57b55324c (diff)
xfs: flatten the dquot lock ordering
Introduce a new XFS_DQ_FREEING flag that tells lookup and mplist walks to skip a dquot that is beeing freed, and use this avoid the trylock on the hash and mplist locks in xfs_qm_dqreclaim_one. Also simplify xfs_dqpurge by moving the inodes to a dispose list after marking them XFS_DQ_FREEING and avoid the locker ordering constraints. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_qm.c')
-rw-r--r--fs/xfs/xfs_qm.c134
1 files changed, 49 insertions, 85 deletions
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index 6a0c4f0d9306..f418731e90f4 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -398,7 +398,8 @@ again:
398 mutex_lock(&q->qi_dqlist_lock); 398 mutex_lock(&q->qi_dqlist_lock);
399 list_for_each_entry(dqp, &q->qi_dqlist, q_mplist) { 399 list_for_each_entry(dqp, &q->qi_dqlist, q_mplist) {
400 xfs_dqlock(dqp); 400 xfs_dqlock(dqp);
401 if (! XFS_DQ_IS_DIRTY(dqp)) { 401 if ((dqp->dq_flags & XFS_DQ_FREEING) ||
402 !XFS_DQ_IS_DIRTY(dqp)) {
402 xfs_dqunlock(dqp); 403 xfs_dqunlock(dqp);
403 continue; 404 continue;
404 } 405 }
@@ -437,6 +438,7 @@ again:
437 /* return ! busy */ 438 /* return ! busy */
438 return 0; 439 return 0;
439} 440}
441
440/* 442/*
441 * Release the group dquot pointers the user dquots may be 443 * Release the group dquot pointers the user dquots may be
442 * carrying around as a hint. mplist is locked on entry and exit. 444 * carrying around as a hint. mplist is locked on entry and exit.
@@ -453,6 +455,13 @@ xfs_qm_detach_gdquots(
453 ASSERT(mutex_is_locked(&q->qi_dqlist_lock)); 455 ASSERT(mutex_is_locked(&q->qi_dqlist_lock));
454 list_for_each_entry(dqp, &q->qi_dqlist, q_mplist) { 456 list_for_each_entry(dqp, &q->qi_dqlist, q_mplist) {
455 xfs_dqlock(dqp); 457 xfs_dqlock(dqp);
458 if (dqp->dq_flags & XFS_DQ_FREEING) {
459 xfs_dqunlock(dqp);
460 mutex_unlock(&q->qi_dqlist_lock);
461 delay(1);
462 mutex_lock(&q->qi_dqlist_lock);
463 goto again;
464 }
456 if ((gdqp = dqp->q_gdquot)) { 465 if ((gdqp = dqp->q_gdquot)) {
457 xfs_dqlock(gdqp); 466 xfs_dqlock(gdqp);
458 dqp->q_gdquot = NULL; 467 dqp->q_gdquot = NULL;
@@ -489,8 +498,8 @@ xfs_qm_dqpurge_int(
489 struct xfs_quotainfo *q = mp->m_quotainfo; 498 struct xfs_quotainfo *q = mp->m_quotainfo;
490 struct xfs_dquot *dqp, *n; 499 struct xfs_dquot *dqp, *n;
491 uint dqtype; 500 uint dqtype;
492 int nrecl; 501 int nmisses = 0;
493 int nmisses; 502 LIST_HEAD (dispose_list);
494 503
495 if (!q) 504 if (!q)
496 return 0; 505 return 0;
@@ -509,46 +518,26 @@ xfs_qm_dqpurge_int(
509 */ 518 */
510 xfs_qm_detach_gdquots(mp); 519 xfs_qm_detach_gdquots(mp);
511 520
512 again:
513 nmisses = 0;
514 ASSERT(mutex_is_locked(&q->qi_dqlist_lock));
515 /* 521 /*
516 * Try to get rid of all of the unwanted dquots. The idea is to 522 * Try to get rid of all of the unwanted dquots.
517 * get them off mplist and hashlist, but leave them on freelist.
518 */ 523 */
519 list_for_each_entry_safe(dqp, n, &q->qi_dqlist, q_mplist) { 524 list_for_each_entry_safe(dqp, n, &q->qi_dqlist, q_mplist) {
520 xfs_dqlock(dqp); 525 xfs_dqlock(dqp);
521 if ((dqp->dq_flags & dqtype) == 0) { 526 if ((dqp->dq_flags & dqtype) != 0 &&
522 xfs_dqunlock(dqp); 527 !(dqp->dq_flags & XFS_DQ_FREEING)) {
523 continue; 528 if (dqp->q_nrefs == 0) {
529 dqp->dq_flags |= XFS_DQ_FREEING;
530 list_move_tail(&dqp->q_mplist, &dispose_list);
531 } else
532 nmisses++;
524 } 533 }
525 xfs_dqunlock(dqp); 534 xfs_dqunlock(dqp);
526
527 if (!mutex_trylock(&dqp->q_hash->qh_lock)) {
528 nrecl = q->qi_dqreclaims;
529 mutex_unlock(&q->qi_dqlist_lock);
530 mutex_lock(&dqp->q_hash->qh_lock);
531 mutex_lock(&q->qi_dqlist_lock);
532
533 /*
534 * XXXTheoretically, we can get into a very long
535 * ping pong game here.
536 * No one can be adding dquots to the mplist at
537 * this point, but somebody might be taking things off.
538 */
539 if (nrecl != q->qi_dqreclaims) {
540 mutex_unlock(&dqp->q_hash->qh_lock);
541 goto again;
542 }
543 }
544
545 /*
546 * Take the dquot off the mplist and hashlist. It may remain on
547 * freelist in INACTIVE state.
548 */
549 nmisses += xfs_qm_dqpurge(dqp);
550 } 535 }
551 mutex_unlock(&q->qi_dqlist_lock); 536 mutex_unlock(&q->qi_dqlist_lock);
537
538 list_for_each_entry_safe(dqp, n, &dispose_list, q_mplist)
539 xfs_qm_dqpurge(dqp);
540
552 return nmisses; 541 return nmisses;
553} 542}
554 543
@@ -1667,25 +1656,16 @@ xfs_qm_init_quotainos(
1667 1656
1668 1657
1669/* 1658/*
1670 * Just pop the least recently used dquot off the freelist and 1659 * Pop the least recently used dquot off the freelist and recycle it.
1671 * recycle it. The returned dquot is locked.
1672 */ 1660 */
1673STATIC xfs_dquot_t * 1661STATIC struct xfs_dquot *
1674xfs_qm_dqreclaim_one(void) 1662xfs_qm_dqreclaim_one(void)
1675{ 1663{
1676 xfs_dquot_t *dqpout; 1664 struct xfs_dquot *dqp;
1677 xfs_dquot_t *dqp; 1665 int restarts = 0;
1678 int restarts;
1679 int startagain;
1680
1681 restarts = 0;
1682 dqpout = NULL;
1683 1666
1684 /* lockorder: hashchainlock, freelistlock, mplistlock, dqlock, dqflock */
1685again:
1686 startagain = 0;
1687 mutex_lock(&xfs_Gqm->qm_dqfrlist_lock); 1667 mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
1688 1668restart:
1689 list_for_each_entry(dqp, &xfs_Gqm->qm_dqfrlist, q_freelist) { 1669 list_for_each_entry(dqp, &xfs_Gqm->qm_dqfrlist, q_freelist) {
1690 struct xfs_mount *mp = dqp->q_mount; 1670 struct xfs_mount *mp = dqp->q_mount;
1691 xfs_dqlock(dqp); 1671 xfs_dqlock(dqp);
@@ -1701,7 +1681,6 @@ again:
1701 list_del_init(&dqp->q_freelist); 1681 list_del_init(&dqp->q_freelist);
1702 xfs_Gqm->qm_dqfrlist_cnt--; 1682 xfs_Gqm->qm_dqfrlist_cnt--;
1703 restarts++; 1683 restarts++;
1704 startagain = 1;
1705 goto dqunlock; 1684 goto dqunlock;
1706 } 1685 }
1707 1686
@@ -1737,57 +1716,42 @@ again:
1737 } 1716 }
1738 goto dqunlock; 1717 goto dqunlock;
1739 } 1718 }
1719 xfs_dqfunlock(dqp);
1740 1720
1741 /* 1721 /*
1742 * We're trying to get the hashlock out of order. This races 1722 * Prevent lookup now that we are going to reclaim the dquot.
1743 * with dqlookup; so, we giveup and goto the next dquot if 1723 * Once XFS_DQ_FREEING is set lookup won't touch the dquot,
1744 * we couldn't get the hashlock. This way, we won't starve 1724 * thus we can drop the lock now.
1745 * a dqlookup process that holds the hashlock that is
1746 * waiting for the freelist lock.
1747 */ 1725 */
1748 if (!mutex_trylock(&dqp->q_hash->qh_lock)) { 1726 dqp->dq_flags |= XFS_DQ_FREEING;
1749 restarts++; 1727 xfs_dqunlock(dqp);
1750 goto dqfunlock;
1751 }
1752 1728
1753 /* 1729 mutex_lock(&dqp->q_hash->qh_lock);
1754 * This races with dquot allocation code as well as dqflush_all 1730 list_del_init(&dqp->q_hashlist);
1755 * and reclaim code. So, if we failed to grab the mplist lock, 1731 dqp->q_hash->qh_version++;
1756 * giveup everything and start over. 1732 mutex_unlock(&dqp->q_hash->qh_lock);
1757 */
1758 if (!mutex_trylock(&mp->m_quotainfo->qi_dqlist_lock)) {
1759 restarts++;
1760 startagain = 1;
1761 goto qhunlock;
1762 }
1763 1733
1764 ASSERT(dqp->q_nrefs == 0); 1734 mutex_lock(&mp->m_quotainfo->qi_dqlist_lock);
1765 list_del_init(&dqp->q_mplist); 1735 list_del_init(&dqp->q_mplist);
1766 mp->m_quotainfo->qi_dquots--; 1736 mp->m_quotainfo->qi_dquots--;
1767 mp->m_quotainfo->qi_dqreclaims++; 1737 mp->m_quotainfo->qi_dqreclaims++;
1768 list_del_init(&dqp->q_hashlist); 1738 mutex_unlock(&mp->m_quotainfo->qi_dqlist_lock);
1769 dqp->q_hash->qh_version++; 1739
1740 ASSERT(dqp->q_nrefs == 0);
1770 list_del_init(&dqp->q_freelist); 1741 list_del_init(&dqp->q_freelist);
1771 xfs_Gqm->qm_dqfrlist_cnt--; 1742 xfs_Gqm->qm_dqfrlist_cnt--;
1772 dqpout = dqp; 1743
1773 mutex_unlock(&mp->m_quotainfo->qi_dqlist_lock); 1744 mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
1774qhunlock: 1745 return dqp;
1775 mutex_unlock(&dqp->q_hash->qh_lock);
1776dqfunlock:
1777 xfs_dqfunlock(dqp);
1778dqunlock: 1746dqunlock:
1779 xfs_dqunlock(dqp); 1747 xfs_dqunlock(dqp);
1780 if (dqpout)
1781 break;
1782 if (restarts >= XFS_QM_RECLAIM_MAX_RESTARTS) 1748 if (restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
1783 break; 1749 break;
1784 if (startagain) { 1750 goto restart;
1785 mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
1786 goto again;
1787 }
1788 } 1751 }
1752
1789 mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock); 1753 mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
1790 return dqpout; 1754 return NULL;
1791} 1755}
1792 1756
1793/* 1757/*