aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2012-03-13 04:52:34 -0400
committerBen Myers <bpm@sgi.com>2012-03-14 12:09:06 -0400
commitf8739c3ce2ac9a01515b56026b6a066c0808234b (patch)
treec3f7b877b5be6e12c62028de7da46fef3e537dc7 /fs/xfs
parent48776fd22344ad80adcbac0abc9c0da60c6481d2 (diff)
xfs: per-filesystem dquot LRU lists
Replace the global dquot lru lists with a per-filesystem one. Note that the shrinker isn't wire up to the per-superblock VFS shrinker infrastructure as would have problems summing up and splitting the counts for inodes and dquots. I don't think this is a major problem as the quota cache isn't as interwinded with the inode cache as the dentry cache is, because an inode that is dropped from the cache will generally release a dquot reference, but most of the time it won't be the last one. 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')
-rw-r--r--fs/xfs/xfs_dquot.c84
-rw-r--r--fs/xfs/xfs_dquot.h2
-rw-r--r--fs/xfs/xfs_qm.c59
-rw-r--r--fs/xfs/xfs_qm.h7
4 files changed, 74 insertions, 78 deletions
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 98d7e25947fa..fec1a3d78e9f 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -47,7 +47,7 @@
47 * qi->qi_dqlist_lock 47 * qi->qi_dqlist_lock
48 * dquot->q_qlock (xfs_dqlock() and friends) 48 * dquot->q_qlock (xfs_dqlock() and friends)
49 * dquot->q_flush (xfs_dqflock() and friends) 49 * dquot->q_flush (xfs_dqflock() and friends)
50 * xfs_Gqm->qm_dqfrlist_lock 50 * qi->qi_lru_lock
51 * 51 *
52 * If two dquots need to be locked the order is user before group/project, 52 * If two dquots need to be locked the order is user before group/project,
53 * otherwise by the lowest id first, see xfs_dqlock2. 53 * otherwise by the lowest id first, see xfs_dqlock2.
@@ -69,7 +69,7 @@ void
69xfs_qm_dqdestroy( 69xfs_qm_dqdestroy(
70 xfs_dquot_t *dqp) 70 xfs_dquot_t *dqp)
71{ 71{
72 ASSERT(list_empty(&dqp->q_freelist)); 72 ASSERT(list_empty(&dqp->q_lru));
73 73
74 mutex_destroy(&dqp->q_qlock); 74 mutex_destroy(&dqp->q_qlock);
75 kmem_zone_free(xfs_Gqm->qm_dqzone, dqp); 75 kmem_zone_free(xfs_Gqm->qm_dqzone, dqp);
@@ -497,7 +497,7 @@ xfs_qm_dqread(
497 dqp->dq_flags = type; 497 dqp->dq_flags = type;
498 dqp->q_core.d_id = cpu_to_be32(id); 498 dqp->q_core.d_id = cpu_to_be32(id);
499 dqp->q_mount = mp; 499 dqp->q_mount = mp;
500 INIT_LIST_HEAD(&dqp->q_freelist); 500 INIT_LIST_HEAD(&dqp->q_lru);
501 mutex_init(&dqp->q_qlock); 501 mutex_init(&dqp->q_qlock);
502 init_waitqueue_head(&dqp->q_pinwait); 502 init_waitqueue_head(&dqp->q_pinwait);
503 503
@@ -844,38 +844,22 @@ restart:
844} 844}
845 845
846 846
847/* 847STATIC void
848 * Release a reference to the dquot (decrement ref-count) 848xfs_qm_dqput_final(
849 * and unlock it. If there is a group quota attached to this
850 * dquot, carefully release that too without tripping over
851 * deadlocks'n'stuff.
852 */
853void
854xfs_qm_dqput(
855 struct xfs_dquot *dqp) 849 struct xfs_dquot *dqp)
856{ 850{
851 struct xfs_quotainfo *qi = dqp->q_mount->m_quotainfo;
857 struct xfs_dquot *gdqp; 852 struct xfs_dquot *gdqp;
858 853
859 ASSERT(dqp->q_nrefs > 0);
860 ASSERT(XFS_DQ_IS_LOCKED(dqp));
861
862 trace_xfs_dqput(dqp);
863
864recurse:
865 if (--dqp->q_nrefs > 0) {
866 xfs_dqunlock(dqp);
867 return;
868 }
869
870 trace_xfs_dqput_free(dqp); 854 trace_xfs_dqput_free(dqp);
871 855
872 mutex_lock(&xfs_Gqm->qm_dqfrlist_lock); 856 mutex_lock(&qi->qi_lru_lock);
873 if (list_empty(&dqp->q_freelist)) { 857 if (list_empty(&dqp->q_lru)) {
874 list_add_tail(&dqp->q_freelist, &xfs_Gqm->qm_dqfrlist); 858 list_add_tail(&dqp->q_lru, &qi->qi_lru_list);
875 xfs_Gqm->qm_dqfrlist_cnt++; 859 qi->qi_lru_count++;
876 XFS_STATS_INC(xs_qm_dquot_unused); 860 XFS_STATS_INC(xs_qm_dquot_unused);
877 } 861 }
878 mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock); 862 mutex_unlock(&qi->qi_lru_lock);
879 863
880 /* 864 /*
881 * If we just added a udquot to the freelist, then we want to release 865 * If we just added a udquot to the freelist, then we want to release
@@ -892,10 +876,29 @@ recurse:
892 /* 876 /*
893 * If we had a group quota hint, release it now. 877 * If we had a group quota hint, release it now.
894 */ 878 */
895 if (gdqp) { 879 if (gdqp)
896 dqp = gdqp; 880 xfs_qm_dqput(gdqp);
897 goto recurse; 881}
898 } 882
883/*
884 * Release a reference to the dquot (decrement ref-count) and unlock it.
885 *
886 * If there is a group quota attached to this dquot, carefully release that
887 * too without tripping over deadlocks'n'stuff.
888 */
889void
890xfs_qm_dqput(
891 struct xfs_dquot *dqp)
892{
893 ASSERT(dqp->q_nrefs > 0);
894 ASSERT(XFS_DQ_IS_LOCKED(dqp));
895
896 trace_xfs_dqput(dqp);
897
898 if (--dqp->q_nrefs > 0)
899 xfs_dqunlock(dqp);
900 else
901 xfs_qm_dqput_final(dqp);
899} 902}
900 903
901/* 904/*
@@ -1115,6 +1118,7 @@ xfs_qm_dqpurge(
1115{ 1118{
1116 struct xfs_mount *mp = dqp->q_mount; 1119 struct xfs_mount *mp = dqp->q_mount;
1117 struct xfs_dqhash *qh = dqp->q_hash; 1120 struct xfs_dqhash *qh = dqp->q_hash;
1121 struct xfs_quotainfo *qi = mp->m_quotainfo;
1118 1122
1119 xfs_dqlock(dqp); 1123 xfs_dqlock(dqp);
1120 1124
@@ -1165,22 +1169,22 @@ xfs_qm_dqpurge(
1165 qh->qh_version++; 1169 qh->qh_version++;
1166 mutex_unlock(&qh->qh_lock); 1170 mutex_unlock(&qh->qh_lock);
1167 1171
1168 mutex_lock(&mp->m_quotainfo->qi_dqlist_lock); 1172 mutex_lock(&qi->qi_dqlist_lock);
1169 list_del_init(&dqp->q_mplist); 1173 list_del_init(&dqp->q_mplist);
1170 mp->m_quotainfo->qi_dqreclaims++; 1174 qi->qi_dqreclaims++;
1171 mp->m_quotainfo->qi_dquots--; 1175 qi->qi_dquots--;
1172 mutex_unlock(&mp->m_quotainfo->qi_dqlist_lock); 1176 mutex_unlock(&qi->qi_dqlist_lock);
1173 1177
1174 /* 1178 /*
1175 * We move dquots to the freelist as soon as their reference count 1179 * We move dquots to the freelist as soon as their reference count
1176 * hits zero, so it really should be on the freelist here. 1180 * hits zero, so it really should be on the freelist here.
1177 */ 1181 */
1178 mutex_lock(&xfs_Gqm->qm_dqfrlist_lock); 1182 mutex_lock(&qi->qi_lru_lock);
1179 ASSERT(!list_empty(&dqp->q_freelist)); 1183 ASSERT(!list_empty(&dqp->q_lru));
1180 list_del_init(&dqp->q_freelist); 1184 list_del_init(&dqp->q_lru);
1181 xfs_Gqm->qm_dqfrlist_cnt--; 1185 qi->qi_lru_count--;
1182 XFS_STATS_DEC(xs_qm_dquot_unused); 1186 XFS_STATS_DEC(xs_qm_dquot_unused);
1183 mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock); 1187 mutex_unlock(&qi->qi_lru_lock);
1184 1188
1185 xfs_qm_dqdestroy(dqp); 1189 xfs_qm_dqdestroy(dqp);
1186} 1190}
diff --git a/fs/xfs/xfs_dquot.h b/fs/xfs/xfs_dquot.h
index 60b0d72b0241..f291c25e5992 100644
--- a/fs/xfs/xfs_dquot.h
+++ b/fs/xfs/xfs_dquot.h
@@ -47,7 +47,7 @@ struct xfs_trans;
47 */ 47 */
48typedef struct xfs_dquot { 48typedef struct xfs_dquot {
49 uint dq_flags; /* various flags (XFS_DQ_*) */ 49 uint dq_flags; /* various flags (XFS_DQ_*) */
50 struct list_head q_freelist; /* global free list of dquots */ 50 struct list_head q_lru; /* global free list of dquots */
51 struct list_head q_mplist; /* mount's list of dquots */ 51 struct list_head q_mplist; /* mount's list of dquots */
52 struct list_head q_hashlist; /* gloabl hash list of dquots */ 52 struct list_head q_hashlist; /* gloabl hash list of dquots */
53 xfs_dqhash_t *q_hash; /* the hashchain header */ 53 xfs_dqhash_t *q_hash; /* the hashchain header */
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index 0dde1f48c280..a2579e1d687f 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -61,11 +61,6 @@ STATIC int xfs_qm_init_quotainos(xfs_mount_t *);
61STATIC int xfs_qm_init_quotainfo(xfs_mount_t *); 61STATIC int xfs_qm_init_quotainfo(xfs_mount_t *);
62STATIC int xfs_qm_shake(struct shrinker *, struct shrink_control *); 62STATIC int xfs_qm_shake(struct shrinker *, struct shrink_control *);
63 63
64static struct shrinker xfs_qm_shaker = {
65 .shrink = xfs_qm_shake,
66 .seeks = DEFAULT_SEEKS,
67};
68
69/* 64/*
70 * Initialize the XQM structure. 65 * Initialize the XQM structure.
71 * Note that there is not one quota manager per file system. 66 * Note that there is not one quota manager per file system.
@@ -106,13 +101,6 @@ xfs_Gqm_init(void)
106 } 101 }
107 102
108 /* 103 /*
109 * Freelist of all dquots of all file systems
110 */
111 INIT_LIST_HEAD(&xqm->qm_dqfrlist);
112 xqm->qm_dqfrlist_cnt = 0;
113 mutex_init(&xqm->qm_dqfrlist_lock);
114
115 /*
116 * dquot zone. we register our own low-memory callback. 104 * dquot zone. we register our own low-memory callback.
117 */ 105 */
118 if (!qm_dqzone) { 106 if (!qm_dqzone) {
@@ -122,8 +110,6 @@ xfs_Gqm_init(void)
122 } else 110 } else
123 xqm->qm_dqzone = qm_dqzone; 111 xqm->qm_dqzone = qm_dqzone;
124 112
125 register_shrinker(&xfs_qm_shaker);
126
127 /* 113 /*
128 * The t_dqinfo portion of transactions. 114 * The t_dqinfo portion of transactions.
129 */ 115 */
@@ -155,12 +141,6 @@ xfs_qm_destroy(
155 ASSERT(xqm != NULL); 141 ASSERT(xqm != NULL);
156 ASSERT(xqm->qm_nrefs == 0); 142 ASSERT(xqm->qm_nrefs == 0);
157 143
158 unregister_shrinker(&xfs_qm_shaker);
159
160 mutex_lock(&xqm->qm_dqfrlist_lock);
161 ASSERT(list_empty(&xqm->qm_dqfrlist));
162 mutex_unlock(&xqm->qm_dqfrlist_lock);
163
164 hsize = xqm->qm_dqhashmask + 1; 144 hsize = xqm->qm_dqhashmask + 1;
165 for (i = 0; i < hsize; i++) { 145 for (i = 0; i < hsize; i++) {
166 xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i])); 146 xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i]));
@@ -826,6 +806,10 @@ xfs_qm_init_quotainfo(
826 mutex_init(&qinf->qi_dqlist_lock); 806 mutex_init(&qinf->qi_dqlist_lock);
827 lockdep_set_class(&qinf->qi_dqlist_lock, &xfs_quota_mplist_class); 807 lockdep_set_class(&qinf->qi_dqlist_lock, &xfs_quota_mplist_class);
828 808
809 INIT_LIST_HEAD(&qinf->qi_lru_list);
810 qinf->qi_lru_count = 0;
811 mutex_init(&qinf->qi_lru_lock);
812
829 qinf->qi_dqreclaims = 0; 813 qinf->qi_dqreclaims = 0;
830 814
831 /* mutex used to serialize quotaoffs */ 815 /* mutex used to serialize quotaoffs */
@@ -893,6 +877,9 @@ xfs_qm_init_quotainfo(
893 qinf->qi_rtbwarnlimit = XFS_QM_RTBWARNLIMIT; 877 qinf->qi_rtbwarnlimit = XFS_QM_RTBWARNLIMIT;
894 } 878 }
895 879
880 qinf->qi_shrinker.shrink = xfs_qm_shake;
881 qinf->qi_shrinker.seeks = DEFAULT_SEEKS;
882 register_shrinker(&qinf->qi_shrinker);
896 return 0; 883 return 0;
897} 884}
898 885
@@ -912,6 +899,8 @@ xfs_qm_destroy_quotainfo(
912 ASSERT(qi != NULL); 899 ASSERT(qi != NULL);
913 ASSERT(xfs_Gqm != NULL); 900 ASSERT(xfs_Gqm != NULL);
914 901
902 unregister_shrinker(&qi->qi_shrinker);
903
915 /* 904 /*
916 * Release the reference that XQM kept, so that we know 905 * Release the reference that XQM kept, so that we know
917 * when the XQM structure should be freed. We cannot assume 906 * when the XQM structure should be freed. We cannot assume
@@ -1623,6 +1612,7 @@ xfs_qm_dqreclaim_one(
1623 struct list_head *dispose_list) 1612 struct list_head *dispose_list)
1624{ 1613{
1625 struct xfs_mount *mp = dqp->q_mount; 1614 struct xfs_mount *mp = dqp->q_mount;
1615 struct xfs_quotainfo *qi = mp->m_quotainfo;
1626 int error; 1616 int error;
1627 1617
1628 if (!xfs_dqlock_nowait(dqp)) 1618 if (!xfs_dqlock_nowait(dqp))
@@ -1638,8 +1628,8 @@ xfs_qm_dqreclaim_one(
1638 trace_xfs_dqreclaim_want(dqp); 1628 trace_xfs_dqreclaim_want(dqp);
1639 XFS_STATS_INC(xs_qm_dqwants); 1629 XFS_STATS_INC(xs_qm_dqwants);
1640 1630
1641 list_del_init(&dqp->q_freelist); 1631 list_del_init(&dqp->q_lru);
1642 xfs_Gqm->qm_dqfrlist_cnt--; 1632 qi->qi_lru_count--;
1643 XFS_STATS_DEC(xs_qm_dquot_unused); 1633 XFS_STATS_DEC(xs_qm_dquot_unused);
1644 return; 1634 return;
1645 } 1635 }
@@ -1688,8 +1678,8 @@ xfs_qm_dqreclaim_one(
1688 xfs_dqunlock(dqp); 1678 xfs_dqunlock(dqp);
1689 1679
1690 ASSERT(dqp->q_nrefs == 0); 1680 ASSERT(dqp->q_nrefs == 0);
1691 list_move_tail(&dqp->q_freelist, dispose_list); 1681 list_move_tail(&dqp->q_lru, dispose_list);
1692 xfs_Gqm->qm_dqfrlist_cnt--; 1682 qi->qi_lru_count--;
1693 XFS_STATS_DEC(xs_qm_dquot_unused); 1683 XFS_STATS_DEC(xs_qm_dquot_unused);
1694 1684
1695 trace_xfs_dqreclaim_done(dqp); 1685 trace_xfs_dqreclaim_done(dqp);
@@ -1702,7 +1692,7 @@ out_busy:
1702 /* 1692 /*
1703 * Move the dquot to the tail of the list so that we don't spin on it. 1693 * Move the dquot to the tail of the list so that we don't spin on it.
1704 */ 1694 */
1705 list_move_tail(&dqp->q_freelist, &xfs_Gqm->qm_dqfrlist); 1695 list_move_tail(&dqp->q_lru, &qi->qi_lru_list);
1706 1696
1707 trace_xfs_dqreclaim_busy(dqp); 1697 trace_xfs_dqreclaim_busy(dqp);
1708 XFS_STATS_INC(xs_qm_dqreclaim_misses); 1698 XFS_STATS_INC(xs_qm_dqreclaim_misses);
@@ -1713,6 +1703,8 @@ xfs_qm_shake(
1713 struct shrinker *shrink, 1703 struct shrinker *shrink,
1714 struct shrink_control *sc) 1704 struct shrink_control *sc)
1715{ 1705{
1706 struct xfs_quotainfo *qi =
1707 container_of(shrink, struct xfs_quotainfo, qi_shrinker);
1716 int nr_to_scan = sc->nr_to_scan; 1708 int nr_to_scan = sc->nr_to_scan;
1717 LIST_HEAD (dispose_list); 1709 LIST_HEAD (dispose_list);
1718 struct xfs_dquot *dqp; 1710 struct xfs_dquot *dqp;
@@ -1722,24 +1714,23 @@ xfs_qm_shake(
1722 if (!nr_to_scan) 1714 if (!nr_to_scan)
1723 goto out; 1715 goto out;
1724 1716
1725 mutex_lock(&xfs_Gqm->qm_dqfrlist_lock); 1717 mutex_lock(&qi->qi_lru_lock);
1726 while (!list_empty(&xfs_Gqm->qm_dqfrlist)) { 1718 while (!list_empty(&qi->qi_lru_list)) {
1727 if (nr_to_scan-- <= 0) 1719 if (nr_to_scan-- <= 0)
1728 break; 1720 break;
1729 dqp = list_first_entry(&xfs_Gqm->qm_dqfrlist, struct xfs_dquot, 1721 dqp = list_first_entry(&qi->qi_lru_list, struct xfs_dquot,
1730 q_freelist); 1722 q_lru);
1731 xfs_qm_dqreclaim_one(dqp, &dispose_list); 1723 xfs_qm_dqreclaim_one(dqp, &dispose_list);
1732 } 1724 }
1733 mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock); 1725 mutex_unlock(&qi->qi_lru_lock);
1734 1726
1735 while (!list_empty(&dispose_list)) { 1727 while (!list_empty(&dispose_list)) {
1736 dqp = list_first_entry(&dispose_list, struct xfs_dquot, 1728 dqp = list_first_entry(&dispose_list, struct xfs_dquot, q_lru);
1737 q_freelist); 1729 list_del_init(&dqp->q_lru);
1738 list_del_init(&dqp->q_freelist);
1739 xfs_qm_dqfree_one(dqp); 1730 xfs_qm_dqfree_one(dqp);
1740 } 1731 }
1741out: 1732out:
1742 return (xfs_Gqm->qm_dqfrlist_cnt / 100) * sysctl_vfs_cache_pressure; 1733 return (qi->qi_lru_count / 100) * sysctl_vfs_cache_pressure;
1743} 1734}
1744 1735
1745/* 1736/*
diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
index 89f213f7252a..c236bba9bfab 100644
--- a/fs/xfs/xfs_qm.h
+++ b/fs/xfs/xfs_qm.h
@@ -56,9 +56,6 @@ typedef struct xfs_qm {
56 xfs_dqlist_t *qm_usr_dqhtable;/* udquot hash table */ 56 xfs_dqlist_t *qm_usr_dqhtable;/* udquot hash table */
57 xfs_dqlist_t *qm_grp_dqhtable;/* gdquot hash table */ 57 xfs_dqlist_t *qm_grp_dqhtable;/* gdquot hash table */
58 uint qm_dqhashmask; /* # buckets in dq hashtab - 1 */ 58 uint qm_dqhashmask; /* # buckets in dq hashtab - 1 */
59 struct list_head qm_dqfrlist; /* freelist of dquots */
60 struct mutex qm_dqfrlist_lock;
61 int qm_dqfrlist_cnt;
62 uint qm_nrefs; /* file systems with quota on */ 59 uint qm_nrefs; /* file systems with quota on */
63 kmem_zone_t *qm_dqzone; /* dquot mem-alloc zone */ 60 kmem_zone_t *qm_dqzone; /* dquot mem-alloc zone */
64 kmem_zone_t *qm_dqtrxzone; /* t_dqinfo of transactions */ 61 kmem_zone_t *qm_dqtrxzone; /* t_dqinfo of transactions */
@@ -71,6 +68,9 @@ typedef struct xfs_qm {
71typedef struct xfs_quotainfo { 68typedef struct xfs_quotainfo {
72 xfs_inode_t *qi_uquotaip; /* user quota inode */ 69 xfs_inode_t *qi_uquotaip; /* user quota inode */
73 xfs_inode_t *qi_gquotaip; /* group quota inode */ 70 xfs_inode_t *qi_gquotaip; /* group quota inode */
71 struct list_head qi_lru_list;
72 struct mutex qi_lru_lock;
73 int qi_lru_count;
74 struct list_head qi_dqlist; /* all dquots in filesys */ 74 struct list_head qi_dqlist; /* all dquots in filesys */
75 struct mutex qi_dqlist_lock; 75 struct mutex qi_dqlist_lock;
76 int qi_dquots; 76 int qi_dquots;
@@ -91,6 +91,7 @@ typedef struct xfs_quotainfo {
91 xfs_qcnt_t qi_isoftlimit; /* default inode count soft limit */ 91 xfs_qcnt_t qi_isoftlimit; /* default inode count soft limit */
92 xfs_qcnt_t qi_rtbhardlimit;/* default realtime blk hard limit */ 92 xfs_qcnt_t qi_rtbhardlimit;/* default realtime blk hard limit */
93 xfs_qcnt_t qi_rtbsoftlimit;/* default realtime blk soft limit */ 93 xfs_qcnt_t qi_rtbsoftlimit;/* default realtime blk soft limit */
94 struct shrinker qi_shrinker;
94} xfs_quotainfo_t; 95} xfs_quotainfo_t;
95 96
96 97