aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/skbuff.c
diff options
context:
space:
mode:
authorMichael S. Tsirkin <mst@redhat.com>2011-08-31 04:03:29 -0400
committerDavid S. Miller <davem@davemloft.net>2011-09-15 14:49:44 -0400
commit48c830120f2a20b44220aa26feda9ed15f49eaab (patch)
tree5a9bfdf7493cf53e59350b82d5c3c9017fe403a5 /net/core/skbuff.c
parent0542b69e2c57fc9668ce6a03155bea6e1f557901 (diff)
net: copy userspace buffers on device forwarding
dev_forward_skb loops an skb back into host networking stack which might hang on the memory indefinitely. In particular, this can happen in macvtap in bridged mode. Copy the userspace fragments to avoid blocking the sender in that case. As this patch makes skb_copy_ubufs extern now, I also added some documentation and made it clear the SKBTX_DEV_ZEROCOPY flag automatically instead of doing it in all callers. This can be made into a separate patch if people feel it's worth it. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/skbuff.c')
-rw-r--r--net/core/skbuff.c22
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}
612EXPORT_SYMBOL_GPL(skb_morph); 612EXPORT_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
615static 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 */
628int 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);