summaryrefslogtreecommitdiffstats
path: root/net/tipc
diff options
context:
space:
mode:
Diffstat (limited to 'net/tipc')
-rw-r--r--net/tipc/name_table.c103
1 files changed, 53 insertions, 50 deletions
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index dd1c4fa2eb78..bebe88cae07b 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -136,12 +136,12 @@ static struct tipc_service *tipc_service_create(u32 type, struct hlist_head *hd)
136} 136}
137 137
138/** 138/**
139 * tipc_service_find_range - find service range matching a service instance 139 * tipc_service_first_range - find first service range in tree matching instance
140 * 140 *
141 * Very time-critical, so binary search through range rb tree 141 * Very time-critical, so binary search through range rb tree
142 */ 142 */
143static struct service_range *tipc_service_find_range(struct tipc_service *sc, 143static struct service_range *tipc_service_first_range(struct tipc_service *sc,
144 u32 instance) 144 u32 instance)
145{ 145{
146 struct rb_node *n = sc->ranges.rb_node; 146 struct rb_node *n = sc->ranges.rb_node;
147 struct service_range *sr; 147 struct service_range *sr;
@@ -158,6 +158,30 @@ static struct service_range *tipc_service_find_range(struct tipc_service *sc,
158 return NULL; 158 return NULL;
159} 159}
160 160
161/* tipc_service_find_range - find service range matching publication parameters
162 */
163static struct service_range *tipc_service_find_range(struct tipc_service *sc,
164 u32 lower, u32 upper)
165{
166 struct rb_node *n = sc->ranges.rb_node;
167 struct service_range *sr;
168
169 sr = tipc_service_first_range(sc, lower);
170 if (!sr)
171 return NULL;
172
173 /* Look for exact match */
174 for (n = &sr->tree_node; n; n = rb_next(n)) {
175 sr = container_of(n, struct service_range, tree_node);
176 if (sr->upper == upper)
177 break;
178 }
179 if (!n || sr->lower != lower || sr->upper != upper)
180 return NULL;
181
182 return sr;
183}
184
161static struct service_range *tipc_service_create_range(struct tipc_service *sc, 185static struct service_range *tipc_service_create_range(struct tipc_service *sc,
162 u32 lower, u32 upper) 186 u32 lower, u32 upper)
163{ 187{
@@ -238,54 +262,19 @@ err:
238/** 262/**
239 * tipc_service_remove_publ - remove a publication from a service 263 * tipc_service_remove_publ - remove a publication from a service
240 */ 264 */
241static struct publication *tipc_service_remove_publ(struct net *net, 265static struct publication *tipc_service_remove_publ(struct service_range *sr,
242 struct tipc_service *sc, 266 u32 node, u32 key)
243 u32 lower, u32 upper,
244 u32 node, u32 key,
245 struct service_range **rng)
246{ 267{
247 struct tipc_subscription *sub, *tmp;
248 struct service_range *sr;
249 struct publication *p; 268 struct publication *p;
250 bool found = false;
251 bool last = false;
252 struct rb_node *n;
253
254 sr = tipc_service_find_range(sc, lower);
255 if (!sr)
256 return NULL;
257 269
258 /* Find exact matching service range */
259 for (n = &sr->tree_node; n; n = rb_next(n)) {
260 sr = container_of(n, struct service_range, tree_node);
261 if (sr->upper == upper)
262 break;
263 }
264 if (!n || sr->lower != lower || sr->upper != upper)
265 return NULL;
266
267 /* Find publication, if it exists */
268 list_for_each_entry(p, &sr->all_publ, all_publ) { 270 list_for_each_entry(p, &sr->all_publ, all_publ) {
269 if (p->key != key || (node && node != p->node)) 271 if (p->key != key || (node && node != p->node))
270 continue; 272 continue;
271 found = true; 273 list_del(&p->all_publ);
272 break; 274 list_del(&p->local_publ);
275 return p;
273 } 276 }
274 if (!found) 277 return NULL;
275 return NULL;
276
277 list_del(&p->all_publ);
278 list_del(&p->local_publ);
279 if (list_empty(&sr->all_publ))
280 last = true;
281
282 /* Notify any waiting subscriptions */
283 list_for_each_entry_safe(sub, tmp, &sc->subscriptions, service_list) {
284 tipc_sub_report_overlap(sub, p->lower, p->upper, TIPC_WITHDRAWN,
285 p->port, p->node, p->scope, last);
286 }
287 *rng = sr;
288 return p;
289} 278}
290 279
291/** 280/**
@@ -376,17 +365,31 @@ struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type,
376 u32 node, u32 key) 365 u32 node, u32 key)
377{ 366{
378 struct tipc_service *sc = tipc_service_find(net, type); 367 struct tipc_service *sc = tipc_service_find(net, type);
368 struct tipc_subscription *sub, *tmp;
379 struct service_range *sr = NULL; 369 struct service_range *sr = NULL;
380 struct publication *p = NULL; 370 struct publication *p = NULL;
371 bool last;
381 372
382 if (!sc) 373 if (!sc)
383 return NULL; 374 return NULL;
384 375
385 spin_lock_bh(&sc->lock); 376 spin_lock_bh(&sc->lock);
386 p = tipc_service_remove_publ(net, sc, lower, upper, node, key, &sr); 377 sr = tipc_service_find_range(sc, lower, upper);
378 if (!sr)
379 goto exit;
380 p = tipc_service_remove_publ(sr, node, key);
381 if (!p)
382 goto exit;
383
384 /* Notify any waiting subscriptions */
385 last = list_empty(&sr->all_publ);
386 list_for_each_entry_safe(sub, tmp, &sc->subscriptions, service_list) {
387 tipc_sub_report_overlap(sub, lower, upper, TIPC_WITHDRAWN,
388 p->port, node, p->scope, last);
389 }
387 390
388 /* Remove service range item if this was its last publication */ 391 /* Remove service range item if this was its last publication */
389 if (sr && list_empty(&sr->all_publ)) { 392 if (list_empty(&sr->all_publ)) {
390 rb_erase(&sr->tree_node, &sc->ranges); 393 rb_erase(&sr->tree_node, &sc->ranges);
391 kfree(sr); 394 kfree(sr);
392 } 395 }
@@ -396,6 +399,7 @@ struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type,
396 hlist_del_init_rcu(&sc->service_list); 399 hlist_del_init_rcu(&sc->service_list);
397 kfree_rcu(sc, rcu); 400 kfree_rcu(sc, rcu);
398 } 401 }
402exit:
399 spin_unlock_bh(&sc->lock); 403 spin_unlock_bh(&sc->lock);
400 return p; 404 return p;
401} 405}
@@ -437,7 +441,7 @@ u32 tipc_nametbl_translate(struct net *net, u32 type, u32 instance, u32 *dnode)
437 goto not_found; 441 goto not_found;
438 442
439 spin_lock_bh(&sc->lock); 443 spin_lock_bh(&sc->lock);
440 sr = tipc_service_find_range(sc, instance); 444 sr = tipc_service_first_range(sc, instance);
441 if (unlikely(!sr)) 445 if (unlikely(!sr))
442 goto no_match; 446 goto no_match;
443 447
@@ -484,7 +488,7 @@ bool tipc_nametbl_lookup(struct net *net, u32 type, u32 instance, u32 scope,
484 488
485 spin_lock_bh(&sc->lock); 489 spin_lock_bh(&sc->lock);
486 490
487 sr = tipc_service_find_range(sc, instance); 491 sr = tipc_service_first_range(sc, instance);
488 if (!sr) 492 if (!sr)
489 goto no_match; 493 goto no_match;
490 494
@@ -756,8 +760,7 @@ static void tipc_service_delete(struct net *net, struct tipc_service *sc)
756 spin_lock_bh(&sc->lock); 760 spin_lock_bh(&sc->lock);
757 rbtree_postorder_for_each_entry_safe(sr, tmpr, &sc->ranges, tree_node) { 761 rbtree_postorder_for_each_entry_safe(sr, tmpr, &sc->ranges, tree_node) {
758 list_for_each_entry_safe(p, tmp, &sr->all_publ, all_publ) { 762 list_for_each_entry_safe(p, tmp, &sr->all_publ, all_publ) {
759 tipc_service_remove_publ(net, sc, p->lower, p->upper, 763 tipc_service_remove_publ(sr, p->node, p->key);
760 p->node, p->key, &sr);
761 kfree_rcu(p, rcu); 764 kfree_rcu(p, rcu);
762 } 765 }
763 rb_erase(&sr->tree_node, &sc->ranges); 766 rb_erase(&sr->tree_node, &sc->ranges);