summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorSagi Grimberg <sagi@lightbitslabs.com>2018-12-03 20:52:08 -0500
committerChristoph Hellwig <hch@lst.de>2018-12-13 03:58:53 -0500
commit950fcaecd5cc6c014bb96506fd0652a501c85276 (patch)
tree15e815ace068cd74215156fd0957a75ce3a992c1 /net
parentcb002d074dabfaa2248507fd9478d16a542e4f1e (diff)
datagram: consolidate datagram copy to iter helpers
skb_copy_datagram_iter and skb_copy_and_csum_datagram are essentialy the same but with a couple of differences: The first is the copy operation used which either a simple copy or a csum_and_copy, and the second are the behavior on the "short copy" path where simply copy needs to return the number of bytes successfully copied while csum_and_copy needs to fault immediately as the checksum is partial. Introduce __skb_datagram_iter that additionally accepts: 1. copy operation function pointer 2. private data that goes with the copy operation 3. fault_short flag to indicate the action on short copy Suggested-by: David S. Miller <davem@davemloft.net> Acked-by: David S. Miller <davem@davemloft.net> Signed-off-by: Sagi Grimberg <sagi@lightbitslabs.com> Signed-off-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'net')
-rw-r--r--net/core/datagram.c136
1 files changed, 42 insertions, 94 deletions
diff --git a/net/core/datagram.c b/net/core/datagram.c
index abe642181b64..382543302ae5 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -408,27 +408,20 @@ int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags)
408} 408}
409EXPORT_SYMBOL(skb_kill_datagram); 409EXPORT_SYMBOL(skb_kill_datagram);
410 410
411/** 411int __skb_datagram_iter(const struct sk_buff *skb, int offset,
412 * skb_copy_datagram_iter - Copy a datagram to an iovec iterator. 412 struct iov_iter *to, int len, bool fault_short,
413 * @skb: buffer to copy 413 size_t (*cb)(const void *, size_t, void *, struct iov_iter *),
414 * @offset: offset in the buffer to start copying from 414 void *data)
415 * @to: iovec iterator to copy to
416 * @len: amount of data to copy from buffer to iovec
417 */
418int skb_copy_datagram_iter(const struct sk_buff *skb, int offset,
419 struct iov_iter *to, int len)
420{ 415{
421 int start = skb_headlen(skb); 416 int start = skb_headlen(skb);
422 int i, copy = start - offset, start_off = offset, n; 417 int i, copy = start - offset, start_off = offset, n;
423 struct sk_buff *frag_iter; 418 struct sk_buff *frag_iter;
424 419
425 trace_skb_copy_datagram_iovec(skb, len);
426
427 /* Copy header. */ 420 /* Copy header. */
428 if (copy > 0) { 421 if (copy > 0) {
429 if (copy > len) 422 if (copy > len)
430 copy = len; 423 copy = len;
431 n = copy_to_iter(skb->data + offset, copy, to); 424 n = cb(skb->data + offset, copy, data, to);
432 offset += n; 425 offset += n;
433 if (n != copy) 426 if (n != copy)
434 goto short_copy; 427 goto short_copy;
@@ -450,8 +443,8 @@ int skb_copy_datagram_iter(const struct sk_buff *skb, int offset,
450 443
451 if (copy > len) 444 if (copy > len)
452 copy = len; 445 copy = len;
453 n = copy_to_iter(vaddr + frag->page_offset + 446 n = cb(vaddr + frag->page_offset +
454 offset - start, copy, to); 447 offset - start, copy, data, to);
455 kunmap(page); 448 kunmap(page);
456 offset += n; 449 offset += n;
457 if (n != copy) 450 if (n != copy)
@@ -471,8 +464,8 @@ int skb_copy_datagram_iter(const struct sk_buff *skb, int offset,
471 if ((copy = end - offset) > 0) { 464 if ((copy = end - offset) > 0) {
472 if (copy > len) 465 if (copy > len)
473 copy = len; 466 copy = len;
474 if (skb_copy_datagram_iter(frag_iter, offset - start, 467 if (__skb_datagram_iter(frag_iter, offset - start,
475 to, copy)) 468 to, copy, short_copy, cb, data))
476 goto fault; 469 goto fault;
477 if ((len -= copy) == 0) 470 if ((len -= copy) == 0)
478 return 0; 471 return 0;
@@ -493,11 +486,32 @@ fault:
493 return -EFAULT; 486 return -EFAULT;
494 487
495short_copy: 488short_copy:
496 if (iov_iter_count(to)) 489 if (fault_short || iov_iter_count(to))
497 goto fault; 490 goto fault;
498 491
499 return 0; 492 return 0;
500} 493}
494
495static size_t simple_copy_to_iter(const void *addr, size_t bytes,
496 void *data __always_unused, struct iov_iter *i)
497{
498 return copy_to_iter(addr, bytes, i);
499}
500
501/**
502 * skb_copy_datagram_iter - Copy a datagram to an iovec iterator.
503 * @skb: buffer to copy
504 * @offset: offset in the buffer to start copying from
505 * @to: iovec iterator to copy to
506 * @len: amount of data to copy from buffer to iovec
507 */
508int skb_copy_datagram_iter(const struct sk_buff *skb, int offset,
509 struct iov_iter *to, int len)
510{
511 trace_skb_copy_datagram_iovec(skb, len);
512 return __skb_datagram_iter(skb, offset, to, len, false,
513 simple_copy_to_iter, NULL);
514}
501EXPORT_SYMBOL(skb_copy_datagram_iter); 515EXPORT_SYMBOL(skb_copy_datagram_iter);
502 516
503/** 517/**
@@ -648,87 +662,21 @@ int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *from)
648} 662}
649EXPORT_SYMBOL(zerocopy_sg_from_iter); 663EXPORT_SYMBOL(zerocopy_sg_from_iter);
650 664
665/**
666 * skb_copy_and_csum_datagram_iter - Copy datagram to an iovec iterator
667 * and update a checksum.
668 * @skb: buffer to copy
669 * @offset: offset in the buffer to start copying from
670 * @to: iovec iterator to copy to
671 * @len: amount of data to copy from buffer to iovec
672 * @csump: checksum pointer
673 */
651static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, 674static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
652 struct iov_iter *to, int len, 675 struct iov_iter *to, int len,
653 __wsum *csump) 676 __wsum *csump)
654{ 677{
655 int start = skb_headlen(skb); 678 return __skb_datagram_iter(skb, offset, to, len, true,
656 int i, copy = start - offset, start_off = offset; 679 csum_and_copy_to_iter, csump);
657 struct sk_buff *frag_iter;
658 int pos = 0;
659 int n;
660
661 /* Copy header. */
662 if (copy > 0) {
663 if (copy > len)
664 copy = len;
665 n = csum_and_copy_to_iter(skb->data + offset, copy, csump, to);
666 offset += n;
667 if (n != copy)
668 goto fault;
669 if ((len -= copy) == 0)
670 return 0;
671 pos = copy;
672 }
673
674 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
675 int end;
676 const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
677
678 WARN_ON(start > offset + len);
679
680 end = start + skb_frag_size(frag);
681 if ((copy = end - offset) > 0) {
682 __wsum csum2 = 0;
683 struct page *page = skb_frag_page(frag);
684 u8 *vaddr = kmap(page);
685
686 if (copy > len)
687 copy = len;
688 n = csum_and_copy_to_iter(vaddr + frag->page_offset +
689 offset - start, copy,
690 &csum2, to);
691 kunmap(page);
692 offset += n;
693 if (n != copy)
694 goto fault;
695 *csump = csum_block_add(*csump, csum2, pos);
696 if (!(len -= copy))
697 return 0;
698 pos += copy;
699 }
700 start = end;
701 }
702
703 skb_walk_frags(skb, frag_iter) {
704 int end;
705
706 WARN_ON(start > offset + len);
707
708 end = start + frag_iter->len;
709 if ((copy = end - offset) > 0) {
710 __wsum csum2 = 0;
711 if (copy > len)
712 copy = len;
713 if (skb_copy_and_csum_datagram(frag_iter,
714 offset - start,
715 to, copy,
716 &csum2))
717 goto fault;
718 *csump = csum_block_add(*csump, csum2, pos);
719 if ((len -= copy) == 0)
720 return 0;
721 offset += copy;
722 pos += copy;
723 }
724 start = end;
725 }
726 if (!len)
727 return 0;
728
729fault:
730 iov_iter_revert(to, offset - start_off);
731 return -EFAULT;
732} 680}
733 681
734__sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len) 682__sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len)