Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b5b6bc32 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'tipc-next'



Ying Xue says:

====================
tipc: clean up bearer and node layer

This is another commit series which aims at facilitating future
changes to the locking policy around nodes, links and bearers.

Currently, the tipc routing hierarchy comprises the structures 'node',
'link' and 'bearer'. The whole hierarchy is protected by a big
read/write lock (tipc_net_lock), to ensure that nothing is added or
removed while any of these structures is being accessed. Obviously
the locking policy makes node, link and bearer components closely
bound together so that their relationship becomes extremely complex.
In the worst case, such locking policy not only has a negative
influence on performance, but also it's prone to lead to deadlock
occasionally.

In order to decouple the complex relationship between bearer and node
as well as link, the locking policy is adjusted as follows:

- Bearer level
  RTNL lock is used on update side, and RCU is used on read side.
  Meanwhile, all bearer instances including broadcast bearer are
  saved into bearer_list array.

- Node and link level
  All node instances are saved into two tipc_node_list and node_htable
  lists. The two lists are protected by node_list_lock on write side,
  and they are guarded with RCU lock on read side. All members in node
  structure including link instances are protected by node spin lock.

- The relationship between bearer and node
  When link accesses bearer, it first needs to find the bearer with
  its bearer identity from the bearer_list array. When bearer accesses
  node, it can iterate the node_htable hash list with the node address
  to find the corresponding node.

In the new locking policy, every component has its private locking
solution and the relationship between bearer and node is very simple,
that is, they can find each other with node address or bearer identity
from node_htable hash list or bearer_list array.

But, prior to these changes, we need to do some necessary cleanup and
code consolidation. This is what we do with this commit series. In a
later series we will replace net_lock with RTNL as well as RCU lock
to deploy the new locking policy.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1dbe1369 dde20266
Loading
Loading
Loading
Loading
+7 −6
Original line number Diff line number Diff line
@@ -42,8 +42,8 @@
#include "name_distr.h"

#define	MAX_PKT_DEFAULT_MCAST	1500	/* bcast link max packet size (fixed) */

#define	BCLINK_WIN_DEFAULT	20	/* bcast link window size (default) */
#define	BCBEARER		MAX_BEARERS

/**
 * struct tipc_bcbearer_pair - a pair of bearers used by broadcast link
@@ -668,9 +668,8 @@ void tipc_bcbearer_sort(void)
	memset(bp_temp, 0, sizeof(bcbearer->bpairs_temp));

	for (b_index = 0; b_index < MAX_BEARERS; b_index++) {
		struct tipc_bearer *b = &tipc_bearers[b_index];

		if (!b->active || !b->nodes.count)
		struct tipc_bearer *b = bearer_list[b_index];
		if (!b || !b->nodes.count)
			continue;

		if (!bp_temp[b->priority].primary)
@@ -785,6 +784,7 @@ void tipc_bclink_init(void)
	bcl->max_pkt = MAX_PKT_DEFAULT_MCAST;
	tipc_link_set_queue_limits(bcl, BCLINK_WIN_DEFAULT);
	bcl->b_ptr = &bcbearer->bearer;
	bearer_list[BCBEARER] = &bcbearer->bearer;
	bcl->state = WORKING_WORKING;
	strlcpy(bcl->name, tipc_bclink_name, TIPC_MAX_LINK_NAME);
}
@@ -795,6 +795,7 @@ void tipc_bclink_stop(void)
	tipc_link_purge_queues(bcl);
	spin_unlock_bh(&bc_lock);

	bearer_list[BCBEARER] = NULL;
	memset(bclink, 0, sizeof(*bclink));
	memset(bcbearer, 0, sizeof(*bcbearer));
}
+36 −13
Original line number Diff line number Diff line
@@ -49,7 +49,7 @@ static struct tipc_media * const media_info_array[] = {
	NULL
};

struct tipc_bearer tipc_bearers[MAX_BEARERS];
struct tipc_bearer *bearer_list[MAX_BEARERS + 1];

static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down);

@@ -177,8 +177,9 @@ struct tipc_bearer *tipc_bearer_find(const char *name)
	struct tipc_bearer *b_ptr;
	u32 i;

	for (i = 0, b_ptr = tipc_bearers; i < MAX_BEARERS; i++, b_ptr++) {
		if (b_ptr->active && (!strcmp(b_ptr->name, name)))
	for (i = 0; i < MAX_BEARERS; i++) {
		b_ptr = bearer_list[i];
		if (b_ptr && (!strcmp(b_ptr->name, name)))
			return b_ptr;
	}
	return NULL;
@@ -200,8 +201,10 @@ struct sk_buff *tipc_bearer_get_names(void)
	read_lock_bh(&tipc_net_lock);
	for (i = 0; media_info_array[i] != NULL; i++) {
		for (j = 0; j < MAX_BEARERS; j++) {
			b = &tipc_bearers[j];
			if (b->active && (b->media == media_info_array[i])) {
			b = bearer_list[j];
			if (!b)
				continue;
			if (b->media == media_info_array[i]) {
				tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME,
						    b->name,
						    strlen(b->name) + 1);
@@ -284,16 +287,17 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority)
	bearer_id = MAX_BEARERS;
	with_this_prio = 1;
	for (i = MAX_BEARERS; i-- != 0; ) {
		if (!tipc_bearers[i].active) {
		b_ptr = bearer_list[i];
		if (!b_ptr) {
			bearer_id = i;
			continue;
		}
		if (!strcmp(name, tipc_bearers[i].name)) {
		if (!strcmp(name, b_ptr->name)) {
			pr_warn("Bearer <%s> rejected, already enabled\n",
				name);
			goto exit;
		}
		if ((tipc_bearers[i].priority == priority) &&
		if ((b_ptr->priority == priority) &&
		    (++with_this_prio > 2)) {
			if (priority-- == 0) {
				pr_warn("Bearer <%s> rejected, duplicate priority\n",
@@ -311,7 +315,11 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority)
		goto exit;
	}

	b_ptr = &tipc_bearers[bearer_id];
	b_ptr = kzalloc(sizeof(*b_ptr), GFP_ATOMIC);
	if (!b_ptr) {
		res = -ENOMEM;
		goto exit;
	}
	strcpy(b_ptr->name, name);
	b_ptr->media = m_ptr;
	res = m_ptr->enable_media(b_ptr);
@@ -325,7 +333,6 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority)
	b_ptr->tolerance = m_ptr->tolerance;
	b_ptr->window = m_ptr->window;
	b_ptr->net_plane = bearer_id + 'A';
	b_ptr->active = 1;
	b_ptr->priority = priority;

	res = tipc_disc_create(b_ptr, &b_ptr->bcast_addr, disc_domain);
@@ -335,6 +342,9 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority)
			name);
		goto exit;
	}

	bearer_list[bearer_id] = b_ptr;

	pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
		name,
		tipc_addr_string_fill(addr_string, disc_domain), priority);
@@ -362,13 +372,22 @@ static int tipc_reset_bearer(struct tipc_bearer *b_ptr)
 */
