diff options
Diffstat (limited to 'net/tipc')
| -rw-r--r-- | net/tipc/discover.c | 19 | ||||
| -rw-r--r-- | net/tipc/net.c | 45 | ||||
| -rw-r--r-- | net/tipc/net.h | 2 | ||||
| -rw-r--r-- | net/tipc/socket.c | 15 | 
4 files changed, 59 insertions, 22 deletions
| diff --git a/net/tipc/discover.c b/net/tipc/discover.c index 2830709957bd..c138d68e8a69 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -166,7 +166,8 @@ static bool tipc_disc_addr_trial_msg(struct tipc_discoverer *d,  	/* Apply trial address if we just left trial period */  	if (!trial && !self) { -		tipc_net_finalize(net, tn->trial_addr); +		tipc_sched_net_finalize(net, tn->trial_addr); +		msg_set_prevnode(buf_msg(d->skb), tn->trial_addr);  		msg_set_type(buf_msg(d->skb), DSC_REQ_MSG);  	} @@ -300,14 +301,12 @@ static void tipc_disc_timeout(struct timer_list *t)  		goto exit;  	} -	/* Trial period over ? */ -	if (!time_before(jiffies, tn->addr_trial_end)) { -		/* Did we just leave it ? */ -		if (!tipc_own_addr(net)) -			tipc_net_finalize(net, tn->trial_addr); - -		msg_set_type(buf_msg(d->skb), DSC_REQ_MSG); -		msg_set_prevnode(buf_msg(d->skb), tipc_own_addr(net)); +	/* Did we just leave trial period ? */ +	if (!time_before(jiffies, tn->addr_trial_end) && !tipc_own_addr(net)) { +		mod_timer(&d->timer, jiffies + TIPC_DISC_INIT); +		spin_unlock_bh(&d->lock); +		tipc_sched_net_finalize(net, tn->trial_addr); +		return;  	}  	/* Adjust timeout interval according to discovery phase */ @@ -319,6 +318,8 @@ static void tipc_disc_timeout(struct timer_list *t)  			d->timer_intv = TIPC_DISC_SLOW;  		else if (!d->num_nodes && d->timer_intv > TIPC_DISC_FAST)  			d->timer_intv = TIPC_DISC_FAST; +		msg_set_type(buf_msg(d->skb), DSC_REQ_MSG); +		msg_set_prevnode(buf_msg(d->skb), tn->trial_addr);  	}  	mod_timer(&d->timer, jiffies + d->timer_intv); diff --git a/net/tipc/net.c b/net/tipc/net.c index 62199cf5a56c..f076edb74338 100644 --- a/net/tipc/net.c +++ b/net/tipc/net.c @@ -104,6 +104,14 @@   *     - A local spin_lock protecting the queue of subscriber events.  */ +struct tipc_net_work { +	struct work_struct work; +	struct net *net; +	u32 addr; +}; + +static void tipc_net_finalize(struct net *net, u32 addr); +  int tipc_net_init(struct net *net, u8 *node_id, u32 addr)  {  	if (tipc_own_id(net)) { @@ -119,17 +127,38 @@ int tipc_net_init(struct net *net, u8 *node_id, u32 addr)  	return 0;  } -void tipc_net_finalize(struct net *net, u32 addr) +static void tipc_net_finalize(struct net *net, u32 addr)  {  	struct tipc_net *tn = tipc_net(net); -	if (!cmpxchg(&tn->node_addr, 0, addr)) { -		tipc_set_node_addr(net, addr); -		tipc_named_reinit(net); -		tipc_sk_reinit(net); -		tipc_nametbl_publish(net, TIPC_CFG_SRV, addr, addr, -				     TIPC_CLUSTER_SCOPE, 0, addr); -	} +	if (cmpxchg(&tn->node_addr, 0, addr)) +		return; +	tipc_set_node_addr(net, addr); +	tipc_named_reinit(net); +	tipc_sk_reinit(net); +	tipc_nametbl_publish(net, TIPC_CFG_SRV, addr, addr, +			     TIPC_CLUSTER_SCOPE, 0, addr); +} + +static void tipc_net_finalize_work(struct work_struct *work) +{ +	struct tipc_net_work *fwork; + +	fwork = container_of(work, struct tipc_net_work, work); +	tipc_net_finalize(fwork->net, fwork->addr); +	kfree(fwork); +} + +void tipc_sched_net_finalize(struct net *net, u32 addr) +{ +	struct tipc_net_work *fwork = kzalloc(sizeof(*fwork), GFP_ATOMIC); + +	if (!fwork) +		return; +	INIT_WORK(&fwork->work, tipc_net_finalize_work); +	fwork->net = net; +	fwork->addr = addr; +	schedule_work(&fwork->work);  }  void tipc_net_stop(struct net *net) diff --git a/net/tipc/net.h b/net/tipc/net.h index 09ad02b50bb1..b7f2e364eb99 100644 --- a/net/tipc/net.h +++ b/net/tipc/net.h @@ -42,7 +42,7 @@  extern const struct nla_policy tipc_nl_net_policy[];  int tipc_net_init(struct net *net, u8 *node_id, u32 addr); -void tipc_net_finalize(struct net *net, u32 addr); +void tipc_sched_net_finalize(struct net *net, u32 addr);  void tipc_net_stop(struct net *net);  int tipc_nl_net_dump(struct sk_buff *skb, struct netlink_callback *cb);  int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info); diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 636e6131769d..b57b1be7252b 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1555,16 +1555,17 @@ static void tipc_sk_set_orig_addr(struct msghdr *m, struct sk_buff *skb)  /**   * tipc_sk_anc_data_recv - optionally capture ancillary data for received message   * @m: descriptor for message info - * @msg: received message header + * @skb: received message buffer   * @tsk: TIPC port associated with message   *   * Note: Ancillary data is not captured if not requested by receiver.   *   * Returns 0 if successful, otherwise errno   */ -static int tipc_sk_anc_data_recv(struct msghdr *m, struct tipc_msg *msg, +static int tipc_sk_anc_data_recv(struct msghdr *m, struct sk_buff *skb,  				 struct tipc_sock *tsk)  { +	struct tipc_msg *msg;  	u32 anc_data[3];  	u32 err;  	u32 dest_type; @@ -1573,6 +1574,7 @@ static int tipc_sk_anc_data_recv(struct msghdr *m, struct tipc_msg *msg,  	if (likely(m->msg_controllen == 0))  		return 0; +	msg = buf_msg(skb);  	/* Optionally capture errored message object(s) */  	err = msg ? msg_errcode(msg) : 0; @@ -1583,6 +1585,9 @@ static int tipc_sk_anc_data_recv(struct msghdr *m, struct tipc_msg *msg,  		if (res)  			return res;  		if (anc_data[1]) { +			if (skb_linearize(skb)) +				return -ENOMEM; +			msg = buf_msg(skb);  			res = put_cmsg(m, SOL_TIPC, TIPC_RETDATA, anc_data[1],  				       msg_data(msg));  			if (res) @@ -1744,9 +1749,10 @@ static int tipc_recvmsg(struct socket *sock, struct msghdr *m,  	/* Collect msg meta data, including error code and rejected data */  	tipc_sk_set_orig_addr(m, skb); -	rc = tipc_sk_anc_data_recv(m, hdr, tsk); +	rc = tipc_sk_anc_data_recv(m, skb, tsk);  	if (unlikely(rc))  		goto exit; +	hdr = buf_msg(skb);  	/* Capture data if non-error msg, otherwise just set return value */  	if (likely(!err)) { @@ -1856,9 +1862,10 @@ static int tipc_recvstream(struct socket *sock, struct msghdr *m,  		/* Collect msg meta data, incl. error code and rejected data */  		if (!copied) {  			tipc_sk_set_orig_addr(m, skb); -			rc = tipc_sk_anc_data_recv(m, hdr, tsk); +			rc = tipc_sk_anc_data_recv(m, skb, tsk);  			if (rc)  				break; +			hdr = buf_msg(skb);  		}  		/* Copy data if msg ok, otherwise return error/partial data */ | 
