diff options
author | Christoph Hellwig <hch@infradead.org> | 2011-12-06 16:58:18 -0500 |
---|---|---|
committer | Ben Myers <bpm@sgi.com> | 2011-12-14 17:32:21 -0500 |
commit | 92678554abfc2a2f2727ad168da87d8d434ac904 (patch) | |
tree | 082b395f587dca7903c083e8e10529be1890dc4e /fs/xfs/xfs_qm.c | |
parent | be7ffc38a80a78e6b68d0f51fae8e8d57b55324c (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.c | 134 |
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 | */ |
1673 | STATIC xfs_dquot_t * | 1661 | STATIC struct xfs_dquot * |
1674 | xfs_qm_dqreclaim_one(void) | 1662 | xfs_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 */ | ||
1685 | again: | ||
1686 | startagain = 0; | ||
1687 | mutex_lock(&xfs_Gqm->qm_dqfrlist_lock); | 1667 | mutex_lock(&xfs_Gqm->qm_dqfrlist_lock); |
1688 | 1668 | restart: | |
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); |
1774 | qhunlock: | 1745 | return dqp; |
1775 | mutex_unlock(&dqp->q_hash->qh_lock); | ||
1776 | dqfunlock: | ||
1777 | xfs_dqfunlock(dqp); | ||
1778 | dqunlock: | 1746 | dqunlock: |
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 | /* |