diff options
Diffstat (limited to 'net/core/skbuff.c')
| -rw-r--r-- | net/core/skbuff.c | 17 | 
1 files changed, 11 insertions, 6 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 6b0ff396fa9d..08f574081315 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1177,12 +1177,12 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)  	int i, new_frags;  	u32 d_off; -	if (!num_frags) -		return 0; -  	if (skb_shared(skb) || skb_unclone(skb, gfp_mask))  		return -EINVAL; +	if (!num_frags) +		goto release; +  	new_frags = (__skb_pagelen(skb) + PAGE_SIZE - 1) >> PAGE_SHIFT;  	for (i = 0; i < new_frags; i++) {  		page = alloc_page(gfp_mask); @@ -1238,6 +1238,7 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)  	__skb_fill_page_desc(skb, new_frags - 1, head, 0, d_off);  	skb_shinfo(skb)->nr_frags = new_frags; +release:  	skb_zcopy_clear(skb, false);  	return 0;  } @@ -3654,8 +3655,6 @@ normal:  		skb_shinfo(nskb)->tx_flags |= skb_shinfo(head_skb)->tx_flags &  					      SKBTX_SHARED_FRAG; -		if (skb_zerocopy_clone(nskb, head_skb, GFP_ATOMIC)) -			goto err;  		while (pos < offset + len) {  			if (i >= nfrags) { @@ -3681,6 +3680,8 @@ normal:  			if (unlikely(skb_orphan_frags(frag_skb, GFP_ATOMIC)))  				goto err; +			if (skb_zerocopy_clone(nskb, frag_skb, GFP_ATOMIC)) +				goto err;  			*nskb_frag = *frag;  			__skb_frag_ref(nskb_frag); @@ -4293,7 +4294,7 @@ void skb_complete_tx_timestamp(struct sk_buff *skb,  	struct sock *sk = skb->sk;  	if (!skb_may_tx_timestamp(sk, false)) -		return; +		goto err;  	/* Take a reference to prevent skb_orphan() from freeing the socket,  	 * but only if the socket refcount is not zero. @@ -4302,7 +4303,11 @@ void skb_complete_tx_timestamp(struct sk_buff *skb,  		*skb_hwtstamps(skb) = *hwtstamps;  		__skb_complete_tx_timestamp(skb, sk, SCM_TSTAMP_SND, false);  		sock_put(sk); +		return;  	} + +err: +	kfree_skb(skb);  }  EXPORT_SYMBOL_GPL(skb_complete_tx_timestamp);  |