diff options
Diffstat (limited to 'net/tipc/node.c')
| -rw-r--r-- | net/tipc/node.c | 63 | 
1 files changed, 37 insertions, 26 deletions
| diff --git a/net/tipc/node.c b/net/tipc/node.c index 9d2f4c2b08ab..4512e83652b1 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -263,6 +263,11 @@ static void tipc_node_write_lock(struct tipc_node *n)  	write_lock_bh(&n->lock);  } +static void tipc_node_write_unlock_fast(struct tipc_node *n) +{ +	write_unlock_bh(&n->lock); +} +  static void tipc_node_write_unlock(struct tipc_node *n)  {  	struct net *net = n->net; @@ -417,7 +422,7 @@ void tipc_node_subscribe(struct net *net, struct list_head *subscr, u32 addr)  	}  	tipc_node_write_lock(n);  	list_add_tail(subscr, &n->publ_list); -	tipc_node_write_unlock(n); +	tipc_node_write_unlock_fast(n);  	tipc_node_put(n);  } @@ -435,7 +440,7 @@ void tipc_node_unsubscribe(struct net *net, struct list_head *subscr, u32 addr)  	}  	tipc_node_write_lock(n);  	list_del_init(subscr); -	tipc_node_write_unlock(n); +	tipc_node_write_unlock_fast(n);  	tipc_node_put(n);  } @@ -1167,7 +1172,7 @@ msg_full:   * @list: chain of buffers containing message   * @dnode: address of destination node   * @selector: a number used for deterministic link selection - * Consumes the buffer chain, except when returning -ELINKCONG + * Consumes the buffer chain.   * Returns 0 if success, otherwise: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE,-ENOBUF   */  int tipc_node_xmit(struct net *net, struct sk_buff_head *list, @@ -1206,10 +1211,10 @@ int tipc_node_xmit(struct net *net, struct sk_buff_head *list,  	spin_unlock_bh(&le->lock);  	tipc_node_read_unlock(n); -	if (likely(rc == 0)) -		tipc_bearer_xmit(net, bearer_id, &xmitq, &le->maddr); -	else if (rc == -ENOBUFS) +	if (unlikely(rc == -ENOBUFS))  		tipc_node_link_down(n, bearer_id, false); +	else +		tipc_bearer_xmit(net, bearer_id, &xmitq, &le->maddr);  	tipc_node_put(n); @@ -1221,20 +1226,15 @@ int tipc_node_xmit(struct net *net, struct sk_buff_head *list,   * messages, which will not be rejected   * The only exception is datagram messages rerouted after secondary   * lookup, which are rare and safe to dispose of anyway. - * TODO: Return real return value, and let callers use - * tipc_wait_for_sendpkt() where applicable   */  int tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dnode,  		       u32 selector)  {  	struct sk_buff_head head; -	int rc;  	skb_queue_head_init(&head);  	__skb_queue_tail(&head, skb); -	rc = tipc_node_xmit(net, &head, dnode, selector); -	if (rc == -ELINKCONG) -		kfree_skb(skb); +	tipc_node_xmit(net, &head, dnode, selector);  	return 0;  } @@ -1262,6 +1262,19 @@ void tipc_node_broadcast(struct net *net, struct sk_buff *skb)  	kfree_skb(skb);  } +static void tipc_node_mcast_rcv(struct tipc_node *n) +{ +	struct tipc_bclink_entry *be = &n->bc_entry; + +	/* 'arrvq' is under inputq2's lock protection */ +	spin_lock_bh(&be->inputq2.lock); +	spin_lock_bh(&be->inputq1.lock); +	skb_queue_splice_tail_init(&be->inputq1, &be->arrvq); +	spin_unlock_bh(&be->inputq1.lock); +	spin_unlock_bh(&be->inputq2.lock); +	tipc_sk_mcast_rcv(n->net, &be->arrvq, &be->inputq2); +} +  static void tipc_node_bc_sync_rcv(struct tipc_node *n, struct tipc_msg *hdr,  				  int bearer_id, struct sk_buff_head *xmitq)  { @@ -1335,15 +1348,8 @@ static void tipc_node_bc_rcv(struct net *net, struct sk_buff *skb, int bearer_id  	if (!skb_queue_empty(&xmitq))  		tipc_bearer_xmit(net, bearer_id, &xmitq, &le->maddr); -	/* Deliver. 'arrvq' is under inputq2's lock protection */ -	if (!skb_queue_empty(&be->inputq1)) { -		spin_lock_bh(&be->inputq2.lock); -		spin_lock_bh(&be->inputq1.lock); -		skb_queue_splice_tail_init(&be->inputq1, &be->arrvq); -		spin_unlock_bh(&be->inputq1.lock); -		spin_unlock_bh(&be->inputq2.lock); -		tipc_sk_mcast_rcv(net, &be->arrvq, &be->inputq2); -	} +	if (!skb_queue_empty(&be->inputq1)) +		tipc_node_mcast_rcv(n);  	if (rc & TIPC_LINK_DOWN_EVT) {  		/* Reception reassembly failure => reset all links to peer */ @@ -1499,19 +1505,21 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b)  {  	struct sk_buff_head xmitq;  	struct tipc_node *n; -	struct tipc_msg *hdr = buf_msg(skb); -	int usr = msg_user(hdr); +	struct tipc_msg *hdr;  	int bearer_id = b->identity;  	struct tipc_link_entry *le; -	u16 bc_ack = msg_bcast_ack(hdr);  	u32 self = tipc_own_addr(net); -	int rc = 0; +	int usr, rc = 0; +	u16 bc_ack;  	__skb_queue_head_init(&xmitq); -	/* Ensure message is well-formed */ +	/* Ensure message is well-formed before touching the header */  	if (unlikely(!tipc_msg_validate(skb)))  		goto discard; +	hdr = buf_msg(skb); +	usr = msg_user(hdr); +	bc_ack = msg_bcast_ack(hdr);  	/* Handle arrival of discovery or broadcast packet */  	if (unlikely(msg_non_seq(hdr))) { @@ -1570,6 +1578,9 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b)  	if (unlikely(!skb_queue_empty(&n->bc_entry.namedq)))  		tipc_named_rcv(net, &n->bc_entry.namedq); +	if (unlikely(!skb_queue_empty(&n->bc_entry.inputq1))) +		tipc_node_mcast_rcv(n); +  	if (!skb_queue_empty(&le->inputq))  		tipc_sk_rcv(net, &le->inputq); | 
