diff options
author | Sagi Grimberg <sagi@lightbitslabs.com> | 2018-12-03 20:52:08 -0500 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2018-12-13 03:58:53 -0500 |
commit | 950fcaecd5cc6c014bb96506fd0652a501c85276 (patch) | |
tree | 15e815ace068cd74215156fd0957a75ce3a992c1 /net | |
parent | cb002d074dabfaa2248507fd9478d16a542e4f1e (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.c | 136 |
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 | } |
409 | EXPORT_SYMBOL(skb_kill_datagram); | 409 | EXPORT_SYMBOL(skb_kill_datagram); |
410 | 410 | ||
411 | /** | 411 | int __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 | */ | ||
418 | int 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 | ||
495 | short_copy: | 488 | short_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 | |||
495 | static 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 | */ | ||
508 | int 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 | } | ||
501 | EXPORT_SYMBOL(skb_copy_datagram_iter); | 515 | EXPORT_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 | } |
649 | EXPORT_SYMBOL(zerocopy_sg_from_iter); | 663 | EXPORT_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 | */ | ||
651 | static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, | 674 | static 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 | |||
729 | fault: | ||
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) |