提交 6851cf28 编写于 作者: D David S. Miller

Merge branch 'tipc-slim-down-name-table'

Jon Maloy says:

====================
tipc: slim down name table

We clean up and improve the name binding table:

 - Replace the memory consuming 'sub_sequence/service range' array with
   an RB tree.
 - Introduce support for overlapping service sequences/ranges

 v2: #1: Fixed a missing initialization reported by David Miller
     #4: Obsoleted and replaced a few more macros to get a consistent
         terminology in the API.
     #5: Added new commit to fix a potential string overflow bug (it
         is still only in net-next) reported by Arnd Bergmann
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
...@@ -45,33 +45,33 @@ ...@@ -45,33 +45,33 @@
* TIPC addressing primitives * TIPC addressing primitives
*/ */
struct tipc_portid { struct tipc_socket_addr {
__u32 ref; __u32 ref;
__u32 node; __u32 node;
}; };
struct tipc_name { struct tipc_service_addr {
__u32 type; __u32 type;
__u32 instance; __u32 instance;
}; };
struct tipc_name_seq { struct tipc_service_range {
__u32 type; __u32 type;
__u32 lower; __u32 lower;
__u32 upper; __u32 upper;
}; };
/* /*
* Application-accessible port name types * Application-accessible service types
*/ */
#define TIPC_CFG_SRV 0 /* configuration service name type */ #define TIPC_NODE_STATE 0 /* node state service type */
#define TIPC_TOP_SRV 1 /* topology service name type */ #define TIPC_TOP_SRV 1 /* topology server service type */
#define TIPC_LINK_STATE 2 /* link state name type */ #define TIPC_LINK_STATE 2 /* link state service type */
#define TIPC_RESERVED_TYPES 64 /* lowest user-publishable name type */ #define TIPC_RESERVED_TYPES 64 /* lowest user-allowed service type */
/* /*
* Publication scopes when binding port names and port name sequences * Publication scopes when binding service / service range
*/ */
enum tipc_scope { enum tipc_scope {
TIPC_CLUSTER_SCOPE = 2, /* 0 can also be used */ TIPC_CLUSTER_SCOPE = 2, /* 0 can also be used */
...@@ -108,28 +108,28 @@ enum tipc_scope { ...@@ -108,28 +108,28 @@ enum tipc_scope {
* TIPC topology subscription service definitions * TIPC topology subscription service definitions
*/ */
#define TIPC_SUB_PORTS 0x01 /* filter for port availability */ #define TIPC_SUB_PORTS 0x01 /* filter: evt at each match */
#define TIPC_SUB_SERVICE 0x02 /* filter for service availability */ #define TIPC_SUB_SERVICE 0x02 /* filter: evt at first up/last down */
#define TIPC_SUB_CANCEL 0x04 /* cancel a subscription */ #define TIPC_SUB_CANCEL 0x04 /* filter: cancel a subscription */
#define TIPC_WAIT_FOREVER (~0) /* timeout for permanent subscription */ #define TIPC_WAIT_FOREVER (~0) /* timeout for permanent subscription */
struct tipc_subscr { struct tipc_subscr {
struct tipc_name_seq seq; /* name sequence of interest */ struct tipc_service_range seq; /* range of interest */
__u32 timeout; /* subscription duration (in ms) */ __u32 timeout; /* subscription duration (in ms) */
__u32 filter; /* bitmask of filter options */ __u32 filter; /* bitmask of filter options */
char usr_handle[8]; /* available for subscriber use */ char usr_handle[8]; /* available for subscriber use */
}; };
#define TIPC_PUBLISHED 1 /* publication event */ #define TIPC_PUBLISHED 1 /* publication event */
#define TIPC_WITHDRAWN 2 /* withdraw event */ #define TIPC_WITHDRAWN 2 /* withdrawal event */
#define TIPC_SUBSCR_TIMEOUT 3 /* subscription timeout event */ #define TIPC_SUBSCR_TIMEOUT 3 /* subscription timeout event */
struct tipc_event { struct tipc_event {
__u32 event; /* event type */ __u32 event; /* event type */
__u32 found_lower; /* matching name seq instances */ __u32 found_lower; /* matching range */
__u32 found_upper; /* " " " " */ __u32 found_upper; /* " " */
struct tipc_portid port; /* associated port */ struct tipc_socket_addr port; /* associated socket */
struct tipc_subscr s; /* associated subscription */ struct tipc_subscr s; /* associated subscription */
}; };
...@@ -149,20 +149,20 @@ struct tipc_event { ...@@ -149,20 +149,20 @@ struct tipc_event {
#define SOL_TIPC 271 #define SOL_TIPC 271
#endif #endif
#define TIPC_ADDR_NAMESEQ 1
#define TIPC_ADDR_MCAST 1 #define TIPC_ADDR_MCAST 1
#define TIPC_ADDR_NAME 2 #define TIPC_SERVICE_RANGE 1
#define TIPC_ADDR_ID 3 #define TIPC_SERVICE_ADDR 2
#define TIPC_SOCKET_ADDR 3
struct sockaddr_tipc { struct sockaddr_tipc {
unsigned short family; unsigned short family;
unsigned char addrtype; unsigned char addrtype;
signed char scope; signed char scope;
union { union {
struct tipc_portid id; struct tipc_socket_addr id;
struct tipc_name_seq nameseq; struct tipc_service_range nameseq;
struct { struct {
struct tipc_name name; struct tipc_service_addr name;
__u32 domain; __u32 domain;
} name; } name;
} addr; } addr;
...@@ -216,7 +216,7 @@ struct tipc_group_req { ...@@ -216,7 +216,7 @@ struct tipc_group_req {
#define TIPC_MAX_MEDIA_NAME 16 #define TIPC_MAX_MEDIA_NAME 16
#define TIPC_MAX_IF_NAME 16 #define TIPC_MAX_IF_NAME 16
#define TIPC_MAX_BEARER_NAME 32 #define TIPC_MAX_BEARER_NAME 32
#define TIPC_MAX_LINK_NAME 60 #define TIPC_MAX_LINK_NAME 68
#define SIOCGETLINKNAME SIOCPROTOPRIVATE #define SIOCGETLINKNAME SIOCPROTOPRIVATE
...@@ -230,8 +230,13 @@ struct tipc_sioc_ln_req { ...@@ -230,8 +230,13 @@ struct tipc_sioc_ln_req {
/* The macros and functions below are deprecated: /* The macros and functions below are deprecated:
*/ */
#define TIPC_CFG_SRV 0
#define TIPC_ZONE_SCOPE 1 #define TIPC_ZONE_SCOPE 1
#define TIPC_ADDR_NAMESEQ 1
#define TIPC_ADDR_NAME 2
#define TIPC_ADDR_ID 3
#define TIPC_NODE_BITS 12 #define TIPC_NODE_BITS 12
#define TIPC_CLUSTER_BITS 12 #define TIPC_CLUSTER_BITS 12
#define TIPC_ZONE_BITS 8 #define TIPC_ZONE_BITS 8
...@@ -250,6 +255,10 @@ struct tipc_sioc_ln_req { ...@@ -250,6 +255,10 @@ struct tipc_sioc_ln_req {
#define TIPC_ZONE_CLUSTER_MASK (TIPC_ZONE_MASK | TIPC_CLUSTER_MASK) #define TIPC_ZONE_CLUSTER_MASK (TIPC_ZONE_MASK | TIPC_CLUSTER_MASK)
#define tipc_portid tipc_socket_addr
#define tipc_name tipc_service_addr
#define tipc_name_seq tipc_service_range
static inline __u32 tipc_addr(unsigned int zone, static inline __u32 tipc_addr(unsigned int zone,
unsigned int cluster, unsigned int cluster,
unsigned int node) unsigned int node)
......
...@@ -58,6 +58,7 @@ ...@@ -58,6 +58,7 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <net/netns/generic.h> #include <net/netns/generic.h>
#include <linux/rhashtable.h> #include <linux/rhashtable.h>
#include <net/genetlink.h>
struct tipc_node; struct tipc_node;
struct tipc_bearer; struct tipc_bearer;
......
...@@ -462,7 +462,8 @@ bool tipc_link_create(struct net *net, char *if_name, int bearer_id, ...@@ -462,7 +462,8 @@ bool tipc_link_create(struct net *net, char *if_name, int bearer_id,
sprintf(peer_str, "%x", peer); sprintf(peer_str, "%x", peer);
} }
/* Peer i/f name will be completed by reset/activate message */ /* Peer i/f name will be completed by reset/activate message */
sprintf(l->name, "%s:%s-%s:unknown", self_str, if_name, peer_str); snprintf(l->name, sizeof(l->name), "%s:%s-%s:unknown",
self_str, if_name, peer_str);
strcpy(l->if_name, if_name); strcpy(l->if_name, if_name);
l->addr = peer; l->addr = peer;
...@@ -1810,7 +1811,7 @@ int tipc_link_bc_nack_rcv(struct tipc_link *l, struct sk_buff *skb, ...@@ -1810,7 +1811,7 @@ int tipc_link_bc_nack_rcv(struct tipc_link *l, struct sk_buff *skb,
void tipc_link_set_queue_limits(struct tipc_link *l, u32 win) void tipc_link_set_queue_limits(struct tipc_link *l, u32 win)
{ {
int max_bulk = TIPC_MAX_PUBLICATIONS / (l->mtu / ITEM_SIZE); int max_bulk = TIPC_MAX_PUBL / (l->mtu / ITEM_SIZE);
l->window = win; l->window = win;
l->backlog[TIPC_LOW_IMPORTANCE].limit = max_t(u16, 50, win); l->backlog[TIPC_LOW_IMPORTANCE].limit = max_t(u16, 50, win);
......
...@@ -204,12 +204,12 @@ void tipc_named_node_up(struct net *net, u32 dnode) ...@@ -204,12 +204,12 @@ void tipc_named_node_up(struct net *net, u32 dnode)
*/ */
static void tipc_publ_purge(struct net *net, struct publication *publ, u32 addr) static void tipc_publ_purge(struct net *net, struct publication *publ, u32 addr)
{ {
struct tipc_net *tn = net_generic(net, tipc_net_id); struct tipc_net *tn = tipc_net(net);
struct publication *p; struct publication *p;
spin_lock_bh(&tn->nametbl_lock); spin_lock_bh(&tn->nametbl_lock);
p = tipc_nametbl_remove_publ(net, publ->type, publ->lower, p = tipc_nametbl_remove_publ(net, publ->type, publ->lower, publ->upper,
publ->node, publ->port, publ->key); publ->node, publ->key);
if (p) if (p)
tipc_node_unsubscribe(net, &p->binding_node, addr); tipc_node_unsubscribe(net, &p->binding_node, addr);
spin_unlock_bh(&tn->nametbl_lock); spin_unlock_bh(&tn->nametbl_lock);
...@@ -261,81 +261,37 @@ void tipc_publ_notify(struct net *net, struct list_head *nsub_list, u32 addr) ...@@ -261,81 +261,37 @@ void tipc_publ_notify(struct net *net, struct list_head *nsub_list, u32 addr)
static bool tipc_update_nametbl(struct net *net, struct distr_item *i, static bool tipc_update_nametbl(struct net *net, struct distr_item *i,
u32 node, u32 dtype) u32 node, u32 dtype)
{ {
struct publication *publ = NULL; struct publication *p = NULL;
u32 lower = ntohl(i->lower);
u32 upper = ntohl(i->upper);
u32 type = ntohl(i->type);
u32 port = ntohl(i->port);
u32 key = ntohl(i->key);
if (dtype == PUBLICATION) { if (dtype == PUBLICATION) {
publ = tipc_nametbl_insert_publ(net, ntohl(i->type), p = tipc_nametbl_insert_publ(net, type, lower, upper,
ntohl(i->lower),
ntohl(i->upper),
TIPC_CLUSTER_SCOPE, node, TIPC_CLUSTER_SCOPE, node,
ntohl(i->port), ntohl(i->key)); port, key);
if (publ) { if (p) {
tipc_node_subscribe(net, &publ->binding_node, node); tipc_node_subscribe(net, &p->binding_node, node);
return true; return true;
} }
} else if (dtype == WITHDRAWAL) { } else if (dtype == WITHDRAWAL) {
publ = tipc_nametbl_remove_publ(net, ntohl(i->type), p = tipc_nametbl_remove_publ(net, type, lower,
ntohl(i->lower), upper, node, key);
node, ntohl(i->port), if (p) {
ntohl(i->key)); tipc_node_unsubscribe(net, &p->binding_node, node);
if (publ) { kfree_rcu(p, rcu);
tipc_node_unsubscribe(net, &publ->binding_node, node);
kfree_rcu(publ, rcu);
return true; return true;
} }
pr_warn_ratelimited("Failed to remove binding %u,%u from %x\n",
type, lower, node);
} else { } else {
pr_warn("Unrecognized name table message received\n"); pr_warn("Unrecognized name table message received\n");
} }
return false; return false;
} }
/**
* tipc_named_add_backlog - add a failed name table update to the backlog
*
*/
static void tipc_named_add_backlog(struct net *net, struct distr_item *i,
u32 type, u32 node)
{
struct distr_queue_item *e;
struct tipc_net *tn = net_generic(net, tipc_net_id);
unsigned long now = get_jiffies_64();
e = kzalloc(sizeof(*e), GFP_ATOMIC);
if (!e)
return;
e->dtype = type;
e->node = node;
e->expires = now + msecs_to_jiffies(sysctl_tipc_named_timeout);
memcpy(e, i, sizeof(*i));
list_add_tail(&e->next, &tn->dist_queue);
}
/**
* tipc_named_process_backlog - try to process any pending name table updates
* from the network.
*/
void tipc_named_process_backlog(struct net *net)
{
struct distr_queue_item *e, *tmp;
struct tipc_net *tn = net_generic(net, tipc_net_id);
unsigned long now = get_jiffies_64();
list_for_each_entry_safe(e, tmp, &tn->dist_queue, next) {
if (time_after(e->expires, now)) {
if (!tipc_update_nametbl(net, &e->i, e->node, e->dtype))
continue;
} else {
pr_warn_ratelimited("Dropping name table update (%d) of {%u, %u, %u} from %x key=%u\n",
e->dtype, ntohl(e->i.type),
ntohl(e->i.lower),
ntohl(e->i.upper),
e->node, ntohl(e->i.key));
}
list_del(&e->next);
kfree(e);
}
}
/** /**
* tipc_named_rcv - process name table update messages sent by another node * tipc_named_rcv - process name table update messages sent by another node
*/ */
...@@ -358,12 +314,10 @@ void tipc_named_rcv(struct net *net, struct sk_buff_head *inputq) ...@@ -358,12 +314,10 @@ void tipc_named_rcv(struct net *net, struct sk_buff_head *inputq)
count = msg_data_sz(msg) / ITEM_SIZE; count = msg_data_sz(msg) / ITEM_SIZE;
node = msg_orignode(msg); node = msg_orignode(msg);
while (count--) { while (count--) {
if (!tipc_update_nametbl(net, item, node, mtype)) tipc_update_nametbl(net, item, node, mtype);
tipc_named_add_backlog(net, item, mtype, node);
item++; item++;
} }
kfree_skb(skb); kfree_skb(skb);
tipc_named_process_backlog(net);
} }
spin_unlock_bh(&tn->nametbl_lock); spin_unlock_bh(&tn->nametbl_lock);
} }
......
...@@ -72,7 +72,6 @@ struct sk_buff *tipc_named_withdraw(struct net *net, struct publication *publ); ...@@ -72,7 +72,6 @@ struct sk_buff *tipc_named_withdraw(struct net *net, struct publication *publ);
void tipc_named_node_up(struct net *net, u32 dnode); void tipc_named_node_up(struct net *net, u32 dnode);
void tipc_named_rcv(struct net *net, struct sk_buff_head *msg_queue); void tipc_named_rcv(struct net *net, struct sk_buff_head *msg_queue);
void tipc_named_reinit(struct net *net); void tipc_named_reinit(struct net *net);
void tipc_named_process_backlog(struct net *net);
void tipc_publ_notify(struct net *net, struct list_head *nsub_list, u32 addr); void tipc_publ_notify(struct net *net, struct list_head *nsub_list, u32 addr);
#endif #endif
...@@ -44,52 +44,40 @@ ...@@ -44,52 +44,40 @@
#include "addr.h" #include "addr.h"
#include "node.h" #include "node.h"
#include "group.h" #include "group.h"
#include <net/genetlink.h>
#define TIPC_NAMETBL_SIZE 1024 /* must be a power of 2 */
/**
* struct name_info - name sequence publication info
* @node_list: list of publications on own node of this <type,lower,upper>
* @all_publ: list of all publications of this <type,lower,upper>
*/
struct name_info {
struct list_head local_publ;
struct list_head all_publ;
};
/** /**
* struct sub_seq - container for all published instances of a name sequence * struct service_range - container for all bindings of a service range
* @lower: name sequence lower bound * @lower: service range lower bound
* @upper: name sequence upper bound * @upper: service range upper bound
* @info: pointer to name sequence publication info * @tree_node: member of service range RB tree
* @local_publ: list of identical publications made from this node
* Used by closest_first lookup and multicast lookup algorithm
* @all_publ: all publications identical to this one, whatever node and scope
* Used by round-robin lookup algorithm
*/ */
struct sub_seq { struct service_range {
u32 lower; u32 lower;
u32 upper; u32 upper;
struct name_info *info; struct rb_node tree_node;
struct list_head local_publ;
struct list_head all_publ;
}; };
/** /**
* struct name_seq - container for all published instances of a name type * struct tipc_service - container for all published instances of a service type
* @type: 32 bit 'type' value for name sequence * @type: 32 bit 'type' value for service
* @sseq: pointer to dynamically-sized array of sub-sequences of this 'type'; * @ranges: rb tree containing all service ranges for this service
* sub-sequences are sorted in ascending order * @service_list: links to adjacent name ranges in hash chain
* @alloc: number of sub-sequences currently in array * @subscriptions: list of subscriptions for this service type
* @first_free: array index of first unused sub-sequence entry * @lock: spinlock controlling access to pertaining service ranges/publications
* @ns_list: links to adjacent name sequences in hash chain
* @subscriptions: list of subscriptions for this 'type'
* @lock: spinlock controlling access to publication lists of all sub-sequences
* @rcu: RCU callback head used for deferred freeing * @rcu: RCU callback head used for deferred freeing
*/ */
struct name_seq { struct tipc_service {
u32 type; u32 type;
struct sub_seq *sseqs; struct rb_root ranges;
u32 alloc; struct hlist_node service_list;
u32 first_free;
struct hlist_node ns_list;
struct list_head subscriptions; struct list_head subscriptions;
spinlock_t lock; spinlock_t lock; /* Covers service range list */
struct rcu_head rcu; struct rcu_head rcu;
}; };
...@@ -99,17 +87,16 @@ static int hash(int x) ...@@ -99,17 +87,16 @@ static int hash(int x)
} }
/** /**
* publ_create - create a publication structure * tipc_publ_create - create a publication structure
*/ */
static struct publication *publ_create(u32 type, u32 lower, u32 upper, static struct publication *tipc_publ_create(u32 type, u32 lower, u32 upper,
u32 scope, u32 node, u32 port, u32 scope, u32 node, u32 port,
u32 key) u32 key)
{ {
struct publication *publ = kzalloc(sizeof(*publ), GFP_ATOMIC); struct publication *publ = kzalloc(sizeof(*publ), GFP_ATOMIC);
if (publ == NULL) {
pr_warn("Publication creation failure, no memory\n"); if (!publ)
return NULL; return NULL;
}
publ->type = type; publ->type = type;
publ->lower = lower; publ->lower = lower;
...@@ -119,446 +106,360 @@ static struct publication *publ_create(u32 type, u32 lower, u32 upper, ...@@ -119,446 +106,360 @@ static struct publication *publ_create(u32 type, u32 lower, u32 upper,
publ->port = port; publ->port = port;
publ->key = key; publ->key = key;
INIT_LIST_HEAD(&publ->binding_sock); INIT_LIST_HEAD(&publ->binding_sock);
INIT_LIST_HEAD(&publ->binding_node);
INIT_LIST_HEAD(&publ->local_publ);
INIT_LIST_HEAD(&publ->all_publ);
return publ; return publ;
} }
/** /**
* tipc_subseq_alloc - allocate a specified number of sub-sequence structures * tipc_service_create - create a service structure for the specified 'type'
*/
static struct sub_seq *tipc_subseq_alloc(u32 cnt)
{
return kcalloc(cnt, sizeof(struct sub_seq), GFP_ATOMIC);
}
/**
* tipc_nameseq_create - create a name sequence structure for the specified 'type'
* *
* Allocates a single sub-sequence structure and sets it to all 0's. * Allocates a single range structure and sets it to all 0's.
*/ */
static struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_head) static struct tipc_service *tipc_service_create(u32 type, struct hlist_head *hd)
{ {
struct name_seq *nseq = kzalloc(sizeof(*nseq), GFP_ATOMIC); struct tipc_service *service = kzalloc(sizeof(*service), GFP_ATOMIC);
struct sub_seq *sseq = tipc_subseq_alloc(1);
if (!nseq || !sseq) { if (!service) {
pr_warn("Name sequence creation failed, no memory\n"); pr_warn("Service creation failed, no memory\n");
kfree(nseq);
kfree(sseq);
return NULL; return NULL;
} }
spin_lock_init(&nseq->lock); spin_lock_init(&service->lock);
nseq->type = type; service->type = type;
nseq->sseqs = sseq; service->ranges = RB_ROOT;
nseq->alloc = 1; INIT_HLIST_NODE(&service->service_list);
INIT_HLIST_NODE(&nseq->ns_list); INIT_LIST_HEAD(&service->subscriptions);
INIT_LIST_HEAD(&nseq->subscriptions); hlist_add_head_rcu(&service->service_list, hd);
hlist_add_head_rcu(&nseq->ns_list, seq_head); return service;
return nseq;
} }
/** /**
* nameseq_find_subseq - find sub-sequence (if any) matching a name instance * tipc_service_find_range - find service range matching a service instance
* *
* Very time-critical, so binary searches through sub-sequence array. * Very time-critical, so binary search through range rb tree
*/ */
static struct sub_seq *nameseq_find_subseq(struct name_seq *nseq, static struct service_range *tipc_service_find_range(struct tipc_service *sc,
u32 instance) u32 instance)
{ {
struct sub_seq *sseqs = nseq->sseqs; struct rb_node *n = sc->ranges.rb_node;
int low = 0; struct service_range *sr;
int high = nseq->first_free - 1;
int mid; while (n) {
sr = container_of(n, struct service_range, tree_node);
while (low <= high) { if (sr->lower > instance)
mid = (low + high) / 2; n = n->rb_left;
if (instance < sseqs[mid].lower) else if (sr->upper < instance)
high = mid - 1; n = n->rb_right;
else if (instance > sseqs[mid].upper)
low = mid + 1;
else else
return &sseqs[mid]; return sr;
} }
return NULL; return NULL;
} }
/** static struct service_range *tipc_service_create_range(struct tipc_service *sc,
* nameseq_locate_subseq - determine position of name instance in sub-sequence u32 lower, u32 upper)
*
* Returns index in sub-sequence array of the entry that contains the specified
* instance value; if no entry contains that value, returns the position
* where a new entry for it would be inserted in the array.
*
* Note: Similar to binary search code for locating a sub-sequence.
*/
static u32 nameseq_locate_subseq(struct name_seq *nseq, u32 instance)
{ {
struct sub_seq *sseqs = nseq->sseqs; struct rb_node **n, *parent = NULL;
int low = 0; struct service_range *sr, *tmp;
int high = nseq->first_free - 1;
int mid; n = &sc->ranges.rb_node;
while (*n) {
while (low <= high) { tmp = container_of(*n, struct service_range, tree_node);
mid = (low + high) / 2; parent = *n;
if (instance < sseqs[mid].lower) tmp = container_of(parent, struct service_range, tree_node);
high = mid - 1; if (lower < tmp->lower)
else if (instance > sseqs[mid].upper) n = &(*n)->rb_left;
low = mid + 1; else if (lower > tmp->lower)
n = &(*n)->rb_right;
else if (upper < tmp->upper)
n = &(*n)->rb_left;
else if (upper > tmp->upper)
n = &(*n)->rb_right;
else else
return mid; return tmp;
} }
return low; sr = kzalloc(sizeof(*sr), GFP_ATOMIC);
if (!sr)
return NULL;
sr->lower = lower;
sr->upper = upper;
INIT_LIST_HEAD(&sr->local_publ);
INIT_LIST_HEAD(&sr->all_publ);
rb_link_node(&sr->tree_node, parent, n);
rb_insert_color(&sr->tree_node, &sc->ranges);
return sr;
} }
/** static struct publication *tipc_service_insert_publ(struct net *net,
* tipc_nameseq_insert_publ struct tipc_service *sc,
*/
static struct publication *tipc_nameseq_insert_publ(struct net *net,
struct name_seq *nseq,
u32 type, u32 lower, u32 type, u32 lower,
u32 upper, u32 scope, u32 upper, u32 scope,
u32 node, u32 port, u32 key) u32 node, u32 port,
u32 key)
{ {
struct tipc_subscription *s; struct tipc_subscription *sub, *tmp;
struct tipc_subscription *st; struct service_range *sr;
struct publication *publ; struct publication *p;
struct sub_seq *sseq; bool first = false;
struct name_info *info;
int created_subseq = 0;
sseq = nameseq_find_subseq(nseq, lower);
if (sseq) {
/* Lower end overlaps existing entry => need an exact match */
if ((sseq->lower != lower) || (sseq->upper != upper)) {
return NULL;
}
info = sseq->info;
/* Check if an identical publication already exists */
list_for_each_entry(publ, &info->all_publ, all_publ) {
if (publ->port == port && publ->key == key &&
(!publ->node || publ->node == node))
return NULL;
}
} else {
u32 inspos;
struct sub_seq *freesseq;
/* Find where lower end should be inserted */
inspos = nameseq_locate_subseq(nseq, lower);
/* Fail if upper end overlaps into an existing entry */
if ((inspos < nseq->first_free) &&
(upper >= nseq->sseqs[inspos].lower)) {
return NULL;
}
/* Ensure there is space for new sub-sequence */ sr = tipc_service_create_range(sc, lower, upper);
if (nseq->first_free == nseq->alloc) { if (!sr)
struct sub_seq *sseqs = tipc_subseq_alloc(nseq->alloc * 2); goto err;
if (!sseqs) { first = list_empty(&sr->all_publ);
pr_warn("Cannot publish {%u,%u,%u}, no memory\n",
type, lower, upper);
return NULL;
}
memcpy(sseqs, nseq->sseqs,
nseq->alloc * sizeof(struct sub_seq));
kfree(nseq->sseqs);
nseq->sseqs = sseqs;
nseq->alloc *= 2;
}
info = kzalloc(sizeof(*info), GFP_ATOMIC); /* Return if the publication already exists */
if (!info) { list_for_each_entry(p, &sr->all_publ, all_publ) {
pr_warn("Cannot publish {%u,%u,%u}, no memory\n", if (p->key == key && (!p->node || p->node == node))
type, lower, upper);
return NULL; return NULL;
} }
INIT_LIST_HEAD(&info->local_publ); /* Create and insert publication */
INIT_LIST_HEAD(&info->all_publ); p = tipc_publ_create(type, lower, upper, scope, node, port, key);
if (!p)
/* Insert new sub-sequence */ goto err;
sseq = &nseq->sseqs[inspos];
freesseq = &nseq->sseqs[nseq->first_free];
memmove(sseq + 1, sseq, (freesseq - sseq) * sizeof(*sseq));
memset(sseq, 0, sizeof(*sseq));
nseq->first_free++;
sseq->lower = lower;
sseq->upper = upper;
sseq->info = info;
created_subseq = 1;
}
/* Insert a publication */
publ = publ_create(type, lower, upper, scope, node, port, key);
if (!publ)
return NULL;
list_add(&publ->all_publ, &info->all_publ);
if (in_own_node(net, node)) if (in_own_node(net, node))
list_add(&publ->local_publ, &info->local_publ); list_add(&p->local_publ, &sr->local_publ);
list_add(&p->all_publ, &sr->all_publ);
/* Any subscriptions waiting for notification? */ /* Any subscriptions waiting for notification? */
list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) { list_for_each_entry_safe(sub, tmp, &sc->subscriptions, service_list) {
tipc_sub_report_overlap(s, publ->lower, publ->upper, tipc_sub_report_overlap(sub, p->lower, p->upper, TIPC_PUBLISHED,
TIPC_PUBLISHED, publ->port, p->port, p->node, p->scope, first);
publ->node, publ->scope,
created_subseq);
} }
return publ; return p;
err:
pr_warn("Failed to bind to %u,%u,%u, no memory\n", type, lower, upper);
return NULL;
} }
/** /**
* tipc_nameseq_remove_publ * tipc_service_remove_publ - remove a publication from a service
*
* NOTE: There may be cases where TIPC is asked to remove a publication
* that is not in the name table. For example, if another node issues a
* publication for a name sequence that overlaps an existing name sequence
* the publication will not be recorded, which means the publication won't
* be found when the name sequence is later withdrawn by that node.
* A failed withdraw request simply returns a failure indication and lets the
* caller issue any error or warning messages associated with such a problem.
*/ */
static struct publication *tipc_nameseq_remove_publ(struct net *net, static struct publication *tipc_service_remove_publ(struct net *net,
struct name_seq *nseq, struct tipc_service *sc,
u32 inst, u32 node, u32 lower, u32 upper,
u32 port, u32 key) u32 node, u32 key)
{ {
struct publication *publ; struct tipc_subscription *sub, *tmp;
struct sub_seq *sseq = nameseq_find_subseq(nseq, inst); struct service_range *sr;
struct name_info *info; struct publication *p;
struct sub_seq *free; bool found = false;
struct tipc_subscription *s, *st; bool last = false;
int removed_subseq = 0; struct rb_node *n;
if (!sseq) sr = tipc_service_find_range(sc, lower);
if (!sr)
return NULL; return NULL;
info = sseq->info; /* 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;
/* Locate publication, if it exists */ /* Find publication, if it exists */
list_for_each_entry(publ, &info->all_publ, all_publ) { list_for_each_entry(p, &sr->all_publ, all_publ) {
if (publ->key == key && publ->port == port && if (p->key != key || (node && node != p->node))
(!publ->node || publ->node == node)) continue;
goto found; found = true;
break;
} }
if (!found)
return NULL; return NULL;
found: list_del(&p->all_publ);
list_del(&publ->all_publ); list_del(&p->local_publ);
if (in_own_node(net, node))
list_del(&publ->local_publ); /* Remove service range item if this was its last publication */
if (list_empty(&sr->all_publ)) {
/* Contract subseq list if no more publications for that subseq */ last = true;
if (list_empty(&info->all_publ)) { rb_erase(&sr->tree_node, &sc->ranges);
kfree(info); kfree(sr);
free = &nseq->sseqs[nseq->first_free--];
memmove(sseq, sseq + 1, (free - (sseq + 1)) * sizeof(*sseq));
removed_subseq = 1;
} }
/* Notify any waiting subscriptions */ /* Notify any waiting subscriptions */
list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) { list_for_each_entry_safe(sub, tmp, &sc->subscriptions, service_list) {
tipc_sub_report_overlap(s, publ->lower, publ->upper, tipc_sub_report_overlap(sub, p->lower, p->upper, TIPC_WITHDRAWN,
TIPC_WITHDRAWN, publ->port, p->port, p->node, p->scope, last);
publ->node, publ->scope,
removed_subseq);
} }
return p;
return publ;
} }
/** /**
* tipc_nameseq_subscribe - attach a subscription, and optionally * tipc_service_subscribe - attach a subscription, and optionally
* issue the prescribed number of events if there is any sub- * issue the prescribed number of events if there is any service
* sequence overlapping with the requested sequence * range overlapping with the requested range
*/ */
static void tipc_nameseq_subscribe(struct name_seq *nseq, static void tipc_service_subscribe(struct tipc_service *service,
struct tipc_subscription *sub) struct tipc_subscription *sub)
{ {
struct sub_seq *sseq = nseq->sseqs; struct tipc_subscr *sb = &sub->evt.s;
struct service_range *sr;
struct tipc_name_seq ns; struct tipc_name_seq ns;
struct tipc_subscr *s = &sub->evt.s; struct publication *p;
bool no_status; struct rb_node *n;
bool first;
ns.type = tipc_sub_read(s, seq.type); ns.type = tipc_sub_read(sb, seq.type);
ns.lower = tipc_sub_read(s, seq.lower); ns.lower = tipc_sub_read(sb, seq.lower);
ns.upper = tipc_sub_read(s, seq.upper); ns.upper = tipc_sub_read(sb, seq.upper);
no_status = tipc_sub_read(s, filter) & TIPC_SUB_NO_STATUS;
tipc_sub_get(sub); tipc_sub_get(sub);
list_add(&sub->nameseq_list, &nseq->subscriptions); list_add(&sub->service_list, &service->subscriptions);
if (no_status || !sseq) if (tipc_sub_read(sb, filter) & TIPC_SUB_NO_STATUS)
return; return;
while (sseq != &nseq->sseqs[nseq->first_free]) { for (n = rb_first(&service->ranges); n; n = rb_next(n)) {
if (tipc_sub_check_overlap(&ns, sseq->lower, sseq->upper)) { sr = container_of(n, struct service_range, tree_node);
struct publication *crs; if (sr->lower > ns.upper)
struct name_info *info = sseq->info; break;
int must_report = 1; if (!tipc_sub_check_overlap(&ns, sr->lower, sr->upper))
continue;
list_for_each_entry(crs, &info->all_publ, all_publ) { first = true;
tipc_sub_report_overlap(sub, sseq->lower,
sseq->upper, list_for_each_entry(p, &sr->all_publ, all_publ) {
TIPC_PUBLISHED, tipc_sub_report_overlap(sub, sr->lower, sr->upper,
crs->port, TIPC_PUBLISHED, p->port,
crs->node, p->node, p->scope, first);
crs->scope, first = false;
must_report);
must_report = 0;
}
} }
sseq++;
} }
} }
static struct name_seq *nametbl_find_seq(struct net *net, u32 type) static struct tipc_service *tipc_service_find(struct net *net, u32 type)
{ {
struct tipc_net *tn = net_generic(net, tipc_net_id); struct name_table *nt = tipc_name_table(net);
struct hlist_head *seq_head; struct hlist_head *service_head;
struct name_seq *ns; struct tipc_service *service;
seq_head = &tn->nametbl->seq_hlist[hash(type)]; service_head = &nt->services[hash(type)];
hlist_for_each_entry_rcu(ns, seq_head, ns_list) { hlist_for_each_entry_rcu(service, service_head, service_list) {
if (ns->type == type) if (service->type == type)
return ns; return service;
} }
return NULL; return NULL;
}; };
struct publication *tipc_nametbl_insert_publ(struct net *net, u32 type, struct publication *tipc_nametbl_insert_publ(struct net *net, u32 type,
u32 lower, u32 upper, u32 scope, u32 lower, u32 upper,
u32 node, u32 port, u32 key) u32 scope, u32 node,
u32 port, u32 key)
{ {
struct tipc_net *tn = net_generic(net, tipc_net_id); struct name_table *nt = tipc_name_table(net);
struct publication *publ; struct tipc_service *sc;
struct name_seq *seq = nametbl_find_seq(net, type); struct publication *p;
int index = hash(type);
if (scope > TIPC_NODE_SCOPE || lower > upper) { if (scope > TIPC_NODE_SCOPE || lower > upper) {
pr_debug("Failed to publish illegal {%u,%u,%u} with scope %u\n", pr_debug("Failed to bind illegal {%u,%u,%u} with scope %u\n",
type, lower, upper, scope); type, lower, upper, scope);
return NULL; return NULL;
} }
sc = tipc_service_find(net, type);
if (!seq) if (!sc)
seq = tipc_nameseq_create(type, &tn->nametbl->seq_hlist[index]); sc = tipc_service_create(type, &nt->services[hash(type)]);
if (!seq) if (!sc)
return NULL; return NULL;
spin_lock_bh(&seq->lock); spin_lock_bh(&sc->lock);
publ = tipc_nameseq_insert_publ(net, seq, type, lower, upper, p = tipc_service_insert_publ(net, sc, type, lower, upper,
scope, node, port, key); scope, node, port, key);
spin_unlock_bh(&seq->lock); spin_unlock_bh(&sc->lock);
return publ; return p;
} }
struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type, struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type,
u32 lower, u32 node, u32 port, u32 lower, u32 upper,
u32 key) u32 node, u32 key)
{ {
struct publication *publ; struct tipc_service *sc = tipc_service_find(net, type);
struct name_seq *seq = nametbl_find_seq(net, type); struct publication *p = NULL;
if (!seq) if (!sc)
return NULL; return NULL;
spin_lock_bh(&seq->lock); spin_lock_bh(&sc->lock);
publ = tipc_nameseq_remove_publ(net, seq, lower, node, port, key); p = tipc_service_remove_publ(net, sc, lower, upper, node, key);
if (!seq->first_free && list_empty(&seq->subscriptions)) {
hlist_del_init_rcu(&seq->ns_list); /* Delete service item if this no more publications and subscriptions */
kfree(seq->sseqs); if (RB_EMPTY_ROOT(&sc->ranges) && list_empty(&sc->subscriptions)) {
spin_unlock_bh(&seq->lock); hlist_del_init_rcu(&sc->service_list);
kfree_rcu(seq, rcu); kfree_rcu(sc, rcu);
return publ;
} }
spin_unlock_bh(&seq->lock); spin_unlock_bh(&sc->lock);
return publ; return p;
} }
/** /**
* tipc_nametbl_translate - perform name translation * tipc_nametbl_translate - perform service instance to socket translation
* *
* On entry, 'destnode' is the search domain used during translation. * On entry, 'dnode' is the search domain used during translation.
* *
* On exit: * On exit:
* - if name translation is deferred to another node/cluster/zone, * - if translation is deferred to another node, leave 'dnode' unchanged and
* leaves 'destnode' unchanged (will be non-zero) and returns 0 * return 0
* - if name translation is attempted and succeeds, sets 'destnode' * - if translation is attempted and succeeds, set 'dnode' to the publishing
* to publishing node and returns port reference (will be non-zero) * node and return the published (non-zero) port number
* - if name translation is attempted and fails, sets 'destnode' to 0 * - if translation is attempted and fails, set 'dnode' to 0 and return 0
* and returns 0 *
* Note that for legacy users (node configured with Z.C.N address format) the
* 'closest-first' lookup algorithm must be maintained, i.e., if dnode is 0
* we must look in the local binding list first
*/ */
u32 tipc_nametbl_translate(struct net *net, u32 type, u32 instance, u32 tipc_nametbl_translate(struct net *net, u32 type, u32 instance, u32 *dnode)
u32 *destnode)
{ {
struct tipc_net *tn = tipc_net(net); struct tipc_net *tn = tipc_net(net);
bool legacy = tn->legacy_addr_format; bool legacy = tn->legacy_addr_format;
u32 self = tipc_own_addr(net); u32 self = tipc_own_addr(net);
struct sub_seq *sseq; struct service_range *sr;
struct name_info *info; struct tipc_service *sc;
struct publication *publ; struct list_head *list;
struct name_seq *seq; struct publication *p;
u32 port = 0; u32 port = 0;
u32 node = 0; u32 node = 0;
if (!tipc_in_scope(legacy, *destnode, self)) if (!tipc_in_scope(legacy, *dnode, self))
return 0; return 0;
rcu_read_lock(); rcu_read_lock();
seq = nametbl_find_seq(net, type); sc = tipc_service_find(net, type);
if (unlikely(!seq)) if (unlikely(!sc))
goto not_found; goto not_found;
spin_lock_bh(&seq->lock);
sseq = nameseq_find_subseq(seq, instance);
if (unlikely(!sseq))
goto no_match;
info = sseq->info;
/* Closest-First Algorithm */ spin_lock_bh(&sc->lock);
if (legacy && !*destnode) { sr = tipc_service_find_range(sc, instance);
if (!list_empty(&info->local_publ)) { if (unlikely(!sr))
publ = list_first_entry(&info->local_publ, goto no_match;
struct publication,
local_publ);
list_move_tail(&publ->local_publ,
&info->local_publ);
} else {
publ = list_first_entry(&info->all_publ,
struct publication,
all_publ);
list_move_tail(&publ->all_publ,
&info->all_publ);
}
}
/* Round-Robin Algorithm */ /* Select lookup algorithm: local, closest-first or round-robin */
else if (*destnode == tipc_own_addr(net)) { if (*dnode == self) {
if (list_empty(&info->local_publ)) list = &sr->local_publ;
if (list_empty(list))
goto no_match; goto no_match;
publ = list_first_entry(&info->local_publ, struct publication, p = list_first_entry(list, struct publication, local_publ);
local_publ); list_move_tail(&p->local_publ, &sr->local_publ);
list_move_tail(&publ->local_publ, &info->local_publ); } else if (legacy && !*dnode && !list_empty(&sr->local_publ)) {
list = &sr->local_publ;
p = list_first_entry(list, struct publication, local_publ);
list_move_tail(&p->local_publ, &sr->local_publ);
} else { } else {
publ = list_first_entry(&info->all_publ, struct publication, list = &sr->all_publ;
all_publ); p = list_first_entry(list, struct publication, all_publ);
list_move_tail(&publ->all_publ, &info->all_publ); list_move_tail(&p->all_publ, &sr->all_publ);
} }
port = p->port;
port = publ->port; node = p->node;
node = publ->node;
no_match: no_match:
spin_unlock_bh(&seq->lock); spin_unlock_bh(&sc->lock);
not_found: not_found:
rcu_read_unlock(); rcu_read_unlock();
*destnode = node; *dnode = node;
return port; return port;
} }
...@@ -567,34 +468,36 @@ bool tipc_nametbl_lookup(struct net *net, u32 type, u32 instance, u32 scope, ...@@ -567,34 +468,36 @@ bool tipc_nametbl_lookup(struct net *net, u32 type, u32 instance, u32 scope,
bool all) bool all)
{ {
u32 self = tipc_own_addr(net); u32 self = tipc_own_addr(net);
struct publication *publ; struct service_range *sr;
struct name_info *info; struct tipc_service *sc;
struct name_seq *seq; struct publication *p;
struct sub_seq *sseq;
*dstcnt = 0; *dstcnt = 0;
rcu_read_lock(); rcu_read_lock();
seq = nametbl_find_seq(net, type); sc = tipc_service_find(net, type);
if (unlikely(!seq)) if (unlikely(!sc))
goto exit; goto exit;
spin_lock_bh(&seq->lock);
sseq = nameseq_find_subseq(seq, instance); spin_lock_bh(&sc->lock);
if (likely(sseq)) {
info = sseq->info; sr = tipc_service_find_range(sc, instance);
list_for_each_entry(publ, &info->all_publ, all_publ) { if (!sr)
if (publ->scope != scope) goto no_match;
list_for_each_entry(p, &sr->all_publ, all_publ) {
if (p->scope != scope)
continue; continue;
if (publ->port == exclude && publ->node == self) if (p->port == exclude && p->node == self)
continue; continue;
tipc_dest_push(dsts, publ->node, publ->port); tipc_dest_push(dsts, p->node, p->port);
(*dstcnt)++; (*dstcnt)++;
if (all) if (all)
continue; continue;
list_move_tail(&publ->all_publ, &info->all_publ); list_move_tail(&p->all_publ, &sr->all_publ);
break; break;
} }
} no_match:
spin_unlock_bh(&seq->lock); spin_unlock_bh(&sc->lock);
exit: exit:
rcu_read_unlock(); rcu_read_unlock();
return !list_empty(dsts); return !list_empty(dsts);
...@@ -603,61 +506,64 @@ bool tipc_nametbl_lookup(struct net *net, u32 type, u32 instance, u32 scope, ...@@ -603,61 +506,64 @@ bool tipc_nametbl_lookup(struct net *net, u32 type, u32 instance, u32 scope,
void tipc_nametbl_mc_lookup(struct net *net, u32 type, u32 lower, u32 upper, void tipc_nametbl_mc_lookup(struct net *net, u32 type, u32 lower, u32 upper,
u32 scope, bool exact, struct list_head *dports) u32 scope, bool exact, struct list_head *dports)
{ {
struct sub_seq *sseq_stop; struct service_range *sr;
struct name_info *info; struct tipc_service *sc;
struct publication *p; struct publication *p;
struct name_seq *seq; struct rb_node *n;
struct sub_seq *sseq;
rcu_read_lock(); rcu_read_lock();
seq = nametbl_find_seq(net, type); sc = tipc_service_find(net, type);
if (!seq) if (!sc)
goto exit; goto exit;
spin_lock_bh(&seq->lock); spin_lock_bh(&sc->lock);
sseq = seq->sseqs + nameseq_locate_subseq(seq, lower);
sseq_stop = seq->sseqs + seq->first_free; for (n = rb_first(&sc->ranges); n; n = rb_next(n)) {
for (; sseq != sseq_stop; sseq++) { sr = container_of(n, struct service_range, tree_node);
if (sseq->lower > upper) if (sr->upper < lower)
continue;
if (sr->lower > upper)
break; break;
info = sseq->info; list_for_each_entry(p, &sr->local_publ, local_publ) {
list_for_each_entry(p, &info->local_publ, local_publ) {
if (p->scope == scope || (!exact && p->scope < scope)) if (p->scope == scope || (!exact && p->scope < scope))
tipc_dest_push(dports, 0, p->port); tipc_dest_push(dports, 0, p->port);
} }
} }
spin_unlock_bh(&seq->lock); spin_unlock_bh(&sc->lock);
exit: exit:
rcu_read_unlock(); rcu_read_unlock();
} }
/* tipc_nametbl_lookup_dst_nodes - find broadcast destination nodes /* tipc_nametbl_lookup_dst_nodes - find broadcast destination nodes
* - Creates list of nodes that overlap the given multicast address * - Creates list of nodes that overlap the given multicast address
* - Determines if any node local ports overlap * - Determines if any node local destinations overlap
*/ */
void tipc_nametbl_lookup_dst_nodes(struct net *net, u32 type, u32 lower, void tipc_nametbl_lookup_dst_nodes(struct net *net, u32 type, u32 lower,
u32 upper, struct tipc_nlist *nodes) u32 upper, struct tipc_nlist *nodes)
{ {
struct sub_seq *sseq, *stop; struct service_range *sr;
struct publication *publ; struct tipc_service *sc;
struct name_info *info; struct publication *p;
struct name_seq *seq; struct rb_node *n;
rcu_read_lock(); rcu_read_lock();
seq = nametbl_find_seq(net, type); sc = tipc_service_find(net, type);
if (!seq) if (!sc)
goto exit; goto exit;
spin_lock_bh(&seq->lock); spin_lock_bh(&sc->lock);
sseq = seq->sseqs + nameseq_locate_subseq(seq, lower);
stop = seq->sseqs + seq->first_free; for (n = rb_first(&sc->ranges); n; n = rb_next(n)) {
for (; sseq != stop && sseq->lower <= upper; sseq++) { sr = container_of(n, struct service_range, tree_node);
info = sseq->info; if (sr->upper < lower)
list_for_each_entry(publ, &info->all_publ, all_publ) { continue;
tipc_nlist_add(nodes, publ->node); if (sr->lower > upper)
break;
list_for_each_entry(p, &sr->all_publ, all_publ) {
tipc_nlist_add(nodes, p->node);
} }
} }
spin_unlock_bh(&seq->lock); spin_unlock_bh(&sc->lock);
exit: exit:
rcu_read_unlock(); rcu_read_unlock();
} }
...@@ -667,90 +573,85 @@ void tipc_nametbl_lookup_dst_nodes(struct net *net, u32 type, u32 lower, ...@@ -667,90 +573,85 @@ void tipc_nametbl_lookup_dst_nodes(struct net *net, u32 type, u32 lower,
void tipc_nametbl_build_group(struct net *net, struct tipc_group *grp, void tipc_nametbl_build_group(struct net *net, struct tipc_group *grp,
u32 type, u32 scope) u32 type, u32 scope)
{ {
struct sub_seq *sseq, *stop; struct service_range *sr;
struct name_info *info; struct tipc_service *sc;
struct publication *p; struct publication *p;
struct name_seq *seq; struct rb_node *n;
rcu_read_lock(); rcu_read_lock();
seq = nametbl_find_seq(net, type); sc = tipc_service_find(net, type);
if (!seq) if (!sc)
goto exit; goto exit;
spin_lock_bh(&seq->lock); spin_lock_bh(&sc->lock);
sseq = seq->sseqs; for (n = rb_first(&sc->ranges); n; n = rb_next(n)) {
stop = seq->sseqs + seq->first_free; sr = container_of(n, struct service_range, tree_node);
for (; sseq != stop; sseq++) { list_for_each_entry(p, &sr->all_publ, all_publ) {
info = sseq->info;
list_for_each_entry(p, &info->all_publ, all_publ) {
if (p->scope != scope) if (p->scope != scope)
continue; continue;
tipc_group_add_member(grp, p->node, p->port, p->lower); tipc_group_add_member(grp, p->node, p->port, p->lower);
} }
} }
spin_unlock_bh(&seq->lock); spin_unlock_bh(&sc->lock);
exit: exit:
rcu_read_unlock(); rcu_read_unlock();
} }
/* /* tipc_nametbl_publish - add service binding to name table
* tipc_nametbl_publish - add name publication to network name tables
*/ */
struct publication *tipc_nametbl_publish(struct net *net, u32 type, u32 lower, struct publication *tipc_nametbl_publish(struct net *net, u32 type, u32 lower,
u32 upper, u32 scope, u32 port_ref, u32 upper, u32 scope, u32 port,
u32 key) u32 key)
{ {
struct publication *publ; struct name_table *nt = tipc_name_table(net);
struct sk_buff *buf = NULL; struct tipc_net *tn = tipc_net(net);
struct tipc_net *tn = net_generic(net, tipc_net_id); struct publication *p = NULL;
struct sk_buff *skb = NULL;
spin_lock_bh(&tn->nametbl_lock); spin_lock_bh(&tn->nametbl_lock);
if (tn->nametbl->local_publ_count >= TIPC_MAX_PUBLICATIONS) {
pr_warn("Publication failed, local publication limit reached (%u)\n", if (nt->local_publ_count >= TIPC_MAX_PUBL) {
TIPC_MAX_PUBLICATIONS); pr_warn("Bind failed, max limit %u reached\n", TIPC_MAX_PUBL);
spin_unlock_bh(&tn->nametbl_lock); goto exit;
return NULL;
} }
publ = tipc_nametbl_insert_publ(net, type, lower, upper, scope, p = tipc_nametbl_insert_publ(net, type, lower, upper, scope,
tipc_own_addr(net), port_ref, key); tipc_own_addr(net), port, key);
if (likely(publ)) { if (p) {
tn->nametbl->local_publ_count++; nt->local_publ_count++;
buf = tipc_named_publish(net, publ); skb = tipc_named_publish(net, p);
/* Any pending external events? */
tipc_named_process_backlog(net);
} }
exit:
spin_unlock_bh(&tn->nametbl_lock); spin_unlock_bh(&tn->nametbl_lock);
if (buf) if (skb)
tipc_node_broadcast(net, buf); tipc_node_broadcast(net, skb);
return publ; return p;
} }
/** /**
* tipc_nametbl_withdraw - withdraw name publication from network name tables * tipc_nametbl_withdraw - withdraw a service binding
*/ */
int tipc_nametbl_withdraw(struct net *net, u32 type, u32 lower, u32 port, int tipc_nametbl_withdraw(struct net *net, u32 type, u32 lower,
u32 key) u32 upper, u32 key)
{ {
struct publication *publ; struct name_table *nt = tipc_name_table(net);
struct tipc_net *tn = tipc_net(net);
u32 self = tipc_own_addr(net);
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
struct tipc_net *tn = net_generic(net, tipc_net_id); struct publication *p;
spin_lock_bh(&tn->nametbl_lock); spin_lock_bh(&tn->nametbl_lock);
publ = tipc_nametbl_remove_publ(net, type, lower, tipc_own_addr(net),
port, key); p = tipc_nametbl_remove_publ(net, type, lower, upper, self, key);
if (likely(publ)) { if (p) {
tn->nametbl->local_publ_count--; nt->local_publ_count--;
skb = tipc_named_withdraw(net, publ); skb = tipc_named_withdraw(net, p);
/* Any pending external events? */ list_del_init(&p->binding_sock);
tipc_named_process_backlog(net); kfree_rcu(p, rcu);
list_del_init(&publ->binding_sock);
kfree_rcu(publ, rcu);
} else { } else {
pr_err("Unable to remove local publication\n" pr_err("Failed to remove local publication {%u,%u,%u}/%u\n",
"(type=%u, lower=%u, port=%u, key=%u)\n", type, lower, upper, key);
type, lower, port, key);
} }
spin_unlock_bh(&tn->nametbl_lock); spin_unlock_bh(&tn->nametbl_lock);
...@@ -766,27 +667,24 @@ int tipc_nametbl_withdraw(struct net *net, u32 type, u32 lower, u32 port, ...@@ -766,27 +667,24 @@ int tipc_nametbl_withdraw(struct net *net, u32 type, u32 lower, u32 port,
*/ */
void tipc_nametbl_subscribe(struct tipc_subscription *sub) void 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_net *tn = tipc_net(sub->net);
struct tipc_subscr *s = &sub->evt.s; struct tipc_subscr *s = &sub->evt.s;
u32 type = tipc_sub_read(s, seq.type); u32 type = tipc_sub_read(s, seq.type);
int index = hash(type); struct tipc_service *sc;
struct name_seq *seq;
struct tipc_name_seq ns;
spin_lock_bh(&tn->nametbl_lock); spin_lock_bh(&tn->nametbl_lock);
seq = nametbl_find_seq(sub->net, type); sc = tipc_service_find(sub->net, type);
if (!seq) if (!sc)
seq = tipc_nameseq_create(type, &tn->nametbl->seq_hlist[index]); sc = tipc_service_create(type, &nt->services[hash(type)]);
if (seq) { if (sc) {
spin_lock_bh(&seq->lock); spin_lock_bh(&sc->lock);
tipc_nameseq_subscribe(seq, sub); tipc_service_subscribe(sc, sub);
spin_unlock_bh(&seq->lock); spin_unlock_bh(&sc->lock);
} else { } else {
ns.type = tipc_sub_read(s, seq.type); pr_warn("Failed to subscribe for {%u,%u,%u}\n", type,
ns.lower = tipc_sub_read(s, seq.lower); tipc_sub_read(s, seq.lower),
ns.upper = tipc_sub_read(s, seq.upper); tipc_sub_read(s, seq.upper));
pr_warn("Failed to create subscription for {%u,%u,%u}\n",
ns.type, ns.lower, ns.upper);
} }
spin_unlock_bh(&tn->nametbl_lock); spin_unlock_bh(&tn->nametbl_lock);
} }
...@@ -796,124 +694,122 @@ void tipc_nametbl_subscribe(struct tipc_subscription *sub) ...@@ -796,124 +694,122 @@ void tipc_nametbl_subscribe(struct tipc_subscription *sub)
*/ */
void tipc_nametbl_unsubscribe(struct tipc_subscription *sub) void tipc_nametbl_unsubscribe(struct tipc_subscription *sub)
{ {
struct tipc_subscr *s = &sub->evt.s;
struct tipc_net *tn = tipc_net(sub->net); struct tipc_net *tn = tipc_net(sub->net);
struct name_seq *seq; struct tipc_subscr *s = &sub->evt.s;
u32 type = tipc_sub_read(s, seq.type); u32 type = tipc_sub_read(s, seq.type);
struct tipc_service *sc;
spin_lock_bh(&tn->nametbl_lock); spin_lock_bh(&tn->nametbl_lock);
seq = nametbl_find_seq(sub->net, type); sc = tipc_service_find(sub->net, type);
if (seq != NULL) { if (!sc)
spin_lock_bh(&seq->lock); goto exit;
list_del_init(&sub->nameseq_list);
spin_lock_bh(&sc->lock);
list_del_init(&sub->service_list);
tipc_sub_put(sub); tipc_sub_put(sub);
if (!seq->first_free && list_empty(&seq->subscriptions)) {
hlist_del_init_rcu(&seq->ns_list); /* Delete service item if no more publications and subscriptions */
kfree(seq->sseqs); if (RB_EMPTY_ROOT(&sc->ranges) && list_empty(&sc->subscriptions)) {
spin_unlock_bh(&seq->lock); hlist_del_init_rcu(&sc->service_list);
kfree_rcu(seq, rcu); kfree_rcu(sc, rcu);
} else {
spin_unlock_bh(&seq->lock);
}
} }
spin_unlock_bh(&sc->lock);
exit:
spin_unlock_bh(&tn->nametbl_lock); spin_unlock_bh(&tn->nametbl_lock);
} }
int tipc_nametbl_init(struct net *net) int tipc_nametbl_init(struct net *net)
{ {
struct tipc_net *tn = net_generic(net, tipc_net_id); struct tipc_net *tn = tipc_net(net);
struct name_table *tipc_nametbl; struct name_table *nt;
int i; int i;
tipc_nametbl = kzalloc(sizeof(*tipc_nametbl), GFP_ATOMIC); nt = kzalloc(sizeof(*nt), GFP_ATOMIC);
if (!tipc_nametbl) if (!nt)
return -ENOMEM; return -ENOMEM;
for (i = 0; i < TIPC_NAMETBL_SIZE; i++) for (i = 0; i < TIPC_NAMETBL_SIZE; i++)
INIT_HLIST_HEAD(&tipc_nametbl->seq_hlist[i]); INIT_HLIST_HEAD(&nt->services[i]);
INIT_LIST_HEAD(&tipc_nametbl->node_scope); INIT_LIST_HEAD(&nt->node_scope);
INIT_LIST_HEAD(&tipc_nametbl->cluster_scope); INIT_LIST_HEAD(&nt->cluster_scope);
tn->nametbl = tipc_nametbl; tn->nametbl = nt;
spin_lock_init(&tn->nametbl_lock); spin_lock_init(&tn->nametbl_lock);
return 0; return 0;
} }
/** /**
* tipc_purge_publications - remove all publications for a given type * tipc_service_delete - purge all publications for a service and delete it
*
* tipc_nametbl_lock must be held when calling this function
*/ */
static void tipc_purge_publications(struct net *net, struct name_seq *seq) static void tipc_service_delete(struct net *net, struct tipc_service *sc)
{ {
struct publication *publ, *safe; struct service_range *sr, *tmpr;
struct sub_seq *sseq; struct publication *p, *tmpb;
struct name_info *info;
spin_lock_bh(&sc->lock);
spin_lock_bh(&seq->lock); rbtree_postorder_for_each_entry_safe(sr, tmpr, &sc->ranges, tree_node) {
sseq = seq->sseqs; list_for_each_entry_safe(p, tmpb,
info = sseq->info; &sr->all_publ, all_publ) {
list_for_each_entry_safe(publ, safe, &info->all_publ, all_publ) { tipc_service_remove_publ(net, sc, p->lower, p->upper,
tipc_nameseq_remove_publ(net, seq, publ->lower, publ->node, p->node, p->key);
publ->port, publ->key); kfree_rcu(p, rcu);
kfree_rcu(publ, rcu);
} }
hlist_del_init_rcu(&seq->ns_list); }
kfree(seq->sseqs); hlist_del_init_rcu(&sc->service_list);
spin_unlock_bh(&seq->lock); spin_unlock_bh(&sc->lock);
kfree_rcu(sc, rcu);
kfree_rcu(seq, rcu);
} }
void tipc_nametbl_stop(struct net *net) void tipc_nametbl_stop(struct net *net)
{ {
struct name_table *nt = tipc_name_table(net);
struct tipc_net *tn = tipc_net(net);
struct hlist_head *service_head;
struct tipc_service *service;
u32 i; u32 i;
struct name_seq *seq;
struct hlist_head *seq_head;
struct tipc_net *tn = net_generic(net, tipc_net_id);
struct name_table *tipc_nametbl = tn->nametbl;
/* Verify name table is empty and purge any lingering /* Verify name table is empty and purge any lingering
* publications, then release the name table * publications, then release the name table
*/ */
spin_lock_bh(&tn->nametbl_lock); spin_lock_bh(&tn->nametbl_lock);
for (i = 0; i < TIPC_NAMETBL_SIZE; i++) { for (i = 0; i < TIPC_NAMETBL_SIZE; i++) {
if (hlist_empty(&tipc_nametbl->seq_hlist[i])) if (hlist_empty(&nt->services[i]))
continue; continue;
seq_head = &tipc_nametbl->seq_hlist[i]; service_head = &nt->services[i];
hlist_for_each_entry_rcu(seq, seq_head, ns_list) { hlist_for_each_entry_rcu(service, service_head, service_list) {
tipc_purge_publications(net, seq); tipc_service_delete(net, service);
} }
} }
spin_unlock_bh(&tn->nametbl_lock); spin_unlock_bh(&tn->nametbl_lock);
synchronize_net(); synchronize_net();
kfree(tipc_nametbl); kfree(nt);
} }
static int __tipc_nl_add_nametable_publ(struct tipc_nl_msg *msg, static int __tipc_nl_add_nametable_publ(struct tipc_nl_msg *msg,
struct name_seq *seq, struct tipc_service *service,
struct sub_seq *sseq, u32 *last_publ) struct service_range *sr,
u32 *last_key)
{ {
void *hdr;
struct nlattr *attrs;
struct nlattr *publ;
struct publication *p; struct publication *p;
struct nlattr *attrs;
struct nlattr *b;
void *hdr;
if (*last_publ) { if (*last_key) {
list_for_each_entry(p, &sseq->info->all_publ, all_publ) list_for_each_entry(p, &sr->all_publ, all_publ)
if (p->key == *last_publ) if (p->key == *last_key)
break; break;
if (p->key != *last_publ) if (p->key != *last_key)
return -EPIPE; return -EPIPE;
} else { } else {
p = list_first_entry(&sseq->info->all_publ, struct publication, p = list_first_entry(&sr->all_publ,
struct publication,
all_publ); all_publ);
} }
list_for_each_entry_from(p, &sseq->info->all_publ, all_publ) { list_for_each_entry_from(p, &sr->all_publ, all_publ) {
*last_publ = p->key; *last_key = p->key;
hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, hdr = genlmsg_put(msg->skb, msg->portid, msg->seq,
&tipc_genl_family, NLM_F_MULTI, &tipc_genl_family, NLM_F_MULTI,
...@@ -925,15 +821,15 @@ static int __tipc_nl_add_nametable_publ(struct tipc_nl_msg *msg, ...@@ -925,15 +821,15 @@ static int __tipc_nl_add_nametable_publ(struct tipc_nl_msg *msg,
if (!attrs) if (!attrs)
goto msg_full; goto msg_full;
publ = nla_nest_start(msg->skb, TIPC_NLA_NAME_TABLE_PUBL); b = nla_nest_start(msg->skb, TIPC_NLA_NAME_TABLE_PUBL);
if (!publ) if (!b)
goto attr_msg_full; goto attr_msg_full;
if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_TYPE, seq->type)) if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_TYPE, service->type))
goto publ_msg_full; goto publ_msg_full;
if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_LOWER, sseq->lower)) if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_LOWER, sr->lower))
goto publ_msg_full; goto publ_msg_full;
if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_UPPER, sseq->upper)) if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_UPPER, sr->upper))
goto publ_msg_full; goto publ_msg_full;
if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_SCOPE, p->scope)) if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_SCOPE, p->scope))
goto publ_msg_full; goto publ_msg_full;
...@@ -944,16 +840,16 @@ static int __tipc_nl_add_nametable_publ(struct tipc_nl_msg *msg, ...@@ -944,16 +840,16 @@ static int __tipc_nl_add_nametable_publ(struct tipc_nl_msg *msg,
if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_KEY, p->key)) if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_KEY, p->key))
goto publ_msg_full; goto publ_msg_full;
nla_nest_end(msg->skb, publ); nla_nest_end(msg->skb, b);
nla_nest_end(msg->skb, attrs); nla_nest_end(msg->skb, attrs);
genlmsg_end(msg->skb, hdr); genlmsg_end(msg->skb, hdr);
} }
*last_publ = 0; *last_key = 0;
return 0; return 0;
publ_msg_full: publ_msg_full:
nla_nest_cancel(msg->skb, publ); nla_nest_cancel(msg->skb, b);
attr_msg_full: attr_msg_full:
nla_nest_cancel(msg->skb, attrs); nla_nest_cancel(msg->skb, attrs);
msg_full: msg_full:
...@@ -962,39 +858,34 @@ static int __tipc_nl_add_nametable_publ(struct tipc_nl_msg *msg, ...@@ -962,39 +858,34 @@ static int __tipc_nl_add_nametable_publ(struct tipc_nl_msg *msg,
return -EMSGSIZE; return -EMSGSIZE;
} }
static int __tipc_nl_subseq_list(struct tipc_nl_msg *msg, struct name_seq *seq, static int __tipc_nl_service_range_list(struct tipc_nl_msg *msg,
u32 *last_lower, u32 *last_publ) struct tipc_service *sc,
u32 *last_lower, u32 *last_key)
{ {
struct sub_seq *sseq; struct service_range *sr;
struct sub_seq *sseq_start; struct rb_node *n;
int err; int err;
if (*last_lower) { for (n = rb_first(&sc->ranges); n; n = rb_next(n)) {
sseq_start = nameseq_find_subseq(seq, *last_lower); sr = container_of(n, struct service_range, tree_node);
if (!sseq_start) if (sr->lower < *last_lower)
return -EPIPE; continue;
} else { err = __tipc_nl_add_nametable_publ(msg, sc, sr, last_key);
sseq_start = seq->sseqs;
}
for (sseq = sseq_start; sseq != &seq->sseqs[seq->first_free]; sseq++) {
err = __tipc_nl_add_nametable_publ(msg, seq, sseq, last_publ);
if (err) { if (err) {
*last_lower = sseq->lower; *last_lower = sr->lower;
return err; return err;
} }
} }
*last_lower = 0; *last_lower = 0;
return 0; return 0;
} }
static int tipc_nl_seq_list(struct net *net, struct tipc_nl_msg *msg, static int tipc_nl_service_list(struct net *net, struct tipc_nl_msg *msg,
u32 *last_type, u32 *last_lower, u32 *last_publ) u32 *last_type, u32 *last_lower, u32 *last_key)
{ {
struct tipc_net *tn = net_generic(net, tipc_net_id); struct tipc_net *tn = tipc_net(net);
struct hlist_head *seq_head; struct tipc_service *service = NULL;
struct name_seq *seq = NULL; struct hlist_head *head;
int err; int err;
int i; int i;
...@@ -1004,30 +895,31 @@ static int tipc_nl_seq_list(struct net *net, struct tipc_nl_msg *msg, ...@@ -1004,30 +895,31 @@ static int tipc_nl_seq_list(struct net *net, struct tipc_nl_msg *msg,
i = 0; i = 0;
for (; i < TIPC_NAMETBL_SIZE; i++) { for (; i < TIPC_NAMETBL_SIZE; i++) {
seq_head = &tn->nametbl->seq_hlist[i]; head = &tn->nametbl->services[i];
if (*last_type) { if (*last_type) {
seq = nametbl_find_seq(net, *last_type); service = tipc_service_find(net, *last_type);
if (!seq) if (!service)
return -EPIPE; return -EPIPE;
} else { } else {
hlist_for_each_entry_rcu(seq, seq_head, ns_list) hlist_for_each_entry_rcu(service, head, service_list)
break; break;
if (!seq) if (!service)
continue; continue;
} }
hlist_for_each_entry_from_rcu(seq, ns_list) { hlist_for_each_entry_from_rcu(service, service_list) {
spin_lock_bh(&seq->lock); spin_lock_bh(&service->lock);
err = __tipc_nl_subseq_list(msg, seq, last_lower, err = __tipc_nl_service_range_list(msg, service,
last_publ); last_lower,
last_key);
if (err) { if (err) {
*last_type = seq->type; *last_type = service->type;
spin_unlock_bh(&seq->lock); spin_unlock_bh(&service->lock);
return err; return err;
} }
spin_unlock_bh(&seq->lock); spin_unlock_bh(&service->lock);
} }
*last_type = 0; *last_type = 0;
} }
...@@ -1036,13 +928,13 @@ static int tipc_nl_seq_list(struct net *net, struct tipc_nl_msg *msg, ...@@ -1036,13 +928,13 @@ static int tipc_nl_seq_list(struct net *net, struct tipc_nl_msg *msg,
int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb) int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb)
{ {
int err; struct net *net = sock_net(skb->sk);
int done = cb->args[3];
u32 last_type = cb->args[0]; u32 last_type = cb->args[0];
u32 last_lower = cb->args[1]; u32 last_lower = cb->args[1];
u32 last_publ = cb->args[2]; u32 last_key = cb->args[2];
struct net *net = sock_net(skb->sk); int done = cb->args[3];
struct tipc_nl_msg msg; struct tipc_nl_msg msg;
int err;
if (done) if (done)
return 0; return 0;
...@@ -1052,7 +944,8 @@ int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1052,7 +944,8 @@ int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb)
msg.seq = cb->nlh->nlmsg_seq; msg.seq = cb->nlh->nlmsg_seq;
rcu_read_lock(); rcu_read_lock();
err = tipc_nl_seq_list(net, &msg, &last_type, &last_lower, &last_publ); err = tipc_nl_service_list(net, &msg, &last_type,
&last_lower, &last_key);
if (!err) { if (!err) {
done = 1; done = 1;
} else if (err != -EMSGSIZE) { } else if (err != -EMSGSIZE) {
...@@ -1068,7 +961,7 @@ int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1068,7 +961,7 @@ int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb)
cb->args[0] = last_type; cb->args[0] = last_type;
cb->args[1] = last_lower; cb->args[1] = last_lower;
cb->args[2] = last_publ; cb->args[2] = last_key;
cb->args[3] = done; cb->args[3] = done;
return skb->len; return skb->len;
......
...@@ -97,7 +97,7 @@ struct publication { ...@@ -97,7 +97,7 @@ struct publication {
* @local_publ_count: number of publications issued by this node * @local_publ_count: number of publications issued by this node
*/ */
struct name_table { struct name_table {
struct hlist_head seq_hlist[TIPC_NAMETBL_SIZE]; struct hlist_head services[TIPC_NAMETBL_SIZE];
struct list_head node_scope; struct list_head node_scope;
struct list_head cluster_scope; struct list_head cluster_scope;
u32 local_publ_count; u32 local_publ_count;
...@@ -116,16 +116,16 @@ bool tipc_nametbl_lookup(struct net *net, u32 type, u32 instance, u32 domain, ...@@ -116,16 +116,16 @@ bool tipc_nametbl_lookup(struct net *net, u32 type, u32 instance, u32 domain,
struct list_head *dsts, int *dstcnt, u32 exclude, struct list_head *dsts, int *dstcnt, u32 exclude,
bool all); bool all);
struct publication *tipc_nametbl_publish(struct net *net, u32 type, u32 lower, struct publication *tipc_nametbl_publish(struct net *net, u32 type, u32 lower,
u32 upper, u32 scope, u32 port_ref, u32 upper, u32 scope, u32 port,
u32 key); u32 key);
int tipc_nametbl_withdraw(struct net *net, u32 type, u32 lower, u32 ref, int tipc_nametbl_withdraw(struct net *net, u32 type, u32 lower, u32 upper,
u32 key); u32 key);
struct publication *tipc_nametbl_insert_publ(struct net *net, u32 type, struct publication *tipc_nametbl_insert_publ(struct net *net, u32 type,
u32 lower, u32 upper, u32 scope, u32 lower, u32 upper, u32 scope,
u32 node, u32 ref, u32 key); u32 node, u32 ref, u32 key);
struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type, struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type,
u32 lower, u32 node, u32 ref, u32 lower, u32 upper,
u32 key); u32 node, u32 key);
void tipc_nametbl_subscribe(struct tipc_subscription *s); void tipc_nametbl_subscribe(struct tipc_subscription *s);
void tipc_nametbl_unsubscribe(struct tipc_subscription *s); void tipc_nametbl_unsubscribe(struct tipc_subscription *s);
int tipc_nametbl_init(struct net *net); int tipc_nametbl_init(struct net *net);
......
...@@ -136,7 +136,7 @@ void tipc_net_stop(struct net *net) ...@@ -136,7 +136,7 @@ void tipc_net_stop(struct net *net)
if (!self) if (!self)
return; return;
tipc_nametbl_withdraw(net, TIPC_CFG_SRV, self, 0, self); tipc_nametbl_withdraw(net, TIPC_CFG_SRV, self, self, self);
rtnl_lock(); rtnl_lock();
tipc_bearer_stop(net); tipc_bearer_stop(net);
tipc_node_stop(net); tipc_node_stop(net);
......
...@@ -324,12 +324,12 @@ static void tipc_node_write_unlock(struct tipc_node *n) ...@@ -324,12 +324,12 @@ static void tipc_node_write_unlock(struct tipc_node *n)
if (flags & TIPC_NOTIFY_LINK_UP) { if (flags & TIPC_NOTIFY_LINK_UP) {
tipc_mon_peer_up(net, addr, bearer_id); tipc_mon_peer_up(net, addr, bearer_id);
tipc_nametbl_publish(net, TIPC_LINK_STATE, addr, addr, tipc_nametbl_publish(net, TIPC_LINK_STATE, addr, addr,
TIPC_NODE_SCOPE, link_id, addr); TIPC_NODE_SCOPE, link_id, link_id);
} }
if (flags & TIPC_NOTIFY_LINK_DOWN) { if (flags & TIPC_NOTIFY_LINK_DOWN) {
tipc_mon_peer_down(net, addr, bearer_id); tipc_mon_peer_down(net, addr, bearer_id);
tipc_nametbl_withdraw(net, TIPC_LINK_STATE, addr, tipc_nametbl_withdraw(net, TIPC_LINK_STATE, addr,
link_id, addr); addr, link_id);
} }
} }
......
...@@ -2634,12 +2634,12 @@ static int tipc_sk_withdraw(struct tipc_sock *tsk, uint scope, ...@@ -2634,12 +2634,12 @@ static int tipc_sk_withdraw(struct tipc_sock *tsk, uint scope,
if (publ->upper != seq->upper) if (publ->upper != seq->upper)
break; break;
tipc_nametbl_withdraw(net, publ->type, publ->lower, tipc_nametbl_withdraw(net, publ->type, publ->lower,
publ->port, publ->key); publ->upper, publ->key);
rc = 0; rc = 0;
break; break;
} }
tipc_nametbl_withdraw(net, publ->type, publ->lower, tipc_nametbl_withdraw(net, publ->type, publ->lower,
publ->port, publ->key); publ->upper, publ->key);
rc = 0; rc = 0;
} }
if (list_empty(&tsk->publications)) if (list_empty(&tsk->publications))
......
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
#include "topsrv.h" #include "topsrv.h"
#define TIPC_MAX_SUBSCR 65535 #define TIPC_MAX_SUBSCR 65535
#define TIPC_MAX_PUBLICATIONS 65535 #define TIPC_MAX_PUBL 65535
struct tipc_subscription; struct tipc_subscription;
struct tipc_conn; struct tipc_conn;
...@@ -58,7 +58,7 @@ struct tipc_subscription { ...@@ -58,7 +58,7 @@ struct tipc_subscription {
struct kref kref; struct kref kref;
struct net *net; struct net *net;
struct timer_list timer; struct timer_list timer;
struct list_head nameseq_list; struct list_head service_list;
struct list_head sub_list; struct list_head sub_list;
struct tipc_event evt; struct tipc_event evt;
int conid; int conid;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册