1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37#include "core.h"
38#include "config.h"
39#include "name_table.h"
40#include "name_distr.h"
41#include "subscr.h"
42#include "port.h"
43
44#define TIPC_NAMETBL_SIZE 1024
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59struct name_info {
60 struct list_head node_list;
61 struct list_head cluster_list;
62 struct list_head zone_list;
63 u32 node_list_size;
64 u32 cluster_list_size;
65 u32 zone_list_size;
66};
67
68
69
70
71
72
73
74struct sub_seq {
75 u32 lower;
76 u32 upper;
77 struct name_info *info;
78};
79
80
81
82
83
84
85
86
87
88
89
90
91struct name_seq {
92 u32 type;
93 struct sub_seq *sseqs;
94 u32 alloc;
95 u32 first_free;
96 struct hlist_node ns_list;
97 struct list_head subscriptions;
98 spinlock_t lock;
99};
100
101
102
103
104
105
106
107struct name_table {
108 struct hlist_head *types;
109 u32 local_publ_count;
110};
111
112static struct name_table table;
113DEFINE_RWLOCK(tipc_nametbl_lock);
114
115static int hash(int x)
116{
117 return x & (TIPC_NAMETBL_SIZE - 1);
118}
119
120
121
122
123static struct publication *publ_create(u32 type, u32 lower, u32 upper,
124 u32 scope, u32 node, u32 port_ref,
125 u32 key)
126{
127 struct publication *publ = kzalloc(sizeof(*publ), GFP_ATOMIC);
128 if (publ == NULL) {
129 pr_warn("Publication creation failure, no memory\n");
130 return NULL;
131 }
132
133 publ->type = type;
134 publ->lower = lower;
135 publ->upper = upper;
136 publ->scope = scope;
137 publ->node = node;
138 publ->ref = port_ref;
139 publ->key = key;
140 INIT_LIST_HEAD(&publ->local_list);
141 INIT_LIST_HEAD(&publ->pport_list);
142 INIT_LIST_HEAD(&publ->subscr.nodesub_list);
143 return publ;
144}
145
146
147
148
149static struct sub_seq *tipc_subseq_alloc(u32 cnt)
150{
151 struct sub_seq *sseq = kcalloc(cnt, sizeof(struct sub_seq), GFP_ATOMIC);
152 return sseq;
153}
154
155
156
157
158
159
160static struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_head)
161{
162 struct name_seq *nseq = kzalloc(sizeof(*nseq), GFP_ATOMIC);
163 struct sub_seq *sseq = tipc_subseq_alloc(1);
164
165 if (!nseq || !sseq) {
166 pr_warn("Name sequence creation failed, no memory\n");
167 kfree(nseq);
168 kfree(sseq);
169 return NULL;
170 }
171
172 spin_lock_init(&nseq->lock);
173 nseq->type = type;
174 nseq->sseqs = sseq;
175 nseq->alloc = 1;
176 INIT_HLIST_NODE(&nseq->ns_list);
177 INIT_LIST_HEAD(&nseq->subscriptions);
178 hlist_add_head(&nseq->ns_list, seq_head);
179 return nseq;
180}
181
182
183
184
185static void nameseq_delete_empty(struct name_seq *seq)
186{
187 if (!seq->first_free && list_empty(&seq->subscriptions)) {
188 hlist_del_init(&seq->ns_list);
189 kfree(seq->sseqs);
190 kfree(seq);
191 }
192}
193
194
195
196
197
198
199static struct sub_seq *nameseq_find_subseq(struct name_seq *nseq,
200 u32 instance)
201{
202 struct sub_seq *sseqs = nseq->sseqs;
203 int low = 0;
204 int high = nseq->first_free - 1;
205 int mid;
206
207 while (low <= high) {
208 mid = (low + high) / 2;
209 if (instance < sseqs[mid].lower)
210 high = mid - 1;
211 else if (instance > sseqs[mid].upper)
212 low = mid + 1;
213 else
214 return &sseqs[mid];
215 }
216 return NULL;
217}
218
219
220
221
222
223
224
225
226
227
228static u32 nameseq_locate_subseq(struct name_seq *nseq, u32 instance)
229{
230 struct sub_seq *sseqs = nseq->sseqs;
231 int low = 0;
232 int high = nseq->first_free - 1;
233 int mid;
234
235 while (low <= high) {
236 mid = (low + high) / 2;
237 if (instance < sseqs[mid].lower)
238 high = mid - 1;
239 else if (instance > sseqs[mid].upper)
240 low = mid + 1;
241 else
242 return mid;
243 }
244 return low;
245}
246
247
248
249
250static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
251 u32 type, u32 lower, u32 upper,
252 u32 scope, u32 node, u32 port, u32 key)
253{
254 struct tipc_subscription *s;
255 struct tipc_subscription *st;
256 struct publication *publ;
257 struct sub_seq *sseq;
258 struct name_info *info;
259 int created_subseq = 0;
260
261 sseq = nameseq_find_subseq(nseq, lower);
262 if (sseq) {
263
264
265 if ((sseq->lower != lower) || (sseq->upper != upper)) {
266 pr_warn("Cannot publish {%u,%u,%u}, overlap error\n",
267 type, lower, upper);
268 return NULL;
269 }
270
271 info = sseq->info;
272
273
274 list_for_each_entry(publ, &info->zone_list, zone_list) {
275 if ((publ->ref == port) && (publ->key == key) &&
276 (!publ->node || (publ->node == node)))
277 return NULL;
278 }
279 } else {
280 u32 inspos;
281 struct sub_seq *freesseq;
282
283
284 inspos = nameseq_locate_subseq(nseq, lower);
285
286
287 if ((inspos < nseq->first_free) &&
288 (upper >= nseq->sseqs[inspos].lower)) {
289 pr_warn("Cannot publish {%u,%u,%u}, overlap error\n",
290 type, lower, upper);
291 return NULL;
292 }
293
294
295 if (nseq->first_free == nseq->alloc) {
296 struct sub_seq *sseqs = tipc_subseq_alloc(nseq->alloc * 2);
297
298 if (!sseqs) {
299 pr_warn("Cannot publish {%u,%u,%u}, no memory\n",
300 type, lower, upper);
301 return NULL;
302 }
303 memcpy(sseqs, nseq->sseqs,
304 nseq->alloc * sizeof(struct sub_seq));
305 kfree(nseq->sseqs);
306 nseq->sseqs = sseqs;
307 nseq->alloc *= 2;
308 }
309
310 info = kzalloc(sizeof(*info), GFP_ATOMIC);
311 if (!info) {
312 pr_warn("Cannot publish {%u,%u,%u}, no memory\n",
313 type, lower, upper);
314 return NULL;
315 }
316
317 INIT_LIST_HEAD(&info->node_list);
318 INIT_LIST_HEAD(&info->cluster_list);
319 INIT_LIST_HEAD(&info->zone_list);
320
321
322 sseq = &nseq->sseqs[inspos];
323 freesseq = &nseq->sseqs[nseq->first_free];
324 memmove(sseq + 1, sseq, (freesseq - sseq) * sizeof(*sseq));
325 memset(sseq, 0, sizeof(*sseq));
326 nseq->first_free++;
327 sseq->lower = lower;
328 sseq->upper = upper;
329 sseq->info = info;
330 created_subseq = 1;
331 }
332
333
334 publ = publ_create(type, lower, upper, scope, node, port, key);
335 if (!publ)
336 return NULL;
337
338 list_add(&publ->zone_list, &info->zone_list);
339 info->zone_list_size++;
340
341 if (in_own_cluster(node)) {
342 list_add(&publ->cluster_list, &info->cluster_list);
343 info->cluster_list_size++;
344 }
345
346 if (in_own_node(node)) {
347 list_add(&publ->node_list, &info->node_list);
348 info->node_list_size++;
349 }
350
351
352 list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) {
353 tipc_subscr_report_overlap(s,
354 publ->lower,
355 publ->upper,
356 TIPC_PUBLISHED,
357 publ->ref,
358 publ->node,
359 created_subseq);
360 }
361 return publ;
362}
363
364
365
366
367
368
369
370
371
372
373
374
375static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 inst,
376 u32 node, u32 ref, u32 key)
377{
378 struct publication *publ;
379 struct sub_seq *sseq = nameseq_find_subseq(nseq, inst);
380 struct name_info *info;
381 struct sub_seq *free;
382 struct tipc_subscription *s, *st;
383 int removed_subseq = 0;
384
385 if (!sseq)
386 return NULL;
387
388 info = sseq->info;
389
390
391 list_for_each_entry(publ, &info->zone_list, zone_list) {
392 if ((publ->key == key) && (publ->ref == ref) &&
393 (!publ->node || (publ->node == node)))
394 goto found;
395 }
396 return NULL;
397
398found:
399
400 list_del(&publ->zone_list);
401 info->zone_list_size--;
402
403
404 if (in_own_cluster(node)) {
405 list_del(&publ->cluster_list);
406 info->cluster_list_size--;
407 }
408
409
410 if (in_own_node(node)) {
411 list_del(&publ->node_list);
412 info->node_list_size--;
413 }
414
415
416 if (list_empty(&info->zone_list)) {
417 kfree(info);
418 free = &nseq->sseqs[nseq->first_free--];
419 memmove(sseq, sseq + 1, (free - (sseq + 1)) * sizeof(*sseq));
420 removed_subseq = 1;
421 }
422
423
424 list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) {
425 tipc_subscr_report_overlap(s,
426 publ->lower,
427 publ->upper,
428 TIPC_WITHDRAWN,
429 publ->ref,
430 publ->node,
431 removed_subseq);
432 }
433
434 return publ;
435}
436
437
438
439
440
441
442static void tipc_nameseq_subscribe(struct name_seq *nseq,
443 struct tipc_subscription *s)
444{
445 struct sub_seq *sseq = nseq->sseqs;
446
447 list_add(&s->nameseq_list, &nseq->subscriptions);
448
449 if (!sseq)
450 return;
451
452 while (sseq != &nseq->sseqs[nseq->first_free]) {
453 if (tipc_subscr_overlap(s, sseq->lower, sseq->upper)) {
454 struct publication *crs;
455 struct name_info *info = sseq->info;
456 int must_report = 1;
457
458 list_for_each_entry(crs, &info->zone_list, zone_list) {
459 tipc_subscr_report_overlap(s,
460 sseq->lower,
461 sseq->upper,
462 TIPC_PUBLISHED,
463 crs->ref,
464 crs->node,
465 must_report);
466 must_report = 0;
467 }
468 }
469 sseq++;
470 }
471}
472
473static struct name_seq *nametbl_find_seq(u32 type)
474{
475 struct hlist_head *seq_head;
476 struct name_seq *ns;
477
478 seq_head = &table.types[hash(type)];
479 hlist_for_each_entry(ns, seq_head, ns_list) {
480 if (ns->type == type)
481 return ns;
482 }
483
484 return NULL;
485};
486
487struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper,
488 u32 scope, u32 node, u32 port, u32 key)
489{
490 struct name_seq *seq = nametbl_find_seq(type);
491
492 if ((scope < TIPC_ZONE_SCOPE) || (scope > TIPC_NODE_SCOPE) ||
493 (lower > upper)) {
494 pr_debug("Failed to publish illegal {%u,%u,%u} with scope %u\n",
495 type, lower, upper, scope);
496 return NULL;
497 }
498
499 if (!seq)
500 seq = tipc_nameseq_create(type, &table.types[hash(type)]);
501 if (!seq)
502 return NULL;
503
504 return tipc_nameseq_insert_publ(seq, type, lower, upper,
505 scope, node, port, key);
506}
507
508struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower,
509 u32 node, u32 ref, u32 key)
510{
511 struct publication *publ;
512 struct name_seq *seq = nametbl_find_seq(type);
513
514 if (!seq)
515 return NULL;
516
517 publ = tipc_nameseq_remove_publ(seq, lower, node, ref, key);
518 nameseq_delete_empty(seq);
519 return publ;
520}
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode)
536{
537 struct sub_seq *sseq;
538 struct name_info *info;
539 struct publication *publ;
540 struct name_seq *seq;
541 u32 ref = 0;
542 u32 node = 0;
543
544 if (!tipc_in_scope(*destnode, tipc_own_addr))
545 return 0;
546
547 read_lock_bh(&tipc_nametbl_lock);
548 seq = nametbl_find_seq(type);
549 if (unlikely(!seq))
550 goto not_found;
551 sseq = nameseq_find_subseq(seq, instance);
552 if (unlikely(!sseq))
553 goto not_found;
554 spin_lock_bh(&seq->lock);
555 info = sseq->info;
556
557
558 if (likely(!*destnode)) {
559 if (!list_empty(&info->node_list)) {
560 publ = list_first_entry(&info->node_list,
561 struct publication,
562 node_list);
563 list_move_tail(&publ->node_list,
564 &info->node_list);
565 } else if (!list_empty(&info->cluster_list)) {
566 publ = list_first_entry(&info->cluster_list,
567 struct publication,
568 cluster_list);
569 list_move_tail(&publ->cluster_list,
570 &info->cluster_list);
571 } else {
572 publ = list_first_entry(&info->zone_list,
573 struct publication,
574 zone_list);
575 list_move_tail(&publ->zone_list,
576 &info->zone_list);
577 }
578 }
579
580
581 else if (*destnode == tipc_own_addr) {
582 if (list_empty(&info->node_list))
583 goto no_match;
584 publ = list_first_entry(&info->node_list, struct publication,
585 node_list);
586 list_move_tail(&publ->node_list, &info->node_list);
587 } else if (in_own_cluster_exact(*destnode)) {
588 if (list_empty(&info->cluster_list))
589 goto no_match;
590 publ = list_first_entry(&info->cluster_list, struct publication,
591 cluster_list);
592 list_move_tail(&publ->cluster_list, &info->cluster_list);
593 } else {
594 publ = list_first_entry(&info->zone_list, struct publication,
595 zone_list);
596 list_move_tail(&publ->zone_list, &info->zone_list);
597 }
598
599 ref = publ->ref;
600 node = publ->node;
601no_match:
602 spin_unlock_bh(&seq->lock);
603not_found:
604 read_unlock_bh(&tipc_nametbl_lock);
605 *destnode = node;
606 return ref;
607}
608
609
610
611
612
613
614
615
616
617
618
619
620
621int tipc_nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit,
622 struct tipc_port_list *dports)
623{
624 struct name_seq *seq;
625 struct sub_seq *sseq;
626 struct sub_seq *sseq_stop;
627 struct name_info *info;
628 int res = 0;
629
630 read_lock_bh(&tipc_nametbl_lock);
631 seq = nametbl_find_seq(type);
632 if (!seq)
633 goto exit;
634
635 spin_lock_bh(&seq->lock);
636
637 sseq = seq->sseqs + nameseq_locate_subseq(seq, lower);
638 sseq_stop = seq->sseqs + seq->first_free;
639 for (; sseq != sseq_stop; sseq++) {
640 struct publication *publ;
641
642 if (sseq->lower > upper)
643 break;
644
645 info = sseq->info;
646 list_for_each_entry(publ, &info->node_list, node_list) {
647 if (publ->scope <= limit)
648 tipc_port_list_add(dports, publ->ref);
649 }
650
651 if (info->cluster_list_size != info->node_list_size)
652 res = 1;
653 }
654
655 spin_unlock_bh(&seq->lock);
656exit:
657 read_unlock_bh(&tipc_nametbl_lock);
658 return res;
659}
660
661
662
663
664struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper,
665 u32 scope, u32 port_ref, u32 key)
666{
667 struct publication *publ;
668
669 if (table.local_publ_count >= TIPC_MAX_PUBLICATIONS) {
670 pr_warn("Publication failed, local publication limit reached (%u)\n",
671 TIPC_MAX_PUBLICATIONS);
672 return NULL;
673 }
674
675 write_lock_bh(&tipc_nametbl_lock);
676 publ = tipc_nametbl_insert_publ(type, lower, upper, scope,
677 tipc_own_addr, port_ref, key);
678 if (likely(publ)) {
679 table.local_publ_count++;
680 tipc_named_publish(publ);
681 }
682 write_unlock_bh(&tipc_nametbl_lock);
683 return publ;
684}
685
686
687
688
689int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key)
690{
691 struct publication *publ;
692
693 write_lock_bh(&tipc_nametbl_lock);
694 publ = tipc_nametbl_remove_publ(type, lower, tipc_own_addr, ref, key);
695 if (likely(publ)) {
696 table.local_publ_count--;
697 tipc_named_withdraw(publ);
698 write_unlock_bh(&tipc_nametbl_lock);
699 list_del_init(&publ->pport_list);
700 kfree(publ);
701 return 1;
702 }
703 write_unlock_bh(&tipc_nametbl_lock);
704 pr_err("Unable to remove local publication\n"
705 "(type=%u, lower=%u, ref=%u, key=%u)\n",
706 type, lower, ref, key);
707 return 0;
708}
709
710
711
712
713void tipc_nametbl_subscribe(struct tipc_subscription *s)
714{
715 u32 type = s->seq.type;
716 struct name_seq *seq;
717
718 write_lock_bh(&tipc_nametbl_lock);
719 seq = nametbl_find_seq(type);
720 if (!seq)
721 seq = tipc_nameseq_create(type, &table.types[hash(type)]);
722 if (seq) {
723 spin_lock_bh(&seq->lock);
724 tipc_nameseq_subscribe(seq, s);
725 spin_unlock_bh(&seq->lock);
726 } else {
727 pr_warn("Failed to create subscription for {%u,%u,%u}\n",
728 s->seq.type, s->seq.lower, s->seq.upper);
729 }
730 write_unlock_bh(&tipc_nametbl_lock);
731}
732
733
734
735
736void tipc_nametbl_unsubscribe(struct tipc_subscription *s)
737{
738 struct name_seq *seq;
739
740 write_lock_bh(&tipc_nametbl_lock);
741 seq = nametbl_find_seq(s->seq.type);
742 if (seq != NULL) {
743 spin_lock_bh(&seq->lock);
744 list_del_init(&s->nameseq_list);
745 spin_unlock_bh(&seq->lock);
746 nameseq_delete_empty(seq);
747 }
748 write_unlock_bh(&tipc_nametbl_lock);
749}
750
751
752
753
754
755static int subseq_list(struct sub_seq *sseq, char *buf, int len, u32 depth,
756 u32 index)
757{
758 char portIdStr[27];
759 const char *scope_str[] = {"", " zone", " cluster", " node"};
760 struct publication *publ;
761 struct name_info *info;
762 int ret;
763
764 ret = tipc_snprintf(buf, len, "%-10u %-10u ", sseq->lower, sseq->upper);
765
766 if (depth == 2) {
767 ret += tipc_snprintf(buf - ret, len + ret, "\n");
768 return ret;
769 }
770
771 info = sseq->info;
772
773 list_for_each_entry(publ, &info->zone_list, zone_list) {
774 sprintf(portIdStr, "<%u.%u.%u:%u>",
775 tipc_zone(publ->node), tipc_cluster(publ->node),
776 tipc_node(publ->node), publ->ref);
777 ret += tipc_snprintf(buf + ret, len - ret, "%-26s ", portIdStr);
778 if (depth > 3) {
779 ret += tipc_snprintf(buf + ret, len - ret, "%-10u %s",
780 publ->key, scope_str[publ->scope]);
781 }
782 if (!list_is_last(&publ->zone_list, &info->zone_list))
783 ret += tipc_snprintf(buf + ret, len - ret,
784 "\n%33s", " ");
785 }
786
787 ret += tipc_snprintf(buf + ret, len - ret, "\n");
788 return ret;
789}
790
791
792
793
794static int nameseq_list(struct name_seq *seq, char *buf, int len, u32 depth,
795 u32 type, u32 lowbound, u32 upbound, u32 index)
796{
797 struct sub_seq *sseq;
798 char typearea[11];
799 int ret = 0;
800
801 if (seq->first_free == 0)
802 return 0;
803
804 sprintf(typearea, "%-10u", seq->type);
805
806 if (depth == 1) {
807 ret += tipc_snprintf(buf, len, "%s\n", typearea);
808 return ret;
809 }
810
811 for (sseq = seq->sseqs; sseq != &seq->sseqs[seq->first_free]; sseq++) {
812 if ((lowbound <= sseq->upper) && (upbound >= sseq->lower)) {
813 ret += tipc_snprintf(buf + ret, len - ret, "%s ",
814 typearea);
815 spin_lock_bh(&seq->lock);
816 ret += subseq_list(sseq, buf + ret, len - ret,
817 depth, index);
818 spin_unlock_bh(&seq->lock);
819 sprintf(typearea, "%10s", " ");
820 }
821 }
822 return ret;
823}
824
825
826
827
828static int nametbl_header(char *buf, int len, u32 depth)
829{
830 const char *header[] = {
831 "Type ",
832 "Lower Upper ",
833 "Port Identity ",
834 "Publication Scope"
835 };
836
837 int i;
838 int ret = 0;
839
840 if (depth > 4)
841 depth = 4;
842 for (i = 0; i < depth; i++)
843 ret += tipc_snprintf(buf + ret, len - ret, header[i]);
844 ret += tipc_snprintf(buf + ret, len - ret, "\n");
845 return ret;
846}
847
848
849
850
851static int nametbl_list(char *buf, int len, u32 depth_info,
852 u32 type, u32 lowbound, u32 upbound)
853{
854 struct hlist_head *seq_head;
855 struct name_seq *seq;
856 int all_types;
857 int ret = 0;
858 u32 depth;
859 u32 i;
860
861 all_types = (depth_info & TIPC_NTQ_ALLTYPES);
862 depth = (depth_info & ~TIPC_NTQ_ALLTYPES);
863
864 if (depth == 0)
865 return 0;
866
867 if (all_types) {
868
869 ret += nametbl_header(buf, len, depth);
870 lowbound = 0;
871 upbound = ~0;
872 for (i = 0; i < TIPC_NAMETBL_SIZE; i++) {
873 seq_head = &table.types[i];
874 hlist_for_each_entry(seq, seq_head, ns_list) {
875 ret += nameseq_list(seq, buf + ret, len - ret,
876 depth, seq->type,
877 lowbound, upbound, i);
878 }
879 }
880 } else {
881
882 if (upbound < lowbound) {
883 ret += tipc_snprintf(buf + ret, len - ret,
884 "invalid name sequence specified\n");
885 return ret;
886 }
887 ret += nametbl_header(buf + ret, len - ret, depth);
888 i = hash(type);
889 seq_head = &table.types[i];
890 hlist_for_each_entry(seq, seq_head, ns_list) {
891 if (seq->type == type) {
892 ret += nameseq_list(seq, buf + ret, len - ret,
893 depth, type,
894 lowbound, upbound, i);
895 break;
896 }
897 }
898 }
899 return ret;
900}
901
902struct sk_buff *tipc_nametbl_get(const void *req_tlv_area, int req_tlv_space)
903{
904 struct sk_buff *buf;
905 struct tipc_name_table_query *argv;
906 struct tlv_desc *rep_tlv;
907 char *pb;
908 int pb_len;
909 int str_len;
910
911 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NAME_TBL_QUERY))
912 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
913
914 buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN));
915 if (!buf)
916 return NULL;
917
918 rep_tlv = (struct tlv_desc *)buf->data;
919 pb = TLV_DATA(rep_tlv);
920 pb_len = ULTRA_STRING_MAX_LEN;
921 argv = (struct tipc_name_table_query *)TLV_DATA(req_tlv_area);
922 read_lock_bh(&tipc_nametbl_lock);
923 str_len = nametbl_list(pb, pb_len, ntohl(argv->depth),
924 ntohl(argv->type),
925 ntohl(argv->lowbound), ntohl(argv->upbound));
926 read_unlock_bh(&tipc_nametbl_lock);
927 str_len += 1;
928 skb_put(buf, TLV_SPACE(str_len));
929 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
930
931 return buf;
932}
933
934int tipc_nametbl_init(void)
935{
936 table.types = kcalloc(TIPC_NAMETBL_SIZE, sizeof(struct hlist_head),
937 GFP_ATOMIC);
938 if (!table.types)
939 return -ENOMEM;
940
941 table.local_publ_count = 0;
942 return 0;
943}
944
945void tipc_nametbl_stop(void)
946{
947 u32 i;
948
949 if (!table.types)
950 return;
951
952
953 write_lock_bh(&tipc_nametbl_lock);
954 for (i = 0; i < TIPC_NAMETBL_SIZE; i++) {
955 if (hlist_empty(&table.types[i]))
956 continue;
957 pr_err("nametbl_stop(): orphaned hash chain detected\n");
958 break;
959 }
960 kfree(table.types);
961 table.types = NULL;
962 write_unlock_bh(&tipc_nametbl_lock);
963}
964