aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorShirley Ma <mashirle@us.ibm.com>2011-07-06 08:22:12 -0400
committerDavid S. Miller <davem@davemloft.net>2011-07-07 07:41:13 -0400
commita6686f2f382b13f8a7253401a66690c3633b6a74 (patch)
tree36a9a4546163a3c5b9a9ab3daa3b6bbe34af55aa /net/core
parent1cdebb423202e255366a321814fc6df079802a0d (diff)
skbuff: skb supports zero-copy buffers
This patch adds userspace buffers support in skb shared info. A new struct skb_ubuf_info is needed to maintain the userspace buffers argument and index, a callback is used to notify userspace to release the buffers once lower device has done DMA (Last reference to that skb has gone). If there is any userspace apps to reference these userspace buffers, then these userspaces buffers will be copied into kernel. This way we can prevent userspace apps from holding these userspace buffers too long. Use destructor_arg to point to the userspace buffer info; a new tx flags SKBTX_DEV_ZEROCOPY is added for zero-copy buffer check. Signed-off-by: Shirley Ma <xma@...ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r--net/core/skbuff.c80
1 files changed, 79 insertions, 1 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 46cbd28f40f9..a9577a2f3a43 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -329,6 +329,18 @@ static void skb_release_data(struct sk_buff *skb)
329 put_page(skb_shinfo(skb)->frags[i].page); 329 put_page(skb_shinfo(skb)->frags[i].page);
330 } 330 }
331 331
332 /*
333 * If skb buf is from userspace, we need to notify the caller
334 * the lower device DMA has done;
335 */
336 if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
337 struct ubuf_info *uarg;
338
339 uarg = skb_shinfo(skb)->destructor_arg;
340 if (uarg->callback)
341 uarg->callback(uarg);
342 }
343
332 if (skb_has_frag_list(skb)) 344 if (skb_has_frag_list(skb))
333 skb_drop_fraglist(skb); 345 skb_drop_fraglist(skb);
334 346
@@ -481,6 +493,9 @@ bool skb_recycle_check(struct sk_buff *skb, int skb_size)
481 if (irqs_disabled()) 493 if (irqs_disabled())
482 return false; 494 return false;
483 495
496 if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY)
497 return false;
498
484 if (skb_is_nonlinear(skb) || skb->fclone != SKB_FCLONE_UNAVAILABLE) 499 if (skb_is_nonlinear(skb) || skb->fclone != SKB_FCLONE_UNAVAILABLE)
485 return false; 500 return false;
486 501
@@ -596,6 +611,51 @@ struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src)
596} 611}
597EXPORT_SYMBOL_GPL(skb_morph); 612EXPORT_SYMBOL_GPL(skb_morph);
598 613
614/* skb frags copy userspace buffers to kernel */
615static int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
616{
617 int i;
618 int num_frags = skb_shinfo(skb)->nr_frags;
619 struct page *page, *head = NULL;
620 struct ubuf_info *uarg = skb_shinfo(skb)->destructor_arg;
621
622 for (i = 0; i < num_frags; i++) {
623 u8 *vaddr;
624 skb_frag_t *f = &skb_shinfo(skb)->frags[i];
625
626 page = alloc_page(GFP_ATOMIC);
627 if (!page) {
628 while (head) {
629 struct page *next = (struct page *)head->private;
630 put_page(head);
631 head = next;
632 }
633 return -ENOMEM;
634 }
635 vaddr = kmap_skb_frag(&skb_shinfo(skb)->frags[i]);
636 memcpy(page_address(page),
637 vaddr + f->page_offset, f->size);
638 kunmap_skb_frag(vaddr);
639 page->private = (unsigned long)head;
640 head = page;
641 }
642
643 /* skb frags release userspace buffers */
644 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
645 put_page(skb_shinfo(skb)->frags[i].page);
646
647 uarg->callback(uarg);
648
649 /* skb frags point to kernel buffers */
650 for (i = skb_shinfo(skb)->nr_frags; i > 0; i--) {
651 skb_shinfo(skb)->frags[i - 1].page_offset = 0;
652 skb_shinfo(skb)->frags[i - 1].page = head;
653 head = (struct page *)head->private;
654 }
655 return 0;
656}
657
658
599/** 659/**
600 * skb_clone - duplicate an sk_buff 660 * skb_clone - duplicate an sk_buff
601 * @skb: buffer to clone 661 * @skb: buffer to clone
@@ -614,6 +674,11 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
614{ 674{
615 struct sk_buff *n; 675 struct sk_buff *n;
616 676
677 if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
678 if (skb_copy_ubufs(skb, gfp_mask))
679 return NULL;
680 }
681
617 n = skb + 1; 682 n = skb + 1;
618 if (skb->fclone == SKB_FCLONE_ORIG && 683 if (skb->fclone == SKB_FCLONE_ORIG &&
619 n->fclone == SKB_FCLONE_UNAVAILABLE) { 684 n->fclone == SKB_FCLONE_UNAVAILABLE) {
@@ -731,6 +796,12 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask)
731 if (skb_shinfo(skb)->nr_frags) { 796 if (skb_shinfo(skb)->nr_frags) {
732 int i; 797 int i;
733 798
799 if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
800 if (skb_copy_ubufs(skb, gfp_mask)) {
801 kfree(n);
802 goto out;
803 }
804 }
734 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 805 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
735 skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i]; 806 skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i];
736 get_page(skb_shinfo(n)->frags[i].page); 807 get_page(skb_shinfo(n)->frags[i].page);
@@ -788,7 +859,6 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
788 fastpath = true; 859 fastpath = true;
789 else { 860 else {
790 int delta = skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1; 861 int delta = skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1;
791
792 fastpath = atomic_read(&skb_shinfo(skb)->dataref) == delta; 862 fastpath = atomic_read(&skb_shinfo(skb)->dataref) == delta;
793 } 863 }
794 864
@@ -819,6 +889,11 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
819 if (fastpath) { 889 if (fastpath) {
820 kfree(skb->head); 890 kfree(skb->head);
821 } else { 891 } else {
892 /* copy this zero copy skb frags */
893 if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
894 if (skb_copy_ubufs(skb, gfp_mask))
895 goto nofrags;
896 }
822 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) 897 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
823 get_page(skb_shinfo(skb)->frags[i].page); 898 get_page(skb_shinfo(skb)->frags[i].page);
824 899
@@ -853,6 +928,8 @@ adjust_others:
853 atomic_set(&skb_shinfo(skb)->dataref, 1); 928 atomic_set(&skb_shinfo(skb)->dataref, 1);
854 return 0; 929 return 0;
855 930
931nofrags:
932 kfree(data);
856nodata: 933nodata:
857 return -ENOMEM; 934 return -ENOMEM;
858} 935}
@@ -1354,6 +1431,7 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
1354 } 1431 }
1355 start = end; 1432 start = end;
1356 } 1433 }
1434
1357 if (!len) 1435 if (!len)
1358 return 0; 1436 return 0;
1359 1437