static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down)
{
	u32 i;

	pr_info("Disabling bearer <%s>\n", b_ptr->name);
	b_ptr->media->disable_media(b_ptr);

	tipc_link_delete_list(b_ptr->identity, shutting_down);
	if (b_ptr->link_req)
		tipc_disc_delete(b_ptr->link_req);
	memset(b_ptr, 0, sizeof(struct tipc_bearer));

	for (i = 0; i < MAX_BEARERS; i++) {
		if (b_ptr == bearer_list[i]) {
			bearer_list[i] = NULL;
			break;
		}
	}
	kfree(b_ptr);
}

int tipc_disable_bearer(const char *name)
@@ -603,10 +622,14 @@ void tipc_bearer_cleanup(void)

void tipc_bearer_stop(void)
{
	struct tipc_bearer *b_ptr;
	u32 i;

	for (i = 0; i < MAX_BEARERS; i++) {
		if (tipc_bearers[i].active)
			bearer_disable(&tipc_bearers[i], true);
		b_ptr = bearer_list[i];
		if (b_ptr) {
			bearer_disable(b_ptr, true);
			bearer_list[i] = NULL;
		}
	}
}
+1 −3
Original line number Diff line number Diff line
@@ -118,7 +118,6 @@ struct tipc_media {
 * @tolerance: default link tolerance for bearer
 * @identity: array index of this bearer within TIPC bearer array
 * @link_req: ptr to (optional) structure making periodic link setup requests
 * @active: non-zero if bearer structure is represents a bearer
 * @net_plane: network plane ('A' through 'H') currently associated with bearer
 * @nodes: indicates which nodes in cluster can be reached through bearer
 *
@@ -138,7 +137,6 @@ struct tipc_bearer {
	u32 tolerance;
	u32 identity;
	struct tipc_link_req *link_req;
	int active;
	char net_plane;
	struct tipc_node_map nodes;
};
@@ -150,7 +148,7 @@ struct tipc_bearer_names {

struct tipc_link;

extern struct tipc_bearer tipc_bearers[];
extern struct tipc_bearer *bearer_list[];

/*
 * TIPC routines available to supported media types
+3 −104
Original line number Diff line number Diff line
@@ -43,13 +43,11 @@
#define REPLY_TRUNCATED "<truncated>\n"

static DEFINE_MUTEX(config_mutex);
static struct tipc_server cfgsrv;

static const void *req_tlv_area;	/* request message TLV area */
static int req_tlv_space;		/* request message TLV area size */
static int rep_headroom;		/* reply message headroom to use */


struct sk_buff *tipc_cfg_reply_alloc(int payload_size)
{
	struct sk_buff *buf;
@@ -185,18 +183,6 @@ static struct sk_buff *cfg_set_own_addr(void)
	return tipc_cfg_reply_none();
}

static struct sk_buff *cfg_set_remote_mng(void)
{
	u32 value;

	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);

	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
	tipc_remote_management = (value != 0);
	return tipc_cfg_reply_none();
}

static struct sk_buff *cfg_set_max_ports(void)
{
	u32 value;
@@ -247,21 +233,10 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
	/* Check command authorization */
	if (likely(in_own_node(orig_node))) {
		/* command is permitted */
	} else if (cmd >= 0x8000) {
	} else {
		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
							  " (cannot be done remotely)");
		goto exit;
	} else if (!tipc_remote_management) {
		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NO_REMOTE);
		goto exit;
	} else if (cmd >= 0x4000) {
		u32 domain = 0;

		if ((tipc_nametbl_translate(TIPC_ZM_SRV, 0, &domain) == 0) ||
		    (domain != orig_node)) {
			rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_ZONE_MSTR);
			goto exit;
		}
	}

	/* Call appropriate processing routine */
