aboutsummaryrefslogtreecommitdiffstats
path: root/net/decnet/dn_table.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/decnet/dn_table.c')
-rw-r--r--net/decnet/dn_table.c125
1 files changed, 91 insertions, 34 deletions
diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c
index eca7c1e10c80..10e87262b6fb 100644
--- a/net/decnet/dn_table.c
+++ b/net/decnet/dn_table.c
@@ -75,9 +75,9 @@ for( ; ((f) = *(fp)) != NULL; (fp) = &(f)->fn_next)
75for( ; ((f) = *(fp)) != NULL && dn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_next) 75for( ; ((f) = *(fp)) != NULL && dn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_next)
76 76
77#define RT_TABLE_MIN 1 77#define RT_TABLE_MIN 1
78 78#define DN_FIB_TABLE_HASHSZ 256
79static struct hlist_head dn_fib_table_hash[DN_FIB_TABLE_HASHSZ];
79static DEFINE_RWLOCK(dn_fib_tables_lock); 80static DEFINE_RWLOCK(dn_fib_tables_lock);
80struct dn_fib_table *dn_fib_tables[RT_TABLE_MAX + 1];
81 81
82static kmem_cache_t *dn_hash_kmem __read_mostly; 82static kmem_cache_t *dn_hash_kmem __read_mostly;
83static int dn_fib_hash_zombies; 83static int dn_fib_hash_zombies;
@@ -361,7 +361,7 @@ static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb,
361{ 361{
362 int i, s_i; 362 int i, s_i;
363 363
364 s_i = cb->args[3]; 364 s_i = cb->args[4];
365 for(i = 0; f; i++, f = f->fn_next) { 365 for(i = 0; f; i++, f = f->fn_next) {
366 if (i < s_i) 366 if (i < s_i)
367 continue; 367 continue;
@@ -374,11 +374,11 @@ static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb,
374 (f->fn_state & DN_S_ZOMBIE) ? 0 : f->fn_type, 374 (f->fn_state & DN_S_ZOMBIE) ? 0 : f->fn_type,
375 f->fn_scope, &f->fn_key, dz->dz_order, 375 f->fn_scope, &f->fn_key, dz->dz_order,
376 f->fn_info, NLM_F_MULTI) < 0) { 376 f->fn_info, NLM_F_MULTI) < 0) {
377 cb->args[3] = i; 377 cb->args[4] = i;
378 return -1; 378 return -1;
379 } 379 }
380 } 380 }
381 cb->args[3] = i; 381 cb->args[4] = i;
382 return skb->len; 382 return skb->len;
383} 383}
384 384
@@ -389,20 +389,20 @@ static __inline__ int dn_hash_dump_zone(struct sk_buff *skb,
389{ 389{
390 int h, s_h; 390 int h, s_h;
391 391
392 s_h = cb->args[2]; 392 s_h = cb->args[3];
393 for(h = 0; h < dz->dz_divisor; h++) { 393 for(h = 0; h < dz->dz_divisor; h++) {
394 if (h < s_h) 394 if (h < s_h)
395 continue; 395 continue;
396 if (h > s_h) 396 if (h > s_h)
397 memset(&cb->args[3], 0, sizeof(cb->args) - 3*sizeof(cb->args[0])); 397 memset(&cb->args[4], 0, sizeof(cb->args) - 4*sizeof(cb->args[0]));
398 if (dz->dz_hash == NULL || dz->dz_hash[h] == NULL) 398 if (dz->dz_hash == NULL || dz->dz_hash[h] == NULL)
399 continue; 399 continue;
400 if (dn_hash_dump_bucket(skb, cb, tb, dz, dz->dz_hash[h]) < 0) { 400 if (dn_hash_dump_bucket(skb, cb, tb, dz, dz->dz_hash[h]) < 0) {
401 cb->args[2] = h; 401 cb->args[3] = h;
402 return -1; 402 return -1;
403 } 403 }
404 } 404 }
405 cb->args[2] = h; 405 cb->args[3] = h;
406 return skb->len; 406 return skb->len;
407} 407}
408 408
@@ -413,26 +413,63 @@ static int dn_fib_table_dump(struct dn_fib_table *tb, struct sk_buff *skb,
413 struct dn_zone *dz; 413 struct dn_zone *dz;
414 struct dn_hash *table = (struct dn_hash *)tb->data; 414 struct dn_hash *table = (struct dn_hash *)tb->data;
415 415
416 s_m = cb->args[1]; 416 s_m = cb->args[2];
417 read_lock(&dn_fib_tables_lock); 417 read_lock(&dn_fib_tables_lock);
418 for(dz = table->dh_zone_list, m = 0; dz; dz = dz->dz_next, m++) { 418 for(dz = table->dh_zone_list, m = 0; dz; dz = dz->dz_next, m++) {
419 if (m < s_m) 419 if (m < s_m)
420 continue; 420 continue;
421 if (m > s_m) 421 if (m > s_m)
422 memset(&cb->args[2], 0, sizeof(cb->args) - 2*sizeof(cb->args[0])); 422 memset(&cb->args[3], 0, sizeof(cb->args) - 3*sizeof(cb->args[0]));
423 423
424 if (dn_hash_dump_zone(skb, cb, tb, dz) < 0) { 424 if (dn_hash_dump_zone(skb, cb, tb, dz) < 0) {
425 cb->args[1] = m; 425 cb->args[2] = m;
426 read_unlock(&dn_fib_tables_lock); 426 read_unlock(&dn_fib_tables_lock);
427 return -1; 427 return -1;
428 } 428 }
429 } 429 }
430 read_unlock(&dn_fib_tables_lock); 430 read_unlock(&dn_fib_tables_lock);
431 cb->args[1] = m; 431 cb->args[2] = m;
432 432
433 return skb->len; 433 return skb->len;
434} 434}
435 435
436int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb)
437{
438 unsigned int h, s_h;
439 unsigned int e = 0, s_e;
440 struct dn_fib_table *tb;
441 struct hlist_node *node;
442 int dumped = 0;
443
444 if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) &&
445 ((struct rtmsg *)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)
446 return dn_cache_dump(skb, cb);
447
448 s_h = cb->args[0];
449 s_e = cb->args[1];
450
451 for (h = s_h; h < DN_FIB_TABLE_HASHSZ; h++, s_h = 0) {
452 e = 0;
453 hlist_for_each_entry(tb, node, &dn_fib_table_hash[h], hlist) {
454 if (e < s_e)
455 goto next;
456 if (dumped)
457 memset(&cb->args[2], 0, sizeof(cb->args) -
458 2 * sizeof(cb->args[0]));
459 if (tb->dump(tb, skb, cb) < 0)
460 goto out;
461 dumped = 1;
462next:
463 e++;
464 }
465 }
466out:
467 cb->args[1] = e;
468 cb->args[0] = h;
469
470 return skb->len;
471}
472
436static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req) 473static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req)
437{ 474{
438 struct dn_hash *table = (struct dn_hash *)tb->data; 475 struct dn_hash *table = (struct dn_hash *)tb->data;
@@ -744,6 +781,8 @@ out:
744struct dn_fib_table *dn_fib_get_table(u32 n, int create) 781struct dn_fib_table *dn_fib_get_table(u32 n, int create)
745{ 782{
746 struct dn_fib_table *t; 783 struct dn_fib_table *t;
784 struct hlist_node *node;
785 unsigned int h;
747 786
748 if (n < RT_TABLE_MIN) 787 if (n < RT_TABLE_MIN)
749 return NULL; 788 return NULL;
@@ -751,8 +790,15 @@ struct dn_fib_table *dn_fib_get_table(u32 n, int create)
751 if (n > RT_TABLE_MAX) 790 if (n > RT_TABLE_MAX)
752 return NULL; 791 return NULL;
753 792
754 if (dn_fib_tables[n]) 793 h = n & (DN_FIB_TABLE_HASHSZ - 1);
755 return dn_fib_tables[n]; 794 rcu_read_lock();
795 hlist_for_each_entry_rcu(t, node, &dn_fib_table_hash[h], hlist) {
796 if (t->n == n) {
797 rcu_read_unlock();
798 return t;
799 }
800 }
801 rcu_read_unlock();
756 802
757 if (!create) 803 if (!create)
758 return NULL; 804 return NULL;
@@ -773,33 +819,37 @@ struct dn_fib_table *dn_fib_get_table(u32 n, int create)
773 t->flush = dn_fib_table_flush; 819 t->flush = dn_fib_table_flush;
774 t->dump = dn_fib_table_dump; 820 t->dump = dn_fib_table_dump;
775 memset(t->data, 0, sizeof(struct dn_hash)); 821 memset(t->data, 0, sizeof(struct dn_hash));
776 dn_fib_tables[n] = t; 822 hlist_add_head_rcu(&t->hlist, &dn_fib_table_hash[h]);
777 823
778 return t; 824 return t;
779} 825}
780 826
781static void dn_fib_del_tree(u32 n)
782{
783 struct dn_fib_table *t;
784
785 write_lock(&dn_fib_tables_lock);
786 t = dn_fib_tables[n];
787 dn_fib_tables[n] = NULL;
788 write_unlock(&dn_fib_tables_lock);
789
790 kfree(t);
791}
792
793struct dn_fib_table *dn_fib_empty_table(void) 827struct dn_fib_table *dn_fib_empty_table(void)
794{ 828{
795 u32 id; 829 u32 id;
796 830
797 for(id = RT_TABLE_MIN; id <= RT_TABLE_MAX; id++) 831 for(id = RT_TABLE_MIN; id <= RT_TABLE_MAX; id++)
798 if (dn_fib_tables[id] == NULL) 832 if (dn_fib_get_table(id, 0) == NULL)
799 return dn_fib_get_table(id, 1); 833 return dn_fib_get_table(id, 1);
800 return NULL; 834 return NULL;
801} 835}
802 836
837void dn_fib_flush(void)
838{
839 int flushed = 0;
840 struct dn_fib_table *tb;
841 struct hlist_node *node;
842 unsigned int h;
843
844 for (h = 0; h < DN_FIB_TABLE_HASHSZ; h++) {
845 hlist_for_each_entry(tb, node, &dn_fib_table_hash[h], hlist)
846 flushed += tb->flush(tb);
847 }
848
849 if (flushed)
850 dn_rt_cache_flush(-1);
851}
852
803void __init dn_fib_table_init(void) 853void __init dn_fib_table_init(void)
804{ 854{
805 dn_hash_kmem = kmem_cache_create("dn_fib_info_cache", 855 dn_hash_kmem = kmem_cache_create("dn_fib_info_cache",
@@ -810,10 +860,17 @@ void __init dn_fib_table_init(void)
810 860
811void __exit dn_fib_table_cleanup(void) 861void __exit dn_fib_table_cleanup(void)
812{ 862{
813 int i; 863 struct dn_fib_table *t;
814 864 struct hlist_node *node, *next;
815 for (i = RT_TABLE_MIN; i <= RT_TABLE_MAX; ++i) 865 unsigned int h;
816 dn_fib_del_tree(i);
817 866
818 return; 867 write_lock(&dn_fib_tables_lock);
868 for (h = 0; h < DN_FIB_TABLE_HASHSZ; h++) {
869 hlist_for_each_entry_safe(t, node, next, &dn_fib_table_hash[h],
870 hlist) {
871 hlist_del(&t->hlist);
872 kfree(t);
873 }
874 }
875 write_unlock(&dn_fib_tables_lock);
819} 876}