aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2012-02-01 08:57:20 -0500
committerBen Myers <bpm@sgi.com>2012-02-10 13:02:05 -0500
commit04da0c8196ac0b12fb6b84f4b7a51ad2fa56d869 (patch)
tree1348207af6e7824a9baa268236768b857db00712
parent4505360376637832f79f84f352588b0a045ad113 (diff)
xfs: use a normal shrinker for the dquot freelist
Stop reusing dquots from the freelist when allocating new ones directly, and implement a shrinker that actually follows the specifications for the interface. The shrinker implementation is still highly suboptimal at this point, but we can gradually work on it. This also fixes an bug in the previous lock ordering, where we would take the hash and dqlist locks inside of the freelist lock against the normal lock ordering. This is only solvable by introducing the dispose list, and thus not when using direct reclaim of unused dquots for new allocations. As a side-effect the quota upper bound and used to free ratio values in /proc/fs/xfs/xqm are set to 0 as these values don't make any sense in the new world order. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Ben Myers <bpm@sgi.com>
-rw-r--r--fs/xfs/kmem.h6
-rw-r--r--fs/xfs/xfs_dquot.c103
-rw-r--r--fs/xfs/xfs_qm.c291
-rw-r--r--fs/xfs/xfs_qm.h14
-rw-r--r--fs/xfs/xfs_qm_stats.c4
-rw-r--r--fs/xfs/xfs_trace.h5
6 files changed, 141 insertions, 282 deletions
diff --git a/fs/xfs/kmem.h b/fs/xfs/kmem.h
index 292eff198030..ab7c53fe346e 100644
--- a/fs/xfs/kmem.h
+++ b/fs/xfs/kmem.h
@@ -110,10 +110,4 @@ kmem_zone_destroy(kmem_zone_t *zone)
110extern void *kmem_zone_alloc(kmem_zone_t *, unsigned int __nocast); 110extern void *kmem_zone_alloc(kmem_zone_t *, unsigned int __nocast);
111extern void *kmem_zone_zalloc(kmem_zone_t *, unsigned int __nocast); 111extern void *kmem_zone_zalloc(kmem_zone_t *, unsigned int __nocast);
112 112
113static inline int
114kmem_shake_allow(gfp_t gfp_mask)
115{
116 return ((gfp_mask & __GFP_WAIT) && (gfp_mask & __GFP_FS));
117}
118
119#endif /* __XFS_SUPPORT_KMEM_H__ */ 113#endif /* __XFS_SUPPORT_KMEM_H__ */
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index b4ff40b5f918..cbcb7bea38e2 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -63,82 +63,6 @@ int xfs_dqerror_mod = 33;
63static struct lock_class_key xfs_dquot_other_class; 63static struct lock_class_key xfs_dquot_other_class;
64 64
65/* 65/*
66 * Allocate and initialize a dquot. We don't always allocate fresh memory;
67 * we try to reclaim a free dquot if the number of incore dquots are above
68 * a threshold.
69 * The only field inside the core that gets initialized at this point
70 * is the d_id field. The idea is to fill in the entire q_core
71 * when we read in the on disk dquot.
72 */
73STATIC xfs_dquot_t *
74xfs_qm_dqinit(
75 xfs_mount_t *mp,
76 xfs_dqid_t id,
77 uint type)
78{
79 xfs_dquot_t *dqp;
80 boolean_t brandnewdquot;
81
82 brandnewdquot = xfs_qm_dqalloc_incore(&dqp);
83 dqp->dq_flags = type;
84 dqp->q_core.d_id = cpu_to_be32(id);
85 dqp->q_mount = mp;
86
87 /*
88 * No need to re-initialize these if this is a reclaimed dquot.
89 */
90 if (brandnewdquot) {
91 INIT_LIST_HEAD(&dqp->q_freelist);
92 mutex_init(&dqp->q_qlock);
93 init_waitqueue_head(&dqp->q_pinwait);
94
95 /*
96 * Because we want to use a counting completion, complete
97 * the flush completion once to allow a single access to
98 * the flush completion without blocking.
99 */
100 init_completion(&dqp->q_flush);
101 complete(&dqp->q_flush);
102
103 trace_xfs_dqinit(dqp);
104 } else {
105 /*
106 * Only the q_core portion was zeroed in dqreclaim_one().
107 * So, we need to reset others.
108 */
109 dqp->q_nrefs = 0;
110 dqp->q_blkno = 0;
111 INIT_LIST_HEAD(&dqp->q_mplist);
112 INIT_LIST_HEAD(&dqp->q_hashlist);
113 dqp->q_bufoffset = 0;
114 dqp->q_fileoffset = 0;
115 dqp->q_transp = NULL;
116 dqp->q_gdquot = NULL;
117 dqp->q_res_bcount = 0;
118 dqp->q_res_icount = 0;
119 dqp->q_res_rtbcount = 0;
120 atomic_set(&dqp->q_pincount, 0);
121 dqp->q_hash = NULL;
122 ASSERT(list_empty(&dqp->q_freelist));
123
124 trace_xfs_dqreuse(dqp);
125 }
126
127 /*
128 * In either case we need to make sure group quotas have a different
129 * lock class than user quotas, to make sure lockdep knows we can
130 * locks of one of each at the same time.
131 */
132 if (!(type & XFS_DQ_USER))
133 lockdep_set_class(&dqp->q_qlock, &xfs_dquot_other_class);
134
135 /*
136 * log item gets initialized later
137 */
138 return (dqp);
139}
140
141/*
142 * This is called to free all the memory associated with a dquot 66 * This is called to free all the memory associated with a dquot
143 */ 67 */
144void 68void
@@ -567,7 +491,32 @@ xfs_qm_dqread(
567 int error; 491 int error;
568 int cancelflags = 0; 492 int cancelflags = 0;
569 493
570 dqp = xfs_qm_dqinit(mp, id, type); 494
495 dqp = kmem_zone_zalloc(xfs_Gqm->qm_dqzone, KM_SLEEP);
496
497 dqp->dq_flags = type;
498 dqp->q_core.d_id = cpu_to_be32(id);
499 dqp->q_mount = mp;
500 INIT_LIST_HEAD(&dqp->q_freelist);
501 mutex_init(&dqp->q_qlock);
502 init_waitqueue_head(&dqp->q_pinwait);
503
504 /*
505 * Because we want to use a counting completion, complete
506 * the flush completion once to allow a single access to
507 * the flush completion without blocking.
508 */
509 init_completion(&dqp->q_flush);
510 complete(&dqp->q_flush);
511
512 /*
513 * Make sure group quotas have a different lock class than user
514 * quotas.
515 */
516 if (!(type & XFS_DQ_USER))
517 lockdep_set_class(&dqp->q_qlock, &xfs_dquot_other_class);
518
519 atomic_inc(&xfs_Gqm->qm_totaldquots);
571 520
572 trace_xfs_dqread(dqp); 521 trace_xfs_dqread(dqp);
573 522
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index 671f37eae1c7..c436def733bf 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -50,7 +50,6 @@
50 */ 50 */
51struct mutex xfs_Gqm_lock; 51struct mutex xfs_Gqm_lock;
52struct xfs_qm *xfs_Gqm; 52struct xfs_qm *xfs_Gqm;
53uint ndquot;
54 53
55kmem_zone_t *qm_dqzone; 54kmem_zone_t *qm_dqzone;
56kmem_zone_t *qm_dqtrxzone; 55kmem_zone_t *qm_dqtrxzone;
@@ -93,7 +92,6 @@ xfs_Gqm_init(void)
93 goto out_free_udqhash; 92 goto out_free_udqhash;
94 93
95 hsize /= sizeof(xfs_dqhash_t); 94 hsize /= sizeof(xfs_dqhash_t);
96 ndquot = hsize << 8;
97 95
98 xqm = kmem_zalloc(sizeof(xfs_qm_t), KM_SLEEP); 96 xqm = kmem_zalloc(sizeof(xfs_qm_t), KM_SLEEP);
99 xqm->qm_dqhashmask = hsize - 1; 97 xqm->qm_dqhashmask = hsize - 1;
@@ -137,7 +135,6 @@ xfs_Gqm_init(void)
137 xqm->qm_dqtrxzone = qm_dqtrxzone; 135 xqm->qm_dqtrxzone = qm_dqtrxzone;
138 136
139 atomic_set(&xqm->qm_totaldquots, 0); 137 atomic_set(&xqm->qm_totaldquots, 0);
140 xqm->qm_dqfree_ratio = XFS_QM_DQFREE_RATIO;
141 xqm->qm_nrefs = 0; 138 xqm->qm_nrefs = 0;
142 return xqm; 139 return xqm;
143 140
@@ -1600,216 +1597,150 @@ xfs_qm_init_quotainos(
1600 return 0; 1597 return 0;
1601} 1598}
1602 1599
1600STATIC void
1601xfs_qm_dqfree_one(
1602 struct xfs_dquot *dqp)
1603{
1604 struct xfs_mount *mp = dqp->q_mount;
1605 struct xfs_quotainfo *qi = mp->m_quotainfo;
1603 1606
1607 mutex_lock(&dqp->q_hash->qh_lock);
1608 list_del_init(&dqp->q_hashlist);
1609 dqp->q_hash->qh_version++;
1610 mutex_unlock(&dqp->q_hash->qh_lock);
1604 1611
1605/* 1612 mutex_lock(&qi->qi_dqlist_lock);
1606 * Pop the least recently used dquot off the freelist and recycle it. 1613 list_del_init(&dqp->q_mplist);
1607 */ 1614 qi->qi_dquots--;
1608STATIC struct xfs_dquot * 1615 qi->qi_dqreclaims++;
1609xfs_qm_dqreclaim_one(void) 1616 mutex_unlock(&qi->qi_dqlist_lock);