diff options
Diffstat (limited to 'net/core/skbuff.c')
| -rw-r--r-- | net/core/skbuff.c | 22 | 
1 files changed, 17 insertions, 5 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 27002dffe7e..387703f56fc 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -611,8 +611,21 @@ struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src)  }  EXPORT_SYMBOL_GPL(skb_morph); -/* skb frags copy userspace buffers to kernel */ -static int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask) +/*	skb_copy_ubufs	-	copy userspace skb frags buffers to kernel + *	@skb: the skb to modify + *	@gfp_mask: allocation priority + * + *	This must be called on SKBTX_DEV_ZEROCOPY skb. + *	It will copy all frags into kernel and drop the reference + *	to userspace pages. + * + *	If this function is called from an interrupt gfp_mask() must be + *	%GFP_ATOMIC. + * + *	Returns 0 on success or a negative error code on failure + *	to allocate kernel memory to copy to. + */ +int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)  {  	int i;  	int num_frags = skb_shinfo(skb)->nr_frags; @@ -652,6 +665,8 @@ static int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)  		skb_shinfo(skb)->frags[i - 1].page = head;  		head = (struct page *)head->private;  	} + +	skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;  	return 0;  } @@ -677,7 +692,6 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)  	if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {  		if (skb_copy_ubufs(skb, gfp_mask))  			return NULL; -		skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;  	}  	n = skb + 1; @@ -803,7 +817,6 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask)  				n = NULL;  				goto out;  			} -			skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;  		}  		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {  			skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i]; @@ -896,7 +909,6 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,  		if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {  			if (skb_copy_ubufs(skb, gfp_mask))  				goto nofrags; -			skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;  		}  		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)  			get_page(skb_shinfo(skb)->frags[i].page);  |