Commit 5a50a927 authored by David S. Miller's avatar David S. Miller

Merge branch 'tipc-next'

Ying Xue says:

====================
tipc: purge signal handler infrastructure

When we delay some actions to be executed in asynchronous contexts,
these usually add unnecessary code complexities, and make their
behaviours unpredictable and indeterministic. Moreover, as the signal
handler infrastructure is first stopped when tipc module is removed,
this may cause some potential risks for us. For instance, although
signal handler is already stopped, some tipc components still submit
signal requests to signal handler infrastructure, which may lead to
some resources not to be released or freed correctly.

So the series aims to convert all actions being performed in tasklet
context asynchronously with interface provided by signal handler
infrastructure to be executed synchronously, thereby deleting the
whole infrastructure of signal handler.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5b579e21 52ff8720
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
obj-$(CONFIG_TIPC) := tipc.o obj-$(CONFIG_TIPC) := tipc.o
tipc-y += addr.o bcast.o bearer.o config.o \ tipc-y += addr.o bcast.o bearer.o config.o \
core.o handler.o link.o discover.o msg.o \ core.o link.o discover.o msg.o \
name_distr.o subscr.o name_table.o net.o \ name_distr.o subscr.o name_table.o net.o \
netlink.o node.o node_subscr.o port.o ref.o \ netlink.o node.o node_subscr.o port.o ref.o \
socket.o log.o eth_media.o server.o socket.o log.o eth_media.o server.o
......
This diff is collapsed.
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#define MAX_NODES 4096 #define MAX_NODES 4096
#define WSIZE 32 #define WSIZE 32
#define TIPC_BCLINK_RESET 1
/** /**
* struct tipc_node_map - set of node identifiers * struct tipc_node_map - set of node identifiers
...@@ -81,8 +82,9 @@ static inline int tipc_nmap_equal(struct tipc_node_map *nm_a, ...@@ -81,8 +82,9 @@ static inline int tipc_nmap_equal(struct tipc_node_map *nm_a,
void tipc_port_list_add(struct tipc_port_list *pl_ptr, u32 port); void tipc_port_list_add(struct tipc_port_list *pl_ptr, u32 port);
void tipc_port_list_free(struct tipc_port_list *pl_ptr); void tipc_port_list_free(struct tipc_port_list *pl_ptr);
void tipc_bclink_init(void); int tipc_bclink_init(void);
void tipc_bclink_stop(void); void tipc_bclink_stop(void);
void tipc_bclink_set_flags(unsigned int flags);
void tipc_bclink_add_node(u32 addr); void tipc_bclink_add_node(u32 addr);
void tipc_bclink_remove_node(u32 addr); void tipc_bclink_remove_node(u32 addr);
struct tipc_node *tipc_bclink_retransmit_to(void); struct tipc_node *tipc_bclink_retransmit_to(void);
......
...@@ -177,8 +177,10 @@ static struct sk_buff *cfg_set_own_addr(void) ...@@ -177,8 +177,10 @@ static struct sk_buff *cfg_set_own_addr(void)
if (tipc_own_addr) if (tipc_own_addr)
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (cannot change node address once assigned)"); " (cannot change node address once assigned)");
tipc_net_start(addr); if (!tipc_net_start(addr))
return tipc_cfg_reply_none(); return tipc_cfg_reply_none();
return tipc_cfg_reply_error_string("cannot change to network mode");
} }
static struct sk_buff *cfg_set_max_ports(void) static struct sk_buff *cfg_set_max_ports(void)
......
...@@ -80,7 +80,6 @@ struct sk_buff *tipc_buf_acquire(u32 size) ...@@ -80,7 +80,6 @@ struct sk_buff *tipc_buf_acquire(u32 size)
*/ */
static void tipc_core_stop(void) static void tipc_core_stop(void)
{ {
tipc_handler_stop();
tipc_net_stop(); tipc_net_stop();
tipc_bearer_cleanup(); tipc_bearer_cleanup();
tipc_netlink_stop(); tipc_netlink_stop();
...@@ -100,10 +99,6 @@ static int tipc_core_start(void) ...@@ -100,10 +99,6 @@ static int tipc_core_start(void)
get_random_bytes(&tipc_random, sizeof(tipc_random)); get_random_bytes(&tipc_random, sizeof(tipc_random));
err = tipc_handler_start();
if (err)
goto out_handler;
err = tipc_ref_table_init(tipc_max_ports, tipc_random); err = tipc_ref_table_init(tipc_max_ports, tipc_random);
if (err) if (err)
goto out_reftbl; goto out_reftbl;
...@@ -146,8 +141,6 @@ static int tipc_core_start(void) ...@@ -146,8 +141,6 @@ static int tipc_core_start(void)
out_nametbl: out_nametbl:
tipc_ref_table_stop(); tipc_ref_table_stop();
out_reftbl: out_reftbl:
tipc_handler_stop();
out_handler:
return err; return err;
} }
......
...@@ -89,8 +89,6 @@ extern int tipc_random __read_mostly; ...@@ -89,8 +89,6 @@ extern int tipc_random __read_mostly;
/* /*
* Routines available to privileged subsystems * Routines available to privileged subsystems
*/ */
int tipc_handler_start(void);
void tipc_handler_stop(void);
int tipc_netlink_start(void); int tipc_netlink_start(void);
void tipc_netlink_stop(void); void tipc_netlink_stop(void);
int tipc_socket_init(void); int tipc_socket_init(void);
...@@ -109,12 +107,10 @@ void tipc_unregister_sysctl(void); ...@@ -109,12 +107,10 @@ void tipc_unregister_sysctl(void);
#endif #endif
/* /*
* TIPC timer and signal code * TIPC timer code
*/ */
typedef void (*Handler) (unsigned long); typedef void (*Handler) (unsigned long);
u32 tipc_k_signal(Handler routine, unsigned long argument);
/** /**
* k_init_timer - initialize a timer * k_init_timer - initialize a timer
* @timer: pointer to timer structure * @timer: pointer to timer structure
......
/*
* net/tipc/handler.c: TIPC signal handling
*
* Copyright (c) 2000-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "core.h"
struct queue_item {
struct list_head next_signal;
void (*handler) (unsigned long);
unsigned long data;
};
static struct kmem_cache *tipc_queue_item_cache;
static struct list_head signal_queue_head;
static DEFINE_SPINLOCK(qitem_lock);
static int handler_enabled __read_mostly;
static void process_signal_queue(unsigned long dummy);
static DECLARE_TASKLET_DISABLED(tipc_tasklet, process_signal_queue, 0);
unsigned int tipc_k_signal(Handler routine, unsigned long argument)
{
struct queue_item *item;
spin_lock_bh(&qitem_lock);
if (!handler_enabled) {
spin_unlock_bh(&qitem_lock);
return -ENOPROTOOPT;
}
item = kmem_cache_alloc(tipc_queue_item_cache, GFP_ATOMIC);
if (!item) {
pr_err("Signal queue out of memory\n");
spin_unlock_bh(&qitem_lock);
return -ENOMEM;
}
item->handler = routine;
item->data = argument;
list_add_tail(&item->next_signal, &signal_queue_head);
spin_unlock_bh(&qitem_lock);
tasklet_schedule(&tipc_tasklet);
return 0;
}
static void process_signal_queue(unsigned long dummy)
{
struct queue_item *__volatile__ item;
struct list_head *l, *n;
spin_lock_bh(&qitem_lock);
list_for_each_safe(l, n, &signal_queue_head) {
item = list_entry(l, struct queue_item, next_signal);
list_del(&item->next_signal);
spin_unlock_bh(&qitem_lock);
item->handler(item->data);
spin_lock_bh(&qitem_lock);
kmem_cache_free(tipc_queue_item_cache, item);
}
spin_unlock_bh(&qitem_lock);
}
int tipc_handler_start(void)
{
tipc_queue_item_cache =
kmem_cache_create("tipc_queue_items", sizeof(struct queue_item),
0, SLAB_HWCACHE_ALIGN, NULL);
if (!tipc_queue_item_cache)
return -ENOMEM;
INIT_LIST_HEAD(&signal_queue_head);
tasklet_enable(&tipc_tasklet);
handler_enabled = 1;
return 0;
}
void tipc_handler_stop(void)
{
struct list_head *l, *n;
struct queue_item *item;
spin_lock_bh(&qitem_lock);
if (!handler_enabled) {
spin_unlock_bh(&qitem_lock);
return;
}
handler_enabled = 0;
spin_unlock_bh(&qitem_lock);
tasklet_kill(&tipc_tasklet);
spin_lock_bh(&qitem_lock);
list_for_each_safe(l, n, &signal_queue_head) {
item = list_entry(l, struct queue_item, next_signal);
list_del(&item->next_signal);
kmem_cache_free(tipc_queue_item_cache, item);
}
spin_unlock_bh(&qitem_lock);
kmem_cache_destroy(tipc_queue_item_cache);
}
...@@ -297,14 +297,14 @@ void tipc_link_delete_list(unsigned int bearer_id, bool shutting_down) ...@@ -297,14 +297,14 @@ void tipc_link_delete_list(unsigned int bearer_id, bool shutting_down)
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) { list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) {
spin_lock_bh(&n_ptr->lock); tipc_node_lock(n_ptr);
l_ptr = n_ptr->links[bearer_id]; l_ptr = n_ptr->links[bearer_id];
if (l_ptr) { if (l_ptr) {
tipc_link_reset(l_ptr); tipc_link_reset(l_ptr);
if (shutting_down || !tipc_node_is_up(n_ptr)) { if (shutting_down || !tipc_node_is_up(n_ptr)) {
tipc_node_detach_link(l_ptr->owner, l_ptr); tipc_node_detach_link(l_ptr->owner, l_ptr);
tipc_link_reset_fragments(l_ptr); tipc_link_reset_fragments(l_ptr);
spin_unlock_bh(&n_ptr->lock); tipc_node_unlock(n_ptr);
/* Nobody else can access this link now: */ /* Nobody else can access this link now: */
del_timer_sync(&l_ptr->timer); del_timer_sync(&l_ptr->timer);
...@@ -312,12 +312,12 @@ void tipc_link_delete_list(unsigned int bearer_id, bool shutting_down) ...@@ -312,12 +312,12 @@ void tipc_link_delete_list(unsigned int bearer_id, bool shutting_down)
} else { } else {
/* Detach/delete when failover is finished: */ /* Detach/delete when failover is finished: */
l_ptr->flags |= LINK_STOPPED; l_ptr->flags |= LINK_STOPPED;
spin_unlock_bh(&n_ptr->lock); tipc_node_unlock(n_ptr);
del_timer_sync(&l_ptr->timer); del_timer_sync(&l_ptr->timer);
} }
continue; continue;
} }
spin_unlock_bh(&n_ptr->lock); tipc_node_unlock(n_ptr);
} }
rcu_read_unlock(); rcu_read_unlock();
} }
...@@ -474,11 +474,11 @@ void tipc_link_reset_list(unsigned int bearer_id) ...@@ -474,11 +474,11 @@ void tipc_link_reset_list(unsigned int bearer_id)
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) { list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) {
spin_lock_bh(&n_ptr->lock); tipc_node_lock(n_ptr);
l_ptr = n_ptr->links[bearer_id]; l_ptr = n_ptr->links[bearer_id];
if (l_ptr) if (l_ptr)
tipc_link_reset(l_ptr); tipc_link_reset(l_ptr);
spin_unlock_bh(&n_ptr->lock); tipc_node_unlock(n_ptr);
} }
rcu_read_unlock(); rcu_read_unlock();
} }
...@@ -1259,29 +1259,24 @@ void tipc_link_push_queue(struct tipc_link *l_ptr) ...@@ -1259,29 +1259,24 @@ void tipc_link_push_queue(struct tipc_link *l_ptr)
} while (!res); } while (!res);
} }
static void link_reset_all(unsigned long addr) void tipc_link_reset_all(struct tipc_node *node)
{ {
struct tipc_node *n_ptr;
char addr_string[16]; char addr_string[16];
u32 i; u32 i;
n_ptr = tipc_node_find((u32)addr); tipc_node_lock(node);
if (!n_ptr)
return; /* node no longer exists */
tipc_node_lock(n_ptr);
pr_warn("Resetting all links to %s\n", pr_warn("Resetting all links to %s\n",
tipc_addr_string_fill(addr_string, n_ptr->addr)); tipc_addr_string_fill(addr_string, node->addr));
for (i = 0; i < MAX_BEARERS; i++) { for (i = 0; i < MAX_BEARERS; i++) {
if (n_ptr->links[i]) { if (node->links[i]) {
link_print(n_ptr->links[i], "Resetting link\n"); link_print(node->links[i], "Resetting link\n");
tipc_link_reset(n_ptr->links[i]); tipc_link_reset(node->links[i]);
} }
} }
tipc_node_unlock(n_ptr); tipc_node_unlock(node);
} }
static void link_retransmit_failure(struct tipc_link *l_ptr, static void link_retransmit_failure(struct tipc_link *l_ptr,
...@@ -1318,10 +1313,9 @@ static void link_retransmit_failure(struct tipc_link *l_ptr, ...@@ -1318,10 +1313,9 @@ static void link_retransmit_failure(struct tipc_link *l_ptr,
n_ptr->bclink.oos_state, n_ptr->bclink.oos_state,
n_ptr->bclink.last_sent); n_ptr->bclink.last_sent);
tipc_k_signal((Handler)link_reset_all, (unsigned long)n_ptr->addr);
tipc_node_unlock(n_ptr); tipc_node_unlock(n_ptr);
tipc_bclink_set_flags(TIPC_BCLINK_RESET);
l_ptr->stale_count = 0; l_ptr->stale_count = 0;
} }
} }
...@@ -1495,14 +1489,14 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr) ...@@ -1495,14 +1489,14 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr)
goto unlock_discard; goto unlock_discard;
/* Verify that communication with node is currently allowed */ /* Verify that communication with node is currently allowed */
if ((n_ptr->block_setup & WAIT_PEER_DOWN) && if ((n_ptr->flags & TIPC_NODE_DOWN) &&
msg_user(msg) == LINK_PROTOCOL && msg_user(msg) == LINK_PROTOCOL &&
(msg_type(msg) == RESET_MSG || (msg_type(msg) == RESET_MSG ||
msg_type(msg) == ACTIVATE_MSG) && msg_type(msg) == ACTIVATE_MSG) &&
!msg_redundant_link(msg)) !msg_redundant_link(msg))
n_ptr->block_setup &= ~WAIT_PEER_DOWN; n_ptr->flags &= ~TIPC_NODE_DOWN;
if (n_ptr->block_setup) if (tipc_node_blocked(n_ptr))
goto unlock_discard; goto unlock_discard;
/* Validate message sequence number info */ /* Validate message sequence number info */
...@@ -1744,7 +1738,7 @@ void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int probe_msg, ...@@ -1744,7 +1738,7 @@ void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int probe_msg,
return; return;
/* Abort non-RESET send if communication with node is prohibited */ /* Abort non-RESET send if communication with node is prohibited */
if ((l_ptr->owner->block_setup) && (msg_typ != RESET_MSG)) if ((tipc_node_blocked(l_ptr->owner)) && (msg_typ != RESET_MSG))
return; return;
/* Create protocol message with "out-of-sequence" sequence number */ /* Create protocol message with "out-of-sequence" sequence number */
...@@ -1859,7 +1853,7 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, struct sk_buff *buf) ...@@ -1859,7 +1853,7 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, struct sk_buff *buf)
* peer has lost contact -- don't allow peer's links * peer has lost contact -- don't allow peer's links
* to reactivate before we recognize loss & clean up * to reactivate before we recognize loss & clean up
*/ */
l_ptr->owner->block_setup = WAIT_NODE_DOWN; l_ptr->owner->flags = TIPC_NODE_RESET;
} }
link_state_event(l_ptr, RESET_MSG); link_state_event(l_ptr, RESET_MSG);
......
...@@ -230,6 +230,7 @@ struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area, ...@@ -230,6 +230,7 @@ struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area,
int req_tlv_space); int req_tlv_space);
struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area,
int req_tlv_space); int req_tlv_space);
void tipc_link_reset_all(struct tipc_node *node);
void tipc_link_reset(struct tipc_link *l_ptr); void tipc_link_reset(struct tipc_link *l_ptr);
void tipc_link_reset_list(unsigned int bearer_id); void tipc_link_reset_list(unsigned int bearer_id);
int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector); int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector);
......
...@@ -38,34 +38,6 @@ ...@@ -38,34 +38,6 @@
#include "link.h" #include "link.h"
#include "name_distr.h" #include "name_distr.h"
#define ITEM_SIZE sizeof(struct distr_item)
/**
* struct distr_item - publication info distributed to other nodes
* @type: name sequence type
* @lower: name sequence lower bound
* @upper: name sequence upper bound
* @ref: publishing port reference
* @key: publication key
*
* ===> All fields are stored in network byte order. <===
*
* First 3 fields identify (name or) name sequence being published.
* Reference field uniquely identifies port that published name sequence.
* Key field uniquely identifies publication, in the event a port has
* multiple publications of the same name sequence.
*
* Note: There is no field that identifies the publishing node because it is
* the same for all items contained within a publication message.
*/
struct distr_item {
__be32 type;
__be32 lower;
__be32 upper;
__be32 ref;
__be32 key;
};
/** /**
* struct publ_list - list of publications made by this node * struct publ_list - list of publications made by this node
* @list: circular list of publications * @list: circular list of publications
...@@ -135,18 +107,18 @@ void named_cluster_distribute(struct sk_buff *buf) ...@@ -135,18 +107,18 @@ void named_cluster_distribute(struct sk_buff *buf)
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) { list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) {
spin_lock_bh(&n_ptr->lock); tipc_node_lock(n_ptr);
l_ptr = n_ptr->active_links[n_ptr->addr & 1]; l_ptr = n_ptr->active_links[n_ptr->addr & 1];
if (l_ptr) { if (l_ptr) {
buf_copy = skb_copy(buf, GFP_ATOMIC); buf_copy = skb_copy(buf, GFP_ATOMIC);
if (!buf_copy) { if (!buf_copy) {
spin_unlock_bh(&n_ptr->lock); tipc_node_unlock(n_ptr);
break; break;
} }
msg_set_destnode(buf_msg(buf_copy), n_ptr->addr); msg_set_destnode(buf_msg(buf_copy), n_ptr->addr);
__tipc_link_xmit(l_ptr, buf_copy); __tipc_link_xmit(l_ptr, buf_copy);
} }
spin_unlock_bh(&n_ptr->lock); tipc_node_unlock(n_ptr);
} }
rcu_read_unlock(); rcu_read_unlock();
...@@ -239,29 +211,9 @@ static void named_distribute(struct list_head *message_list, u32 node, ...@@ -239,29 +211,9 @@ static void named_distribute(struct list_head *message_list, u32 node,
/** /**
* tipc_named_node_up - tell specified node about all publications by this node * tipc_named_node_up - tell specified node about all publications by this node
*/ */
void tipc_named_node_up(unsigned long nodearg) void tipc_named_node_up(u32 max_item_buf, u32 node)
{ {
struct tipc_node *n_ptr; LIST_HEAD(message_list);
struct tipc_link *l_ptr;
struct list_head message_list;
u32 node = (u32)nodearg;
u32 max_item_buf = 0;
/* compute maximum amount of publication data to send per message */
n_ptr = tipc_node_find(node);
if (n_ptr) {
tipc_node_lock(n_ptr);
l_ptr = n_ptr->active_links[0];
if (l_ptr)
max_item_buf = ((l_ptr->max_pkt - INT_H_SIZE) /
ITEM_SIZE) * ITEM_SIZE;
tipc_node_unlock(n_ptr);
}
if (!max_item_buf)
return;
/* create list of publication messages, then send them as a unit */
INIT_LIST_HEAD(&message_list);
read_lock_bh(&tipc_nametbl_lock); read_lock_bh(&tipc_nametbl_lock);
named_distribute(&message_list, node, &publ_cluster, max_item_buf); named_distribute(&message_list, node, &publ_cluster, max_item_buf);
......
...@@ -39,10 +39,38 @@ ...@@ -39,10 +39,38 @@
#include "name_table.h" #include "name_table.h"
#define ITEM_SIZE sizeof(struct distr_item)
/**
* struct distr_item - publication info distributed to other nodes
* @type: name sequence type
* @lower: name sequence lower bound
* @upper: name sequence upper bound
* @ref: publishing port reference
* @key: publication key
*
* ===> All fields are stored in network byte order. <===
*
* First 3 fields identify (name or) name sequence being published.
* Reference field uniquely identifies port that published name sequence.
* Key field uniquely identifies publication, in the event a port has
* multiple publications of the same name sequence.
*
* Note: There is no field that identifies the publishing node because it is
* the same for all items contained within a publication message.
*/
struct distr_item {
__be32 type;
__be32 lower;
__be32 upper;
__be32 ref;
__be32 key;
};
struct sk_buff *tipc_named_publish(struct publication *publ); struct sk_buff *tipc_named_publish(struct publication *publ);
struct sk_buff *tipc_named_withdraw(struct publication *publ); struct sk_buff *tipc_named_withdraw(struct publication *publ);
void named_cluster_distribute(struct sk_buff *buf); void named_cluster_distribute(struct sk_buff *buf);
void tipc_named_node_up(unsigned long node); void tipc_named_node_up(u32 max_item_buf, u32 node);
void tipc_named_rcv(struct sk_buff *buf); void tipc_named_rcv(struct sk_buff *buf);
void tipc_named_reinit(void); void tipc_named_reinit(void);
......
...@@ -164,20 +164,25 @@ void tipc_net_route_msg(struct sk_buff *buf) ...@@ -164,20 +164,25 @@ void tipc_net_route_msg(struct sk_buff *buf)
tipc_link_xmit(buf, dnode, msg_link_selector(msg)); tipc_link_xmit(buf, dnode, msg_link_selector(msg));
} }
void tipc_net_start(u32 addr) int tipc_net_start(u32 addr)
{ {
char addr_string[16]; char addr_string[16];
int res;
tipc_own_addr = addr; tipc_own_addr = addr;
tipc_named_reinit(); tipc_named_reinit();
tipc_port_reinit(); tipc_port_reinit();
tipc_bclink_init(); res = tipc_bclink_init();
if (res)
return res;
tipc_nametbl_publish(TIPC_CFG_SRV, tipc_own_addr, tipc_own_addr, tipc_nametbl_publish(TIPC_CFG_SRV, tipc_own_addr, tipc_own_addr,
TIPC_ZONE_SCOPE, 0, tipc_own_addr); TIPC_ZONE_SCOPE, 0, tipc_own_addr);
pr_info("Started in network mode\n"); pr_info("Started in network mode\n");
pr_info("Own node address %s, network identity %u\n", pr_info("Own node address %s, network identity %u\n",
tipc_addr_string_fill(addr_string, tipc_own_addr), tipc_net_id); tipc_addr_string_fill(addr_string, tipc_own_addr), tipc_net_id);
return 0;
} }
void tipc_net_stop(void) void tipc_net_stop(void)
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
void tipc_net_route_msg(struct sk_buff *buf); void tipc_net_route_msg(struct sk_buff *buf);
void tipc_net_start(u32 addr); int tipc_net_start(u32 addr);
void tipc_net_stop(void); void tipc_net_stop(void);
#endif #endif
...@@ -108,7 +108,7 @@ struct tipc_node *tipc_node_create(u32 addr) ...@@ -108,7 +108,7 @@ struct tipc_node *tipc_node_create(u32 addr)
break; break;
} }
list_add_tail_rcu(&n_ptr->list, &temp_node->list); list_add_tail_rcu(&n_ptr->list, &temp_node->list);
n_ptr->block_setup = WAIT_PEER_DOWN; n_ptr->flags = TIPC_NODE_DOWN;
n_ptr->signature = INVALID_NODE_SIG; n_ptr->signature = INVALID_NODE_SIG;
tipc_num_nodes++; tipc_num_nodes++;
...@@ -267,24 +267,12 @@ void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr) ...@@ -267,24 +267,12 @@ void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
static void node_established_contact(struct tipc_node *n_ptr) static void node_established_contact(struct tipc_node *n_ptr)
{ {
tipc_k_signal((Handler)tipc_named_node_up, n_ptr->addr); n_ptr->flags |= TIPC_NODE_UP;
n_ptr->bclink.oos_state = 0; n_ptr->bclink.oos_state = 0;
n_ptr->bclink.acked = tipc_bclink_get_last_sent(); n_ptr->bclink.acked = tipc_bclink_get_last_sent();
tipc_bclink_add_node(n_ptr->addr); tipc_bclink_add_node(n_ptr->addr);
} }
static void node_name_purge_complete(unsigned long node_addr)
{
struct tipc_node *n_ptr;
n_ptr = tipc_node_find(node_addr);
if (n_ptr) {
tipc_node_lock(n_ptr);
n_ptr->block_setup &= ~WAIT_NAMES_GONE;
tipc_node_unlock(n_ptr);
}
}
static void node_lost_contact(struct tipc_node *n_ptr) static void node_lost_contact(struct tipc_node *n_ptr)
{ {
char addr_string[16]; char addr_string[16];
...@@ -320,12 +308,10 @@ static void node_lost_contact(struct tipc_node *n_ptr) ...@@ -320,12 +308,10 @@ static void node_lost_contact(struct tipc_node *n_ptr)
tipc_link_reset_fragments(l_ptr); tipc_link_reset_fragments(l_ptr);
} }
/* Notify subscribers */ /* Notify subscribers and prevent re-contact with node until
tipc_nodesub_notify(n_ptr); * cleanup is done.
*/
/* Prevent re-contact with node until cleanup is done */ n_ptr->flags = TIPC_NODE_DOWN | TIPC_NODE_LOST;
n_ptr->block_setup = WAIT_PEER_DOWN | WAIT_NAMES_GONE;
tipc_k_signal((Handler)node_name_purge_complete, n_ptr->addr);
} }
struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space) struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
...@@ -465,3 +451,36 @@ int tipc_node_get_linkname(u32 bearer_id, u32 addr, char *linkname, size_t len) ...@@ -465,3 +451,36 @@ int tipc_node_get_linkname(u32 bearer_id, u32 addr, char *linkname, size_t len)
tipc_node_unlock(node); tipc_node_unlock(node);
return -EINVAL; return -EINVAL;
} }
void tipc_node_unlock(struct tipc_node *node)
{
LIST_HEAD(nsub_list);
struct tipc_link *link;
int pkt_sz = 0;
u32 addr = 0;
if (likely(!node->flags)) {
spin_unlock_bh(&node->lock);
return;
}
if (node->flags & TIPC_NODE_LOST) {
list_replace_init(&node->nsub, &nsub_list);
node->flags &= ~TIPC_NODE_LOST;
}
if (node->flags & TIPC_NODE_UP) {
link = node->active_links[0];
node->flags &= ~TIPC_NODE_UP;
if (link) {
pkt_sz = ((link->max_pkt - INT_H_SIZE) / ITEM_SIZE) *
ITEM_SIZE;
addr = node->addr;
}
}
spin_unlock_bh(&node->lock);
if (!list_empty(&nsub_list))
tipc_nodesub_notify(&nsub_list);
if (pkt_sz)
tipc_named_node_up(pkt_sz, addr);
}
...@@ -47,62 +47,78 @@ ...@@ -47,62 +47,78 @@
*/ */
#define INVALID_NODE_SIG 0x10000 #define INVALID_NODE_SIG 0x10000
/* Flags used to block (re)establishment of contact with a neighboring node */ /* Flags used to block (re)establishment of contact with a neighboring node
#define WAIT_PEER_DOWN 0x0001 /* wait to see that peer's links are down */ * TIPC_NODE_DOWN: indicate node is down and it's used to block the node's
#define WAIT_NAMES_GONE 0x0002 /* wait for peer's publications to be purged */ * links until RESET or ACTIVE message arrives
#define WAIT_NODE_DOWN 0x0004 /* wait until peer node is declared down */ * TIPC_NODE_RESET: indicate node is reset
* TIPC_NODE_LOST: indicate node is lost and it's used to notify subscriptions
* when node lock is released
* TIPC_NODE_UP: indicate node is up and it's used to deliver local name table
* when node lock is released
*/
enum {
TIPC_NODE_DOWN = (1 << 1),
TIPC_NODE_RESET = (1 << 2),
TIPC_NODE_LOST = (1 << 3),
TIPC_NODE_UP = (1 << 4)
};
/**
* struct tipc_node_bclink - TIPC node bclink structure
* @acked: sequence # of last outbound b'cast message acknowledged by node
* @last_in: sequence # of last in-sequence b'cast message received from node
* @last_sent: sequence # of last b'cast message sent by node
* @oos_state: state tracker for handling OOS b'cast messages
* @deferred_size: number of OOS b'cast messages in deferred queue
* @deferred_head: oldest OOS b'cast message received from node
* @deferred_tail: newest OOS b'cast message received from node
* @reasm_head: broadcast reassembly queue head from node
* @reasm_tail: last broadcast fragment received from node
* @recv_permitted: true if node is allowed to receive b'cast messages
*/
struct tipc_node_bclink {
u32 acked;
u32 last_in;
u32 last_sent;
u32 oos_state;
u32 deferred_size;
struct sk_buff *deferred_head;
struct sk_buff *deferred_tail;
struct sk_buff *reasm_head;
struct sk_buff *reasm_tail;
bool recv_permitted;
};
/** /**
* struct tipc_node - TIPC node structure * struct tipc_node - TIPC node structure
* @addr: network address of node * @addr: network address of node
* @lock: spinlock governing access to structure * @lock: spinlock governing access to structure
* @hash: links to adjacent nodes in unsorted hash chain * @hash: links to adjacent nodes in unsorted hash chain
* @list: links to adjacent nodes in sorted list of cluster's nodes
* @nsub: list of "node down" subscriptions monitoring node
* @active_links: pointers to active links to node * @active_links: pointers to active links to node
* @links: pointers to all links to node * @links: pointers to all links to node
* @flags: bit mask of conditions preventing link establishment to node
* @bclink: broadcast-related info
* @list: links to adjacent nodes in sorted list of cluster's nodes
* @working_links: number of working links to node (both active and standby) * @working_links: number of working links to node (both active and standby)
* @block_setup: bit mask of conditions preventing link establishment to node
* @link_cnt: number of links to node * @link_cnt: number of links to node
* @signature: node instance identifier * @signature: node instance identifier
* @bclink: broadcast-related info * @nsub: list of "node down" subscriptions monitoring node
* @rcu: rcu struct for tipc_node * @rcu: rcu struct for tipc_node
* @acked: sequence # of last outbound b'cast message acknowledged by node
* @last_in: sequence # of last in-sequence b'cast message received from node
* @last_sent: sequence # of last b'cast message sent by node
* @oos_state: state tracker for handling OOS b'cast messages
* @deferred_size: number of OOS b'cast messages in deferred queue
* @deferred_head: oldest OOS b'cast message received from node
* @deferred_tail: newest OOS b'cast message received from node
* @reasm_head: broadcast reassembly queue head from node
* @reasm_tail: last broadcast fragment received from node
* @recv_permitted: true if node is allowed to receive b'cast messages
*/ */
struct tipc_node { struct tipc_node {
u32 addr; u32 addr;
spinlock_t lock; spinlock_t lock;
struct hlist_node hash; struct hlist_node hash;
struct list_head list;
struct list_head nsub;
struct tipc_link *active_links[2]; struct tipc_link *active_links[2];
struct tipc_link *links[MAX_BEARERS]; struct tipc_link *links[MAX_BEARERS];
unsigned int flags;
struct tipc_node_bclink bclink;
struct list_head list;
int link_cnt; int link_cnt;
int working_links; int working_links;
int block_setup;
u32 signature; u32 signature;
struct list_head nsub;
struct rcu_head rcu; struct rcu_head rcu;
struct {
u32 acked;
u32 last_in;
u32 last_sent;
u32 oos_state;
u32 deferred_size;
struct sk_buff *deferred_head;
struct sk_buff *deferred_tail;
struct sk_buff *reasm_head;
struct sk_buff *reasm_tail;
bool recv_permitted;
} bclink;
}; };
extern struct list_head tipc_node_list; extern struct list_head tipc_node_list;
...@@ -119,15 +135,17 @@ int tipc_node_is_up(struct tipc_node *n_ptr); ...@@ -119,15 +135,17 @@ int tipc_node_is_up(struct tipc_node *n_ptr);
struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space); struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space);
struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space); struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space);
int tipc_node_get_linkname(u32 bearer_id, u32 node, char *linkname, size_t len); int tipc_node_get_linkname(u32 bearer_id, u32 node, char *linkname, size_t len);
void tipc_node_unlock(struct tipc_node *node);
static inline void tipc_node_lock(struct tipc_node *n_ptr) static inline void tipc_node_lock(struct tipc_node *node)
{ {
spin_lock_bh(&n_ptr->lock); spin_lock_bh(&node->lock);
} }
static inline void tipc_node_unlock(struct tipc_node *n_ptr) static inline bool tipc_node_blocked(struct tipc_node *node)
{ {
spin_unlock_bh(&n_ptr->lock); return (node->flags & (TIPC_NODE_DOWN | TIPC_NODE_LOST |
TIPC_NODE_RESET));
} }
#endif #endif
...@@ -81,14 +81,13 @@ void tipc_nodesub_unsubscribe(struct tipc_node_subscr *node_sub) ...@@ -81,14 +81,13 @@ void tipc_nodesub_unsubscribe(struct tipc_node_subscr *node_sub)
* *
* Note: node is locked by caller * Note: node is locked by caller
*/ */
void tipc_nodesub_notify(struct tipc_node *node) void tipc_nodesub_notify(struct list_head *nsub_list)
{ {
struct tipc_node_subscr *ns; struct tipc_node_subscr *ns, *safe;
list_for_each_entry(ns, &node->nsub, nodesub_list) { list_for_each_entry_safe(ns, safe, nsub_list, nodesub_list) {
if (ns->handle_node_down) { if (ns->handle_node_down) {
tipc_k_signal((Handler)ns->handle_node_down, ns->handle_node_down(ns->usr_handle);
(unsigned long)ns->usr_handle);
ns->handle_node_down = NULL; ns->handle_node_down = NULL;
} }
} }
......
...@@ -58,6 +58,6 @@ struct tipc_node_subscr { ...@@ -58,6 +58,6 @@ struct tipc_node_subscr {
void tipc_nodesub_subscribe(struct tipc_node_subscr *node_sub, u32 addr, void tipc_nodesub_subscribe(struct tipc_node_subscr *node_sub, u32 addr,
void *usr_handle, net_ev_handler handle_down); void *usr_handle, net_ev_handler handle_down);
void tipc_nodesub_unsubscribe(struct tipc_node_subscr *node_sub); void tipc_nodesub_unsubscribe(struct tipc_node_subscr *node_sub);
void tipc_nodesub_notify(struct tipc_node *node); void tipc_nodesub_notify(struct list_head *nsub_list);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment