diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2014-11-24 18:17:55 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-12-09 16:29:10 -0500 |
commit | e5a4b0bb803b39a36478451eae53a880d2663d5b (patch) | |
tree | 2e7c71032ede136c8e8f975bf7a79a692df76535 | |
parent | 17836394e578b8d6475ecdb309ad1356bbcf37a2 (diff) |
switch memcpy_to_msg() and skb_copy{,_and_csum}_datagram_msg() to primitives
... making both non-draining. That means that tcp_recvmsg() becomes
non-draining. And _that_ would break iscsit_do_rx_data() unless we
a) make sure tcp_recvmsg() is uniformly non-draining (it is)
b) make sure it copes with arbitrary (including shifted)
iov_iter (it does, all it uses is iov_iter primitives)
c) make iscsit_do_rx_data() initialize ->msg_iter only once.
Fortunately, (c) is doable with minimal work and we are rid of one
the two places where kernel send/recvmsg users would be unhappy with
non-draining behaviour.
Actually, that makes all but one of ->recvmsg() instances iov_iter-clean.
The exception is skcipher_recvmsg() and it also isn't hard to convert
to primitives (iov_iter_get_pages() is needed there). That'll wait
a bit - there's some interplay with ->sendmsg() path for that one.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | drivers/target/iscsi/iscsi_target_util.c | 12 | ||||
-rw-r--r-- | include/linux/skbuff.h | 16 | ||||
-rw-r--r-- | net/core/datagram.c | 54 |
3 files changed, 28 insertions, 54 deletions
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index ce87ce9bdb9c..7c6a95bcb35e 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c | |||
@@ -1326,21 +1326,19 @@ static int iscsit_do_rx_data( | |||
1326 | struct iscsi_conn *conn, | 1326 | struct iscsi_conn *conn, |
1327 | struct iscsi_data_count *count) | 1327 | struct iscsi_data_count *count) |
1328 | { | 1328 | { |
1329 | int data = count->data_length, rx_loop = 0, total_rx = 0, iov_len; | 1329 | int data = count->data_length, rx_loop = 0, total_rx = 0; |
1330 | struct kvec *iov_p; | ||
1331 | struct msghdr msg; | 1330 | struct msghdr msg; |
1332 | 1331 | ||
1333 | if (!conn || !conn->sock || !conn->conn_ops) | 1332 | if (!conn || !conn->sock || !conn->conn_ops) |
1334 | return -1; | 1333 | return -1; |
1335 | 1334 | ||
1336 | memset(&msg, 0, sizeof(struct msghdr)); | 1335 | memset(&msg, 0, sizeof(struct msghdr)); |
1337 | 1336 | iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC, | |
1338 | iov_p = count->iov; | 1337 | count->iov, count->iov_count, data); |
1339 | iov_len = count->iov_count; | ||
1340 | 1338 | ||
1341 | while (total_rx < data) { | 1339 | while (total_rx < data) { |
1342 | rx_loop = kernel_recvmsg(conn->sock, &msg, iov_p, iov_len, | 1340 | rx_loop = sock_recvmsg(conn->sock, &msg, |
1343 | (data - total_rx), MSG_WAITALL); | 1341 | (data - total_rx), MSG_WAITALL); |
1344 | if (rx_loop <= 0) { | 1342 | if (rx_loop <= 0) { |
1345 | pr_debug("rx_loop: %d total_rx: %d\n", | 1343 | pr_debug("rx_loop: %d total_rx: %d\n", |
1346 | rx_loop, total_rx); | 1344 | rx_loop, total_rx); |
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 52cf1bdac0d8..4902f2df90c8 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
@@ -2651,17 +2651,10 @@ int skb_copy_datagram_iter(const struct sk_buff *from, int offset, | |||
2651 | static inline int skb_copy_datagram_msg(const struct sk_buff *from, int offset, | 2651 | static inline int skb_copy_datagram_msg(const struct sk_buff *from, int offset, |
2652 | struct msghdr *msg, int size) | 2652 | struct msghdr *msg, int size) |
2653 | { | 2653 | { |
2654 | /* XXX: stripping const */ | 2654 | return skb_copy_datagram_iter(from, offset, &msg->msg_iter, size); |
2655 | return skb_copy_datagram_iovec(from, offset, (struct iovec *)msg->msg_iter.iov, size); | ||
2656 | } | ||
2657 | int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb, int hlen, | ||
2658 | struct iovec *iov); | ||
2659 | static inline int skb_copy_and_csum_datagram_msg(struct sk_buff *skb, int hlen, | ||
2660 | struct msghdr *msg) | ||
2661 | { | ||
2662 | /* XXX: stripping const */ | ||
2663 | return skb_copy_and_csum_datagram_iovec(skb, hlen, (struct iovec *)msg->msg_iter.iov); | ||
2664 | } | 2655 | } |
2656 | int skb_copy_and_csum_datagram_msg(struct sk_buff *skb, int hlen, | ||
2657 | struct msghdr *msg); | ||
2665 | int skb_copy_datagram_from_iter(struct sk_buff *skb, int offset, | 2658 | int skb_copy_datagram_from_iter(struct sk_buff *skb, int offset, |
2666 | struct iov_iter *from, int len); | 2659 | struct iov_iter *from, int len); |
2667 | int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *frm); | 2660 | int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *frm); |
@@ -2697,8 +2690,7 @@ static inline int memcpy_from_msg(void *data, struct msghdr *msg, int len) | |||
2697 | 2690 | ||
2698 | static inline int memcpy_to_msg(struct msghdr *msg, void *data, int len) | 2691 | static inline int memcpy_to_msg(struct msghdr *msg, void *data, int len) |
2699 | { | 2692 | { |
2700 | /* XXX: stripping const */ | 2693 | return copy_to_iter(data, len, &msg->msg_iter) == len ? 0 : -EFAULT; |
2701 | return memcpy_toiovec((struct iovec *)msg->msg_iter.iov, data, len); | ||
2702 | } | 2694 | } |
2703 | 2695 | ||
2704 | struct skb_checksum_ops { | 2696 | struct skb_checksum_ops { |
diff --git a/net/core/datagram.c b/net/core/datagram.c index b6e303b0f01f..41075ed6bb52 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c | |||
@@ -615,27 +615,25 @@ int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *from) | |||
615 | EXPORT_SYMBOL(zerocopy_sg_from_iter); | 615 | EXPORT_SYMBOL(zerocopy_sg_from_iter); |
616 | 616 | ||
617 | static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, | 617 | static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, |
618 | u8 __user *to, int len, | 618 | struct iov_iter *to, int len, |
619 | __wsum *csump) | 619 | __wsum *csump) |
620 | { | 620 | { |
621 | int start = skb_headlen(skb); | 621 | int start = skb_headlen(skb); |
622 | int i, copy = start - offset; | 622 | int i, copy = start - offset; |
623 | struct sk_buff *frag_iter; | 623 | struct sk_buff *frag_iter; |
624 | int pos = 0; | 624 | int pos = 0; |
625 | int n; | ||
625 | 626 | ||
626 | /* Copy header. */ | 627 | /* Copy header. */ |
627 | if (copy > 0) { | 628 | if (copy > 0) { |
628 | int err = 0; | ||
629 | if (copy > len) | 629 | if (copy > len) |
630 | copy = len; | 630 | copy = len; |
631 | *csump = csum_and_copy_to_user(skb->data + offset, to, copy, | 631 | n = csum_and_copy_to_iter(skb->data + offset, copy, csump, to); |
632 | *csump, &err); | 632 | if (n != copy) |
633 | if (err) | ||
634 | goto fault; | 633 | goto fault; |
635 | if ((len -= copy) == 0) | 634 | if ((len -= copy) == 0) |
636 | return 0; | 635 | return 0; |
637 | offset += copy; | 636 | offset += copy; |
638 | to += copy; | ||
639 | pos = copy; | 637 | pos = copy; |
640 | } | 638 | } |
641 | 639 | ||
@@ -647,26 +645,22 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, | |||
647 | 645 | ||
648 | end = start + skb_frag_size(frag); | 646 | end = start + skb_frag_size(frag); |
649 | if ((copy = end - offset) > 0) { | 647 | if ((copy = end - offset) > 0) { |
650 | __wsum csum2; | 648 | __wsum csum2 = 0; |
651 | int err = 0; | ||
652 | u8 *vaddr; | ||
653 | struct page *page = skb_frag_page(frag); | 649 | struct page *page = skb_frag_page(frag); |
650 | u8 *vaddr = kmap(page); | ||
654 | 651 | ||
655 | if (copy > len) | 652 | if (copy > len) |
656 | copy = len; | 653 | copy = len; |
657 | vaddr = kmap(page); | 654 | n = csum_and_copy_to_iter(vaddr + frag->page_offset + |
658 | csum2 = csum_and_copy_to_user(vaddr + | 655 | offset - start, copy, |
659 | frag->page_offset + | 656 | &csum2, to); |
660 | offset - start, | ||
661 | to, copy, 0, &err); | ||
662 | kunmap(page); | 657 | kunmap(page); |
663 | if (err) | 658 | if (n != copy) |
664 | goto fault; | 659 | goto fault; |
665 | *csump = csum_block_add(*csump, csum2, pos); | 660 | *csump = csum_block_add(*csump, csum2, pos); |
666 | if (!(len -= copy)) | 661 | if (!(len -= copy)) |
667 | return 0; | 662 | return 0; |
668 | offset += copy; | 663 | offset += copy; |
669 | to += copy; | ||
670 | pos += copy; | 664 | pos += copy; |
671 | } | 665 | } |
672 | start = end; | 666 | start = end; |
@@ -691,7 +685,6 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, | |||
691 | if ((len -= copy) == 0) | 685 | if ((len -= copy) == 0) |
692 | return 0; | 686 | return 0; |
693 | offset += copy; | 687 | offset += copy; |
694 | to += copy; | ||
695 | pos += copy; | 688 | pos += copy; |
696 | } | 689 | } |
697 | start = end; | 690 | start = end; |
@@ -744,20 +737,19 @@ __sum16 __skb_checksum_complete(struct sk_buff *skb) | |||
744 | EXPORT_SYMBOL(__skb_checksum_complete); | 737 | EXPORT_SYMBOL(__skb_checksum_complete); |
745 | 738 | ||
746 | /** | 739 | /** |
747 | * skb_copy_and_csum_datagram_iovec - Copy and checksum skb to user iovec. | 740 | * skb_copy_and_csum_datagram_msg - Copy and checksum skb to user iovec. |
748 | * @skb: skbuff | 741 | * @skb: skbuff |
749 | * @hlen: hardware length | 742 | * @hlen: hardware length |
750 | * @iov: io vector | 743 | * @msg: destination |
751 | * | 744 | * |
752 | * Caller _must_ check that skb will fit to this iovec. | 745 | * Caller _must_ check that skb will fit to this iovec. |
753 | * | 746 | * |
754 | * Returns: 0 - success. | 747 | * Returns: 0 - success. |
755 | * -EINVAL - checksum failure. | 748 | * -EINVAL - checksum failure. |
756 | * -EFAULT - fault during copy. Beware, in this case iovec | 749 | * -EFAULT - fault during copy. |
757 | * can be modified! | ||
758 | */ | 750 | */ |
759 | int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb, | 751 | int skb_copy_and_csum_datagram_msg(struct sk_buff *skb, |
760 | int hlen, struct iovec *iov) | 752 | int hlen, struct msghdr *msg) |
761 | { | 753 | { |
762 | __wsum csum; | 754 | __wsum csum; |
763 | int chunk = skb->len - hlen; | 755 | int chunk = skb->len - hlen; |
@@ -765,28 +757,20 @@ int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb, | |||
765 | if (!chunk) | 757 | if (!chunk) |
766 | return 0; | 758 | return 0; |
767 | 759 | ||
768 | /* Skip filled elements. | 760 | if (iov_iter_count(&msg->msg_iter) < chunk) { |
769 | * Pretty silly, look at memcpy_toiovec, though 8) | ||
770 | */ | ||
771 | while (!iov->iov_len) | ||
772 | iov++; | ||
773 | |||
774 | if (iov->iov_len < chunk) { | ||
775 | if (__skb_checksum_complete(skb)) | 761 | if (__skb_checksum_complete(skb)) |
776 | goto csum_error; | 762 | goto csum_error; |
777 | if (skb_copy_datagram_iovec(skb, hlen, iov, chunk)) | 763 | if (skb_copy_datagram_msg(skb, hlen, msg, chunk)) |
778 | goto fault; | 764 | goto fault; |
779 | } else { | 765 | } else { |
780 | csum = csum_partial(skb->data, hlen, skb->csum); | 766 | csum = csum_partial(skb->data, hlen, skb->csum); |
781 | if (skb_copy_and_csum_datagram(skb, hlen, iov->iov_base, | 767 | if (skb_copy_and_csum_datagram(skb, hlen, &msg->msg_iter, |
782 | chunk, &csum)) | 768 | chunk, &csum)) |
783 | goto fault; | 769 | goto fault; |
784 | if (csum_fold(csum)) | 770 | if (csum_fold(csum)) |
785 | goto csum_error; | 771 | goto csum_error; |
786 | if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE)) | 772 | if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE)) |
787 | netdev_rx_csum_fault(skb->dev); | 773 | netdev_rx_csum_fault(skb->dev); |
788 | iov->iov_len -= chunk; | ||
789 | iov->iov_base += chunk; | ||
790 | } | 774 | } |
791 | return 0; | 775 | return 0; |
792 | csum_error: | 776 | csum_error: |
@@ -794,7 +778,7 @@ csum_error: | |||
794 | fault: | 778 | fault: |
795 | return -EFAULT; | 779 | return -EFAULT; |
796 | } | 780 | } |
797 | EXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec); | 781 | EXPORT_SYMBOL(skb_copy_and_csum_datagram_msg); |
798 | 782 | ||
799 | /** | 783 | /** |
800 | * datagram_poll - generic datagram poll | 784 | * datagram_poll - generic datagram poll |