diff options
Diffstat (limited to 'net/core/dev.c')
| -rw-r--r-- | net/core/dev.c | 68 | 
1 files changed, 28 insertions, 40 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index a5aa1c7444e6..aa61b9344b46 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4881,36 +4881,25 @@ out:   */  void napi_gro_flush(struct napi_struct *napi, bool flush_old)  { -	struct sk_buff *skb, *prev = NULL; - -	/* scan list and build reverse chain */ -	for (skb = napi->gro_list; skb != NULL; skb = skb->next) { -		skb->prev = prev; -		prev = skb; -	} - -	for (skb = prev; skb; skb = prev) { -		skb->next = NULL; +	struct sk_buff *skb, *p; +	list_for_each_entry_safe_reverse(skb, p, &napi->gro_list, list) {  		if (flush_old && NAPI_GRO_CB(skb)->age == jiffies)  			return; - -		prev = skb->prev; +		list_del_init(&skb->list);  		napi_gro_complete(skb);  		napi->gro_count--;  	} - -	napi->gro_list = NULL;  }  EXPORT_SYMBOL(napi_gro_flush);  static void gro_list_prepare(struct napi_struct *napi, struct sk_buff *skb)  { -	struct sk_buff *p;  	unsigned int maclen = skb->dev->hard_header_len;  	u32 hash = skb_get_hash_raw(skb); +	struct sk_buff *p; -	for (p = napi->gro_list; p; p = p->next) { +	list_for_each_entry(p, &napi->gro_list, list) {  		unsigned long diffs;  		NAPI_GRO_CB(p)->flush = 0; @@ -4977,12 +4966,12 @@ static void gro_pull_from_frag0(struct sk_buff *skb, int grow)  static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)  { -	struct sk_buff **pp = NULL; +	struct list_head *head = &offload_base;  	struct packet_offload *ptype;  	__be16 type = skb->protocol; -	struct list_head *head = &offload_base; -	int same_flow; +	struct sk_buff *pp = NULL;  	enum gro_result ret; +	int same_flow;  	int grow;  	if (netif_elide_gro(skb->dev)) @@ -5039,11 +5028,8 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff  	ret = NAPI_GRO_CB(skb)->free ? GRO_MERGED_FREE : GRO_MERGED;  	if (pp) { -		struct sk_buff *nskb = *pp; - -		*pp = nskb->next; -		nskb->next = NULL; -		napi_gro_complete(nskb); +		list_del_init(&pp->list); +		napi_gro_complete(pp);  		napi->gro_count--;  	} @@ -5054,15 +5040,10 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff  		goto normal;  	if (unlikely(napi->gro_count >= MAX_GRO_SKBS)) { -		struct sk_buff *nskb = napi->gro_list; +		struct sk_buff *nskb; -		/* locate the end of the list to select the 'oldest' flow */ -		while (nskb->next) { -			pp = &nskb->next; -			nskb = *pp; -		} -		*pp = NULL; -		nskb->next = NULL; +		nskb = list_last_entry(&napi->gro_list, struct sk_buff, list); +		list_del(&nskb->list);  		napi_gro_complete(nskb);  	} else {  		napi->gro_count++; @@ -5071,8 +5052,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff  	NAPI_GRO_CB(skb)->age = jiffies;  	NAPI_GRO_CB(skb)->last = skb;  	skb_shinfo(skb)->gso_size = skb_gro_len(skb); -	skb->next = napi->gro_list; -	napi->gro_list = skb; +	list_add(&skb->list, &napi->gro_list);  	ret = GRO_HELD;  pull: @@ -5478,7 +5458,7 @@ bool napi_complete_done(struct napi_struct *n, int work_done)  				 NAPIF_STATE_IN_BUSY_POLL)))  		return false; -	if (n->gro_list) { +	if (!list_empty(&n->gro_list)) {  		unsigned long timeout = 0;  		if (work_done) @@ -5687,7 +5667,7 @@ static enum hrtimer_restart napi_watchdog(struct hrtimer *timer)  	/* Note : we use a relaxed variant of napi_schedule_prep() not setting  	 * NAPI_STATE_MISSED, since we do not react to a device IRQ.  	 */ -	if (napi->gro_list && !napi_disable_pending(napi) && +	if (!list_empty(&napi->gro_list) && !napi_disable_pending(napi) &&  	    !test_and_set_bit(NAPI_STATE_SCHED, &napi->state))  		__napi_schedule_irqoff(napi); @@ -5701,7 +5681,7 @@ void netif_napi_add(struct net_device *dev, struct napi_struct *napi,  	hrtimer_init(&napi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);  	napi->timer.function = napi_watchdog;  	napi->gro_count = 0; -	napi->gro_list = NULL; +	INIT_LIST_HEAD(&napi->gro_list);  	napi->skb = NULL;  	napi->poll = poll;  	if (weight > NAPI_POLL_WEIGHT) @@ -5734,6 +5714,14 @@ void napi_disable(struct napi_struct *n)  }  EXPORT_SYMBOL(napi_disable); +static void gro_list_free(struct list_head *head) +{ +	struct sk_buff *skb, *p; + +	list_for_each_entry_safe(skb, p, head, list) +		kfree_skb(skb); +} +  /* Must be called in process context */  void netif_napi_del(struct napi_struct *napi)  { @@ -5743,8 +5731,8 @@ void netif_napi_del(struct napi_struct *napi)  	list_del_init(&napi->dev_list);  	napi_free_frags(napi); -	kfree_skb_list(napi->gro_list); -	napi->gro_list = NULL; +	gro_list_free(&napi->gro_list); +	INIT_LIST_HEAD(&napi->gro_list);  	napi->gro_count = 0;  }  EXPORT_SYMBOL(netif_napi_del); @@ -5787,7 +5775,7 @@ static int napi_poll(struct napi_struct *n, struct list_head *repoll)  		goto out_unlock;  	} -	if (n->gro_list) { +	if (!list_empty(&n->gro_list)) {  		/* flush too old packets  		 * If HZ < 1000, flush all packets.  		 */  | 
