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 27002dffe7ed..387703f56fce 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) | |||
611 | } | 611 | } |
612 | EXPORT_SYMBOL_GPL(skb_morph); | 612 | EXPORT_SYMBOL_GPL(skb_morph); |
613 | 613 | ||
614 | /* skb frags copy userspace buffers to kernel */ | 614 | /* skb_copy_ubufs - copy userspace skb frags buffers to kernel |
615 | static int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask) | 615 | * @skb: the skb to modify |
616 | * @gfp_mask: allocation priority | ||
617 | * | ||
618 | * This must be called on SKBTX_DEV_ZEROCOPY skb. | ||
619 | * It will copy all frags into kernel and drop the reference | ||
620 | * to userspace pages. | ||
621 | * | ||
622 | * If this function is called from an interrupt gfp_mask() must be | ||
623 | * %GFP_ATOMIC. | ||
624 | * | ||
625 | * Returns 0 on success or a negative error code on failure | ||
626 | * to allocate kernel memory to copy to. | ||
627 | */ | ||
628 | int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask) | ||
616 | { | 629 | { |
617 | int i; | 630 | int i; |
618 | int num_frags = skb_shinfo(skb)->nr_frags; | 631 | 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) | |||
652 | skb_shinfo(skb)->frags[i - 1].page = head; | 665 | skb_shinfo(skb)->frags[i - 1].page = head; |
653 | head = (struct page *)head->private; | 666 | head = (struct page *)head->private; |
654 | } | 667 | } |
668 | |||
669 | skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY; | ||
655 | return 0; | 670 | return 0; |
656 | } | 671 | } |
657 | 672 | ||
@@ -677,7 +692,6 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask) | |||
677 | if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) { | 692 | if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) { |
678 | if (skb_copy_ubufs(skb, gfp_mask)) | 693 | if (skb_copy_ubufs(skb, gfp_mask)) |
679 | return NULL; | 694 | return NULL; |
680 | skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY; | ||
681 | } | 695 | } |
682 | 696 | ||
683 | n = skb + 1; | 697 | n = skb + 1; |
@@ -803,7 +817,6 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask) | |||
803 | n = NULL; | 817 | n = NULL; |
804 | goto out; | 818 | goto out; |
805 | } | 819 | } |
806 | skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY; | ||
807 | } | 820 | } |
808 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { | 821 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { |
809 | skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i]; | 822 | 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, | |||
896 | if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) { | 909 | if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) { |
897 | if (skb_copy_ubufs(skb, gfp_mask)) | 910 | if (skb_copy_ubufs(skb, gfp_mask)) |
898 | goto nofrags; | 911 | goto nofrags; |
899 | skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY; | ||
900 | } | 912 | } |
901 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) | 913 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) |
902 | get_page(skb_shinfo(skb)->frags[i].page); | 914 | get_page(skb_shinfo(skb)->frags[i].page); |