|
@@ -136,12 +136,12 @@ static struct tipc_service *tipc_service_create(u32 type, struct hlist_head *hd)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * tipc_service_find_range - find service range matching a service instance
|
|
|
+ * tipc_service_first_range - find first service range in tree matching instance
|
|
|
*
|
|
|
* Very time-critical, so binary search through range rb tree
|
|
|
*/
|
|
|
-static struct service_range *tipc_service_find_range(struct tipc_service *sc,
|
|
|
- u32 instance)
|
|
|
+static struct service_range *tipc_service_first_range(struct tipc_service *sc,
|
|
|
+ u32 instance)
|
|
|
{
|
|
|
struct rb_node *n = sc->ranges.rb_node;
|
|
|
struct service_range *sr;
|
|
@@ -158,6 +158,30 @@ static struct service_range *tipc_service_find_range(struct tipc_service *sc,
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+/* tipc_service_find_range - find service range matching publication parameters
|
|
|
+ */
|
|
|
+static struct service_range *tipc_service_find_range(struct tipc_service *sc,
|
|
|
+ u32 lower, u32 upper)
|
|
|
+{
|
|
|
+ struct rb_node *n = sc->ranges.rb_node;
|
|
|
+ struct service_range *sr;
|
|
|
+
|
|
|
+ sr = tipc_service_first_range(sc, lower);
|
|
|
+ if (!sr)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ /* Look for exact match */
|
|
|
+ for (n = &sr->tree_node; n; n = rb_next(n)) {
|
|
|
+ sr = container_of(n, struct service_range, tree_node);
|
|
|
+ if (sr->upper == upper)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (!n || sr->lower != lower || sr->upper != upper)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ return sr;
|
|
|
+}
|
|
|
+
|
|
|
static struct service_range *tipc_service_create_range(struct tipc_service *sc,
|
|
|
u32 lower, u32 upper)
|
|
|
{
|
|
@@ -238,54 +262,19 @@ err:
|
|
|
/**
|
|
|
* tipc_service_remove_publ - remove a publication from a service
|
|
|
*/
|
|
|
-static struct publication *tipc_service_remove_publ(struct net *net,
|
|
|
- struct tipc_service *sc,
|
|
|
- u32 lower, u32 upper,
|
|
|
- u32 node, u32 key,
|
|
|
- struct service_range **rng)
|
|
|
+static struct publication *tipc_service_remove_publ(struct service_range *sr,
|
|
|
+ u32 node, u32 key)
|
|
|
{
|
|
|
- struct tipc_subscription *sub, *tmp;
|
|
|
- struct service_range *sr;
|
|
|
struct publication *p;
|
|
|
- bool found = false;
|
|
|
- bool last = false;
|
|
|
- struct rb_node *n;
|
|
|
-
|
|
|
- sr = tipc_service_find_range(sc, lower);
|
|
|
- if (!sr)
|
|
|
- return NULL;
|
|
|
|
|
|
- /* Find exact matching service range */
|
|
|
- for (n = &sr->tree_node; n; n = rb_next(n)) {
|
|
|
- sr = container_of(n, struct service_range, tree_node);
|
|
|
- if (sr->upper == upper)
|
|
|
- break;
|
|
|
- }
|
|
|
- if (!n || sr->lower != lower || sr->upper != upper)
|
|
|
- return NULL;
|
|
|
-
|
|
|
- /* Find publication, if it exists */
|
|
|
list_for_each_entry(p, &sr->all_publ, all_publ) {
|
|
|
if (p->key != key || (node && node != p->node))
|
|
|
continue;
|
|
|
- found = true;
|
|
|
- break;
|
|
|
+ list_del(&p->all_publ);
|
|
|
+ list_del(&p->local_publ);
|
|
|
+ return p;
|
|
|
}
|
|
|
- if (!found)
|
|
|
- return NULL;
|
|
|
-
|
|
|
- list_del(&p->all_publ);
|
|
|
- list_del(&p->local_publ);
|
|
|
- if (list_empty(&sr->all_publ))
|
|
|
- last = true;
|
|
|
-
|
|
|
- /* Notify any waiting subscriptions */
|
|
|
- list_for_each_entry_safe(sub, tmp, &sc->subscriptions, service_list) {
|
|
|
- tipc_sub_report_overlap(sub, p->lower, p->upper, TIPC_WITHDRAWN,
|
|
|
- p->port, p->node, p->scope, last);
|
|
|
- }
|
|
|
- *rng = sr;
|
|
|
- return p;
|
|
|
+ return NULL;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -376,17 +365,31 @@ struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type,
|
|
|
u32 node, u32 key)
|
|
|
{
|
|
|
struct tipc_service *sc = tipc_service_find(net, type);
|
|
|
+ struct tipc_subscription *sub, *tmp;
|
|
|
struct service_range *sr = NULL;
|
|
|
struct publication *p = NULL;
|
|
|
+ bool last;
|
|
|
|
|
|
if (!sc)
|
|
|
return NULL;
|
|
|
|
|
|
spin_lock_bh(&sc->lock);
|
|
|
- p = tipc_service_remove_publ(net, sc, lower, upper, node, key, &sr);
|
|
|
+ sr = tipc_service_find_range(sc, lower, upper);
|
|
|
+ if (!sr)
|
|
|
+ goto exit;
|
|
|
+ p = tipc_service_remove_publ(sr, node, key);
|
|
|
+ if (!p)
|
|
|
+ goto exit;
|
|
|
+
|
|
|
+ /* Notify any waiting subscriptions */
|
|
|
+ last = list_empty(&sr->all_publ);
|
|
|
+ list_for_each_entry_safe(sub, tmp, &sc->subscriptions, service_list) {
|
|
|
+ tipc_sub_report_overlap(sub, lower, upper, TIPC_WITHDRAWN,
|
|
|
+ p->port, node, p->scope, last);
|
|
|
+ }
|
|
|
|
|
|
/* Remove service range item if this was its last publication */
|
|
|
- if (sr && list_empty(&sr->all_publ)) {
|
|
|
+ if (list_empty(&sr->all_publ)) {
|
|
|
rb_erase(&sr->tree_node, &sc->ranges);
|
|
|
kfree(sr);
|
|
|
}
|
|
@@ -396,6 +399,7 @@ struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type,
|
|
|
hlist_del_init_rcu(&sc->service_list);
|
|
|
kfree_rcu(sc, rcu);
|
|
|
}
|
|
|
+exit:
|
|
|
spin_unlock_bh(&sc->lock);
|
|
|
return p;
|
|
|
}
|
|
@@ -437,7 +441,7 @@ u32 tipc_nametbl_translate(struct net *net, u32 type, u32 instance, u32 *dnode)
|
|
|
goto not_found;
|
|
|
|
|
|
spin_lock_bh(&sc->lock);
|
|
|
- sr = tipc_service_find_range(sc, instance);
|
|
|
+ sr = tipc_service_first_range(sc, instance);
|
|
|
if (unlikely(!sr))
|
|
|
goto no_match;
|
|
|
|
|
@@ -484,7 +488,7 @@ bool tipc_nametbl_lookup(struct net *net, u32 type, u32 instance, u32 scope,
|
|
|
|
|
|
spin_lock_bh(&sc->lock);
|
|
|
|
|
|
- sr = tipc_service_find_range(sc, instance);
|
|
|
+ sr = tipc_service_first_range(sc, instance);
|
|
|
if (!sr)
|
|
|
goto no_match;
|
|
|
|
|
@@ -756,8 +760,7 @@ static void tipc_service_delete(struct net *net, struct tipc_service *sc)
|
|
|
spin_lock_bh(&sc->lock);
|
|
|
rbtree_postorder_for_each_entry_safe(sr, tmpr, &sc->ranges, tree_node) {
|
|
|
list_for_each_entry_safe(p, tmp, &sr->all_publ, all_publ) {
|
|
|
- tipc_service_remove_publ(net, sc, p->lower, p->upper,
|
|
|
- p->node, p->key, &sr);
|
|
|
+ tipc_service_remove_publ(sr, p->node, p->key);
|
|
|
kfree_rcu(p, rcu);
|
|
|
}
|
|
|
rb_erase(&sr->tree_node, &sc->ranges);
|