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); |
