diff options
Diffstat (limited to 'net/sched/sch_api.c')
-rw-r--r-- | net/sched/sch_api.c | 104 |
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 | } |
317 | EXPORT_SYMBOL(qdisc_watchdog_cancel); | 317 | EXPORT_SYMBOL(qdisc_watchdog_cancel); |
318 | 318 | ||
319 | struct 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 | |||
337 | static 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 | |||
347 | void 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 | } | ||
381 | EXPORT_SYMBOL(qdisc_class_hash_grow); | ||
382 | |||
383 | int 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 | } | ||
395 | EXPORT_SYMBOL(qdisc_class_hash_init); | ||
396 | |||
397 | void qdisc_class_hash_destroy(struct Qdisc_class_hash *clhash) | ||
398 | { | ||
399 | qdisc_class_hash_free(clhash->hash, clhash->hashsize); | ||
400 | } | ||
401 | EXPORT_SYMBOL(qdisc_class_hash_destroy); | ||
402 | |||
403 | void 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 | } | ||
413 | EXPORT_SYMBOL(qdisc_class_hash_insert); | ||
414 | |||
415 | void 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 | } | ||
421 | EXPORT_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 | ||
321 | static u32 qdisc_alloc_handle(struct net_device *dev) | 425 | static u32 qdisc_alloc_handle(struct net_device *dev) |