aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/name_table.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/tipc/name_table.c')
-rw-r--r--net/tipc/name_table.c373
1 files changed, 283 insertions, 90 deletions
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index 3a6a0a7c0759..c8df0223371a 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -1,8 +1,8 @@
1/* 1/*
2 * net/tipc/name_table.c: TIPC name table code 2 * net/tipc/name_table.c: TIPC name table code
3 * 3 *
4 * Copyright (c) 2000-2006, Ericsson AB 4 * Copyright (c) 2000-2006, 2014, Ericsson AB
5 * Copyright (c) 2004-2008, 2010-2011, Wind River Systems 5 * Copyright (c) 2004-2008, 2010-2014, Wind River Systems
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
8 * Redistribution and use in source and binary forms, with or without 8 * Redistribution and use in source and binary forms, with or without
@@ -42,6 +42,12 @@
42 42
43#define TIPC_NAMETBL_SIZE 1024 /* must be a power of 2 */ 43#define TIPC_NAMETBL_SIZE 1024 /* must be a power of 2 */
44 44
45static const struct nla_policy
46tipc_nl_name_table_policy[TIPC_NLA_NAME_TABLE_MAX + 1] = {
47 [TIPC_NLA_NAME_TABLE_UNSPEC] = { .type = NLA_UNSPEC },
48 [TIPC_NLA_NAME_TABLE_PUBL] = { .type = NLA_NESTED }
49};
50
45/** 51/**
46 * struct name_info - name sequence publication info 52 * struct name_info - name sequence publication info
47 * @node_list: circular list of publications made by own node 53 * @node_list: circular list of publications made by own node
@@ -86,6 +92,7 @@ struct sub_seq {
86 * @ns_list: links to adjacent name sequences in hash chain 92 * @ns_list: links to adjacent name sequences in hash chain
87 * @subscriptions: list of subscriptions for this 'type' 93 * @subscriptions: list of subscriptions for this 'type'
88 * @lock: spinlock controlling access to publication lists of all sub-sequences 94 * @lock: spinlock controlling access to publication lists of all sub-sequences
95 * @rcu: RCU callback head used for deferred freeing
89 */ 96 */
90struct name_seq { 97struct name_seq {
91 u32 type; 98 u32 type;
@@ -95,21 +102,11 @@ struct name_seq {
95 struct hlist_node ns_list; 102 struct hlist_node ns_list;
96 struct list_head subscriptions; 103 struct list_head subscriptions;
97 spinlock_t lock; 104 spinlock_t lock;
105 struct rcu_head rcu;
98}; 106};
99 107
100/** 108struct name_table *tipc_nametbl;
101 * struct name_table - table containing all existing port name publications 109DEFINE_SPINLOCK(tipc_nametbl_lock);
102 * @types: pointer to fixed-sized array of name sequence lists,
103 * accessed via hashing on 'type'; name sequence lists are *not* sorted
104 * @local_publ_count: number of publications issued by this node
105 */
106struct name_table {
107 struct hlist_head *types;
108 u32 local_publ_count;
109};
110
111static struct name_table table;
112DEFINE_RWLOCK(tipc_nametbl_lock);
113 110
114static int hash(int x) 111static int hash(int x)
115{ 112{
@@ -136,9 +133,7 @@ static struct publication *publ_create(u32 type, u32 lower, u32 upper,
136 publ->node = node; 133 publ->node = node;
137 publ->ref = port_ref; 134 publ->ref = port_ref;
138 publ->key = key; 135 publ->key = key;
139 INIT_LIST_HEAD(&publ->local_list);
140 INIT_LIST_HEAD(&publ->pport_list); 136 INIT_LIST_HEAD(&publ->pport_list);
141 INIT_LIST_HEAD(&publ->subscr.nodesub_list);
142 return publ; 137 return publ;
143} 138}
144 139
@@ -173,22 +168,10 @@ static struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_hea
173 nseq->alloc = 1; 168 nseq->alloc = 1;
174 INIT_HLIST_NODE(&nseq->ns_list); 169 INIT_HLIST_NODE(&nseq->ns_list);
175 INIT_LIST_HEAD(&nseq->subscriptions); 170 INIT_LIST_HEAD(&nseq->subscriptions);
176 hlist_add_head(&nseq->ns_list, seq_head); 171 hlist_add_head_rcu(&nseq->ns_list, seq_head);
177 return nseq; 172 return nseq;
178} 173}
179 174
180/*
181 * nameseq_delete_empty - deletes a name sequence structure if now unused
182 */
183static void nameseq_delete_empty(struct name_seq *seq)
184{
185 if (!seq->first_free && list_empty(&seq->subscriptions)) {
186 hlist_del_init(&seq->ns_list);
187 kfree(seq->sseqs);
188 kfree(seq);
189 }
190}
191
192/** 175/**
193 * nameseq_find_subseq - find sub-sequence (if any) matching a name instance 176 * nameseq_find_subseq - find sub-sequence (if any) matching a name instance
194 * 177 *
@@ -469,8 +452,8 @@ static struct name_seq *nametbl_find_seq(u32 type)
469 struct hlist_head *seq_head; 452 struct hlist_head *seq_head;
470 struct name_seq *ns; 453 struct name_seq *ns;
471 454
472 seq_head = &table.types[hash(type)]; 455 seq_head = &tipc_nametbl->seq_hlist[hash(type)];
473 hlist_for_each_entry(ns, seq_head, ns_list) { 456 hlist_for_each_entry_rcu(ns, seq_head, ns_list) {
474 if (ns->type == type) 457 if (ns->type == type)
475 return ns; 458 return ns;
476 } 459 }
@@ -481,7 +464,9 @@ static struct name_seq *nametbl_find_seq(u32 type)
481struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper, 464struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper,
482 u32 scope, u32 node, u32 port, u32 key) 465 u32 scope, u32 node, u32 port, u32 key)
483{ 466{
467 struct publication *publ;
484 struct name_seq *seq = nametbl_find_seq(type); 468 struct name_seq *seq = nametbl_find_seq(type);
469 int index = hash(type);
485 470
486 if ((scope < TIPC_ZONE_SCOPE) || (scope > TIPC_NODE_SCOPE) || 471 if ((scope < TIPC_ZONE_SCOPE) || (scope > TIPC_NODE_SCOPE) ||
487 (lower > upper)) { 472 (lower > upper)) {
@@ -491,12 +476,16 @@ struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper,
491 } 476 }
492 477
493 if (!seq) 478 if (!seq)
494 seq = tipc_nameseq_create(type, &table.types[hash(type)]); 479 seq = tipc_nameseq_create(type,
480 &tipc_nametbl->seq_hlist[index]);
495 if (!seq) 481 if (!seq)
496 return NULL; 482 return NULL;
497 483
498 return tipc_nameseq_insert_publ(seq, type, lower, upper, 484 spin_lock_bh(&seq->lock);
485 publ = tipc_nameseq_insert_publ(seq, type, lower, upper,
499 scope, node, port, key); 486 scope, node, port, key);
487 spin_unlock_bh(&seq->lock);
488 return publ;
500} 489}
501 490
502struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower, 491struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower,
@@ -508,8 +497,16 @@ struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower,
508 if (!seq) 497 if (!seq)
509 return NULL; 498 return NULL;
510 499
500 spin_lock_bh(&seq->lock);
511 publ = tipc_nameseq_remove_publ(seq, lower, node, ref, key); 501 publ = tipc_nameseq_remove_publ(seq, lower, node, ref, key);
512 nameseq_delete_empty(seq); 502 if (!seq->first_free && list_empty(&seq->subscriptions)) {
503 hlist_del_init_rcu(&seq->ns_list);
504 kfree(seq->sseqs);
505 spin_unlock_bh(&seq->lock);
506 kfree_rcu(seq, rcu);
507 return publ;
508 }
509 spin_unlock_bh(&seq->lock);
513 return publ; 510 return publ;
514} 511}
515 512
@@ -538,14 +535,14 @@ u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode)
538 if (!tipc_in_scope(*destnode, tipc_own_addr)) 535 if (!tipc_in_scope(*destnode, tipc_own_addr))
539 return 0; 536 return 0;
540 537
541 read_lock_bh(&tipc_nametbl_lock); 538 rcu_read_lock();
542 seq = nametbl_find_seq(type); 539 seq = nametbl_find_seq(type);
543 if (unlikely(!seq)) 540 if (unlikely(!seq))
544 goto not_found; 541 goto not_found;
542 spin_lock_bh(&seq->lock);
545 sseq = nameseq_find_subseq(seq, instance); 543 sseq = nameseq_find_subseq(seq, instance);
546 if (unlikely(!sseq)) 544 if (unlikely(!sseq))
547 goto not_found; 545 goto no_match;
548 spin_lock_bh(&seq->lock);
549 info = sseq->info; 546 info = sseq->info;
550 547
551 /* Closest-First Algorithm */ 548 /* Closest-First Algorithm */
@@ -595,7 +592,7 @@ u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode)
595no_match: 592no_match:
596 spin_unlock_bh(&seq->lock); 593 spin_unlock_bh(&seq->lock);
597not_found: 594not_found:
598 read_unlock_bh(&tipc_nametbl_lock); 595 rcu_read_unlock();
599 *destnode = node; 596 *destnode = node;
600 return ref; 597 return ref;
601} 598}
@@ -621,13 +618,12 @@ int tipc_nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit,
621 struct name_info *info; 618 struct name_info *info;
622 int res = 0; 619 int res = 0;
623 620
624 read_lock_bh(&tipc_nametbl_lock); 621 rcu_read_lock();
625 seq = nametbl_find_seq(type); 622 seq = nametbl_find_seq(type);
626 if (!seq) 623 if (!seq)
627 goto exit; 624 goto exit;
628 625
629 spin_lock_bh(&seq->lock); 626 spin_lock_bh(&seq->lock);
630
631 sseq = seq->sseqs + nameseq_locate_subseq(seq, lower); 627 sseq = seq->sseqs + nameseq_locate_subseq(seq, lower);
632 sseq_stop = seq->sseqs + seq->first_free; 628 sseq_stop = seq->sseqs + seq->first_free;
633 for (; sseq != sseq_stop; sseq++) { 629 for (; sseq != sseq_stop; sseq++) {
@@ -645,10 +641,9 @@ int tipc_nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit,
645 if (info->cluster_list_size != info->node_list_size) 641 if (info->cluster_list_size != info->node_list_size)
646 res = 1; 642 res = 1;
647 } 643 }
648
649 spin_unlock_bh(&seq->lock); 644 spin_unlock_bh(&seq->lock);
650exit: 645exit:
651 read_unlock_bh(&tipc_nametbl_lock); 646 rcu_read_unlock();
652 return res; 647 return res;
653} 648}
654 649
@@ -661,22 +656,23 @@ struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper,
661 struct publication *publ; 656 struct publication *publ;
662 struct sk_buff *buf = NULL; 657 struct sk_buff *buf = NULL;
663 658
664 if (table.local_publ_count >= TIPC_MAX_PUBLICATIONS) { 659 spin_lock_bh(&tipc_nametbl_lock);
660 if (tipc_nametbl->local_publ_count >= TIPC_MAX_PUBLICATIONS) {
665 pr_warn("Publication failed, local publication limit reached (%u)\n", 661 pr_warn("Publication failed, local publication limit reached (%u)\n",
666 TIPC_MAX_PUBLICATIONS); 662 TIPC_MAX_PUBLICATIONS);
663 spin_unlock_bh(&tipc_nametbl_lock);
667 return NULL; 664 return NULL;
668 } 665 }
669 666
670 write_lock_bh(&tipc_nametbl_lock);
671 publ = tipc_nametbl_insert_publ(type, lower, upper, scope, 667 publ = tipc_nametbl_insert_publ(type, lower, upper, scope,
672 tipc_own_addr, port_ref, key); 668 tipc_own_addr, port_ref, key);
673 if (likely(publ)) { 669 if (likely(publ)) {
674 table.local_publ_count++; 670 tipc_nametbl->local_publ_count++;
675 buf = tipc_named_publish(publ); 671 buf = tipc_named_publish(publ);
676 /* Any pending external events? */ 672 /* Any pending external events? */
677 tipc_named_process_backlog(); 673 tipc_named_process_backlog();
678 } 674 }
679 write_unlock_bh(&tipc_nametbl_lock); 675 spin_unlock_bh(&tipc_nametbl_lock);
680 676
681 if (buf) 677 if (buf)
682 named_cluster_distribute(buf); 678 named_cluster_distribute(buf);
@@ -689,27 +685,28 @@ struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper,
689int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key) 685int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key)
690{ 686{
691 struct publication *publ; 687 struct publication *publ;
692 struct sk_buff *buf; 688 struct sk_buff *skb = NULL;
693 689
694 write_lock_bh(&tipc_nametbl_lock); 690 spin_lock_bh(&tipc_nametbl_lock);
695 publ = tipc_nametbl_remove_publ(type, lower, tipc_own_addr, ref, key); 691 publ = tipc_nametbl_remove_publ(type, lower, tipc_own_addr, ref, key);
696 if (likely(publ)) { 692 if (likely(publ)) {
697 table.local_publ_count--; 693 tipc_nametbl->local_publ_count--;
698 buf = tipc_named_withdraw(publ); 694 skb = tipc_named_withdraw(publ);
699 /* Any pending external events? */ 695 /* Any pending external events? */
700 tipc_named_process_backlog(); 696 tipc_named_process_backlog();
701 write_unlock_bh(&tipc_nametbl_lock);
702 list_del_init(&publ->pport_list); 697 list_del_init(&publ->pport_list);
703 kfree(publ); 698 kfree_rcu(publ, rcu);
699 } else {
700 pr_err("Unable to remove local publication\n"
701 "(type=%u, lower=%u, ref=%u, key=%u)\n",
702 type, lower, ref, key);
703 }
704 spin_unlock_bh(&tipc_nametbl_lock);
704 705
705 if (buf) 706 if (skb) {
706 named_cluster_distribute(buf); 707 named_cluster_distribute(skb);
707 return 1; 708 return 1;
708 } 709 }
709 write_unlock_bh(&tipc_nametbl_lock);
710 pr_err("Unable to remove local publication\n"
711 "(type=%u, lower=%u, ref=%u, key=%u)\n",
712 type, lower, ref, key);
713 return 0; 710 return 0;
714} 711}
715 712
@@ -719,12 +716,14 @@ int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key)
719void tipc_nametbl_subscribe(struct tipc_subscription *s) 716void tipc_nametbl_subscribe(struct tipc_subscription *s)
720{ 717{
721 u32 type = s->seq.type; 718 u32 type = s->seq.type;
719 int index = hash(type);
722 struct name_seq *seq; 720 struct name_seq *seq;
723 721
724 write_lock_bh(&tipc_nametbl_lock); 722 spin_lock_bh(&tipc_nametbl_lock);
725 seq = nametbl_find_seq(type); 723 seq = nametbl_find_seq(type);
726 if (!seq) 724 if (!seq)
727 seq = tipc_nameseq_create(type, &table.types[hash(type)]); 725 seq = tipc_nameseq_create(type,
726 &tipc_nametbl->seq_hlist[index]);
728 if (seq) { 727 if (seq) {
729 spin_lock_bh(&seq->lock); 728 spin_lock_bh(&seq->lock);
730 tipc_nameseq_subscribe(seq, s); 729 tipc_nameseq_subscribe(seq, s);
@@ -733,7 +732,7 @@ void tipc_nametbl_subscribe(struct tipc_subscription *s)
733 pr_warn("Failed to create subscription for {%u,%u,%u}\n", 732 pr_warn("Failed to create subscription for {%u,%u,%u}\n",
734 s->seq.type, s->seq.lower, s->seq.upper); 733 s->seq.type, s->seq.lower, s->seq.upper);
735 } 734 }
736 write_unlock_bh(&tipc_nametbl_lock); 735 spin_unlock_bh(&tipc_nametbl_lock);
737} 736}
738 737
739/** 738/**
@@ -743,18 +742,23 @@ void tipc_nametbl_unsubscribe(struct tipc_subscription *s)
743{ 742{
744 struct name_seq *seq; 743 struct name_seq *seq;
745 744
746 write_lock_bh(&tipc_nametbl_lock); 745 spin_lock_bh(&tipc_nametbl_lock);
747 seq = nametbl_find_seq(s->seq.type); 746 seq = nametbl_find_seq(s->seq.type);
748 if (seq != NULL) { 747 if (seq != NULL) {
749 spin_lock_bh(&seq->lock); 748 spin_lock_bh(&seq->lock);
750 list_del_init(&s->nameseq_list); 749 list_del_init(&s->nameseq_list);
751 spin_unlock_bh(&seq->lock); 750 if (!seq->first_free && list_empty(&seq->subscriptions)) {
752 nameseq_delete_empty(seq); 751 hlist_del_init_rcu(&seq->ns_list);
752 kfree(seq->sseqs);
753 spin_unlock_bh(&seq->lock);
754 kfree_rcu(seq, rcu);
755 } else {
756 spin_unlock_bh(&seq->lock);
757 }
753 } 758 }
754 write_unlock_bh(&tipc_nametbl_lock); 759 spin_unlock_bh(&tipc_nametbl_lock);
755} 760}
756 761
757
758/** 762/**
759 * subseq_list - print specified sub-sequence contents into the given buffer 763 * subseq_list - print specified sub-sequence contents into the given buffer
760 */ 764 */
@@ -876,8 +880,8 @@ static int nametbl_list(char *buf, int len, u32 depth_info,
876 lowbound = 0; 880 lowbound = 0;
877 upbound = ~0; 881 upbound = ~0;
878 for (i = 0; i < TIPC_NAMETBL_SIZE; i++) { 882 for (i = 0; i < TIPC_NAMETBL_SIZE; i++) {
879 seq_head = &table.types[i]; 883 seq_head = &tipc_nametbl->seq_hlist[i];
880 hlist_for_each_entry(seq, seq_head, ns_list) { 884 hlist_for_each_entry_rcu(seq, seq_head, ns_list) {
881 ret += nameseq_list(seq, buf + ret, len - ret, 885 ret += nameseq_list(seq, buf + ret, len - ret,
882 depth, seq->type, 886 depth, seq->type,
883 lowbound, upbound, i); 887 lowbound, upbound, i);
@@ -892,8 +896,8 @@ static int nametbl_list(char *buf, int len, u32 depth_info,
892 } 896 }
893 ret += nametbl_header(buf + ret, len - ret, depth); 897 ret += nametbl_header(buf + ret, len - ret, depth);
894 i = hash(type); 898 i = hash(type);
895 seq_head = &table.types[i]; 899 seq_head = &tipc_nametbl->seq_hlist[i];
896 hlist_for_each_entry(seq, seq_head, ns_list) { 900 hlist_for_each_entry_rcu(seq, seq_head, ns_list) {
897 if (seq->type == type) { 901 if (seq->type == type) {
898 ret += nameseq_list(seq, buf + ret, len - ret, 902 ret += nameseq_list(seq, buf + ret, len - ret,
899 depth, type, 903 depth, type,
@@ -925,11 +929,11 @@ struct sk_buff *tipc_nametbl_get(const void *req_tlv_area, int req_tlv_space)
925 pb = TLV_DATA(rep_tlv); 929 pb = TLV_DATA(rep_tlv);
926 pb_len = ULTRA_STRING_MAX_LEN; 930 pb_len = ULTRA_STRING_MAX_LEN;
927 argv = (struct tipc_name_table_query *)TLV_DATA(req_tlv_area); 931 argv = (struct tipc_name_table_query *)TLV_DATA(req_tlv_area);
928 read_lock_bh(&tipc_nametbl_lock); 932 rcu_read_lock();
929 str_len = nametbl_list(pb, pb_len, ntohl(argv->depth), 933 str_len = nametbl_list(pb, pb_len, ntohl(argv->depth),
930 ntohl(argv->type), 934 ntohl(argv->type),
931 ntohl(argv->lowbound), ntohl(argv->upbound)); 935 ntohl(argv->lowbound), ntohl(argv->upbound));
932 read_unlock_bh(&tipc_nametbl_lock); 936 rcu_read_unlock();
933 str_len += 1; /* for "\0" */ 937 str_len += 1; /* for "\0" */
934 skb_put(buf, TLV_SPACE(str_len)); 938 skb_put(buf, TLV_SPACE(str_len));
935 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len); 939 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
@@ -939,12 +943,18 @@ struct sk_buff *tipc_nametbl_get(const void *req_tlv_area, int req_tlv_space)
939 943
940int tipc_nametbl_init(void) 944int tipc_nametbl_init(void)
941{ 945{
942 table.types = kcalloc(TIPC_NAMETBL_SIZE, sizeof(struct hlist_head), 946 int i;
943 GFP_ATOMIC); 947
944 if (!table.types) 948 tipc_nametbl = kzalloc(sizeof(*tipc_nametbl), GFP_ATOMIC);
949 if (!tipc_nametbl)
945 return -ENOMEM; 950 return -ENOMEM;
946 951
947 table.local_publ_count = 0; 952 for (i = 0; i < TIPC_NAMETBL_SIZE; i++)
953 INIT_HLIST_HEAD(&tipc_nametbl->seq_hlist[i]);
954
955 INIT_LIST_HEAD(&tipc_nametbl->publ_list[TIPC_ZONE_SCOPE]);
956 INIT_LIST_HEAD(&tipc_nametbl->publ_list[TIPC_CLUSTER_SCOPE]);
957 INIT_LIST_HEAD(&tipc_nametbl->publ_list[TIPC_NODE_SCOPE]);
948 return 0; 958 return 0;
949} 959}
950 960
@@ -959,17 +969,19 @@ static void tipc_purge_publications(struct name_seq *seq)
959 struct sub_seq *sseq; 969 struct sub_seq *sseq;
960 struct name_info *info; 970 struct name_info *info;
961 971
962 if (!seq->sseqs) { 972 spin_lock_bh(&seq->lock);
963 nameseq_delete_empty(seq);
964 return;
965 }
966 sseq = seq->sseqs; 973 sseq = seq->sseqs;
967 info = sseq->info; 974 info = sseq->info;
968 list_for_each_entry_safe(publ, safe, &info->zone_list, zone_list) { 975 list_for_each_entry_safe(publ, safe, &info->zone_list, zone_list) {
969 tipc_nametbl_remove_publ(publ->type, publ->lower, publ->node, 976 tipc_nametbl_remove_publ(publ->type, publ->lower, publ->node,
970 publ->ref, publ->key); 977 publ->ref, publ->key);
971 kfree(publ); 978 kfree_rcu(publ, rcu);
972 } 979 }
980 hlist_del_init_rcu(&seq->ns_list);
981 kfree(seq->sseqs);
982 spin_unlock_bh(&seq->lock);
983
984 kfree_rcu(seq, rcu);
973} 985}
974 986
975void tipc_nametbl_stop(void) 987void tipc_nametbl_stop(void)
@@ -977,21 +989,202 @@ void tipc_nametbl_stop(void)
977 u32 i; 989 u32 i;
978 struct name_seq *seq; 990 struct name_seq *seq;
979 struct hlist_head *seq_head; 991 struct hlist_head *seq_head;
980 struct hlist_node *safe;
981 992
982 /* Verify name table is empty and purge any lingering 993 /* Verify name table is empty and purge any lingering
983 * publications, then release the name table 994 * publications, then release the name table
984 */ 995 */
985 write_lock_bh(&tipc_nametbl_lock); 996 spin_lock_bh(&tipc_nametbl_lock);
986 for (i = 0; i < TIPC_NAMETBL_SIZE; i++) { 997 for (i = 0; i < TIPC_NAMETBL_SIZE; i++) {
987 if (hlist_empty(&table.types[i])) 998 if (hlist_empty(&tipc_nametbl->seq_hlist[i]))
988 continue; 999 continue;
989 seq_head = &table.types[i]; 1000 seq_head = &tipc_nametbl->seq_hlist[i];
990 hlist_for_each_entry_safe(seq, safe, seq_head, ns_list) { 1001 hlist_for_each_entry_rcu(seq, seq_head, ns_list) {
991 tipc_purge_publications(seq); 1002 tipc_purge_publications(seq);
992 } 1003 }
993 } 1004 }
994 kfree(table.types); 1005 spin_unlock_bh(&tipc_nametbl_lock);
995 table.types = NULL; 1006
996 write_unlock_bh(&tipc_nametbl_lock); 1007 synchronize_net();
1008 kfree(tipc_nametbl);
1009
1010}
1011
1012static int __tipc_nl_add_nametable_publ(struct tipc_nl_msg *msg,
1013 struct name_seq *seq,
1014 struct sub_seq *sseq, u32 *last_publ)
1015{
1016 void *hdr;
1017 struct nlattr *attrs;
1018 struct nlattr *publ;
1019 struct publication *p;
1020
1021 if (*last_publ) {
1022 list_for_each_entry(p, &sseq->info->zone_list, zone_list)
1023 if (p->key == *last_publ)
1024 break;
1025 if (p->key != *last_publ)
1026 return -EPIPE;
1027 } else {
1028 p = list_first_entry(&sseq->info->zone_list, struct publication,
1029 zone_list);
1030 }
1031
1032 list_for_each_entry_from(p, &sseq->info->zone_list, zone_list) {
1033 *last_publ = p->key;
1034
1035 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq,
1036 &tipc_genl_v2_family, NLM_F_MULTI,
1037 TIPC_NL_NAME_TABLE_GET);
1038 if (!hdr)
1039 return -EMSGSIZE;
1040
1041 attrs = nla_nest_start(msg->skb, TIPC_NLA_NAME_TABLE);
1042 if (!attrs)
1043 goto msg_full;
1044
1045 publ = nla_nest_start(msg->skb, TIPC_NLA_NAME_TABLE_PUBL);
1046 if (!publ)
1047 goto attr_msg_full;
1048
1049 if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_TYPE, seq->type))
1050 goto publ_msg_full;
1051 if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_LOWER, sseq->lower))
1052 goto publ_msg_full;
1053 if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_UPPER, sseq->upper))
1054 goto publ_msg_full;
1055 if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_SCOPE, p->scope))
1056 goto publ_msg_full;
1057 if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_NODE, p->node))
1058 goto publ_msg_full;
1059 if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_REF, p->ref))
1060 goto publ_msg_full;
1061 if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_KEY, p->key))
1062 goto publ_msg_full;
1063
1064 nla_nest_end(msg->skb, publ);
1065 nla_nest_end(msg->skb, attrs);
1066 genlmsg_end(msg->skb, hdr);
1067 }
1068 *last_publ = 0;
1069
1070 return 0;
1071
1072publ_msg_full:
1073 nla_nest_cancel(msg->skb, publ);
1074attr_msg_full:
1075 nla_nest_cancel(msg->skb, attrs);
1076msg_full:
1077 genlmsg_cancel(msg->skb, hdr);
1078
1079 return -EMSGSIZE;
1080}
1081
1082static int __tipc_nl_subseq_list(struct tipc_nl_msg *msg, struct name_seq *seq,
1083 u32 *last_lower, u32 *last_publ)
1084{
1085 struct sub_seq *sseq;
1086 struct sub_seq *sseq_start;
1087 int err;
1088
1089 if (*last_lower) {
1090 sseq_start = nameseq_find_subseq(seq, *last_lower);
1091 if (!sseq_start)
1092 return -EPIPE;
1093 } else {
1094 sseq_start = seq->sseqs;
1095 }
1096
1097 for (sseq = sseq_start; sseq != &seq->sseqs[seq->first_free]; sseq++) {
1098 err = __tipc_nl_add_nametable_publ(msg, seq, sseq, last_publ);
1099 if (err) {
1100 *last_lower = sseq->lower;
1101 return err;
1102 }
1103 }
1104 *last_lower = 0;
1105
1106 return 0;
1107}
1108
1109static int __tipc_nl_seq_list(struct tipc_nl_msg *msg, u32 *last_type,
1110 u32 *last_lower, u32 *last_publ)
1111{
1112 struct hlist_head *seq_head;
1113 struct name_seq *seq = NULL;
1114 int err;
1115 int i;
1116
1117 if (*last_type)
1118 i = hash(*last_type);
1119 else
1120 i = 0;
1121
1122 for (; i < TIPC_NAMETBL_SIZE; i++) {
1123 seq_head = &tipc_nametbl->seq_hlist[i];
1124
1125 if (*last_type) {
1126 seq = nametbl_find_seq(*last_type);
1127 if (!seq)
1128 return -EPIPE;
1129 } else {
1130 hlist_for_each_entry_rcu(seq, seq_head, ns_list)
1131 break;
1132 if (!seq)
1133 continue;
1134 }
1135
1136 hlist_for_each_entry_from_rcu(seq, ns_list) {
1137 spin_lock_bh(&seq->lock);
1138 err = __tipc_nl_subseq_list(msg, seq, last_lower,
1139 last_publ);
1140
1141 if (err) {
1142 *last_type = seq->type;
1143 spin_unlock_bh(&seq->lock);
1144 return err;
1145 }
1146 spin_unlock_bh(&seq->lock);
1147 }
1148 *last_type = 0;
1149 }
1150 return 0;
1151}
1152
1153int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb)
1154{
1155 int err;
1156 int done = cb->args[3];
1157 u32 last_type = cb->args[0];
1158 u32 last_lower = cb->args[1];
1159 u32 last_publ = cb->args[2];
1160 struct tipc_nl_msg msg;
1161
1162 if (done)
1163 return 0;
1164
1165 msg.skb = skb;
1166 msg.portid = NETLINK_CB(cb->skb).portid;
1167 msg.seq = cb->nlh->nlmsg_seq;
1168
1169 rcu_read_lock();
1170 err = __tipc_nl_seq_list(&msg, &last_type, &last_lower, &last_publ);
1171 if (!err) {
1172 done = 1;
1173 } else if (err != -EMSGSIZE) {
1174 /* We never set seq or call nl_dump_check_consistent() this
1175 * means that setting prev_seq here will cause the consistence
1176 * check to fail in the netlink callback handler. Resulting in
1177 * the NLMSG_DONE message having the NLM_F_DUMP_INTR flag set if
1178 * we got an error.
1179 */
1180 cb->prev_seq = 1;
1181 }
1182 rcu_read_unlock();
1183
1184 cb->args[0] = last_type;
1185 cb->args[1] = last_lower;
1186 cb->args[2] = last_publ;
1187 cb->args[3] = done;
1188
1189 return skb->len;
997} 1190}