diff options
author | Steve French <sfrench@us.ibm.com> | 2006-01-17 22:49:59 -0500 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2006-01-17 22:49:59 -0500 |
commit | d65177c1ae7f085723154105c5dc8d9e16ae8265 (patch) | |
tree | 14408129d880d89cc5e937f2810f243ed1e6fcde /net/tipc/name_table.c | |
parent | d41f084a74de860fe879403fbbad13abdf7aea8e (diff) | |
parent | 15578eeb6cd4b74492f26e60624aa1a9a52ddd7b (diff) |
Merge with /pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'net/tipc/name_table.c')
-rw-r--r-- | net/tipc/name_table.c | 1079 |
1 files changed, 1079 insertions, 0 deletions
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c new file mode 100644 index 000000000000..972c83eb83b4 --- /dev/null +++ b/net/tipc/name_table.c | |||
@@ -0,0 +1,1079 @@ | |||
1 | /* | ||
2 | * net/tipc/name_table.c: TIPC name table code | ||
3 | * | ||
4 | * Copyright (c) 2000-2006, Ericsson AB | ||
5 | * Copyright (c) 2004-2005, Wind River Systems | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions are met: | ||
10 | * | ||
11 | * 1. Redistributions of source code must retain the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer. | ||
13 | * 2. Redistributions in binary form must reproduce the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer in the | ||
15 | * documentation and/or other materials provided with the distribution. | ||
16 | * 3. Neither the names of the copyright holders nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived from | ||
18 | * this software without specific prior written permission. | ||
19 | * | ||
20 | * Alternatively, this software may be distributed under the terms of the | ||
21 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
22 | * Software Foundation. | ||
23 | * | ||
24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
25 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
32 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
34 | * POSSIBILITY OF SUCH DAMAGE. | ||
35 | */ | ||
36 | |||
37 | #include "core.h" | ||
38 | #include "config.h" | ||
39 | #include "dbg.h" | ||
40 | #include "name_table.h" | ||
41 | #include "name_distr.h" | ||
42 | #include "addr.h" | ||
43 | #include "node_subscr.h" | ||
44 | #include "subscr.h" | ||
45 | #include "port.h" | ||
46 | #include "cluster.h" | ||
47 | #include "bcast.h" | ||
48 | |||
49 | int tipc_nametbl_size = 1024; /* must be a power of 2 */ | ||
50 | |||
51 | /** | ||
52 | * struct sub_seq - container for all published instances of a name sequence | ||
53 | * @lower: name sequence lower bound | ||
54 | * @upper: name sequence upper bound | ||
55 | * @node_list: circular list of matching publications with >= node scope | ||
56 | * @cluster_list: circular list of matching publications with >= cluster scope | ||
57 | * @zone_list: circular list of matching publications with >= zone scope | ||
58 | */ | ||
59 | |||
60 | struct sub_seq { | ||
61 | u32 lower; | ||
62 | u32 upper; | ||
63 | struct publication *node_list; | ||
64 | struct publication *cluster_list; | ||
65 | struct publication *zone_list; | ||
66 | }; | ||
67 | |||
68 | /** | ||
69 | * struct name_seq - container for all published instances of a name type | ||
70 | * @type: 32 bit 'type' value for name sequence | ||
71 | * @sseq: pointer to dynamically-sized array of sub-sequences of this 'type'; | ||
72 | * sub-sequences are sorted in ascending order | ||
73 | * @alloc: number of sub-sequences currently in array | ||
74 | * @first_free: upper bound of highest sub-sequence + 1 | ||
75 | * @ns_list: links to adjacent name sequences in hash chain | ||
76 | * @subscriptions: list of subscriptions for this 'type' | ||
77 | * @lock: spinlock controlling access to name sequence structure | ||
78 | */ | ||
79 | |||
80 | struct name_seq { | ||
81 | u32 type; | ||
82 | struct sub_seq *sseqs; | ||
83 | u32 alloc; | ||
84 | u32 first_free; | ||
85 | struct hlist_node ns_list; | ||
86 | struct list_head subscriptions; | ||
87 | spinlock_t lock; | ||
88 | }; | ||
89 | |||
90 | /** | ||
91 | * struct name_table - table containing all existing port name publications | ||
92 | * @types: pointer to fixed-sized array of name sequence lists, | ||
93 | * accessed via hashing on 'type'; name sequence lists are *not* sorted | ||
94 | * @local_publ_count: number of publications issued by this node | ||
95 | */ | ||
96 | |||
97 | struct name_table { | ||
98 | struct hlist_head *types; | ||
99 | u32 local_publ_count; | ||
100 | }; | ||
101 | |||
102 | struct name_table table = { NULL } ; | ||
103 | static atomic_t rsv_publ_ok = ATOMIC_INIT(0); | ||
104 | rwlock_t nametbl_lock = RW_LOCK_UNLOCKED; | ||
105 | |||
106 | |||
107 | static inline int hash(int x) | ||
108 | { | ||
109 | return(x & (tipc_nametbl_size - 1)); | ||
110 | } | ||
111 | |||
112 | /** | ||
113 | * publ_create - create a publication structure | ||
114 | */ | ||
115 | |||
116 | static struct publication *publ_create(u32 type, u32 lower, u32 upper, | ||
117 | u32 scope, u32 node, u32 port_ref, | ||
118 | u32 key) | ||
119 | { | ||
120 | struct publication *publ = | ||
121 | (struct publication *)kmalloc(sizeof(*publ), GFP_ATOMIC); | ||
122 | if (publ == NULL) { | ||
123 | warn("Memory squeeze; failed to create publication\n"); | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | memset(publ, 0, sizeof(*publ)); | ||
128 | publ->type = type; | ||
129 | publ->lower = lower; | ||
130 | publ->upper = upper; | ||
131 | publ->scope = scope; | ||
132 | publ->node = node; | ||
133 | publ->ref = port_ref; | ||
134 | publ->key = key; | ||
135 | INIT_LIST_HEAD(&publ->local_list); | ||
136 | INIT_LIST_HEAD(&publ->pport_list); | ||
137 | INIT_LIST_HEAD(&publ->subscr.nodesub_list); | ||
138 | return publ; | ||
139 | } | ||
140 | |||
141 | /** | ||
142 | * subseq_alloc - allocate a specified number of sub-sequence structures | ||
143 | */ | ||
144 | |||
145 | struct sub_seq *subseq_alloc(u32 cnt) | ||
146 | { | ||
147 | u32 sz = cnt * sizeof(struct sub_seq); | ||
148 | struct sub_seq *sseq = (struct sub_seq *)kmalloc(sz, GFP_ATOMIC); | ||
149 | |||
150 | if (sseq) | ||
151 | memset(sseq, 0, sz); | ||
152 | return sseq; | ||
153 | } | ||
154 | |||
155 | /** | ||
156 | * nameseq_create - create a name sequence structure for the specified 'type' | ||
157 | * | ||
158 | * Allocates a single sub-sequence structure and sets it to all 0's. | ||
159 | */ | ||
160 | |||
161 | struct name_seq *nameseq_create(u32 type, struct hlist_head *seq_head) | ||
162 | { | ||
163 | struct name_seq *nseq = | ||
164 | (struct name_seq *)kmalloc(sizeof(*nseq), GFP_ATOMIC); | ||
165 | struct sub_seq *sseq = subseq_alloc(1); | ||
166 | |||
167 | if (!nseq || !sseq) { | ||
168 | warn("Memory squeeze; failed to create name sequence\n"); | ||
169 | kfree(nseq); | ||
170 | kfree(sseq); | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | memset(nseq, 0, sizeof(*nseq)); | ||
175 | nseq->lock = SPIN_LOCK_UNLOCKED; | ||
176 | nseq->type = type; | ||
177 | nseq->sseqs = sseq; | ||
178 | dbg("nameseq_create() nseq = %x type %u, ssseqs %x, ff: %u\n", | ||
179 | nseq, type, nseq->sseqs, nseq->first_free); | ||
180 | nseq->alloc = 1; | ||
181 | INIT_HLIST_NODE(&nseq->ns_list); | ||
182 | INIT_LIST_HEAD(&nseq->subscriptions); | ||
183 | hlist_add_head(&nseq->ns_list, seq_head); | ||
184 | return nseq; | ||
185 | } | ||
186 | |||
187 | /** | ||
188 | * nameseq_find_subseq - find sub-sequence (if any) matching a name instance | ||
189 | * | ||
190 | * Very time-critical, so binary searches through sub-sequence array. | ||
191 | */ | ||
192 | |||
193 | static inline struct sub_seq *nameseq_find_subseq(struct name_seq *nseq, | ||
194 | u32 instance) | ||
195 | { | ||
196 | struct sub_seq *sseqs = nseq->sseqs; | ||
197 | int low = 0; | ||
198 | int high = nseq->first_free - 1; | ||
199 | int mid; | ||
200 | |||
201 | while (low <= high) { | ||
202 | mid = (low + high) / 2; | ||
203 | if (instance < sseqs[mid].lower) | ||
204 | high = mid - 1; | ||
205 | else if (instance > sseqs[mid].upper) | ||
206 | low = mid + 1; | ||
207 | else | ||
208 | return &sseqs[mid]; | ||
209 | } | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | /** | ||
214 | * nameseq_locate_subseq - determine position of name instance in sub-sequence | ||
215 | * | ||
216 | * Returns index in sub-sequence array of the entry that contains the specified | ||
217 | * instance value; if no entry contains that value, returns the position | ||
218 | * where a new entry for it would be inserted in the array. | ||
219 | * | ||
220 | * Note: Similar to binary search code for locating a sub-sequence. | ||
221 | */ | ||
222 | |||
223 | static u32 nameseq_locate_subseq(struct name_seq *nseq, u32 instance) | ||
224 | { | ||
225 | struct sub_seq *sseqs = nseq->sseqs; | ||
226 | int low = 0; | ||
227 | int high = nseq->first_free - 1; | ||
228 | int mid; | ||
229 | |||
230 | while (low <= high) { | ||
231 | mid = (low + high) / 2; | ||
232 | if (instance < sseqs[mid].lower) | ||
233 | high = mid - 1; | ||
234 | else if (instance > sseqs[mid].upper) | ||
235 | low = mid + 1; | ||
236 | else | ||
237 | return mid; | ||
238 | } | ||
239 | return low; | ||
240 | } | ||
241 | |||
242 | /** | ||
243 | * nameseq_insert_publ - | ||
244 | */ | ||
245 | |||
246 | struct publication *nameseq_insert_publ(struct name_seq *nseq, | ||
247 | u32 type, u32 lower, u32 upper, | ||
248 | u32 scope, u32 node, u32 port, u32 key) | ||
249 | { | ||
250 | struct subscription *s; | ||
251 | struct subscription *st; | ||
252 | struct publication *publ; | ||
253 | struct sub_seq *sseq; | ||
254 | int created_subseq = 0; | ||
255 | |||
256 | assert(nseq->first_free <= nseq->alloc); | ||
257 | sseq = nameseq_find_subseq(nseq, lower); | ||
258 | dbg("nameseq_ins: for seq %x,<%u,%u>, found sseq %x\n", | ||
259 | nseq, type, lower, sseq); | ||
260 | if (sseq) { | ||
261 | |||
262 | /* Lower end overlaps existing entry => need an exact match */ | ||
263 | |||
264 | if ((sseq->lower != lower) || (sseq->upper != upper)) { | ||
265 | warn("Overlapping publ <%u,%u,%u>\n", type, lower, upper); | ||
266 | return 0; | ||
267 | } | ||
268 | } else { | ||
269 | u32 inspos; | ||
270 | struct sub_seq *freesseq; | ||
271 | |||
272 | /* Find where lower end should be inserted */ | ||
273 | |||
274 | inspos = nameseq_locate_subseq(nseq, lower); | ||
275 | |||
276 | /* Fail if upper end overlaps into an existing entry */ | ||
277 | |||
278 | if ((inspos < nseq->first_free) && | ||
279 | (upper >= nseq->sseqs[inspos].lower)) { | ||
280 | warn("Overlapping publ <%u,%u,%u>\n", type, lower, upper); | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | /* Ensure there is space for new sub-sequence */ | ||
285 | |||
286 | if (nseq->first_free == nseq->alloc) { | ||
287 | struct sub_seq *sseqs = nseq->sseqs; | ||
288 | nseq->sseqs = subseq_alloc(nseq->alloc * 2); | ||
289 | if (nseq->sseqs != NULL) { | ||
290 | memcpy(nseq->sseqs, sseqs, | ||
291 | nseq->alloc * sizeof (struct sub_seq)); | ||
292 | kfree(sseqs); | ||
293 | dbg("Allocated %u sseqs\n", nseq->alloc); | ||
294 | nseq->alloc *= 2; | ||
295 | } else { | ||
296 | warn("Memory squeeze; failed to create sub-sequence\n"); | ||
297 | return 0; | ||
298 | } | ||
299 | } | ||
300 | dbg("Have %u sseqs for type %u\n", nseq->alloc, type); | ||
301 | |||
302 | /* Insert new sub-sequence */ | ||
303 | |||
304 | dbg("ins in pos %u, ff = %u\n", inspos, nseq->first_free); | ||
305 | sseq = &nseq->sseqs[inspos]; | ||
306 | freesseq = &nseq->sseqs[nseq->first_free]; | ||
307 | memmove(sseq + 1, sseq, (freesseq - sseq) * sizeof (*sseq)); | ||
308 | memset(sseq, 0, sizeof (*sseq)); | ||
309 | nseq->first_free++; | ||
310 | sseq->lower = lower; | ||
311 | sseq->upper = upper; | ||
312 | created_subseq = 1; | ||
313 | } | ||
314 | dbg("inserting (%u %u %u) from %x:%u into sseq %x(%u,%u) of seq %x\n", | ||
315 | type, lower, upper, node, port, sseq, | ||
316 | sseq->lower, sseq->upper, nseq); | ||
317 | |||
318 | /* Insert a publication: */ | ||
319 | |||
320 | publ = publ_create(type, lower, upper, scope, node, port, key); | ||
321 | if (!publ) | ||
322 | return 0; | ||
323 | dbg("inserting publ %x, node=%x publ->node=%x, subscr->node=%x\n", | ||
324 | publ, node, publ->node, publ->subscr.node); | ||
325 | |||
326 | if (!sseq->zone_list) | ||
327 | sseq->zone_list = publ->zone_list_next = publ; | ||
328 | else { | ||
329 | publ->zone_list_next = sseq->zone_list->zone_list_next; | ||
330 | sseq->zone_list->zone_list_next = publ; | ||
331 | } | ||
332 | |||
333 | if (in_own_cluster(node)) { | ||
334 | if (!sseq->cluster_list) | ||
335 | sseq->cluster_list = publ->cluster_list_next = publ; | ||
336 | else { | ||
337 | publ->cluster_list_next = | ||
338 | sseq->cluster_list->cluster_list_next; | ||
339 | sseq->cluster_list->cluster_list_next = publ; | ||
340 | } | ||
341 | } | ||
342 | |||
343 | if (node == tipc_own_addr) { | ||
344 | if (!sseq->node_list) | ||
345 | sseq->node_list = publ->node_list_next = publ; | ||
346 | else { | ||
347 | publ->node_list_next = sseq->node_list->node_list_next; | ||
348 | sseq->node_list->node_list_next = publ; | ||
349 | } | ||
350 | } | ||
351 | |||
352 | /* | ||
353 | * Any subscriptions waiting for notification? | ||
354 | */ | ||
355 | list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) { | ||
356 | dbg("calling report_overlap()\n"); | ||
357 | subscr_report_overlap(s, | ||
358 | publ->lower, | ||
359 | publ->upper, | ||
360 | TIPC_PUBLISHED, | ||
361 | publ->ref, | ||
362 | publ->node, | ||
363 | created_subseq); | ||
364 | } | ||
365 | return publ; | ||
366 | } | ||
367 | |||
368 | /** | ||
369 | * nameseq_remove_publ - | ||
370 | */ | ||
371 | |||
372 | struct publication *nameseq_remove_publ(struct name_seq *nseq, u32 inst, | ||
373 | u32 node, u32 ref, u32 key) | ||
374 | { | ||
375 | struct publication *publ; | ||
376 | struct publication *prev; | ||
377 | struct sub_seq *sseq = nameseq_find_subseq(nseq, inst); | ||
378 | struct sub_seq *free; | ||
379 | struct subscription *s, *st; | ||
380 | int removed_subseq = 0; | ||
381 | |||
382 | assert(nseq); | ||
383 | |||
384 | if (!sseq) { | ||
385 | int i; | ||
386 | |||
387 | warn("Withdraw unknown <%u,%u>?\n", nseq->type, inst); | ||
388 | assert(nseq->sseqs); | ||
389 | dbg("Dumping subseqs %x for %x, alloc = %u,ff=%u\n", | ||
390 | nseq->sseqs, nseq, nseq->alloc, | ||
391 | nseq->first_free); | ||
392 | for (i = 0; i < nseq->first_free; i++) { | ||
393 | dbg("Subseq %u(%x): lower = %u,upper = %u\n", | ||
394 | i, &nseq->sseqs[i], nseq->sseqs[i].lower, | ||
395 | nseq->sseqs[i].upper); | ||
396 | } | ||
397 | return 0; | ||
398 | } | ||
399 | dbg("nameseq_remove: seq: %x, sseq %x, <%u,%u> key %u\n", | ||
400 | nseq, sseq, nseq->type, inst, key); | ||
401 | |||
402 | prev = sseq->zone_list; | ||
403 | publ = sseq->zone_list->zone_list_next; | ||
404 | while ((publ->key != key) || (publ->ref != ref) || | ||
405 | (publ->node && (publ->node != node))) { | ||
406 | prev = publ; | ||
407 | publ = publ->zone_list_next; | ||
408 | assert(prev != sseq->zone_list); | ||
409 | } | ||
410 | if (publ != sseq->zone_list) | ||
411 | prev->zone_list_next = publ->zone_list_next; | ||
412 | else if (publ->zone_list_next != publ) { | ||
413 | prev->zone_list_next = publ->zone_list_next; | ||
414 | sseq->zone_list = publ->zone_list_next; | ||
415 | } else { | ||
416 | sseq->zone_list = 0; | ||
417 | } | ||
418 | |||
419 | if (in_own_cluster(node)) { | ||
420 | prev = sseq->cluster_list; | ||
421 | publ = sseq->cluster_list->cluster_list_next; | ||
422 | while ((publ->key != key) || (publ->ref != ref) || | ||
423 | (publ->node && (publ->node != node))) { | ||
424 | prev = publ; | ||
425 | publ = publ->cluster_list_next; | ||
426 | assert(prev != sseq->cluster_list); | ||
427 | } | ||
428 | if (publ != sseq->cluster_list) | ||
429 | prev->cluster_list_next = publ->cluster_list_next; | ||
430 | else if (publ->cluster_list_next != publ) { | ||
431 | prev->cluster_list_next = publ->cluster_list_next; | ||
432 | sseq->cluster_list = publ->cluster_list_next; | ||
433 | } else { | ||
434 | sseq->cluster_list = 0; | ||
435 | } | ||
436 | } | ||
437 | |||
438 | if (node == tipc_own_addr) { | ||
439 | prev = sseq->node_list; | ||
440 | publ = sseq->node_list->node_list_next; | ||
441 | while ((publ->key != key) || (publ->ref != ref) || | ||
442 | (publ->node && (publ->node != node))) { | ||
443 | prev = publ; | ||
444 | publ = publ->node_list_next; | ||
445 | assert(prev != sseq->node_list); | ||
446 | } | ||
447 | if (publ != sseq->node_list) | ||
448 | prev->node_list_next = publ->node_list_next; | ||
449 | else if (publ->node_list_next != publ) { | ||
450 | prev->node_list_next = publ->node_list_next; | ||
451 | sseq->node_list = publ->node_list_next; | ||
452 | } else { | ||
453 | sseq->node_list = 0; | ||
454 | } | ||
455 | } | ||
456 | assert(!publ->node || (publ->node == node)); | ||
457 | assert(publ->ref == ref); | ||
458 | assert(publ->key == key); | ||
459 | |||
460 | /* | ||
461 | * Contract subseq list if no more publications: | ||
462 | */ | ||
463 | if (!sseq->node_list && !sseq->cluster_list && !sseq->zone_list) { | ||
464 | free = &nseq->sseqs[nseq->first_free--]; | ||
465 | memmove(sseq, sseq + 1, (free - (sseq + 1)) * sizeof (*sseq)); | ||
466 | removed_subseq = 1; | ||
467 | } | ||
468 | |||
469 | /* | ||
470 | * Any subscriptions waiting ? | ||
471 | */ | ||
472 | list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) { | ||
473 | subscr_report_overlap(s, | ||
474 | publ->lower, | ||
475 | publ->upper, | ||
476 | TIPC_WITHDRAWN, | ||
477 | publ->ref, | ||
478 | publ->node, | ||
479 | removed_subseq); | ||
480 | } | ||
481 | return publ; | ||
482 | } | ||
483 | |||
484 | /** | ||
485 | * nameseq_subscribe: attach a subscription, and issue | ||
486 | * the prescribed number of events if there is any sub- | ||
487 | * sequence overlapping with the requested sequence | ||
488 | */ | ||
489 | |||
490 | void nameseq_subscribe(struct name_seq *nseq, struct subscription *s) | ||
491 | { | ||
492 | struct sub_seq *sseq = nseq->sseqs; | ||
493 | |||
494 | list_add(&s->nameseq_list, &nseq->subscriptions); | ||
495 | |||
496 | if (!sseq) | ||
497 | return; | ||
498 | |||
499 | while (sseq != &nseq->sseqs[nseq->first_free]) { | ||
500 | struct publication *zl = sseq->zone_list; | ||
501 | if (zl && subscr_overlap(s,sseq->lower,sseq->upper)) { | ||
502 | struct publication *crs = zl; | ||
503 | int must_report = 1; | ||
504 | |||
505 | do { | ||
506 | subscr_report_overlap(s, | ||
507 | sseq->lower, | ||
508 | sseq->upper, | ||
509 | TIPC_PUBLISHED, | ||
510 | crs->ref, | ||
511 | crs->node, | ||
512 | must_report); | ||
513 | must_report = 0; | ||
514 | crs = crs->zone_list_next; | ||
515 | } while (crs != zl); | ||
516 | } | ||
517 | sseq++; | ||
518 | } | ||
519 | } | ||
520 | |||
521 | static struct name_seq *nametbl_find_seq(u32 type) | ||
522 | { | ||
523 | struct hlist_head *seq_head; | ||
524 | struct hlist_node *seq_node; | ||
525 | struct name_seq *ns; | ||
526 | |||
527 | dbg("find_seq %u,(%u,0x%x) table = %p, hash[type] = %u\n", | ||
528 | type, ntohl(type), type, table.types, hash(type)); | ||
529 | |||
530 | seq_head = &table.types[hash(type)]; | ||
531 | hlist_for_each_entry(ns, seq_node, seq_head, ns_list) { | ||
532 | if (ns->type == type) { | ||
533 | dbg("found %x\n", ns); | ||
534 | return ns; | ||
535 | } | ||
536 | } | ||
537 | |||
538 | return 0; | ||
539 | }; | ||
540 | |||
541 | struct publication *nametbl_insert_publ(u32 type, u32 lower, u32 upper, | ||
542 | u32 scope, u32 node, u32 port, u32 key) | ||
543 | { | ||
544 | struct name_seq *seq = nametbl_find_seq(type); | ||
545 | |||
546 | dbg("ins_publ: <%u,%x,%x> found %x\n", type, lower, upper, seq); | ||
547 | if (lower > upper) { | ||
548 | warn("Failed to publish illegal <%u,%u,%u>\n", | ||
549 | type, lower, upper); | ||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | dbg("Publishing <%u,%u,%u> from %x\n", type, lower, upper, node); | ||
554 | if (!seq) { | ||
555 | seq = nameseq_create(type, &table.types[hash(type)]); | ||
556 | dbg("nametbl_insert_publ: created %x\n", seq); | ||
557 | } | ||
558 | if (!seq) | ||
559 | return 0; | ||
560 | |||
561 | assert(seq->type == type); | ||
562 | return nameseq_insert_publ(seq, type, lower, upper, | ||
563 | scope, node, port, key); | ||
564 | } | ||
565 | |||
566 | struct publication *nametbl_remove_publ(u32 type, u32 lower, | ||
567 | u32 node, u32 ref, u32 key) | ||
568 | { | ||
569 | struct publication *publ; | ||
570 | struct name_seq *seq = nametbl_find_seq(type); | ||
571 | |||
572 | if (!seq) | ||
573 | return 0; | ||
574 | |||
575 | dbg("Withdrawing <%u,%u> from %x\n", type, lower, node); | ||
576 | publ = nameseq_remove_publ(seq, lower, node, ref, key); | ||
577 | |||
578 | if (!seq->first_free && list_empty(&seq->subscriptions)) { | ||
579 | hlist_del_init(&seq->ns_list); | ||
580 | kfree(seq->sseqs); | ||
581 | kfree(seq); | ||
582 | } | ||
583 | return publ; | ||
584 | } | ||
585 | |||
586 | /* | ||
587 | * nametbl_translate(): Translate tipc_name -> tipc_portid. | ||
588 | * Very time-critical. | ||
589 | * | ||
590 | * Note: on entry 'destnode' is the search domain used during translation; | ||
591 | * on exit it passes back the node address of the matching port (if any) | ||
592 | */ | ||
593 | |||
594 | u32 nametbl_translate(u32 type, u32 instance, u32 *destnode) | ||
595 | { | ||
596 | struct sub_seq *sseq; | ||
597 | struct publication *publ = 0; | ||
598 | struct name_seq *seq; | ||
599 | u32 ref; | ||
600 | |||
601 | if (!in_scope(*destnode, tipc_own_addr)) | ||
602 | return 0; | ||
603 | |||
604 | read_lock_bh(&nametbl_lock); | ||
605 | seq = nametbl_find_seq(type); | ||
606 | if (unlikely(!seq)) | ||
607 | goto not_found; | ||
608 | sseq = nameseq_find_subseq(seq, instance); | ||
609 | if (unlikely(!sseq)) | ||
610 | goto not_found; | ||
611 | spin_lock_bh(&seq->lock); | ||
612 | |||
613 | /* Closest-First Algorithm: */ | ||
614 | if (likely(!*destnode)) { | ||
615 | publ = sseq->node_list; | ||
616 | if (publ) { | ||
617 | sseq->node_list = publ->node_list_next; | ||
618 | found: | ||
619 | ref = publ->ref; | ||
620 | *destnode = publ->node; | ||
621 | spin_unlock_bh(&seq->lock); | ||
622 | read_unlock_bh(&nametbl_lock); | ||
623 | return ref; | ||
624 | } | ||
625 | publ = sseq->cluster_list; | ||
626 | if (publ) { | ||
627 | sseq->cluster_list = publ->cluster_list_next; | ||
628 | goto found; | ||
629 | } | ||
630 | publ = sseq->zone_list; | ||
631 | if (publ) { | ||
632 | sseq->zone_list = publ->zone_list_next; | ||
633 | goto found; | ||
634 | } | ||
635 | } | ||
636 | |||
637 | /* Round-Robin Algorithm: */ | ||
638 | else if (*destnode == tipc_own_addr) { | ||
639 | publ = sseq->node_list; | ||
640 | if (publ) { | ||
641 | sseq->node_list = publ->node_list_next; | ||
642 | goto found; | ||
643 | } | ||
644 | } else if (in_own_cluster(*destnode)) { | ||
645 | publ = sseq->cluster_list; | ||
646 | if (publ) { | ||
647 | sseq->cluster_list = publ->cluster_list_next; | ||
648 | goto found; | ||
649 | } | ||
650 | } else { | ||
651 | publ = sseq->zone_list; | ||
652 | if (publ) { | ||
653 | sseq->zone_list = publ->zone_list_next; | ||
654 | goto found; | ||
655 | } | ||
656 | } | ||
657 | spin_unlock_bh(&seq->lock); | ||
658 | not_found: | ||
659 | *destnode = 0; | ||
660 | read_unlock_bh(&nametbl_lock); | ||
661 | return 0; | ||
662 | } | ||
663 | |||
664 | /** | ||
665 | * nametbl_mc_translate - find multicast destinations | ||
666 | * | ||
667 | * Creates list of all local ports that overlap the given multicast address; | ||
668 | * also determines if any off-node ports overlap. | ||
669 | * | ||
670 | * Note: Publications with a scope narrower than 'limit' are ignored. | ||
671 | * (i.e. local node-scope publications mustn't receive messages arriving | ||
672 | * from another node, even if the multcast link brought it here) | ||
673 | * | ||
674 | * Returns non-zero if any off-node ports overlap | ||
675 | */ | ||
676 | |||
677 | int nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit, | ||
678 | struct port_list *dports) | ||
679 | { | ||
680 | struct name_seq *seq; | ||
681 | struct sub_seq *sseq; | ||
682 | struct sub_seq *sseq_stop; | ||
683 | int res = 0; | ||
684 | |||
685 | read_lock_bh(&nametbl_lock); | ||
686 | seq = nametbl_find_seq(type); | ||
687 | if (!seq) | ||
688 | goto exit; | ||
689 | |||
690 | spin_lock_bh(&seq->lock); | ||
691 | |||
692 | sseq = seq->sseqs + nameseq_locate_subseq(seq, lower); | ||
693 | sseq_stop = seq->sseqs + seq->first_free; | ||
694 | for (; sseq != sseq_stop; sseq++) { | ||
695 | struct publication *publ; | ||
696 | |||
697 | if (sseq->lower > upper) | ||
698 | break; | ||
699 | publ = sseq->cluster_list; | ||
700 | if (publ && (publ->scope <= limit)) | ||
701 | do { | ||
702 | if (publ->node == tipc_own_addr) | ||
703 | port_list_add(dports, publ->ref); | ||
704 | else | ||
705 | res = 1; | ||
706 | publ = publ->cluster_list_next; | ||
707 | } while (publ != sseq->cluster_list); | ||
708 | } | ||
709 | |||
710 | spin_unlock_bh(&seq->lock); | ||
711 | exit: | ||
712 | read_unlock_bh(&nametbl_lock); | ||
713 | return res; | ||
714 | } | ||
715 | |||
716 | /** | ||
717 | * nametbl_publish_rsv - publish port name using a reserved name type | ||
718 | */ | ||
719 | |||
720 | int nametbl_publish_rsv(u32 ref, unsigned int scope, | ||
721 | struct tipc_name_seq const *seq) | ||
722 | { | ||
723 | int res; | ||
724 | |||
725 | atomic_inc(&rsv_publ_ok); | ||
726 | res = tipc_publish(ref, scope, seq); | ||
727 | atomic_dec(&rsv_publ_ok); | ||
728 | return res; | ||
729 | } | ||
730 | |||
731 | /** | ||
732 | * nametbl_publish - add name publication to network name tables | ||
733 | */ | ||
734 | |||
735 | struct publication *nametbl_publish(u32 type, u32 lower, u32 upper, | ||
736 | u32 scope, u32 port_ref, u32 key) | ||
737 | { | ||
738 | struct publication *publ; | ||
739 | |||
740 | if (table.local_publ_count >= tipc_max_publications) { | ||
741 | warn("Failed publish: max %u local publication\n", | ||
742 | tipc_max_publications); | ||
743 | return 0; | ||
744 | } | ||
745 | if ((type < TIPC_RESERVED_TYPES) && !atomic_read(&rsv_publ_ok)) { | ||
746 | warn("Failed to publish reserved name <%u,%u,%u>\n", | ||
747 | type, lower, upper); | ||
748 | return 0; | ||
749 | } | ||
750 | |||
751 | write_lock_bh(&nametbl_lock); | ||
752 | table.local_publ_count++; | ||
753 | publ = nametbl_insert_publ(type, lower, upper, scope, | ||
754 | tipc_own_addr, port_ref, key); | ||
755 | if (publ && (scope != TIPC_NODE_SCOPE)) { | ||
756 | named_publish(publ); | ||
757 | } | ||
758 | write_unlock_bh(&nametbl_lock); | ||
759 | return publ; | ||
760 | } | ||
761 | |||
762 | /** | ||
763 | * nametbl_withdraw - withdraw name publication from network name tables | ||
764 | */ | ||
765 | |||
766 | int nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key) | ||
767 | { | ||
768 | struct publication *publ; | ||
769 | |||
770 | dbg("nametbl_withdraw:<%d,%d,%d>\n", type, lower, key); | ||
771 | write_lock_bh(&nametbl_lock); | ||
772 | publ = nametbl_remove_publ(type, lower, tipc_own_addr, ref, key); | ||
773 | if (publ) { | ||
774 | table.local_publ_count--; | ||
775 | if (publ->scope != TIPC_NODE_SCOPE) | ||
776 | named_withdraw(publ); | ||
777 | write_unlock_bh(&nametbl_lock); | ||
778 | list_del_init(&publ->pport_list); | ||
779 | kfree(publ); | ||
780 | return 1; | ||
781 | } | ||
782 | write_unlock_bh(&nametbl_lock); | ||
783 | return 0; | ||
784 | } | ||
785 | |||
786 | /** | ||
787 | * nametbl_subscribe - add a subscription object to the name table | ||
788 | */ | ||
789 | |||
790 | void | ||
791 | nametbl_subscribe(struct subscription *s) | ||
792 | { | ||
793 | u32 type = s->seq.type; | ||
794 | struct name_seq *seq; | ||
795 | |||
796 | write_lock_bh(&nametbl_lock); | ||
797 | seq = nametbl_find_seq(type); | ||
798 | if (!seq) { | ||
799 | seq = nameseq_create(type, &table.types[hash(type)]); | ||
800 | } | ||
801 | if (seq){ | ||
802 | spin_lock_bh(&seq->lock); | ||
803 | dbg("nametbl_subscribe:found %x for <%u,%u,%u>\n", | ||
804 | seq, type, s->seq.lower, s->seq.upper); | ||
805 | assert(seq->type == type); | ||
806 | nameseq_subscribe(seq, s); | ||
807 | spin_unlock_bh(&seq->lock); | ||
808 | } | ||
809 | write_unlock_bh(&nametbl_lock); | ||
810 | } | ||
811 | |||
812 | /** | ||
813 | * nametbl_unsubscribe - remove a subscription object from name table | ||
814 | */ | ||
815 | |||
816 | void | ||
817 | nametbl_unsubscribe(struct subscription *s) | ||
818 | { | ||
819 | struct name_seq *seq; | ||
820 | |||
821 | write_lock_bh(&nametbl_lock); | ||
822 | seq = nametbl_find_seq(s->seq.type); | ||
823 | if (seq != NULL){ | ||
824 | spin_lock_bh(&seq->lock); | ||
825 | list_del_init(&s->nameseq_list); | ||
826 | spin_unlock_bh(&seq->lock); | ||
827 | if ((seq->first_free == 0) && list_empty(&seq->subscriptions)) { | ||
828 | hlist_del_init(&seq->ns_list); | ||
829 | kfree(seq->sseqs); | ||
830 | kfree(seq); | ||
831 | } | ||
832 | } | ||
833 | write_unlock_bh(&nametbl_lock); | ||
834 | } | ||
835 | |||
836 | |||
837 | /** | ||
838 | * subseq_list: print specified sub-sequence contents into the given buffer | ||
839 | */ | ||
840 | |||
841 | static void subseq_list(struct sub_seq *sseq, struct print_buf *buf, u32 depth, | ||
842 | u32 index) | ||
843 | { | ||
844 | char portIdStr[27]; | ||
845 | char *scopeStr; | ||
846 | struct publication *publ = sseq->zone_list; | ||
847 | |||
848 | tipc_printf(buf, "%-10u %-10u ", sseq->lower, sseq->upper); | ||
849 | |||
850 | if (depth == 2 || !publ) { | ||
851 | tipc_printf(buf, "\n"); | ||
852 | return; | ||
853 | } | ||
854 | |||
855 | do { | ||
856 | sprintf (portIdStr, "<%u.%u.%u:%u>", | ||
857 | tipc_zone(publ->node), tipc_cluster(publ->node), | ||
858 | tipc_node(publ->node), publ->ref); | ||
859 | tipc_printf(buf, "%-26s ", portIdStr); | ||
860 | if (depth > 3) { | ||
861 | if (publ->node != tipc_own_addr) | ||
862 | scopeStr = ""; | ||
863 | else if (publ->scope == TIPC_NODE_SCOPE) | ||
864 | scopeStr = "node"; | ||
865 | else if (publ->scope == TIPC_CLUSTER_SCOPE) | ||
866 | scopeStr = "cluster"; | ||
867 | else | ||
868 | scopeStr = "zone"; | ||
869 | tipc_printf(buf, "%-10u %s", publ->key, scopeStr); | ||
870 | } | ||
871 | |||
872 | publ = publ->zone_list_next; | ||
873 | if (publ == sseq->zone_list) | ||
874 | break; | ||
875 | |||
876 | tipc_printf(buf, "\n%33s", " "); | ||
877 | } while (1); | ||
878 | |||
879 | tipc_printf(buf, "\n"); | ||
880 | } | ||
881 | |||
882 | /** | ||
883 | * nameseq_list: print specified name sequence contents into the given buffer | ||
884 | */ | ||
885 | |||
886 | static void nameseq_list(struct name_seq *seq, struct print_buf *buf, u32 depth, | ||
887 | u32 type, u32 lowbound, u32 upbound, u32 index) | ||
888 | { | ||
889 | struct sub_seq *sseq; | ||
890 | char typearea[11]; | ||
891 | |||
892 | sprintf(typearea, "%-10u", seq->type); | ||
893 | |||
894 | if (depth == 1) { | ||
895 | tipc_printf(buf, "%s\n", typearea); | ||
896 | return; | ||
897 | } | ||
898 | |||
899 | for (sseq = seq->sseqs; sseq != &seq->sseqs[seq->first_free]; sseq++) { | ||
900 | if ((lowbound <= sseq->upper) && (upbound >= sseq->lower)) { | ||
901 | tipc_printf(buf, "%s ", typearea); | ||
902 | subseq_list(sseq, buf, depth, index); | ||
903 | sprintf(typearea, "%10s", " "); | ||
904 | } | ||
905 | } | ||
906 | } | ||
907 | |||
908 | /** | ||
909 | * nametbl_header - print name table header into the given buffer | ||
910 | */ | ||
911 | |||
912 | static void nametbl_header(struct print_buf *buf, u32 depth) | ||
913 | { | ||
914 | tipc_printf(buf, "Type "); | ||
915 | |||
916 | if (depth > 1) | ||
917 | tipc_printf(buf, "Lower Upper "); | ||
918 | if (depth > 2) | ||
919 | tipc_printf(buf, "Port Identity "); | ||
920 | if (depth > 3) | ||
921 | tipc_printf(buf, "Publication"); | ||
922 | |||
923 | tipc_printf(buf, "\n-----------"); | ||
924 | |||
925 | if (depth > 1) | ||
926 | tipc_printf(buf, "--------------------- "); | ||
927 | if (depth > 2) | ||
928 | tipc_printf(buf, "-------------------------- "); | ||
929 | if (depth > 3) | ||
930 | tipc_printf(buf, "------------------"); | ||
931 | |||
932 | tipc_printf(buf, "\n"); | ||
933 | } | ||
934 | |||
935 | /** | ||
936 | * nametbl_list - print specified name table contents into the given buffer | ||
937 | */ | ||
938 | |||
939 | static void nametbl_list(struct print_buf *buf, u32 depth_info, | ||
940 | u32 type, u32 lowbound, u32 upbound) | ||
941 | { | ||
942 | struct hlist_head *seq_head; | ||
943 | struct hlist_node *seq_node; | ||
944 | struct name_seq *seq; | ||
945 | int all_types; | ||
946 | u32 depth; | ||
947 | u32 i; | ||
948 | |||
949 | all_types = (depth_info & TIPC_NTQ_ALLTYPES); | ||
950 | depth = (depth_info & ~TIPC_NTQ_ALLTYPES); | ||
951 | |||
952 | if (depth == 0) | ||
953 | return; | ||
954 | |||
955 | if (all_types) { | ||
956 | /* display all entries in name table to specified depth */ | ||
957 | nametbl_header(buf, depth); | ||
958 | lowbound = 0; | ||
959 | upbound = ~0; | ||
960 | for (i = 0; i < tipc_nametbl_size; i++) { | ||
961 | seq_head = &table.types[i]; | ||
962 | hlist_for_each_entry(seq, seq_node, seq_head, ns_list) { | ||
963 | nameseq_list(seq, buf, depth, seq->type, | ||
964 | lowbound, upbound, i); | ||
965 | } | ||
966 | } | ||
967 | } else { | ||
968 | /* display only the sequence that matches the specified type */ | ||
969 | if (upbound < lowbound) { | ||
970 | tipc_printf(buf, "invalid name sequence specified\n"); | ||
971 | return; | ||
972 | } | ||
973 | nametbl_header(buf, depth); | ||
974 | i = hash(type); | ||
975 | seq_head = &table.types[i]; | ||
976 | hlist_for_each_entry(seq, seq_node, seq_head, ns_list) { | ||
977 | if (seq->type == type) { | ||
978 | nameseq_list(seq, buf, depth, type, | ||
979 | lowbound, upbound, i); | ||
980 | break; | ||
981 | } | ||
982 | } | ||
983 | } | ||
984 | } | ||
985 | |||
986 | void nametbl_print(struct print_buf *buf, const char *str) | ||
987 | { | ||
988 | tipc_printf(buf, str); | ||
989 | read_lock_bh(&nametbl_lock); | ||
990 | nametbl_list(buf, 0, 0, 0, 0); | ||
991 | read_unlock_bh(&nametbl_lock); | ||
992 | } | ||
993 | |||
994 | #define MAX_NAME_TBL_QUERY 32768 | ||
995 | |||
996 | struct sk_buff *nametbl_get(const void *req_tlv_area, int req_tlv_space) | ||
997 | { | ||
998 | struct sk_buff *buf; | ||
999 | struct tipc_name_table_query *argv; | ||
1000 | struct tlv_desc *rep_tlv; | ||
1001 | struct print_buf b; | ||
1002 | int str_len; | ||
1003 | |||
1004 | if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NAME_TBL_QUERY)) | ||
1005 | return cfg_reply_error_string(TIPC_CFG_TLV_ERROR); | ||
1006 | |||
1007 | buf = cfg_reply_alloc(TLV_SPACE(MAX_NAME_TBL_QUERY)); | ||
1008 | if (!buf) | ||
1009 | return NULL; | ||
1010 | |||
1011 | rep_tlv = (struct tlv_desc *)buf->data; | ||
1012 | printbuf_init(&b, TLV_DATA(rep_tlv), MAX_NAME_TBL_QUERY); | ||
1013 | argv = (struct tipc_name_table_query *)TLV_DATA(req_tlv_area); | ||
1014 | read_lock_bh(&nametbl_lock); | ||
1015 | nametbl_list(&b, ntohl(argv->depth), ntohl(argv->type), | ||
1016 | ntohl(argv->lowbound), ntohl(argv->upbound)); | ||
1017 | read_unlock_bh(&nametbl_lock); | ||
1018 | str_len = printbuf_validate(&b); | ||
1019 | |||
1020 | skb_put(buf, TLV_SPACE(str_len)); | ||
1021 | TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len); | ||
1022 | |||
1023 | return buf; | ||
1024 | } | ||
1025 | |||
1026 | void nametbl_dump(void) | ||
1027 | { | ||
1028 | nametbl_list(CONS, 0, 0, 0, 0); | ||
1029 | } | ||
1030 | |||
1031 | int nametbl_init(void) | ||
1032 | { | ||
1033 | int array_size = sizeof(struct hlist_head) * tipc_nametbl_size; | ||
1034 | |||
1035 | table.types = (struct hlist_head *)kmalloc(array_size, GFP_ATOMIC); | ||
1036 | if (!table.types) | ||
1037 | return -ENOMEM; | ||
1038 | |||
1039 | write_lock_bh(&nametbl_lock); | ||
1040 | memset(table.types, 0, array_size); | ||
1041 | table.local_publ_count = 0; | ||
1042 | write_unlock_bh(&nametbl_lock); | ||
1043 | return 0; | ||
1044 | } | ||
1045 | |||
1046 | void nametbl_stop(void) | ||
1047 | { | ||
1048 | struct hlist_head *seq_head; | ||
1049 | struct hlist_node *seq_node; | ||
1050 | struct hlist_node *tmp; | ||
1051 | struct name_seq *seq; | ||
1052 | u32 i; | ||
1053 | |||
1054 | if (!table.types) | ||
1055 | return; | ||
1056 | |||
1057 | write_lock_bh(&nametbl_lock); | ||
1058 | for (i = 0; i < tipc_nametbl_size; i++) { | ||
1059 | seq_head = &table.types[i]; | ||
1060 | hlist_for_each_entry_safe(seq, seq_node, tmp, seq_head, ns_list) { | ||
1061 | struct sub_seq *sseq = seq->sseqs; | ||
1062 | |||
1063 | for (; sseq != &seq->sseqs[seq->first_free]; sseq++) { | ||
1064 | struct publication *publ = sseq->zone_list; | ||
1065 | assert(publ); | ||
1066 | do { | ||
1067 | struct publication *next = | ||
1068 | publ->zone_list_next; | ||
1069 | kfree(publ); | ||
1070 | publ = next; | ||
1071 | } | ||
1072 | while (publ != sseq->zone_list); | ||
1073 | } | ||
1074 | } | ||
1075 | } | ||
1076 | kfree(table.types); | ||
1077 | table.types = NULL; | ||
1078 | write_unlock_bh(&nametbl_lock); | ||
1079 | } | ||