diff options
Diffstat (limited to 'net/xfrm/xfrm_input.c')
| -rw-r--r-- | net/xfrm/xfrm_input.c | 28 | 
1 files changed, 19 insertions, 9 deletions
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 144238a50f3d..97074f6f2bde 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -20,11 +20,13 @@  #include <net/xfrm.h>  #include <net/ip_tunnels.h>  #include <net/ip6_tunnel.h> +#include <net/dst_metadata.h>  #include "xfrm_inout.h"  struct xfrm_trans_tasklet { -	struct tasklet_struct tasklet; +	struct work_struct work; +	spinlock_t queue_lock;  	struct sk_buff_head queue;  }; @@ -669,7 +671,6 @@ resume:  		x->curlft.bytes += skb->len;  		x->curlft.packets++; -		x->curlft.use_time = ktime_get_real_seconds();  		spin_unlock(&x->lock); @@ -720,7 +721,8 @@ resume:  		sp = skb_sec_path(skb);  		if (sp)  			sp->olen = 0; -		skb_dst_drop(skb); +		if (skb_valid_dst(skb)) +			skb_dst_drop(skb);  		gro_cells_receive(&gro_cells, skb);  		return 0;  	} else { @@ -738,7 +740,8 @@ resume:  			sp = skb_sec_path(skb);  			if (sp)  				sp->olen = 0; -			skb_dst_drop(skb); +			if (skb_valid_dst(skb)) +				skb_dst_drop(skb);  			gro_cells_receive(&gro_cells, skb);  			return err;  		} @@ -761,18 +764,22 @@ int xfrm_input_resume(struct sk_buff *skb, int nexthdr)  }  EXPORT_SYMBOL(xfrm_input_resume); -static void xfrm_trans_reinject(struct tasklet_struct *t) +static void xfrm_trans_reinject(struct work_struct *work)  { -	struct xfrm_trans_tasklet *trans = from_tasklet(trans, t, tasklet); +	struct xfrm_trans_tasklet *trans = container_of(work, struct xfrm_trans_tasklet, work);  	struct sk_buff_head queue;  	struct sk_buff *skb;  	__skb_queue_head_init(&queue); +	spin_lock_bh(&trans->queue_lock);  	skb_queue_splice_init(&trans->queue, &queue); +	spin_unlock_bh(&trans->queue_lock); +	local_bh_disable();  	while ((skb = __skb_dequeue(&queue)))  		XFRM_TRANS_SKB_CB(skb)->finish(XFRM_TRANS_SKB_CB(skb)->net,  					       NULL, skb); +	local_bh_enable();  }  int xfrm_trans_queue_net(struct net *net, struct sk_buff *skb, @@ -783,15 +790,17 @@ int xfrm_trans_queue_net(struct net *net, struct sk_buff *skb,  	trans = this_cpu_ptr(&xfrm_trans_tasklet); -	if (skb_queue_len(&trans->queue) >= netdev_max_backlog) +	if (skb_queue_len(&trans->queue) >= READ_ONCE(netdev_max_backlog))  		return -ENOBUFS;  	BUILD_BUG_ON(sizeof(struct xfrm_trans_cb) > sizeof(skb->cb));  	XFRM_TRANS_SKB_CB(skb)->finish = finish;  	XFRM_TRANS_SKB_CB(skb)->net = net; +	spin_lock_bh(&trans->queue_lock);  	__skb_queue_tail(&trans->queue, skb); -	tasklet_schedule(&trans->tasklet); +	spin_unlock_bh(&trans->queue_lock); +	schedule_work(&trans->work);  	return 0;  }  EXPORT_SYMBOL(xfrm_trans_queue_net); @@ -818,7 +827,8 @@ void __init xfrm_input_init(void)  		struct xfrm_trans_tasklet *trans;  		trans = &per_cpu(xfrm_trans_tasklet, i); +		spin_lock_init(&trans->queue_lock);  		__skb_queue_head_init(&trans->queue); -		tasklet_setup(&trans->tasklet, xfrm_trans_reinject); +		INIT_WORK(&trans->work, xfrm_trans_reinject);  	}  }  |