@@ -310,18 +285,12 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
	case TIPC_CMD_SET_NODE_ADDR:
		rep_tlv_buf = cfg_set_own_addr();
		break;
	case TIPC_CMD_SET_REMOTE_MNG:
		rep_tlv_buf = cfg_set_remote_mng();
		break;
	case TIPC_CMD_SET_MAX_PORTS:
		rep_tlv_buf = cfg_set_max_ports();
		break;
	case TIPC_CMD_SET_NETID:
		rep_tlv_buf = cfg_set_netid();
		break;
	case TIPC_CMD_GET_REMOTE_MNG:
		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_remote_management);
		break;
	case TIPC_CMD_GET_MAX_PORTS:
		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_ports);
		break;
@@ -345,6 +314,8 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
	case TIPC_CMD_SET_MAX_PUBL:
	case TIPC_CMD_GET_MAX_PUBL:
	case TIPC_CMD_SET_LOG_SIZE:
	case TIPC_CMD_SET_REMOTE_MNG:
	case TIPC_CMD_GET_REMOTE_MNG:
	case TIPC_CMD_DUMP_LOG:
		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
							  " (obsolete command)");
@@ -369,75 +340,3 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
	mutex_unlock(&config_mutex);
	return rep_tlv_buf;
}

static void cfg_conn_msg_event(int conid, struct sockaddr_tipc *addr,
			       void *usr_data, void *buf, size_t len)
{
	struct tipc_cfg_msg_hdr *req_hdr;
	struct tipc_cfg_msg_hdr *rep_hdr;
	struct sk_buff *rep_buf;

	/* Validate configuration message header (ignore invalid message) */
	req_hdr = (struct tipc_cfg_msg_hdr *)buf;
	if ((len < sizeof(*req_hdr)) ||
	    (len != TCM_ALIGN(ntohl(req_hdr->tcm_len))) ||
	    (ntohs(req_hdr->tcm_flags) != TCM_F_REQUEST)) {
		pr_warn("Invalid configuration message discarded\n");
		return;
	}

	/* Generate reply for request (if can't, return request) */
	rep_buf = tipc_cfg_do_cmd(addr->addr.id.node, ntohs(req_hdr->tcm_type),
				  buf + sizeof(*req_hdr),
				  len - sizeof(*req_hdr),
				  BUF_HEADROOM + MAX_H_SIZE + sizeof(*rep_hdr));
	if (rep_buf) {
		skb_push(rep_buf, sizeof(*rep_hdr));
		rep_hdr = (struct tipc_cfg_msg_hdr *)rep_buf->data;
		memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr));
		rep_hdr->tcm_len = htonl(rep_buf->len);
		rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST);
		tipc_conn_sendmsg(&cfgsrv, conid, addr, rep_buf->data,
				  rep_buf->len);
		kfree_skb(rep_buf);
	}
}

static struct sockaddr_tipc cfgsrv_addr __read_mostly = {
	.family			= AF_TIPC,
	.addrtype		= TIPC_ADDR_NAMESEQ,
	.addr.nameseq.type	= TIPC_CFG_SRV,
	.addr.nameseq.lower	= 0,
	.addr.nameseq.upper	= 0,
	.scope			= TIPC_ZONE_SCOPE
};

static struct tipc_server cfgsrv __read_mostly = {
	.saddr			= &cfgsrv_addr,
	.imp			= TIPC_CRITICAL_IMPORTANCE,
	.type			= SOCK_RDM,
	.max_rcvbuf_size	= 64 * 1024,
	.name			= "cfg_server",
	.tipc_conn_recvmsg	= cfg_conn_msg_event,
	.tipc_conn_new		= NULL,
	.tipc_conn_shutdown	= NULL
};

int tipc_cfg_init(void)
{
	return tipc_server_start(&cfgsrv);
}

void tipc_cfg_reinit(void)
{
	tipc_server_stop(&cfgsrv);

	cfgsrv_addr.addr.nameseq.lower = tipc_own_addr;
	cfgsrv_addr.addr.nameseq.upper = tipc_own_addr;
	tipc_server_start(&cfgsrv);
}

void tipc_cfg_stop(void)
{
	tipc_server_stop(&cfgsrv);
}
+0 −5
Original line number Diff line number Diff line
@@ -64,9 +64,4 @@ static inline struct sk_buff *tipc_cfg_reply_ultra_string(char *string)
struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd,
				const void *req_tlv_area, int req_tlv_space,
				int headroom);

int  tipc_cfg_init(void);
void tipc_cfg_reinit(void);
void tipc_cfg_stop(void);

#endif
Loading