aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2008-07-06 02:21:31 -0400
committerDavid S. Miller <davem@davemloft.net>2008-07-06 02:21:31 -0400
commit6fe1c7a5556807e9d7154a2d2fb938d8a9e47e5f (patch)
tree27758ea169b402aba70ef68bde8e554e7f135031 /net
parentea2aca084ba82aaf7c148d04914ceed8758ce08a (diff)
net-sched: add dynamically sized qdisc class hash helpers
Currently all qdiscs which allow to create classes uses a fixed sized hash table with size 16 to hash the classes. This causes a large bottleneck when using thousands of classes and unbound filters. Add helpers for dynamically sized class hashes to fix this. The following patches will convert the qdiscs to use them. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/sched/sch_api.c104
1 files changed, 104 insertions, 0 deletions
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 10f01ad04380..e9ebc7af049e 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -316,6 +316,110 @@ void qdisc_watchdog_cancel(struct qdisc_watchdog *wd)
316} 316}
317EXPORT_SYMBOL(qdisc_watchdog_cancel); 317EXPORT_SYMBOL(qdisc_watchdog_cancel);
318 318
319struct hlist_head *qdisc_class_hash_alloc(unsigned int n)
320{
321 unsigned int size = n * sizeof(struct hlist_head), i;
322 struct hlist_head *h;
323
324 if (size <= PAGE_SIZE)
325 h = kmalloc(size, GFP_KERNEL);
326 else
327 h = (struct hlist_head *)
328 __get_free_pages(GFP_KERNEL, get_order(size));
329
330 if (h != NULL) {
331 for (i = 0; i < n; i++)
332 INIT_HLIST_HEAD(&h[i]);
333 }
334 return h;
335}
336
337static void qdisc_class_hash_free(struct hlist_head *h, unsigned int n)
338{
339 unsigned int size = n * sizeof(struct hlist_head);
340
341 if (size <= PAGE_SIZE)
342 kfree(h);
343 else
344 free_pages((unsigned long)h, get_order(size));
345}
346
347void qdisc_class_hash_grow(struct Qdisc *sch, struct Qdisc_class_hash *clhash)
348{
349 struct Qdisc_class_common *cl;
350 struct hlist_node *n, *next;
351 struct hlist_head *nhash, *ohash;
352 unsigned int nsize, nmask, osize;
353 unsigned int i, h;
354
355 /* Rehash when load factor exceeds 0.75 */
356 if (clhash->hashelems * 4 <= clhash->hashsize * 3)
357 return;
358 nsize = clhash->hashsize * 2;
359 nmask = nsize - 1;
360 nhash = qdisc_class_hash_alloc(nsize);
361 if (nhash == NULL)
362 return;
363
364 ohash = clhash->hash;
365 osize = clhash->hashsize;
366
367 sch_tree_lock(sch);
368 for (i = 0; i < osize; i++) {
369 hlist_for_each_entry_safe(cl, n, next, &ohash[i], hnode) {
370 h = qdisc_class_hash(cl->classid, nmask);
371 hlist_add_head(&cl->hnode, &nhash[h]);
372 }
373 }
374 clhash->hash = nhash;
375 clhash->hashsize = nsize;
376 clhash->hashmask = nmask;
377 sch_tree_unlock(sch);
378
379 qdisc_class_hash_free(ohash, osize);
380}
381EXPORT_SYMBOL(qdisc_class_hash_grow);
382
383int qdisc_class_hash_init(struct Qdisc_class_hash *clhash)
384{
385 unsigned int size = 4;
386
387 clhash->hash = qdisc_class_hash_alloc(size);
388 if (clhash->hash == NULL)
389 return -ENOMEM;
390 clhash->hashsize = size;
391 clhash->hashmask = size - 1;
392 clhash->hashelems = 0;
393 return 0;
394}
395EXPORT_SYMBOL(qdisc_class_hash_init);
396
397void qdisc_class_hash_destroy(struct Qdisc_class_hash *clhash)
398{
399 qdisc_class_hash_free(clhash->hash, clhash->hashsize);
400}
401EXPORT_SYMBOL(qdisc_class_hash_destroy);
402
403void qdisc_class_hash_insert(struct Qdisc_class_hash *clhash,
404 struct Qdisc_class_common *cl)
405{
406 unsigned int h;
407
408 INIT_HLIST_NODE(&cl->hnode);
409 h = qdisc_class_hash(cl->classid, clhash->hashmask);
410 hlist_add_head(&cl->hnode, &clhash->hash[h]);
411 clhash->hashelems++;
412}
413EXPORT_SYMBOL(qdisc_class_hash_insert);
414
415void qdisc_class_hash_remove(struct Qdisc_class_hash *clhash,
416 struct Qdisc_class_common *cl)
417{
418 hlist_del(&cl->hnode);
419 clhash->hashelems--;
420}
421EXPORT_SYMBOL(qdisc_class_hash_remove);
422
319/* Allocate an unique handle from space managed by kernel */ 423/* Allocate an unique handle from space managed by kernel */
320 424
321static u32 qdisc_alloc_handle(struct net_device *dev) 425static u32 qdisc_alloc_handle(struct net_device *dev)