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 296afd0aa8d2..5b2c5f1d4dba 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -613,8 +613,21 @@ struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src) | |||
613 | } | 613 | } |
614 | EXPORT_SYMBOL_GPL(skb_morph); | 614 | EXPORT_SYMBOL_GPL(skb_morph); |
615 | 615 | ||
616 | /* skb frags copy userspace buffers to kernel */ | 616 | /* skb_copy_ubufs - copy userspace skb frags buffers to kernel |
617 | static int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask) | 617 | * @skb: the skb to modify |
618 | * @gfp_mask: allocation priority | ||
619 | * | ||
620 | * This must be called on SKBTX_DEV_ZEROCOPY skb. | ||
621 | * It will copy all frags into kernel and drop the reference | ||
622 | * to userspace pages. | ||
623 | * | ||
624 | * If this function is called from an interrupt gfp_mask() must be | ||
625 | * %GFP_ATOMIC. | ||
626 | * | ||
627 | * Returns 0 on success or a negative error code on failure | ||
628 | * to allocate kernel memory to copy to. | ||
629 | */ | ||
630 | int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask) | ||
618 | { | 631 | { |
619 | int i; | 632 | int i; |
620 | int num_frags = skb_shinfo(skb)->nr_frags; | 633 | int num_frags = skb_shinfo(skb)->nr_frags; |
@@ -654,6 +667,8 @@ static int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask) | |||
654 | skb_shinfo(skb)->frags[i - 1].page = head; | 667 | skb_shinfo(skb)->frags[i - 1].page = head; |
655 | head = (struct page *)head->private; | 668 | head = (struct page *)head->private; |
656 | } | 669 | } |
670 | |||
671 | skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY; | ||
657 | return 0; | 672 | return 0; |
658 | } | 673 | } |
659 | 674 | ||
@@ -679,7 +694,6 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask) | |||
679 | if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) { | 694 | if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) { |
680 | if (skb_copy_ubufs(skb, gfp_mask)) | 695 | if (skb_copy_ubufs(skb, gfp_mask)) |
681 | return NULL; | 696 | return NULL; |
682 | skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY; | ||
683 | } | 697 | } |
684 | 698 | ||
685 | n = skb + 1; | 699 | n = skb + 1; |
@@ -805,7 +819,6 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask) | |||
805 | n = NULL; | 819 | n = NULL; |
806 | goto out; | 820 | goto out; |
807 | } | 821 | } |
808 | skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY; | ||
809 | } | 822 | } |
810 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { | 823 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { |
811 | skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i]; | 824 | skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i]; |
@@ -898,7 +911,6 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, | |||
898 | if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) { | 911 | if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) { |
899 | if (skb_copy_ubufs(skb, gfp_mask)) | 912 | if (skb_copy_ubufs(skb, gfp_mask)) |
900 | goto nofrags; | 913 | goto nofrags; |
901 | skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY; | ||
902 | } | 914 | } |
903 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) | 915 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) |
904 | skb_frag_ref(skb, i); | 916 | skb_frag_ref(skb, i); |