aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/gfs2/incore.h4
-rw-r--r--fs/gfs2/main.c1
-rw-r--r--fs/gfs2/quota.c168
-rw-r--r--fs/gfs2/quota.h1
4 files changed, 126 insertions, 48 deletions
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index a99f60c98845..59d99ec9d875 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -428,10 +428,13 @@ enum {
428}; 428};
429 429
430struct gfs2_quota_data { 430struct gfs2_quota_data {
431 struct hlist_bl_node qd_hlist;
431 struct list_head qd_list; 432 struct list_head qd_list;
432 struct kqid qd_id; 433 struct kqid qd_id;
434 struct gfs2_sbd *qd_sbd;
433 struct lockref qd_lockref; 435 struct lockref qd_lockref;
434 struct list_head qd_lru; 436 struct list_head qd_lru;
437 unsigned qd_hash;
435 438
436 unsigned long qd_flags; /* QDF_... */ 439 unsigned long qd_flags; /* QDF_... */
437 440
@@ -450,6 +453,7 @@ struct gfs2_quota_data {
450 453
451 u64 qd_sync_gen; 454 u64 qd_sync_gen;
452 unsigned long qd_last_warn; 455 unsigned long qd_last_warn;
456 struct rcu_head qd_rcu;
453}; 457};
454 458
455struct gfs2_trans { 459struct gfs2_trans {
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c
index 0650db2541ef..c272e73063de 100644
--- a/fs/gfs2/main.c
+++ b/fs/gfs2/main.c
@@ -76,6 +76,7 @@ static int __init init_gfs2_fs(void)
76 76
77 gfs2_str2qstr(&gfs2_qdot, "."); 77 gfs2_str2qstr(&gfs2_qdot, ".");
78 gfs2_str2qstr(&gfs2_qdotdot, ".."); 78 gfs2_str2qstr(&gfs2_qdotdot, "..");
79 gfs2_quota_hash_init();
79 80
80 error = gfs2_sys_init(); 81 error = gfs2_sys_init();
81 if (error) 82 if (error)
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index 1b6b3675ee1d..a1df01d381a8 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -52,6 +52,10 @@
52#include <linux/dqblk_xfs.h> 52#include <linux/dqblk_xfs.h>
53#include <linux/lockref.h> 53#include <linux/lockref.h>
54#include <linux/list_lru.h> 54#include <linux/list_lru.h>
55#include <linux/rcupdate.h>
56#include <linux/rculist_bl.h>
57#include <linux/bit_spinlock.h>
58#include <linux/jhash.h>
55 59
56#include "gfs2.h" 60#include "gfs2.h"
57#include "incore.h" 61#include "incore.h"
@@ -67,10 +71,43 @@
67#include "inode.h" 71#include "inode.h"
68#include "util.h" 72#include "util.h"
69 73
70/* Lock order: qd_lock -> qd->lockref.lock -> lru lock */ 74#define GFS2_QD_HASH_SHIFT 12
75#define GFS2_QD_HASH_SIZE (1 << GFS2_QD_HASH_SHIFT)
76#define GFS2_QD_HASH_MASK (GFS2_QD_HASH_SIZE - 1)
77
78/* Lock order: qd_lock -> bucket lock -> qd->lockref.lock -> lru lock */
71static DEFINE_SPINLOCK(qd_lock); 79static DEFINE_SPINLOCK(qd_lock);
72struct list_lru gfs2_qd_lru; 80struct list_lru gfs2_qd_lru;
73 81
82static struct hlist_bl_head qd_hash_table[GFS2_QD_HASH_SIZE];
83
84static unsigned int gfs2_qd_hash(const struct gfs2_sbd *sdp,
85 const struct kqid qid)
86{
87 unsigned int h;
88
89 h = jhash(&sdp, sizeof(struct gfs2_sbd *), 0);
90 h = jhash(&qid, sizeof(struct kqid), h);
91
92 return h & GFS2_QD_HASH_MASK;
93}
94
95static inline void spin_lock_bucket(unsigned int hash)
96{
97 hlist_bl_lock(&qd_hash_table[hash]);
98}
99
100static inline void spin_unlock_bucket(unsigned int hash)
101{
102 hlist_bl_unlock(&qd_hash_table[hash]);
103}
104
105static void gfs2_qd_dealloc(struct rcu_head *rcu)
106{
107 struct gfs2_quota_data *qd = container_of(rcu, struct gfs2_quota_data, qd_rcu);
108 kmem_cache_free(gfs2_quotad_cachep, qd);
109}
110
74static void gfs2_qd_dispose(struct list_head *list) 111static void gfs2_qd_dispose(struct list_head *list)
75{ 112{
76 struct gfs2_quota_data *qd; 113 struct gfs2_quota_data *qd;
@@ -87,6 +124,10 @@ static void gfs2_qd_dispose(struct list_head *list)
87 list_del(&qd->qd_list); 124 list_del(&qd->qd_list);
88 spin_unlock(&qd_lock); 125 spin_unlock(&qd_lock);
89 126
127 spin_lock_bucket(qd->qd_hash);
128 hlist_bl_del_rcu(&qd->qd_hlist);
129 spin_unlock_bucket(qd->qd_hash);
130
90 gfs2_assert_warn(sdp, !qd->qd_change); 131 gfs2_assert_warn(sdp, !qd->qd_change);
91 gfs2_assert_warn(sdp, !qd->qd_slot_count); 132 gfs2_assert_warn(sdp, !qd->qd_slot_count);
92 gfs2_assert_warn(sdp, !qd->qd_bh_count); 133 gfs2_assert_warn(sdp, !qd->qd_bh_count);
@@ -95,7 +136,7 @@ static void gfs2_qd_dispose(struct list_head *list)
95 atomic_dec(&sdp->sd_quota_count); 136 atomic_dec(&sdp->sd_quota_count);
96 137
97 /* Delete it from the common reclaim list */ 138 /* Delete it from the common reclaim list */
98 kmem_cache_free(gfs2_quotad_cachep, qd); 139 call_rcu(&qd->qd_rcu, gfs2_qd_dealloc);
99 } 140 }
100} 141}
101 142
@@ -165,83 +206,95 @@ static u64 qd2offset(struct gfs2_quota_data *qd)
165 return offset; 206 return offset;
166} 207}
167 208
168static int qd_alloc(struct gfs2_sbd *sdp, struct kqid qid, 209static struct gfs2_quota_data *qd_alloc(unsigned hash, struct gfs2_sbd *sdp, struct kqid qid)
169 struct gfs2_quota_data **qdp)
170{ 210{
171 struct gfs2_quota_data *qd; 211 struct gfs2_quota_data *qd;
172 int error; 212 int error;
173 213
174 qd = kmem_cache_zalloc(gfs2_quotad_cachep, GFP_NOFS); 214 qd = kmem_cache_zalloc(gfs2_quotad_cachep, GFP_NOFS);
175 if (!qd) 215 if (!qd)
176 return -ENOMEM; 216 return NULL;
177 217
218 qd->qd_sbd = sdp;
178 qd->qd_lockref.count = 1; 219 qd->qd_lockref.count = 1;
179 spin_lock_init(&qd->qd_lockref.lock); 220 spin_lock_init(&qd->qd_lockref.lock);
180 qd->qd_id = qid; 221 qd->qd_id = qid;
181 qd->qd_slot = -1; 222 qd->qd_slot = -1;
182 INIT_LIST_HEAD(&qd->qd_lru); 223 INIT_LIST_HEAD(&qd->qd_lru);
224 qd->qd_hash = hash;
183 225
184 error = gfs2_glock_get(sdp, qd2index(qd), 226 error = gfs2_glock_get(sdp, qd2index(qd),
185 &gfs2_quota_glops, CREATE, &qd->qd_gl); 227 &gfs2_quota_glops, CREATE, &qd->qd_gl);
186 if (error) 228 if (error)
187 goto fail; 229 goto fail;
188 230
189 *qdp = qd; 231 return qd;
190
191 return 0;
192 232
193fail: 233fail:
194 kmem_cache_free(gfs2_quotad_cachep, qd); 234 kmem_cache_free(gfs2_quotad_cachep, qd);
195 return error; 235 return NULL;
196} 236}
197 237
198static int qd_get(struct gfs2_sbd *sdp, struct kqid qid, 238static struct gfs2_quota_data *gfs2_qd_search_bucket(unsigned int hash,
199 struct gfs2_quota_data **qdp) 239 const struct gfs2_sbd *sdp,
240 struct kqid qid)
200{ 241{
201 struct gfs2_quota_data *qd = NULL, *new_qd = NULL; 242 struct gfs2_quota_data *qd;
202 int error, found; 243 struct hlist_bl_node *h;
203
204 *qdp = NULL;
205 244
206 for (;;) { 245 hlist_bl_for_each_entry_rcu(qd, h, &qd_hash_table[hash], qd_hlist) {
207 found = 0; 246 if (!qid_eq(qd->qd_id, qid))
208 spin_lock(&qd_lock); 247 continue;
209 list_for_each_entry(qd, &sdp->sd_quota_list, qd_list) { 248 if (qd->qd_sbd != sdp)
210 if (qid_eq(qd->qd_id, qid) && 249 continue;
211 lockref_get_not_dead(&qd->qd_lockref)) { 250 if (lockref_get_not_dead(&qd->qd_lockref)) {
212 list_lru_del(&gfs2_qd_lru, &qd->qd_lru); 251 list_lru_del(&gfs2_qd_lru, &qd->qd_lru);
213 found = 1; 252 return qd;
214 break;
215 }
216 } 253 }
254 }
217 255
218 if (!found) 256 return NULL;
219 qd = NULL; 257}
220 258
221 if (!qd && new_qd) {
222 qd = new_qd;
223 list_add(&qd->qd_list, &sdp->sd_quota_list);
224 atomic_inc(&sdp->sd_quota_count);
225 new_qd = NULL;
226 }
227 259
228 spin_unlock(&qd_lock); 260static int qd_get(struct gfs2_sbd *sdp, struct kqid qid,
261 struct gfs2_quota_data **qdp)
262{
263 struct gfs2_quota_data *qd, *new_qd;
264 unsigned int hash = gfs2_qd_hash(sdp, qid);
229 265
230 if (qd) { 266 rcu_read_lock();
231 if (new_qd) { 267 *qdp = qd = gfs2_qd_search_bucket(hash, sdp, qid);
232 gfs2_glock_put(new_qd->qd_gl); 268 rcu_read_unlock();
233 kmem_cache_free(gfs2_quotad_cachep, new_qd);
234 }
235 *qdp = qd;
236 return 0;
237 }
238 269
239 error = qd_alloc(sdp, qid, &new_qd); 270 if (qd)
240 if (error) 271 return 0;
241 return error; 272
273 new_qd = qd_alloc(hash, sdp, qid);
274 if (!new_qd)
275 return -ENOMEM;
276
277 spin_lock(&qd_lock);
278 spin_lock_bucket(hash);
279 *qdp = qd = gfs2_qd_search_bucket(hash, sdp, qid);
280 if (qd == NULL) {
281 *qdp = new_qd;
282 list_add(&new_qd->qd_list, &sdp->sd_quota_list);
283 hlist_bl_add_head_rcu(&new_qd->qd_hlist, &qd_hash_table[hash]);
284 atomic_inc(&sdp->sd_quota_count);
285 }
286 spin_unlock_bucket(hash);
287 spin_unlock(&qd_lock);
288
289 if (qd) {
290 gfs2_glock_put(new_qd->qd_gl);
291 kmem_cache_free(gfs2_quotad_cachep, new_qd);
242 } 292 }
293
294 return 0;
243} 295}
244 296
297
245static void qd_hold(struct gfs2_quota_data *qd) 298static void qd_hold(struct gfs2_quota_data *qd)
246{ 299{
247 struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; 300 struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
@@ -1215,6 +1268,7 @@ int gfs2_quota_init(struct gfs2_sbd *sdp)
1215 unsigned int blocks = size >> sdp->sd_sb.sb_bsize_shift; 1268 unsigned int blocks = size >> sdp->sd_sb.sb_bsize_shift;
1216 unsigned int x, slot = 0; 1269 unsigned int x, slot = 0;
1217 unsigned int found = 0; 1270 unsigned int found = 0;
1271 unsigned int hash;
1218 u64 dblock; 1272 u64 dblock;
1219 u32 extlen = 0; 1273 u32 extlen = 0;
1220 int error; 1274 int error;
@@ -1272,8 +1326,9 @@ int gfs2_quota_init(struct gfs2_sbd *sdp)
1272 if (!qc_change) 1326 if (!qc_change)
1273 continue; 1327 continue;
1274 1328
1275 error = qd_alloc(sdp, qc_id, &qd); 1329 hash = gfs2_qd_hash(sdp, qc_id);
1276 if (error) { 1330 qd = qd_alloc(hash, sdp, qc_id);
1331 if (qd == NULL) {
1277 brelse(bh); 1332 brelse(bh);
1278 goto fail; 1333 goto fail;
1279 } 1334 }
@@ -1289,6 +1344,10 @@ int gfs2_quota_init(struct gfs2_sbd *sdp)
1289 atomic_inc(&sdp->sd_quota_count); 1344 atomic_inc(&sdp->sd_quota_count);
1290 spin_unlock(&qd_lock); 1345 spin_unlock(&qd_lock);
1291 1346
1347 spin_lock_bucket(hash);
1348 hlist_bl_add_head_rcu(&qd->qd_hlist, &qd_hash_table[hash]);
1349 spin_unlock_bucket(hash);
1350
1292 found++; 1351 found++;
1293 } 1352 }
1294 1353
@@ -1335,11 +1394,16 @@ void gfs2_quota_cleanup(struct gfs2_sbd *sdp)
1335 spin_unlock(&qd->qd_lockref.lock); 1394 spin_unlock(&qd->qd_lockref.lock);
1336 1395
1337 list_del(&qd->qd_list); 1396 list_del(&qd->qd_list);
1397
1338 /* Also remove if this qd exists in the reclaim list */ 1398 /* Also remove if this qd exists in the reclaim list */
1339 list_lru_del(&gfs2_qd_lru, &qd->qd_lru); 1399 list_lru_del(&gfs2_qd_lru, &qd->qd_lru);
1340 atomic_dec(&sdp->sd_quota_count); 1400 atomic_dec(&sdp->sd_quota_count);
1341 spin_unlock(&qd_lock); 1401 spin_unlock(&qd_lock);
1342 1402
1403 spin_lock_bucket(qd->qd_hash);
1404 hlist_bl_del_rcu(&qd->qd_hlist);
1405 spin_unlock_bucket(qd->qd_hash);
1406
1343 if (!qd->qd_lockref.count) { 1407 if (!qd->qd_lockref.count) {
1344 gfs2_assert_warn(sdp, !qd->qd_change); 1408 gfs2_assert_warn(sdp, !qd->qd_change);
1345 gfs2_assert_warn(sdp, !qd->qd_slot_count); 1409 gfs2_assert_warn(sdp, !qd->qd_slot_count);
@@ -1348,7 +1412,7 @@ void gfs2_quota_cleanup(struct gfs2_sbd *sdp)
1348 gfs2_assert_warn(sdp, !qd->qd_bh_count); 1412 gfs2_assert_warn(sdp, !qd->qd_bh_count);
1349 1413
1350 gfs2_glock_put(qd->qd_gl); 1414 gfs2_glock_put(qd->qd_gl);
1351 kmem_cache_free(gfs2_quotad_cachep, qd); 1415 call_rcu(&qd->qd_rcu, gfs2_qd_dealloc);
1352 1416
1353 spin_lock(&qd_lock); 1417 spin_lock(&qd_lock);
1354 } 1418 }
@@ -1643,3 +1707,11 @@ const struct quotactl_ops gfs2_quotactl_ops = {
1643 .get_dqblk = gfs2_get_dqblk, 1707 .get_dqblk = gfs2_get_dqblk,
1644 .set_dqblk = gfs2_set_dqblk, 1708 .set_dqblk = gfs2_set_dqblk,
1645}; 1709};
1710
1711void __init gfs2_quota_hash_init(void)
1712{
1713 unsigned i;
1714
1715 for(i = 0; i < GFS2_QD_HASH_SIZE; i++)
1716 INIT_HLIST_BL_HEAD(&qd_hash_table[i]);
1717}
diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h
index 96e4f34a03b0..55d506eb3c4a 100644
--- a/fs/gfs2/quota.h
+++ b/fs/gfs2/quota.h
@@ -57,5 +57,6 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip)
57extern const struct quotactl_ops gfs2_quotactl_ops; 57extern const struct quotactl_ops gfs2_quotactl_ops;
58extern struct shrinker gfs2_qd_shrinker; 58extern struct shrinker gfs2_qd_shrinker;
59extern struct list_lru gfs2_qd_lru; 59extern struct list_lru gfs2_qd_lru;
60extern void __init gfs2_quota_hash_init(void);
60 61
61#endif /* __QUOTA_DOT_H__ */ 62#endif /* __QUOTA_DOT_H__ */