diff options
Diffstat (limited to 'net/tipc/name_table.c')
| -rw-r--r-- | net/tipc/name_table.c | 34 | 
1 files changed, 21 insertions, 13 deletions
| diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index b1fe20972aa9..dd1c4fa2eb78 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c @@ -241,7 +241,8 @@ err:  static struct publication *tipc_service_remove_publ(struct net *net,  						    struct tipc_service *sc,  						    u32 lower, u32 upper, -						    u32 node, u32 key) +						    u32 node, u32 key, +						    struct service_range **rng)  {  	struct tipc_subscription *sub, *tmp;  	struct service_range *sr; @@ -275,19 +276,15 @@ static struct publication *tipc_service_remove_publ(struct net *net,  	list_del(&p->all_publ);  	list_del(&p->local_publ); - -	/* Remove service range item if this was its last publication */ -	if (list_empty(&sr->all_publ)) { +	if (list_empty(&sr->all_publ))  		last = true; -		rb_erase(&sr->tree_node, &sc->ranges); -		kfree(sr); -	}  	/* 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;  } @@ -379,13 +376,20 @@ 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 service_range *sr = NULL;  	struct publication *p = NULL;  	if (!sc)  		return NULL;  	spin_lock_bh(&sc->lock); -	p = tipc_service_remove_publ(net, sc, lower, upper, node, key); +	p = tipc_service_remove_publ(net, sc, lower, upper, node, key, &sr); + +	/* Remove service range item if this was its last publication */ +	if (sr && list_empty(&sr->all_publ)) { +		rb_erase(&sr->tree_node, &sc->ranges); +		kfree(sr); +	}  	/* Delete service item if this no more publications and subscriptions */  	if (RB_EMPTY_ROOT(&sc->ranges) && list_empty(&sc->subscriptions)) { @@ -665,13 +669,14 @@ int tipc_nametbl_withdraw(struct net *net, u32 type, u32 lower,  /**   * tipc_nametbl_subscribe - add a subscription object to the name table   */ -void tipc_nametbl_subscribe(struct tipc_subscription *sub) +bool tipc_nametbl_subscribe(struct tipc_subscription *sub)  {  	struct name_table *nt = tipc_name_table(sub->net);  	struct tipc_net *tn = tipc_net(sub->net);  	struct tipc_subscr *s = &sub->evt.s;  	u32 type = tipc_sub_read(s, seq.type);  	struct tipc_service *sc; +	bool res = true;  	spin_lock_bh(&tn->nametbl_lock);  	sc = tipc_service_find(sub->net, type); @@ -685,8 +690,10 @@ void tipc_nametbl_subscribe(struct tipc_subscription *sub)  		pr_warn("Failed to subscribe for {%u,%u,%u}\n", type,  			tipc_sub_read(s, seq.lower),  			tipc_sub_read(s, seq.upper)); +		res = false;  	}  	spin_unlock_bh(&tn->nametbl_lock); +	return res;  }  /** @@ -744,16 +751,17 @@ int tipc_nametbl_init(struct net *net)  static void tipc_service_delete(struct net *net, struct tipc_service *sc)  {  	struct service_range *sr, *tmpr; -	struct publication *p, *tmpb; +	struct publication *p, *tmp;  	spin_lock_bh(&sc->lock);  	rbtree_postorder_for_each_entry_safe(sr, tmpr, &sc->ranges, tree_node) { -		list_for_each_entry_safe(p, tmpb, -					 &sr->all_publ, all_publ) { +		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); +						 p->node, p->key, &sr);  			kfree_rcu(p, rcu);  		} +		rb_erase(&sr->tree_node, &sc->ranges); +		kfree(sr);  	}  	hlist_del_init_rcu(&sc->service_list);  	spin_unlock_bh(&sc->lock); |