diff options
Diffstat (limited to 'fs/xfs/xfs_qm.c')
-rw-r--r-- | fs/xfs/xfs_qm.c | 287 |
1 files changed, 151 insertions, 136 deletions
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index 6218a0aeeeea..3e6c2e6c9cd2 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c | |||
@@ -51,8 +51,9 @@ | |||
51 | */ | 51 | */ |
52 | STATIC int xfs_qm_init_quotainos(xfs_mount_t *); | 52 | STATIC int xfs_qm_init_quotainos(xfs_mount_t *); |
53 | STATIC int xfs_qm_init_quotainfo(xfs_mount_t *); | 53 | STATIC int xfs_qm_init_quotainfo(xfs_mount_t *); |
54 | STATIC int xfs_qm_shake(struct shrinker *, struct shrink_control *); | ||
55 | 54 | ||
55 | |||
56 | STATIC void xfs_qm_dqfree_one(struct xfs_dquot *dqp); | ||
56 | /* | 57 | /* |
57 | * We use the batch lookup interface to iterate over the dquots as it | 58 | * We use the batch lookup interface to iterate over the dquots as it |
58 | * currently is the only interface into the radix tree code that allows | 59 | * currently is the only interface into the radix tree code that allows |
@@ -203,12 +204,9 @@ xfs_qm_dqpurge( | |||
203 | * We move dquots to the freelist as soon as their reference count | 204 | * We move dquots to the freelist as soon as their reference count |
204 | * hits zero, so it really should be on the freelist here. | 205 | * hits zero, so it really should be on the freelist here. |
205 | */ | 206 | */ |
206 | mutex_lock(&qi->qi_lru_lock); | ||
207 | ASSERT(!list_empty(&dqp->q_lru)); | 207 | ASSERT(!list_empty(&dqp->q_lru)); |
208 | list_del_init(&dqp->q_lru); | 208 | list_lru_del(&qi->qi_lru, &dqp->q_lru); |
209 | qi->qi_lru_count--; | ||
210 | XFS_STATS_DEC(xs_qm_dquot_unused); | 209 | XFS_STATS_DEC(xs_qm_dquot_unused); |
211 | mutex_unlock(&qi->qi_lru_lock); | ||
212 | 210 | ||
213 | xfs_qm_dqdestroy(dqp); | 211 | xfs_qm_dqdestroy(dqp); |
214 | 212 | ||
@@ -680,6 +678,143 @@ xfs_qm_calc_dquots_per_chunk( | |||
680 | return ndquots; | 678 | return ndquots; |
681 | } | 679 | } |
682 | 680 | ||
681 | struct xfs_qm_isolate { | ||
682 | struct list_head buffers; | ||
683 | struct list_head dispose; | ||
684 | }; | ||
685 | |||
686 | static enum lru_status | ||
687 | xfs_qm_dquot_isolate( | ||
688 | struct list_head *item, | ||
689 | spinlock_t *lru_lock, | ||
690 | void *arg) | ||
691 | { | ||
692 | struct xfs_dquot *dqp = container_of(item, | ||
693 | struct xfs_dquot, q_lru); | ||
694 | struct xfs_qm_isolate *isol = arg; | ||
695 | |||
696 | if (!xfs_dqlock_nowait(dqp)) | ||
697 | goto out_miss_busy; | ||
698 | |||
699 | /* | ||
700 | * This dquot has acquired a reference in the meantime remove it from | ||
701 | * the freelist and try again. | ||
702 | */ | ||
703 | if (dqp->q_nrefs) { | ||
704 | xfs_dqunlock(dqp); | ||
705 | XFS_STATS_INC(xs_qm_dqwants); | ||
706 | |||
707 | trace_xfs_dqreclaim_want(dqp); | ||
708 | list_del_init(&dqp->q_lru); | ||
709 | XFS_STATS_DEC(xs_qm_dquot_unused); | ||
710 | return LRU_REMOVED; | ||
711 | } | ||
712 | |||
713 | /* | ||
714 | * If the dquot is dirty, flush it. If it's already being flushed, just | ||
715 | * skip it so there is time for the IO to complete before we try to | ||
716 | * reclaim it again on the next LRU pass. | ||
717 | */ | ||
718 | if (!xfs_dqflock_nowait(dqp)) { | ||
719 | xfs_dqunlock(dqp); | ||
720 | goto out_miss_busy; | ||
721 | } | ||
722 | |||
723 | if (XFS_DQ_IS_DIRTY(dqp)) { | ||
724 | struct xfs_buf *bp = NULL; | ||
725 | int error; | ||
726 | |||
727 | trace_xfs_dqreclaim_dirty(dqp); | ||
728 | |||
729 | /* we have to drop the LRU lock to flush the dquot */ | ||
730 | spin_unlock(lru_lock); | ||
731 | |||
732 | error = xfs_qm_dqflush(dqp, &bp); | ||
733 | if (error) { | ||
734 | xfs_warn(dqp->q_mount, "%s: dquot %p flush failed", | ||
735 | __func__, dqp); | ||
736 | goto out_unlock_dirty; | ||
737 | } | ||
738 | |||
739 | xfs_buf_delwri_queue(bp, &isol->buffers); | ||
740 | xfs_buf_relse(bp); | ||
741 | goto out_unlock_dirty; | ||
742 | } | ||
743 | xfs_dqfunlock(dqp); | ||
744 | |||
745 | /* | ||
746 | * Prevent lookups now that we are past the point of no return. | ||
747 | */ | ||
748 | dqp->dq_flags |= XFS_DQ_FREEING; | ||
749 | xfs_dqunlock(dqp); | ||
750 | |||
751 | ASSERT(dqp->q_nrefs == 0); | ||
752 | list_move_tail(&dqp->q_lru, &isol->dispose); | ||
753 | XFS_STATS_DEC(xs_qm_dquot_unused); | ||
754 | trace_xfs_dqreclaim_done(dqp); | ||
755 | XFS_STATS_INC(xs_qm_dqreclaims); | ||
756 | return LRU_REMOVED; | ||
757 | |||
758 | out_miss_busy: | ||
759 | trace_xfs_dqreclaim_busy(dqp); | ||
760 | XFS_STATS_INC(xs_qm_dqreclaim_misses); | ||
761 | return LRU_SKIP; | ||
762 | |||
763 | out_unlock_dirty: | ||
764 | trace_xfs_dqreclaim_busy(dqp); | ||
765 | XFS_STATS_INC(xs_qm_dqreclaim_misses); | ||
766 | xfs_dqunlock(dqp); | ||
767 | spin_lock(lru_lock); | ||
768 | return LRU_RETRY; | ||
769 | } | ||
770 | |||
771 | static unsigned long | ||
772 | xfs_qm_shrink_scan( | ||
773 | struct shrinker *shrink, | ||
774 | struct shrink_control *sc) | ||
775 | { | ||
776 | struct xfs_quotainfo *qi = container_of(shrink, | ||
777 | struct xfs_quotainfo, qi_shrinker); | ||
778 | struct xfs_qm_isolate isol; | ||
779 | unsigned long freed; | ||
780 | int error; | ||
781 | unsigned long nr_to_scan = sc->nr_to_scan; | ||
782 | |||
783 | if ((sc->gfp_mask & (__GFP_FS|__GFP_WAIT)) != (__GFP_FS|__GFP_WAIT)) | ||
784 | return 0; | ||
785 | |||
786 | INIT_LIST_HEAD(&isol.buffers); | ||
787 | INIT_LIST_HEAD(&isol.dispose); | ||
788 | |||
789 | freed = list_lru_walk_node(&qi->qi_lru, sc->nid, xfs_qm_dquot_isolate, &isol, | ||
790 | &nr_to_scan); | ||
791 | |||
792 | error = xfs_buf_delwri_submit(&isol.buffers); | ||
793 | if (error) | ||
794 | xfs_warn(NULL, "%s: dquot reclaim failed", __func__); | ||
795 | |||
796 | while (!list_empty(&isol.dispose)) { | ||
797 | struct xfs_dquot *dqp; | ||
798 | |||
799 | dqp = list_first_entry(&isol.dispose, struct xfs_dquot, q_lru); | ||
800 | list_del_init(&dqp->q_lru); | ||
801 | xfs_qm_dqfree_one(dqp); | ||
802 | } | ||
803 | |||
804 | return freed; | ||
805 | } | ||
806 | |||
807 | static unsigned long | ||
808 | xfs_qm_shrink_count( | ||
809 | struct shrinker *shrink, | ||
810 | struct shrink_control *sc) | ||
811 | { | ||
812 | struct xfs_quotainfo *qi = container_of(shrink, | ||
813 | struct xfs_quotainfo, qi_shrinker); | ||
814 | |||
815 | return list_lru_count_node(&qi->qi_lru, sc->nid); | ||
816 | } | ||
817 | |||
683 | /* | 818 | /* |
684 | * This initializes all the quota information that's kept in the | 819 | * This initializes all the quota information that's kept in the |
685 | * mount structure | 820 | * mount structure |
@@ -696,11 +831,18 @@ xfs_qm_init_quotainfo( | |||
696 | 831 | ||
697 | qinf = mp->m_quotainfo = kmem_zalloc(sizeof(xfs_quotainfo_t), KM_SLEEP); | 832 | qinf = mp->m_quotainfo = kmem_zalloc(sizeof(xfs_quotainfo_t), KM_SLEEP); |
698 | 833 | ||
834 | if ((error = list_lru_init(&qinf->qi_lru))) { | ||
835 | kmem_free(qinf); | ||
836 | mp->m_quotainfo = NULL; | ||
837 | return error; | ||
838 | } | ||
839 | |||
699 | /* | 840 | /* |
700 | * See if quotainodes are setup, and if not, allocate them, | 841 | * See if quotainodes are setup, and if not, allocate them, |
701 | * and change the superblock accordingly. | 842 | * and change the superblock accordingly. |
702 | */ | 843 | */ |
703 | if ((error = xfs_qm_init_quotainos(mp))) { | 844 | if ((error = xfs_qm_init_quotainos(mp))) { |
845 | list_lru_destroy(&qinf->qi_lru); | ||
704 | kmem_free(qinf); | 846 | kmem_free(qinf); |
705 | mp->m_quotainfo = NULL; | 847 | mp->m_quotainfo = NULL; |
706 | return error; | 848 | return error; |
@@ -711,10 +853,6 @@ xfs_qm_init_quotainfo( | |||
711 | INIT_RADIX_TREE(&qinf->qi_pquota_tree, GFP_NOFS); | 853 | INIT_RADIX_TREE(&qinf->qi_pquota_tree, GFP_NOFS); |
712 | mutex_init(&qinf->qi_tree_lock); | 854 | mutex_init(&qinf->qi_tree_lock); |
713 | 855 | ||
714 | INIT_LIST_HEAD(&qinf->qi_lru_list); | ||
715 | qinf->qi_lru_count = 0; | ||
716 | mutex_init(&qinf->qi_lru_lock); | ||
717 | |||
718 | /* mutex used to serialize quotaoffs */ | 856 | /* mutex used to serialize quotaoffs */ |
719 | mutex_init(&qinf->qi_quotaofflock); | 857 | mutex_init(&qinf->qi_quotaofflock); |
720 | 858 | ||
@@ -779,8 +917,10 @@ xfs_qm_init_quotainfo( | |||
779 | qinf->qi_rtbwarnlimit = XFS_QM_RTBWARNLIMIT; | 917 | qinf->qi_rtbwarnlimit = XFS_QM_RTBWARNLIMIT; |
780 | } | 918 | } |
781 | 919 | ||
782 | qinf->qi_shrinker.shrink = xfs_qm_shake; | 920 | qinf->qi_shrinker.count_objects = xfs_qm_shrink_count; |
921 | qinf->qi_shrinker.scan_objects = xfs_qm_shrink_scan; | ||
783 | qinf->qi_shrinker.seeks = DEFAULT_SEEKS; | 922 | qinf->qi_shrinker.seeks = DEFAULT_SEEKS; |
923 | qinf->qi_shrinker.flags = SHRINKER_NUMA_AWARE; | ||
784 | register_shrinker(&qinf->qi_shrinker); | 924 | register_shrinker(&qinf->qi_shrinker); |
785 | return 0; | 925 | return 0; |
786 | } | 926 | } |
@@ -801,6 +941,7 @@ xfs_qm_destroy_quotainfo( | |||
801 | ASSERT(qi != NULL); | 941 | ASSERT(qi != NULL); |
802 | 942 | ||
803 | unregister_shrinker(&qi->qi_shrinker); | 943 | unregister_shrinker(&qi->qi_shrinker); |
944 | list_lru_destroy(&qi->qi_lru); | ||
804 | 945 | ||
805 | if (qi->qi_uquotaip) { | 946 | if (qi->qi_uquotaip) { |
806 | IRELE(qi->qi_uquotaip); | 947 | IRELE(qi->qi_uquotaip); |
@@ -1599,132 +1740,6 @@ xfs_qm_dqfree_one( | |||
1599 | xfs_qm_dqdestroy(dqp); | 1740 | xfs_qm_dqdestroy(dqp); |
1600 | } | 1741 | } |
1601 | 1742 | ||
1602 | STATIC void | ||
1603 | xfs_qm_dqreclaim_one( | ||
1604 | struct xfs_dquot *dqp, | ||
1605 | struct list_head *buffer_list, | ||
1606 | struct list_head *dispose_list) | ||
1607 | { | ||
1608 | struct xfs_mount *mp = dqp->q_mount; | ||
1609 | struct xfs_quotainfo *qi = mp->m_quotainfo; | ||
1610 | int error; | ||
1611 | |||
1612 | if (!xfs_dqlock_nowait(dqp)) | ||
1613 | goto out_move_tail; | ||
1614 | |||
1615 | /* | ||
1616 | * This dquot has acquired a reference in the meantime remove it from | ||
1617 | * the freelist and try again. | ||
1618 | */ | ||
1619 | if (dqp->q_nrefs) { | ||
1620 | xfs_dqunlock(dqp); | ||
1621 | |||
1622 | trace_xfs_dqreclaim_want(dqp); | ||
1623 | XFS_STATS_INC(xs_qm_dqwants); | ||
1624 | |||
1625 | list_del_init(&dqp->q_lru); | ||
1626 | qi->qi_lru_count--; | ||
1627 | XFS_STATS_DEC(xs_qm_dquot_unused); | ||
1628 | return; | ||
1629 | } | ||
1630 | |||
1631 | /* | ||
1632 | * Try to grab the flush lock. If this dquot is in the process of | ||
1633 | * getting flushed to disk, we don't want to reclaim it. | ||
1634 | */ | ||
1635 | if (!xfs_dqflock_nowait(dqp)) | ||
1636 | goto out_unlock_move_tail; | ||
1637 | |||
1638 | if (XFS_DQ_IS_DIRTY(dqp)) { | ||
1639 | struct xfs_buf *bp = NULL; | ||
1640 | |||
1641 | trace_xfs_dqreclaim_dirty(dqp); | ||
1642 | |||
1643 | error = xfs_qm_dqflush(dqp, &bp); | ||
1644 | if (error) { | ||
1645 | xfs_warn(mp, "%s: dquot %p flush failed", | ||
1646 | __func__, dqp); | ||
1647 | goto out_unlock_move_tail; | ||
1648 | } | ||
1649 | |||
1650 | xfs_buf_delwri_queue(bp, buffer_list); | ||
1651 | xfs_buf_relse(bp); | ||
1652 | /* | ||
1653 | * Give the dquot another try on the freelist, as the | ||
1654 | * flushing will take some time. | ||
1655 | */ | ||
1656 | goto out_unlock_move_tail; | ||
1657 | } | ||
1658 | xfs_dqfunlock(dqp); | ||
1659 | |||
1660 | /* | ||
1661 | * Prevent lookups now that we are past the point of no return. | ||
1662 | */ | ||
1663 | dqp->dq_flags |= XFS_DQ_FREEING; | ||
1664 | xfs_dqunlock(dqp); | ||
1665 | |||
1666 | ASSERT(dqp->q_nrefs == 0); | ||
1667 | list_move_tail(&dqp->q_lru, dispose_list); | ||
1668 | qi->qi_lru_count--; | ||
1669 | XFS_STATS_DEC(xs_qm_dquot_unused); | ||
1670 | |||
1671 | trace_xfs_dqreclaim_done(dqp); | ||
1672 | XFS_STATS_INC(xs_qm_dqreclaims); | ||
1673 | return; | ||
1674 | |||
1675 | /* | ||
1676 | * Move the dquot to the tail of the list so that we don't spin on it. | ||
1677 | */ | ||
1678 | out_unlock_move_tail: | ||
1679 | xfs_dqunlock(dqp); | ||
1680 | out_move_tail: | ||
1681 | list_move_tail(&dqp->q_lru, &qi->qi_lru_list); | ||
1682 | trace_xfs_dqreclaim_busy(dqp); | ||
1683 | XFS_STATS_INC(xs_qm_dqreclaim_misses); | ||
1684 | } | ||
1685 | |||
1686 | STATIC int | ||
1687 | xfs_qm_shake( | ||
1688 | struct shrinker *shrink, | ||
1689 | struct shrink_control *sc) | ||
1690 | { | ||
1691 | struct xfs_quotainfo *qi = | ||
1692 | container_of(shrink, struct xfs_quotainfo, qi_shrinker); | ||
1693 | int nr_to_scan = sc->nr_to_scan; | ||
1694 | LIST_HEAD (buffer_list); | ||
1695 | LIST_HEAD (dispose_list); | ||
1696 | struct xfs_dquot *dqp; | ||
1697 | int error; | ||
1698 | |||
1699 | if ((sc->gfp_mask & (__GFP_FS|__GFP_WAIT)) != (__GFP_FS|__GFP_WAIT)) | ||
1700 | return 0; | ||
1701 | if (!nr_to_scan) | ||
1702 | goto out; | ||
1703 | |||
1704 | mutex_lock(&qi->qi_lru_lock); | ||
1705 | while (!list_empty(&qi->qi_lru_list)) { | ||
1706 | if (nr_to_scan-- <= 0) | ||
1707 | break; | ||
1708 | dqp = list_first_entry(&qi->qi_lru_list, struct xfs_dquot, | ||
1709 | q_lru); | ||
1710 | xfs_qm_dqreclaim_one(dqp, &buffer_list, &dispose_list); | ||
1711 | } | ||
1712 | mutex_unlock(&qi->qi_lru_lock); | ||
1713 | |||
1714 | error = xfs_buf_delwri_submit(&buffer_list); | ||
1715 | if (error) | ||
1716 | xfs_warn(NULL, "%s: dquot reclaim failed", __func__); | ||
1717 | |||
1718 | while (!list_empty(&dispose_list)) { | ||
1719 | dqp = list_first_entry(&dispose_list, struct xfs_dquot, q_lru); | ||
1720 | list_del_init(&dqp->q_lru); | ||
1721 | xfs_qm_dqfree_one(dqp); | ||
1722 | } | ||
1723 | |||
1724 | out: | ||
1725 | return (qi->qi_lru_count / 100) * sysctl_vfs_cache_pressure; | ||
1726 | } | ||
1727 | |||
1728 | /* | 1743 | /* |
1729 | * Start a transaction and write the incore superblock changes to | 1744 | * Start a transaction and write the incore superblock changes to |
1730 | * disk. flags parameter indicates which fields have changed. | 1745 | * disk. flags parameter indicates which fields have changed. |