diff options
Diffstat (limited to 'net/tipc')
-rw-r--r-- | net/tipc/name_table.c | 103 |
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 | */ |
143 | static struct service_range *tipc_service_find_range(struct tipc_service *sc, | 143 | static 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 | */ | ||
163 | static 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 | |||
161 | static struct service_range *tipc_service_create_range(struct tipc_service *sc, | 185 | static 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 | */ |
241 | static struct publication *tipc_service_remove_publ(struct net *net, | 265 | static 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 | } |
402 | exit: | ||
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); |