more iov_iter conversion in net/*
Subsystems (19)
Al Viro
maintainerRFC PATCH 1/1 more iov_iter conversion in net/*
->sendmsg() side of that business, now. By the end of it, we
get all ->sendmsg() instances leaving iovec unchanged and ->msg_iter - drained.
1/18: netlink: make the check for "send from tx_ring" deterministic
As discussed last year.
2/18: raw_send_hdrinc(): pass msghdr
Switch from passing msg->iov_iter.iov to passing msg itself
3/18: rawv6_send_hdrinc(): pass msghdr
Ditto
4/18: propagate msghdr all way down to __qp_memcpy_to_queue()
Ditto
5/18: switch rxrpc_send_data() to iov_iter primitives
Convert skb_add_data() to iov_iter; allows to get rid of the explicit
messing with iovec in its only caller - skb_add_data() will keep advancing ->msg_iter for us, so there's no need to similate that manually.
6/18: make the users of rxrpc_kernel_send_data() set kvec-backed msg_iter
properly
Use iov_iter_kvec() there, get rid of set_fs() games - now thatrxrpc_send_data() uses iov_iter primitives, it'll handle ITER_KVEC just fine.
7/18: stash a pointer to msghdr in struct ping_fakehdr
... instead of storing its ->mgs_iter.iov there
8/18: convert tcp_sendmsg() to iov_iter primitives
There's one potentially subtle change here: in case of short
copy from userland, mainline tcp_send_syn_data() discards the skb it has allocated and falls back to normal path, where we'll send as much as possible after rereading the same data again. This patch trims SYN+data skb instead - that way we don't need to copy from the same place twice. I _think_ it's correct, but I'd really appreciate a review of that one.
9/18: switch memcpy_fromiovec()/memcpy_fromiovecend() users tocopy_from_iter()
That takes care of the majority of ->sendmsg() instances.
10/18: tipc ->sendmsg() conversion
This one needs to copy the same data from user potentially more than
once. Sadly, MTU changes can trigger that ;-/
11/18: bury net/core/iovec.c - nothing in there is used anymore
12/18: switch af_alg_make_sg() to iov_iter
With that, all ->sendmsg() instances are converted to iov_iter
primitives and are agnostic wrt the kind of iov_iter they are working with. So's the last remaining ->recvmsg() instance that wasn't kind-agnostic yet. All ->sendmsg() and ->recvmsg() advance ->msg_iter by the amount actually copied and none of them modifies the underlying iovec, etc.
13/18: net/socket.c: fold do_sock_{read,write} into callers
14/18: switch sockets to ->read_iter/->write_iter
15/18: switch vhost get_indirect() to iov_iter, kill memcpy_fromiovec()
16/18: vhost: don't bother with copying iovec in handle_tx()
17/18: vhost: don't bother copying iovecs in handle_rx(), killmemcpy_toiovecend()
18/18: vhost: vhost_scsi_handle_vq() should just use copy_from_user()
... and with that lib/iovec.c is gone - nothing in there has callers
left.
The pile after that one will be dealing with the kernel_sendmsg andkernel_recvmg callers - at that point we can start reaping benefits of consistent way ->msg_iter is handled. Note that after these changes if iov_iter_kvec() is used to initialize ->msg_iter, we don't need the games with get_fs()/set_fs() anymore; just sock_sendmsg()/sock_recvmsg() will do, so quite a few of those kernel_{send,recv}msg() callers will turn into sock_{send,recv}msg() ones.
Al Viro
maintainerPATCH 1/18 netlink: make the check for "send from tx_ring" deterministic
From: Al Viro <[email protected]>
As it is, zero msg_iovlen means that the first iovec in the kernel array of iovecs is left uninitialized, so checking if its ->iov_base is NULL is random. Since the real users of that thing are doing sendto(fd, NULL, 0, ...), they are getting msg_iovlen = 1 and msg_iov[0] = {NULL, 0}, which is what this test is trying to catch. As suggested by davem, let's just check that msg_iovlen was 1 and msg_iov[0].iov_base was NULL - _that_ is well-defined and it catches what we want to catch.
--- net/netlink/af_netlink.c | 4 ++++ 1 file changed, 4 insertions(+)
net/netlink/af_netlink.c +4 -0
@@ -2298,7 +2298,11 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, goto out; } +/* It's a really convoluted way for userland to ask for mmaped +* sendmsg(), but that's what we've got... */ if (netlink_tx_is_mmaped (sk) && + msg->msg_iter.type ==ITER_IOVEC && + msg->msg_iter.nr_segs ==1 && msg->msg_iter.iov->iov_base ==NULL ) { err =netlink_mmap_sendmsg (sk, msg, dst_portid, dst_group, &scm);
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH 2/18 raw_send_hdrinc(): pass msghdr
In reply to Al ViroFrom: Al Viro <[email protected]>
--- net/ipv4/raw.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
net/ipv4/raw.c +3 -4
@@ -337,7 +337,7 @@ int raw_rcv(struct sock *sk, struct sk_buff *skb) }static int raw_send_hdrinc (struct sock *sk,struct flowi4 *fl4, -void *from,size_t length, +struct msghdr *msg,size_t length,struct rtable **rtp,unsigned int flags) {
@@ -382,7 +382,7 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, skb->transport_header = skb->network_header; err = -EFAULT ; -if (memcpy_fromiovecend ((void *)iph, from,0 , length)) +if (memcpy_fromiovecend ((void *)iph, msg->msg_iter.iov,0 , length)) goto error_free; iphlen = iph->ihl *4 ;
@@ -625,8 +625,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, back_from_confirm:if (inet->hdrincl) -/* XXX: stripping const */ - err =raw_send_hdrinc (sk, &fl4, (struct iovec *)msg->msg_iter.iov, len, + err =raw_send_hdrinc (sk, &fl4, msg, len, &rt, msg->msg_flags);else {
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH 3/18 rawv6_send_hdrinc(): pass msghdr
In reply to Al ViroFrom: Al Viro <[email protected]>
--- net/ipv6/raw.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
net/ipv6/raw.c +3 -4
@@ -609,7 +609,7 @@ out:return err; } -static int rawv6_send_hdrinc (struct sock *sk,void *from,int length, +static int rawv6_send_hdrinc (struct sock *sk,struct msghdr *msg,int length,struct flowi6 *fl6,struct dst_entry **dstp,unsigned int flags) {
@@ -648,7 +648,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, skb->ip_summed =CHECKSUM_NONE ; skb->transport_header = skb->network_header; - err =memcpy_fromiovecend ((void *)iph, from,0 , length); + err =memcpy_fromiovecend ((void *)iph, msg->msg_iter.iov,0 , length);if (err) goto error_fault;
@@ -886,8 +886,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, back_from_confirm:if (inet->hdrincl) -/* XXX: stripping const */ - err =rawv6_send_hdrinc (sk, (struct iovec *)msg->msg_iter.iov, len, &fl6, &dst, msg->msg_flags); + err =rawv6_send_hdrinc (sk, msg, len, &fl6, &dst, msg->msg_flags);else {lock_sock (sk); err = ip6_append_data(sk, raw6_getfrag, &rfv,
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH 4/18 propagate msghdr all way down to __qp_memcpy_to_queue()
In reply to Al ViroFrom: Al Viro <[email protected]>
--- drivers/misc/vmw_vmci/vmci_queue_pair.c | 16 ++++++++-------- include/linux/vmw_vmci_api.h | 2 +- net/vmw_vsock/vmci_transport.c | 3 +-- 3 files changed, 10 insertions(+), 11 deletions(-)
drivers/misc/vmw_vmci/vmci_queue_pair.c +8 -8
@@ -370,12 +370,12 @@ static int __qp_memcpy_to_queue(struct vmci_queue *queue, to_copy = size - bytes_copied;if (is_iovec) { -struct iovec *iov = (struct iovec *)src; +struct msghdr *msg = (struct msghdr *)src;int err;/* The iovec will track bytes_copied internally. */ - err =memcpy_fromiovec ((u8 *)va + page_offset, - iov, to_copy); + err =memcpy_from_msg ((u8 *)va + page_offset, + msg, to_copy);if (err !=0 ) {if (kernel_if->host)kunmap (kernel_if->u.h.page[page_index]);
@@ -580,7 +580,7 @@ static int qp_memcpy_from_queue(void *dest,*/ static int qp_memcpy_to_queue_iov (struct vmci_queue *queue,u64 queue_offset, -const void *src, +const void *msg,size_t src_offset,size_t size) {
@@ -588,7 +588,7 @@ static int qp_memcpy_to_queue_iov(struct vmci_queue *queue,* We ignore src_offset because src is really a struct iovec * and will * maintain offset internally. */ -return __qp_memcpy_to_queue (queue, queue_offset, src, size, true); +return __qp_memcpy_to_queue (queue, queue_offset, msg, size, true); }/*
@@ -3223,13 +3223,13 @@ EXPORT_SYMBOL_GPL(vmci_qpair_peek);* of bytes enqueued or < 0 on error. */ ssize_t vmci_qpair_enquev (struct vmci_qp *qpair, -void *iov, +struct msghdr *msg,size_t iov_size,int buf_type) {ssize_t result; -if (!qpair || !iov) +if (!qpair)return VMCI_ERROR_INVALID_ARGS ;qp_lock (qpair);
@@ -3238,7 +3238,7 @@ ssize_t vmci_qpair_enquev(struct vmci_qp *qpair, result =qp_enqueue_locked (qpair->produce_q, qpair->consume_q, qpair->produce_q_size, - iov, iov_size, + msg, iov_size, qp_memcpy_to_queue_iov); if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
include/linux/vmw_vmci_api.h +1 -1
@@ -74,7 +74,7 @@ ssize_t vmci_qpair_dequeue(struct vmci_qp *qpair,ssize_t vmci_qpair_peek (struct vmci_qp *qpair,void *buf,size_t buf_size,int mode);ssize_t vmci_qpair_enquev (struct vmci_qp *qpair, -void *iov,size_t iov_size,int mode); +struct msghdr *msg,size_t iov_size,int mode);ssize_t vmci_qpair_dequev (struct vmci_qp *qpair,struct msghdr *msg,size_t iov_size,int mode); ssize_t vmci_qpair_peekv(struct vmci_qp *qpair, struct msghdr *msg, size_t iov_size,
net/vmw_vsock/vmci_transport.c +1 -2
@@ -1850,8 +1850,7 @@ static ssize_t vmci_transport_stream_enqueue( struct msghdr *msg, size_t len) { -/* XXX: stripping const */ -return vmci_qpair_enquev (vmci_trans (vsk)->qpair, (struct iovec *)msg->msg_iter.iov, len,0 ); +return vmci_qpair_enquev (vmci_trans (vsk)->qpair, msg, len,0 ); }static s64 vmci_transport_stream_has_data (struct vsock_sock *vsk)
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH 5/18 switch rxrpc_send_data() to iov_iter primitives
In reply to Al ViroFrom: Al Viro <[email protected]>
... and switch skb_add_data() to iov_iter *, while we are at it - rxrpc_send_data() is its only caller.
--- include/linux/skbuff.h | 11 +++++------ net/rxrpc/ar-output.c | 43 ++++++++++--------------------------------- 2 files changed, 15 insertions(+), 39 deletions(-)
include/linux/skbuff.h +5 -6
@@ -2484,19 +2484,18 @@ static inline int skb_put_padto(struct sk_buff *skb, unsigned int len) }static inline int skb_add_data (struct sk_buff *skb, -char __user *from,int copy) +struct iov_iter *from,int copy) {const int off = skb->len;if (skb->ip_summed ==CHECKSUM_NONE ) { -int err =0 ; -__wsum csum =csum_and_copy_from_user (from,skb_put (skb, copy), - copy,0 , &err); -if (!err) { +__wsum csum =0 ; +if (csum_and_copy_from_iter (skb_put (skb, copy), copy, + &csum, from) == copy) { skb->csum =csum_block_add (skb->csum, csum, off);return 0 ; } - }else if (!copy_from_user (skb_put (skb, copy), from, copy)) + }else if (copy_from_iter (skb_put (skb, copy), copy, from) == copy)return 0 ;__skb_trim (skb, off);
net/rxrpc/ar-output.c +10 -33
97 lines not on this page · raw message
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH 6/18 make the users of rxrpc_kernel_send_data() set kvec-backed msg_iter properly
In reply to Al ViroFrom: Al Viro <[email protected]>
... which makes the games with set_fs() in rxrpc_kernel_send_data() useless.
--- fs/afs/rxrpc.c | 14 +++++++------- net/rxrpc/ar-output.c | 3 --- 2 files changed, 7 insertions(+), 10 deletions(-)
fs/afs/rxrpc.c +7 -7
@@ -306,8 +306,8 @@ static int afs_send_pages(struct afs_call *call, struct msghdr *msg,_debug ("- range %u-%u%s" , offset, to, msg->msg_flags ?" [more]" :"" ); -iov_iter_init (&msg->msg_iter,WRITE , - (struct iovec *) iov,1 , to - offset); +iov_iter_kvec (&msg->msg_iter,WRITE |ITER_KVEC , + iov,1 , to - offset);/* have to change the state *before* sending the last * packet as RxRPC might give us the reply before it
@@ -384,7 +384,7 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, msg.msg_name =NULL ; msg.msg_namelen =0 ; -iov_iter_init (&msg.msg_iter,WRITE , (struct iovec *)iov,1 , +iov_iter_kvec (&msg.msg_iter,WRITE |ITER_KVEC , iov,1 , call->request_size); msg.msg_control =NULL ; msg.msg_controllen =0 ;
@@ -770,7 +770,7 @@ static int afs_deliver_cm_op_id(struct afs_call *call, struct sk_buff *skb,void afs_send_empty_reply (struct afs_call *call) {struct msghdr msg; -struct iovec iov[1 ]; +struct kvec iov[1 ];_enter ("" );
@@ -778,7 +778,7 @@ void afs_send_empty_reply(struct afs_call *call) iov[0 ].iov_len =0 ; msg.msg_name =NULL ; msg.msg_namelen =0 ; -iov_iter_init (&msg.msg_iter,WRITE , iov,0 ,0 );/* WTF? */ +iov_iter_kvec (&msg.msg_iter,WRITE |ITER_KVEC , iov,0 ,0 );/* WTF? */ msg.msg_control =NULL ; msg.msg_controllen =0 ; msg.msg_flags =0 ;
@@ -805,7 +805,7 @@ void afs_send_empty_reply(struct afs_call *call)void afs_send_simple_reply (struct afs_call *call,const void *buf,size_t len) {struct msghdr msg; -struct iovec iov[1 ]; +struct kvec iov[1 ];int n;_enter ("" );
@@ -814,7 +814,7 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len) iov[0 ].iov_len = len; msg.msg_name =NULL ; msg.msg_namelen =0 ; -iov_iter_init (&msg.msg_iter,WRITE , iov,1 , len); +iov_iter_kvec (&msg.msg_iter,WRITE |ITER_KVEC , iov,1 , len); msg.msg_control =NULL ; msg.msg_controllen =0 ; msg.msg_flags =0 ;
net/rxrpc/ar-output.c +0 -3
@@ -232,10 +232,7 @@ int rxrpc_kernel_send_data(struct rxrpc_call *call, struct msghdr *msg, call->state != RXRPC_CALL_SERVER_SEND_REPLY) { ret = -EPROTO; /* request phase complete for this client call */ } else { -mm_segment_t oldfs =get_fs (); -set_fs (KERNEL_DS ); ret =rxrpc_send_data (NULL , call->socket, call, msg, len); -set_fs (oldfs); }release_sock (&call->socket->sk);
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH 7/18 stash a pointer to msghdr in struct ping_fakehdr
In reply to Al ViroFrom: Al Viro <[email protected]>
--- include/net/ping.h | 2 +- net/ipv4/ping.c | 7 +++---- net/ipv6/ping.c | 3 +-- 3 files changed, 5 insertions(+), 7 deletions(-)
include/net/ping.h +1 -1
@@ -59,7 +59,7 @@ extern struct pingv6_ops pingv6_ops;struct pingfakehdr {struct icmphdr icmph; -struct iovec *iov; +struct msghdr *msg;sa_family_t family;__wsum wcheck; };
net/ipv4/ping.c +3 -4
@@ -602,14 +602,14 @@ int ping_getfrag(void *from, char *to,if (fraglen <sizeof (struct icmphdr ))BUG ();if (csum_partial_copy_fromiovecend (to +sizeof (struct icmphdr ), - pfh->iov,0 , fraglen -sizeof (struct icmphdr ), + pfh->msg->msg_iter.iov,0 , fraglen -sizeof (struct icmphdr ), &pfh->wcheck))return -EFAULT ; }else if (offset <sizeof (struct icmphdr )) {BUG (); }else {if (csum_partial_copy_fromiovecend - (to, pfh->iov, offset -sizeof (struct icmphdr ), + (to, pfh->msg->msg_iter.iov, offset -sizeof (struct icmphdr ), fraglen, &pfh->wcheck))return -EFAULT ; }
@@ -811,8 +811,7 @@ back_from_confirm: pfh.icmph.checksum =0 ; pfh.icmph.un.echo.id = inet->inet_sport; pfh.icmph.un.echo.sequence = user_icmph.un.echo.sequence; -/* XXX: stripping const */ - pfh.iov = (struct iovec *)msg->msg_iter.iov; + pfh.msg = msg; pfh.wcheck =0 ; pfh.family =AF_INET ;
net/ipv6/ping.c +1 -2
@@ -163,8 +163,7 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, pfh.icmph.checksum =0 ; pfh.icmph.un.echo.id = inet->inet_sport; pfh.icmph.un.echo.sequence = user_icmph.icmp6_sequence; -/* XXX: stripping const */ - pfh.iov = (struct iovec *)msg->msg_iter.iov; + pfh.msg = msg; pfh.wcheck =0 ; pfh.family =AF_INET6 ;
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH 8/18 convert tcp_sendmsg() to iov_iter primitives
In reply to Al ViroFrom: Al Viro <[email protected]>
patch is actually smaller than it seems to be - most of it is unindenting the inner loop body in tcp_sendmsg() itself...
the bit in tcp_input.c is going to get reverted very soon - that's what memcpy_from_msg() will become, but not in this commit; let's keep it reasonably contained...
--- include/net/sock.h | 18 ++-- net/ipv4/tcp.c | 233 +++++++++++++++++++++++--------------------------- net/ipv4/tcp_input.c | 2 +- net/ipv4/tcp_output.c | 11 ++- 4 files changed, 123 insertions(+), 141 deletions(-)
include/net/sock.h +8 -10
@@ -1803,27 +1803,25 @@ static inline void sk_nocaps_add(struct sock *sk, netdev_features_t flags) }static inline int skb_do_copy_data_nocache (struct sock *sk,struct sk_buff *skb, -char __user *from,char *to, +struct iov_iter *from,char *to,int copy,int offset) {if (skb->ip_summed ==CHECKSUM_NONE ) { -int err =0 ; -__wsum csum =csum_and_copy_from_user (from, to, copy,0 , &err); -if (err) -return err; +__wsum csum =0 ; +if (csum_and_copy_from_iter (to, copy, &csum, from) != copy) +return -EFAULT ; skb->csum =csum_block_add (skb->csum, csum, offset); }else if (sk->sk_route_caps &NETIF_F_NOCACHE_COPY ) { -if (!access_ok (VERIFY_READ , from, copy) || -__copy_from_user_nocache (to, from, copy)) +if (copy_from_iter_nocache (to, copy, from) != copy)return -EFAULT ; - }else if (copy_from_user (to, from, copy)) + }else if (copy_from_iter (to, copy, from) != copy)return -EFAULT ;return 0 ; }static inline int skb_add_data_nocache (struct sock *sk,struct sk_buff *skb, -char __user *from,int copy) +struct iov_iter *from,int copy) {int err, offset = skb->len;
@@ -1835,7 +1833,7 @@ static inline int skb_add_data_nocache(struct sock *sk, struct sk_buff *skb,return err; } -static inline int skb_copy_to_page_nocache (struct sock *sk,char __user *from, +static inline int skb_copy_to_page_nocache (struct sock *sk,struct iov_iter *from,struct sk_buff *skb,struct page *page,int off,int copy)
net/ipv4/tcp.c +106 -127
283 lines not on this page · raw message
net/ipv4/tcp_input.c +1 -1
@@ -4368,7 +4368,7 @@ int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)if (tcp_try_rmem_schedule (sk, skb, skb->truesize)) goto err_free; -if (memcpy_from_msg (skb_put (skb, size), msg, size)) +if (copy_from_iter (skb_put (skb, size), size, &msg->msg_iter) != size) goto err_free;TCP_SKB_CB (skb)->seq =tcp_sk (sk)->rcv_nxt;
net/ipv4/tcp_output.c +8 -3
@@ -3055,7 +3055,7 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) {struct tcp_sock *tp =tcp_sk (sk);struct tcp_fastopen_request *fo = tp->fastopen_req; -int syn_loss =0 , space, err =0 ; +int syn_loss =0 , space, err =0 , copied;unsigned long last_syn_loss =0 ;struct sk_buff *syn_data;
@@ -3093,11 +3093,16 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) goto fallback; syn_data->ip_summed =CHECKSUM_PARTIAL ;memcpy (syn_data->cb, syn->cb,sizeof (syn->cb)); -if (unlikely (memcpy_fromiovecend (skb_put (syn_data, space), - fo->data->msg_iter.iov,0 , space))) { + copied =copy_from_iter (skb_put (syn_data, space), space, + &fo->data->msg_iter); +if (unlikely (!copied)) {kfree_skb (syn_data); goto fallback; } +if (copied != space) { +skb_trim (syn_data, copied); + space = copied; + }/* No more data pending in inet_wait_for_connect() */ if (space == fo->size)
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH 9/18 switch memcpy_fromiovec()/memcpy_fromiovecend() users to copy_from_iter()
In reply to Al ViroFrom: Al Viro <[email protected]>
That takes care of the majority of ->sendmsg() instances - most of them via memcpy_to_msg() or assorted getfrag() callbacks. One place where we still keep memcpy_fromiovecend() is tipc - there we potentially read the same data over and over; separate patch, that...
--- include/linux/skbuff.h | 3 +-- include/net/udplite.h | 3 +-- net/ipv4/ip_output.c | 6 ++---- net/ipv4/ping.c | 14 +++++++------- net/ipv4/raw.c | 2 +- net/ipv4/tcp_input.c | 2 +- net/ipv6/raw.c | 2 +- 7 files changed, 14 insertions(+), 18 deletions(-)
include/linux/skbuff.h +1 -2
@@ -2692,8 +2692,7 @@ int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci);static inline int memcpy_from_msg (void *data,struct msghdr *msg,int len) { -/* XXX: stripping const */ -return memcpy_fromiovec (data, (struct iovec *)msg->msg_iter.iov, len); +return copy_from_iter (data, len, &msg->msg_iter) == len ?0 : -EFAULT ; }static inline int memcpy_to_msg (struct msghdr *msg,void *data,int len)
include/net/udplite.h +1 -2
@@ -20,8 +20,7 @@ static __inline__ int udplite_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb) { struct msghdr *msg = from; -/* XXX: stripping const */ -return memcpy_fromiovecend (to, (struct iovec *)msg->msg_iter.iov, offset, len); +return copy_from_iter (to, len, &msg->msg_iter) != len ? -EFAULT :0 ; }/* Designate sk as UDP-Lite socket */
net/ipv4/ip_output.c +2 -4
@@ -755,13 +755,11 @@ ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct skstruct msghdr *msg = from;if (skb->ip_summed ==CHECKSUM_PARTIAL ) { -/* XXX: stripping const */ -if (memcpy_fromiovecend (to, (struct iovec *)msg->msg_iter.iov, offset, len) <0 ) +if (copy_from_iter (to, len, &msg->msg_iter) != len)return -EFAULT ; }else {__wsum csum =0 ; -/* XXX: stripping const */ -if (csum_partial_copy_fromiovecend (to, (struct iovec *)msg->msg_iter.iov, offset, len, &csum) <0 ) +if (csum_and_copy_from_iter (to, len, &csum, &msg->msg_iter) != len)return -EFAULT ; skb->csum =csum_block_add (skb->csum, csum, odd); }
net/ipv4/ping.c +7 -7
@@ -599,18 +599,18 @@ int ping_getfrag(void *from, char *to,struct pingfakehdr *pfh = (struct pingfakehdr *)from;if (offset ==0 ) { -if (fraglen <sizeof (struct icmphdr )) + fraglen -=sizeof (struct icmphdr ); +if (fraglen <0 )BUG (); -if (csum_partial_copy_fromiovecend (to +sizeof (struct icmphdr ), - pfh->msg->msg_iter.iov,0 , fraglen -sizeof (struct icmphdr ), - &pfh->wcheck)) +if (csum_and_copy_from_iter (to +sizeof (struct icmphdr ), + fraglen, &pfh->wcheck, + &pfh->msg->msg_iter) != fraglen)return -EFAULT ; }else if (offset <sizeof (struct icmphdr )) {BUG (); }else { -if (csum_partial_copy_fromiovecend - (to, pfh->msg->msg_iter.iov, offset -sizeof (struct icmphdr ), - fraglen, &pfh->wcheck)) +if (csum_and_copy_from_iter (to, fraglen, &pfh->wcheck, + &pfh->msg->msg_iter) != fraglen)return -EFAULT ; }
net/ipv4/raw.c +1 -1
@@ -382,7 +382,7 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, skb->transport_header = skb->network_header; err = -EFAULT ; -if (memcpy_fromiovecend ((void *)iph, msg->msg_iter.iov,0 , length)) +if (memcpy_from_msg (iph, msg, length)) goto error_free; iphlen = iph->ihl *4 ;
net/ipv4/tcp_input.c +1 -1
@@ -4368,7 +4368,7 @@ int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)if (tcp_try_rmem_schedule (sk, skb, skb->truesize)) goto err_free; -if (copy_from_iter (skb_put (skb, size), size, &msg->msg_iter) != size) +if (memcpy_from_msg (skb_put (skb, size), msg, size)) goto err_free;TCP_SKB_CB (skb)->seq =tcp_sk (sk)->rcv_nxt;
net/ipv6/raw.c +1 -1
@@ -648,7 +648,7 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, skb->ip_summed =CHECKSUM_NONE ; skb->transport_header = skb->network_header; - err =memcpy_fromiovecend ((void *)iph, msg->msg_iter.iov,0 , length); + err =memcpy_from_msg (iph, msg, length);if (err) goto error_fault;
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH 10/18 tipc ->sendmsg() conversion
In reply to Al ViroFrom: Al Viro <[email protected]>
--- net/tipc/msg.c | 7 ++----- net/tipc/socket.c | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 7 deletions(-)
net/tipc/msg.c +2 -5
@@ -189,7 +189,6 @@ err:* tipc_msg_build - create buffer chain containing specified header and data * @mhdr: Message header, to be prepended to data * @m: User message -* @offset: Posision in iov to start copying from * @dsz: Total length of user data * @pktmax: Max packet size that can be used * @list: Buffer or chain of buffers to be returned to caller
@@ -221,8 +220,7 @@ int tipc_msg_build(struct net *net, struct tipc_msg *mhdr, struct msghdr *m,__skb_queue_tail (list, skb);skb_copy_to_linear_data (skb, mhdr, mhsz); pktpos = skb->data + mhsz; -if (!dsz || !memcpy_fromiovecend (pktpos, m->msg_iter.iov, offset, - dsz)) +if (copy_from_iter (pktpos, dsz, &m->msg_iter) == dsz)return dsz; rc = -EFAULT ; goto error;
@@ -252,12 +250,11 @@ int tipc_msg_build(struct net *net, struct tipc_msg *mhdr, struct msghdr *m,if (drem < pktrem) pktrem = drem; -if (memcpy_fromiovecend (pktpos, m->msg_iter.iov, offset, pktrem)) { +if (copy_from_iter (pktpos, pktrem, &m->msg_iter) != pktrem) { rc = -EFAULT ; goto error; } drem -= pktrem; - offset += pktrem;if (!drem)break ;
net/tipc/socket.c +12 -2
@@ -733,6 +733,7 @@ static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq,struct net *net =sock_net (sk);struct tipc_msg *mhdr = &tipc_sk (sk)->phdr;struct sk_buff_head head; +struct iov_iter save = msg->msg_iter;uint mtu;int rc;
@@ -758,8 +759,10 @@ new_mtu: rc = dsz;break ; } -if (rc == -EMSGSIZE ) +if (rc == -EMSGSIZE ) { + msg->msg_iter = save; goto new_mtu; + }if (rc != -ELINKCONG )break ;tipc_sk (sk)->link_cong =1 ;
@@ -895,6 +898,7 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,struct sk_buff_head head;struct sk_buff *skb;struct tipc_name_seq *seq = &dest->addr.nameseq; +struct iov_iter save;u32 mtu;long timeo;int rc;
@@ -963,6 +967,7 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,msg_set_hdr_sz (mhdr,BASIC_H_SIZE ); } + save = m->msg_iter; new_mtu: mtu =tipc_node_get_mtu (net, dnode, tsk->portid);__skb_queue_head_init (&head);
@@ -980,8 +985,10 @@ new_mtu: rc = dsz;break ; } -if (rc == -EMSGSIZE ) +if (rc == -EMSGSIZE ) { + m->msg_iter = save; goto new_mtu; + }if (rc != -ELINKCONG )break ; tsk->link_cong =1 ;
@@ -1052,6 +1059,7 @@ static int tipc_send_stream(struct kiocb *iocb, struct socket *sock,long timeo;u32 dnode;uint mtu, send, sent =0 ; +struct iov_iter save;/* Handle implied connection establishment */ if (unlikely (dest)) {
@@ -1078,6 +1086,7 @@ static int tipc_send_stream(struct kiocb *iocb, struct socket *sock, dnode =tsk_peer_node (tsk); next: + save = m->msg_iter; mtu = tsk->max_pkt; send =min_t (uint, dsz - sent,TIPC_MAX_USER_MSG_SIZE );__skb_queue_head_init (&head);
@@ -1097,6 +1106,7 @@ next:if (rc == -EMSGSIZE ) { tsk->max_pkt =tipc_node_get_mtu (net, dnode, portid); + m->msg_iter = save; goto next; }if (rc != -ELINKCONG )
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH 11/18 bury net/core/iovec.c - nothing in there is used anymore
In reply to Al ViroFrom: Al Viro <[email protected]>
--- include/linux/socket.h | 7 --- net/core/Makefile | 2 +- net/core/iovec.c | 137 ------------------------------------------------- 3 files changed, 1 insertion(+), 145 deletions(-) delete mode 100644 net/core/iovec.c
include/linux/socket.h +0 -7
@@ -318,13 +318,6 @@ struct ucred {/* IPX options */ #define IPX_TYPE 1 -extern int csum_partial_copy_fromiovecend (unsigned char *kdata, -struct iovec *iov, -int offset, -unsigned int len,__wsum *csump); -extern unsigned long iov_pages (const struct iovec *iov,int offset, -unsigned long nr_segs); -extern int move_addr_to_kernel (void __user *uaddr,int ulen,struct sockaddr_storage *kaddr);extern int put_cmsg (struct msghdr *,int level,int type,int len,void *data);
net/core/Makefile +1 -1
@@ -2,7 +2,7 @@ # Makefile for the Linux networking core. # -obj-y := sock.o request_sock.o skbuff.o iovec.o datagram.o stream.o scm.o \ +obj-y := sock.o request_sock.o skbuff.o datagram.o stream.o scm.o \ gen_stats.o gen_estimator.o net_namespace.o secure_seq.o flow_dissector.o obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
net/core/iovec.c deleted +0 -137
137 lines not on this page · raw message
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH 12/18 switch af_alg_make_sg() to iov_iter
In reply to Al ViroFrom: Al Viro <[email protected]>
--- crypto/af_alg.c | 40 ++++++++------------------ crypto/algif_hash.c | 45 ++++++++++++------------------ crypto/algif_skcipher.c | 74 ++++++++++++++++++++++--------------------------- include/crypto/if_alg.h | 3 +- 4 files changed, 62 insertions(+), 100 deletions(-)
crypto/af_alg.c +11 -29
@@ -338,49 +338,31 @@ static const struct net_proto_family alg_family = { .owner = THIS_MODULE, }; -int af_alg_make_sg (struct af_alg_sgl *sgl,void __user *addr,int len, -int write) +int af_alg_make_sg (struct af_alg_sgl *sgl,struct iov_iter *iter,int len) { -unsigned long from = (unsigned long )addr; -unsigned long npages; -unsigned off; -int err; -int i; - - err = -EFAULT ; -if (!access_ok (write ?VERIFY_READ :VERIFY_WRITE , addr, len)) - goto out; - - off = from & ~PAGE_MASK ; - npages = (off + len +PAGE_SIZE -1 ) >>PAGE_SHIFT ; -if (npages >ALG_MAX_PAGES ) - npages =ALG_MAX_PAGES ; +size_t off; +ssize_t n; +int npages, i; - err =get_user_pages_fast (from, npages, write, sgl->pages); -if (err <0 ) - goto out; + n =iov_iter_get_pages (iter, sgl->pages, len,ALG_MAX_PAGES , &off); +if (n <0 ) +return n; - npages = err; - err = -EINVAL ; + npages =PAGE_ALIGN (off + n);if (WARN_ON (npages ==0 )) - goto out; - - err =0 ; +return -EINVAL ;sg_init_table (sgl->sg, npages); -for (i =0 ; i < npages; i++) { +for (i =0 , len = n; i < npages; i++) {int plen =min_t (int, len,PAGE_SIZE - off);sg_set_page (sgl->sg + i, sgl->pages[i], plen, off); off =0 ; len -= plen; - err += plen; } - -out: -return err; +return n; }EXPORT_SYMBOL_GPL (af_alg_make_sg);
crypto/algif_hash.c +17 -28
62 lines not on this page · raw message
crypto/algif_skcipher.c +33 -41
100 lines not on this page · raw message
include/crypto/if_alg.h +1 -2
@@ -67,8 +67,7 @@ int af_alg_unregister_type(const struct af_alg_type *type);int af_alg_release (struct socket *sock);int af_alg_accept (struct sock *sk,struct socket *newsock); -int af_alg_make_sg (struct af_alg_sgl *sgl,void __user *addr,int len, -int write); +int af_alg_make_sg (struct af_alg_sgl *sgl,struct iov_iter *iter,int len);void af_alg_free_sg (struct af_alg_sgl *sgl);int af_alg_cmsg_send (struct msghdr *msg,struct af_alg_control *con);
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH 13/18 net/socket.c: fold do_sock_{read,write} into callers
In reply to Al ViroFrom: Al Viro <[email protected]>
--- net/socket.c | 56 +++++++++++++++++++++----------------------------------- 1 file changed, 21 insertions(+), 35 deletions(-)
net/socket.c +21 -35
@@ -845,25 +845,11 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos,return sock->ops->splice_read (sock, ppos, pipe, len, flags); } -static ssize_t do_sock_read (struct msghdr *msg,struct kiocb *iocb, -struct file *file,const struct iovec *iov, -unsigned long nr_segs) -{ -struct socket *sock = file->private_data; - - msg->msg_name =NULL ; - msg->msg_namelen =0 ; - msg->msg_control =NULL ; - msg->msg_controllen =0 ; -iov_iter_init (&msg->msg_iter,READ , iov, nr_segs, iocb->ki_nbytes); - msg->msg_flags = (file->f_flags &O_NONBLOCK ) ?MSG_DONTWAIT :0 ; - -return __sock_recvmsg (iocb, sock, msg, iocb->ki_nbytes, msg->msg_flags); -} -static ssize_t sock_aio_read (struct kiocb *iocb,const struct iovec *iov,unsigned long nr_segs,loff_t pos) { +struct file *file = iocb->ki_filp; +struct socket *sock = file->private_data;struct msghdr msg;if (pos !=0 )
@@ -872,36 +858,36 @@ static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,if (iocb->ki_nbytes ==0 )/* Match SYS5 behaviour */ return 0 ; -return do_sock_read (&msg, iocb, iocb->ki_filp, iov, nr_segs); -} - -static ssize_t do_sock_write (struct msghdr *msg,struct kiocb *iocb, -struct file *file,const struct iovec *iov, -unsigned long nr_segs) -{ -struct socket *sock = file->private_data; - - msg->msg_name =NULL ; - msg->msg_namelen =0 ; - msg->msg_control =NULL ; - msg->msg_controllen =0 ; -iov_iter_init (&msg->msg_iter,WRITE , iov, nr_segs, iocb->ki_nbytes); - msg->msg_flags = (file->f_flags &O_NONBLOCK ) ?MSG_DONTWAIT :0 ; -if (sock->type ==SOCK_SEQPACKET ) - msg->msg_flags |=MSG_EOR ; + msg.msg_name =NULL ; + msg.msg_namelen =0 ; + msg.msg_control =NULL ; + msg.msg_controllen =0 ; +iov_iter_init (&msg.msg_iter,READ , iov, nr_segs, iocb->ki_nbytes); + msg.msg_flags = (file->f_flags &O_NONBLOCK ) ?MSG_DONTWAIT :0 ; -return __sock_sendmsg (iocb, sock, msg, iocb->ki_nbytes); +return __sock_recvmsg (iocb, sock, &msg, iocb->ki_nbytes, msg.msg_flags); }static ssize_t sock_aio_write (struct kiocb *iocb,const struct iovec *iov,unsigned long nr_segs,loff_t pos) { +struct file *file = iocb->ki_filp; +struct socket *sock = file->private_data;struct msghdr msg;if (pos !=0 )return -ESPIPE ; -return do_sock_write (&msg, iocb, iocb->ki_filp, iov, nr_segs); + msg.msg_name =NULL ; + msg.msg_namelen =0 ; + msg.msg_control =NULL ; + msg.msg_controllen =0 ; +iov_iter_init (&msg.msg_iter,WRITE , iov, nr_segs, iocb->ki_nbytes); + msg.msg_flags = (file->f_flags &O_NONBLOCK ) ?MSG_DONTWAIT :0 ; +if (sock->type ==SOCK_SEQPACKET ) + msg.msg_flags |=MSG_EOR ; + +return __sock_sendmsg (iocb, sock, &msg, iocb->ki_nbytes); }/*
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH 14/18 switch sockets to ->read_iter/->write_iter
In reply to Al ViroFrom: Al Viro <[email protected]>
--- net/socket.c | 56 +++++++++++++++++++++++++++----------------------------- 1 file changed, 27 insertions(+), 29 deletions(-)
net/socket.c +27 -29
@@ -113,10 +113,8 @@ unsigned int sysctl_net_busy_read __read_mostly;unsigned int sysctl_net_busy_poll__read_mostly ;#endif -static ssize_t sock_aio_read (struct kiocb *iocb,const struct iovec *iov, -unsigned long nr_segs,loff_t pos); -static ssize_t sock_aio_write (struct kiocb *iocb,const struct iovec *iov, -unsigned long nr_segs,loff_t pos); +static ssize_t sock_read_iter (struct kiocb *iocb,struct iov_iter *to); +static ssize_t sock_write_iter (struct kiocb *iocb,struct iov_iter *from);static int sock_mmap (struct file *file,struct vm_area_struct *vma);static int sock_close (struct inode *inode,struct file *file);
@@ -142,8 +140,10 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos,static const struct file_operations socket_file_ops = { .owner =THIS_MODULE , .llseek = no_llseek, - .aio_read = sock_aio_read, - .aio_write = sock_aio_write, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = sock_read_iter, + .write_iter = sock_write_iter, .poll = sock_poll, .unlocked_ioctl = sock_ioctl, #ifdef CONFIG_COMPAT
@@ -845,49 +845,47 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos,return sock->ops->splice_read (sock, ppos, pipe, len, flags); } -static ssize_t sock_aio_read (struct kiocb *iocb,const struct iovec *iov, -unsigned long nr_segs,loff_t pos) +static ssize_t sock_read_iter (struct kiocb *iocb,struct iov_iter *to) {struct file *file = iocb->ki_filp;struct socket *sock = file->private_data; -struct msghdr msg; +struct msghdr msg = {.msg_iter = *to}; +ssize_t res; + +if (file->f_flags &O_NONBLOCK ) + msg.msg_flags =MSG_DONTWAIT ; -if (pos !=0 ) +if (iocb->ki_pos !=0 )return -ESPIPE ;if (iocb->ki_nbytes ==0 )/* Match SYS5 behaviour */ return 0 ; - msg.msg_name =NULL ; - msg.msg_namelen =0 ; - msg.msg_control =NULL ; - msg.msg_controllen =0 ; -iov_iter_init (&msg.msg_iter,READ , iov, nr_segs, iocb->ki_nbytes); - msg.msg_flags = (file->f_flags &O_NONBLOCK ) ?MSG_DONTWAIT :0 ; - -return __sock_recvmsg (iocb, sock, &msg, iocb->ki_nbytes, msg.msg_flags); + res =__sock_recvmsg (iocb, sock, &msg, + iocb->ki_nbytes, msg.msg_flags); + *to = msg.msg_iter; +return res; } -static ssize_t sock_aio_write (struct kiocb *iocb,const struct iovec *iov, -unsigned long nr_segs,loff_t pos) +static ssize_t sock_write_iter (struct kiocb *iocb,struct iov_iter *from) {struct file *file = iocb->ki_filp;struct socket *sock = file->private_data; -struct msghdr msg; +struct msghdr msg = {.msg_iter = *from}; +ssize_t res; -if (pos !=0 ) +if (iocb->ki_pos !=0 )return -ESPIPE ; - msg.msg_name =NULL ; - msg.msg_namelen =0 ; - msg.msg_control =NULL ; - msg.msg_controllen =0 ; -iov_iter_init (&msg.msg_iter,WRITE , iov, nr_segs, iocb->ki_nbytes); - msg.msg_flags = (file->f_flags &O_NONBLOCK ) ?MSG_DONTWAIT :0 ; +if (file->f_flags &O_NONBLOCK ) + msg.msg_flags =MSG_DONTWAIT ; +if (sock->type ==SOCK_SEQPACKET ) msg.msg_flags |=MSG_EOR ; -return __sock_sendmsg (iocb, sock, &msg, iocb->ki_nbytes); + res =__sock_sendmsg (iocb, sock, &msg, iocb->ki_nbytes); + *from = msg.msg_iter; +return res; }/*
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH 15/18 switch vhost get_indirect() to iov_iter, kill memcpy_fromiovec()
In reply to Al ViroFrom: Al Viro <[email protected]>
--- drivers/vhost/vhost.c | 6 ++++-- include/linux/uio.h | 1 - lib/iovec.c | 25 ------------------------- 3 files changed, 4 insertions(+), 28 deletions(-)
drivers/vhost/vhost.c +4 -2
@@ -1125,6 +1125,7 @@ static int get_indirect(struct vhost_virtqueue *vq,struct vring_desc desc;unsigned int i =0 , count, found =0 ;u32 len =vhost32_to_cpu (vq, indirect->len); +struct iov_iter from;int ret;/* Sanity check */
@@ -1142,6 +1143,7 @@ static int get_indirect(struct vhost_virtqueue *vq,vq_err (vq,"Translation failure %d in indirect.\n" , ret);return ret; } +iov_iter_init (&from,READ , vq->indirect, ret, len);/* We will use the result as an address to read from, so most * architectures only need a compiler barrier here. */
@@ -1164,8 +1166,8 @@ static int get_indirect(struct vhost_virtqueue *vq, i, count);return -EINVAL ; } -if (unlikely (memcpy_fromiovec ((unsigned char *)&desc, - vq->indirect,sizeof desc))) { +if (unlikely (copy_from_iter (&desc,sizeof (desc), &from) != +sizeof (desc))) {vq_err (vq,"Failed indirect descriptor: idx %d, %zx\n" , i, (size_t )vhost64_to_cpu (vq, indirect->addr) + i *sizeof desc);return -EINVAL ;
include/linux/uio.h +0 -1
@@ -135,7 +135,6 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count)size_t csum_and_copy_to_iter (void *addr,size_t bytes,__wsum *csum,struct iov_iter *i);size_t csum_and_copy_from_iter (void *addr,size_t bytes,__wsum *csum,struct iov_iter *i); -int memcpy_fromiovec (unsigned char *kdata,struct iovec *iov,int len);int memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov,int offset,int len); int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata,
lib/iovec.c +0 -25
@@ -3,31 +3,6 @@#include <linux/uio.h> /* -* Copy iovec to kernel. Returns -EFAULT on error. -* -* Note: this modifies the original iovec. -*/ - -int memcpy_fromiovec (unsigned char *kdata,struct iovec *iov,int len) -{ -while (len >0 ) { -if (iov->iov_len) { - int copy = min_t(unsigned int, len, iov->iov_len); -if (copy_from_user (kdata, iov->iov_base, copy)) -return -EFAULT ; - len -= copy; - kdata += copy; - iov->iov_base += copy; - iov->iov_len -= copy; - } - iov++; - } - -return 0 ; -} -EXPORT_SYMBOL (memcpy_fromiovec); - -/* * Copy kernel to iovec. Returns -EFAULT on error. */
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH 16/18 vhost: don't bother with copying iovec in handle_tx()
In reply to Al ViroFrom: Al Viro <[email protected]>
just advance the msg.msg_iter and be done with that.
--- drivers/vhost/net.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/vhost/net.c +5 -4
@@ -336,7 +336,7 @@ static void handle_tx(struct vhost_net *net) {struct vhost_net_virtqueue *nvq = &net->vqs[VHOST_NET_VQ_TX ];struct vhost_virtqueue *vq = &nvq->vq; -unsigned out, in, s; +unsigned out, in;int head;struct msghdr msg = { .msg_name =NULL ,
@@ -395,16 +395,17 @@ static void handle_tx(struct vhost_net *net)break ; }/* Skip header. TODO: support TSO. */ - s =move_iovec_hdr (vq->iov, nvq->hdr, hdr_size, out); len =iov_length (vq->iov, out);iov_iter_init (&msg.msg_iter,WRITE , vq->iov, out, len); +iov_iter_advance (&msg.msg_iter, hdr_size);/* Sanity check */ -if (!len) { +if (!iov_iter_count (&msg.msg_iter)) {vq_err (vq,"Unexpected header len for TX: " "%zd expected %zd\n" , -iov_length (nvq->hdr, s), hdr_size); + len, hdr_size);break ; } + len =iov_iter_count (&msg.msg_iter); zcopy_used = zcopy && len >=VHOST_GOODCOPY_LEN && (nvq->upend_idx + 1) % UIO_MAXIOV !=
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH 17/18 vhost: don't bother copying iovecs in handle_rx(), kill memcpy_toiovecend()
In reply to Al ViroFrom: Al Viro <[email protected]>
--- drivers/vhost/net.c | 79 ++++++++++++++--------------------------------------- include/linux/uio.h | 3 -- lib/iovec.c | 26 ------------------ 3 files changed, 20 insertions(+), 88 deletions(-)
drivers/vhost/net.c +20 -59
@@ -84,10 +84,6 @@ struct vhost_net_ubuf_ref {struct vhost_net_virtqueue {struct vhost_virtqueue vq; -/* hdr is used to store the virtio header. -* Since each iovec has >= 1 byte length, we never need more than -* header length entries to store the header. */ -struct iovec hdr[sizeof (struct virtio_net_hdr_mrg_rxbuf )];size_t vhost_hlen;size_t sock_hlen;/* vhost zerocopy support fields below: */
@@ -235,44 +231,6 @@ static bool vhost_sock_zcopy(struct socket *sock)sock_flag (sock->sk,SOCK_ZEROCOPY ); } -/* Pop first len bytes from iovec. Return number of segments used. */ -static int move_iovec_hdr (struct iovec *from,struct iovec *to, -size_t len,int iov_count) -{ -int seg =0 ; -size_t size; - -while (len && seg < iov_count) { - size =min (from->iov_len, len); - to->iov_base = from->iov_base; - to->iov_len = size; - from->iov_len -= size; - from->iov_base += size; - len -= size; - ++from; - ++to; - ++seg; - } -return seg; -} -/* Copy iovec entries for len bytes from iovec. */ -static void copy_iovec_hdr (const struct iovec *from,struct iovec *to, -size_t len,int iovcount) -{ -int seg =0 ; -size_t size; - -while (len && seg < iovcount) { - size =min (from->iov_len, len); - to->iov_base = from->iov_base; - to->iov_len = size; - len -= size; - ++from; - ++to; - ++seg; - } -} -/* In case of DMA done not in order in lower device driver for some reason. * upend_idx is used to track end of used idx, done_idx is used to track head * of used idx. Once lower device DMA done contiguously, we will signal KVM
@@ -570,9 +528,9 @@ static void handle_rx(struct vhost_net *net) .msg_controllen = 0, .msg_flags = MSG_DONTWAIT, }; -struct virtio_net_hdr_mrg_rxbuf hdr = { - .hdr.flags =0 , - .hdr.gso_type =VIRTIO_NET_HDR_GSO_NONE +struct virtio_net_hdr hdr = { + .flags =0 , + .gso_type =VIRTIO_NET_HDR_GSO_NONE };size_t total_len =0 ;int err, mergeable;
@@ -580,6 +538,7 @@ static void handle_rx(struct vhost_net *net)size_t vhost_hlen, sock_hlen;size_t vhost_len, sock_len;struct socket *sock; +struct iov_iter fixup;mutex_lock (&vq->mutex); sock = vq->private_data;
@@ -624,14 +583,17 @@ static void handle_rx(struct vhost_net *net)break ; }/* We don't need to be notified again. */ -if (unlikely ((vhost_hlen))) -/* Skip header. TODO: support TSO. */ -move_iovec_hdr (vq->iov, nvq->hdr, vhost_hlen, in); -else -/* Copy the header for use in VIRTIO_NET_F_MRG_RXBUF: -* needed because recvmsg can modify msg_iov. */ -copy_iovec_hdr (vq->iov, nvq->hdr, sock_hlen, in); -iov_iter_init (&msg.msg_iter,READ , vq->iov, in, sock_len); +iov_iter_init (&msg.msg_iter,READ , vq->iov, in, vhost_len); + fixup = msg.msg_iter; +if (unlikely ((vhost_hlen))) { +/* We will supply the header ourselves +* TODO: support TSO. */ +iov_iter_advance (&msg.msg_iter, vhost_hlen); + }else { +/* It'll come from socket; we'll need to patch +* ->num_buffers over if VIRTIO_NET_F_MRG_RXBUF */ +iov_iter_advance (&fixup,sizeof (hdr)); + } err = sock->ops->recvmsg (NULL , sock, &msg, sock_len,MSG_DONTWAIT |MSG_TRUNC );/* Userspace might have consumed the packet meanwhile:
@@ -643,18 +605,17 @@ static void handle_rx(struct vhost_net *net)vhost_discard_vq_desc (vq, headcount);continue ; } +/* Supply virtio_net_hdr if VHOST_NET_F_VIRTIO_NET_HDR */ if (unlikely (vhost_hlen) && -memcpy_toiovecend (nvq->hdr, (unsigned char *)&hdr,0 , - vhost_hlen)) { +copy_to_iter (&hdr,sizeof (hdr), &fixup) !=sizeof (hdr)) {vq_err (vq,"Unable to write vnet_hdr at addr %p\n" , vq->iov->iov_base);break ; } -/* TODO: Should check and handle checksum. */ +/* Supply (or replace) ->num_buffers if VIRTIO_NET_F_MRG_RXBUF +* TODO: Should check and handle checksum. */ if (likely (mergeable) && -memcpy_toiovecend (nvq->hdr, (unsigned char *)&headcount, - offsetof(typeof (hdr ), num_buffers), -sizeof hdr.num_buffers)) { +copy_to_iter (&headcount,2 , &fixup) !=2 ) {vq_err (vq,"Failed num_buffers write" );vhost_discard_vq_desc (vq, headcount);break ;
include/linux/uio.h +0 -3
@@ -137,7 +137,4 @@ size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct ioint memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov,int offset,int len); -int memcpy_toiovecend (const struct iovec *v,unsigned char *kdata, -int offset,int len); -#endif
lib/iovec.c +0 -26
@@ -3,32 +3,6 @@#include <linux/uio.h> /* -* Copy kernel to iovec. Returns -EFAULT on error. -*/ - -int memcpy_toiovecend (const struct iovec *iov,unsigned char *kdata, -int offset,int len) -{ -int copy; -for (; len >0 ; ++iov) { -/* Skip over the finished iovecs */ -if (unlikely (offset >= iov->iov_len)) { - offset -= iov->iov_len; -continue ; - } - copy = min_t(unsigned int, iov->iov_len - offset, len); -if (copy_to_user (iov->iov_base + offset, kdata, copy)) -return -EFAULT ; - offset =0 ; - kdata += copy; - len -= copy; - } - -return 0 ; -} -EXPORT_SYMBOL (memcpy_toiovecend); - -/* * Copy iovec to kernel. Returns -EFAULT on error. */
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH 18/18 vhost: vhost_scsi_handle_vq() should just use copy_from_user()
In reply to Al ViroFrom: Al Viro <[email protected]>
it has just verified that it asks no more than the length of the first segment of iovec.
And with that the last user of stuff in lib/iovec.c is gone. RIP.
--- drivers/vhost/scsi.c | 2 +- include/linux/uio.h | 2 -- lib/Makefile | 2 +- lib/iovec.c | 36 ------------------------------------ 4 files changed, 2 insertions(+), 40 deletions(-) delete mode 100644 lib/iovec.c
drivers/vhost/scsi.c +1 -1
@@ -1079,7 +1079,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) req_size, vq->iov[0].iov_len);break ; } - ret =memcpy_fromiovecend (req, &vq->iov[0 ],0 , req_size); + ret =copy_from_user (req, vq->iov[0 ].iov_base, req_size);if (unlikely (ret)) {vq_err (vq,"Faulted on virtio_scsi_cmd_req\n" );break ;
include/linux/uio.h +0 -2
@@ -135,6 +135,4 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count)size_t csum_and_copy_to_iter (void *addr,size_t bytes,__wsum *csum,struct iov_iter *i);size_t csum_and_copy_from_iter (void *addr,size_t bytes,__wsum *csum,struct iov_iter *i); -int memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov, -int offset,int len);#endif
lib/Makefile +1 -1
@@ -24,7 +24,7 @@ obj-y += lockref.o obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \ - gcd.o lcm.o list_sort.o uuid.o flex_array.o iovec.o clz_ctz.o \ + gcd.o lcm.o list_sort.o uuid.o flex_array.o clz_ctz.o \ bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o \ percpu-refcount.o percpu_ida.o rhashtable.o reciprocal_div.o obj-y += string_helpers.o
lib/iovec.c deleted +0 -36
@@ -1,36 +0,0 @@ -#include <linux/uaccess.h> -#include <linux/export.h> -#include <linux/uio.h> - -/* -* Copy iovec to kernel. Returns -EFAULT on error. -*/ - -int memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov, -int offset,int len) -{ -/* No data? Done! */ -if (len ==0 ) -return 0 ; - -/* Skip over the finished iovecs */ -while (offset >= iov->iov_len) { - offset -= iov->iov_len; - iov++; - } - -while (len >0 ) { -u8 __user *base = iov->iov_base + offset; - int copy = min_t(unsigned int, len, iov->iov_len - offset); - - offset =0 ; -if (copy_from_user (kdata, base, copy)) -return -EFAULT ; - len -= copy; - kdata += copy; - iov++; - } - -return 0 ; -} -EXPORT_SYMBOL (memcpy_fromiovecend);
Signature · 1 line
2.1.4
Al Viro
maintainerQuoted 54 lines · Al Viro
->sendmsg() side of that business, now. By the end of it, weget all ->sendmsg() instances leaving iovec unchanged and ->msg_iter - drained.
1/18: netlink: make the check for "send from
tx_ring" deterministic
As discussed last year.
2/18:raw_send_hdrinc(): pass msghdrSwitch from passing msg->iov_iter.iov to passing msg itself3/18:
rawv6_send_hdrinc(): pass msghdr
Ditto
4/18: propagate msghdr all way down to__qp_memcpy_to_queue()
Ditto
5/18: switchrxrpc_send_data()toiov_iterprimitives
Convertskb_add_data()toiov_iter; allows to get rid of the explicit
messing with iovec in its only caller -skb_add_data()will keep advancing ->msg_iter for us, so there's no need to similate that manually.
6/18: make the users ofrxrpc_kernel_send_data()set kvec-backedmsg_iter
properly
Useiov_iter_kvec()there, get rid ofset_fs()games - now thatrxrpc_send_data()usesiov_iterprimitives, it'll handleITER_KVECjust fine.
7/18: stash a pointer to msghdr in structping_fakehdr... instead of storing its ->mgs_iter.iov there8/18: convert
tcp_sendmsg()toiov_iterprimitives
There's one potentially subtle change here: in case of short
copy from userland, mainlinetcp_send_syn_data()discards the skb it has allocated and falls back to normal path, where we'll send as much as possible after rereading the same data again. This patch trims SYN+data skb instead - that way we don't need to copy from the same place twice. I _think_ it's correct, but I'd really appreciate a review of that one.
9/18: switch memcpy_fromiovec()/memcpy_fromiovecend() users tocopy_from_iter()That takes care of the majority of ->sendmsg() instances.10/18: tipc ->sendmsg() conversion
This one needs to copy the same data from user potentially more than
once. Sadly, MTU changes can trigger that ;-/
11/18: burynet/core/iovec.c- nothing in there is used anymore
12/18: switchaf_alg_make_sg()toiov_iterWith that, all ->sendmsg() instances are converted to iov_iterprimitives and are agnostic wrt the kind of
iov_iterthey are working with. So's the last remaining ->recvmsg() instance that wasn't kind-agnostic yet. All ->sendmsg() and ->recvmsg() advance ->msg_iter by the amount actually copied and none of them modifies the underlying iovec, etc.
13/18:net/socket.c: fold do_sock_{read,write} into callers
14/18: switch sockets to ->read_iter/->write_iter
15/18: switch vhostget_indirect()toiov_iter, killmemcpy_fromiovec()
16/18: vhost: don't bother with copying iovec inhandle_tx()
17/18: vhost: don't bother copying iovecs inhandle_rx(), killmemcpy_toiovecend()
18/18: vhost:vhost_scsi_handle_vq()should just usecopy_from_user()
... and with thatlib/iovec.cis gone - nothing in there has callers
left.
Quoted 7 lines
The pile after that one will be dealing with the
kernel_sendmsgandkernel_recvmgcallers - at that point we can start reaping benefits of consistent way ->msg_iter is handled. Note that after these changes ifiov_iter_kvec()is used to initialize ->msg_iter, we don't need the games with get_fs()/set_fs() anymore; just sock_sendmsg()/sock_recvmsg() will do, so quite a few of those kernel_{send,recv}msg() callers will turn into sock_{send,recv}msg() ones.
FWIW, for those who prefer to review stuff in git, this pile is ingit://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git for-davem, and diffstat is
crypto/af_alg.c | 40 ++---- crypto/algif_hash.c | 45 +++--- crypto/algif_skcipher.c | 74 +++++----- drivers/misc/vmw_vmci/vmci_queue_pair.c | 16 +-- drivers/vhost/net.c | 88 ++++-------- drivers/vhost/scsi.c | 2 +- drivers/vhost/vhost.c | 6 +- fs/afs/rxrpc.c | 14 +- include/crypto/if_alg.h | 3 +- include/linux/skbuff.h | 14 +- include/linux/socket.h | 7 - include/linux/uio.h | 6 - include/linux/vmw_vmci_api.h | 2 +- include/net/ping.h | 2 +- include/net/sock.h | 18 ++- include/net/udplite.h | 3 +- lib/Makefile | 2 +- lib/iovec.c | 87 ------------ net/core/Makefile | 2 +- net/core/iovec.c | 137 ------------------- net/ipv4/ip_output.c | 6 +- net/ipv4/ping.c | 17 ++- net/ipv4/raw.c | 7 +- net/ipv4/tcp.c | 233 +++++++++++++++----------------- net/ipv4/tcp_output.c | 11 +- net/ipv6/ping.c | 3 +- net/ipv6/raw.c | 7 +- net/netlink/af_netlink.c | 4 + net/rxrpc/ar-output.c | 46 ++----- net/socket.c | 76 ++++------- net/tipc/msg.c | 7 +- net/tipc/socket.c | 14 +- net/vmw_vsock/vmci_transport.c | 3 +- 33 files changed, 316 insertions(+), 686 deletions(-)
Please, review.
David Miller
maintainerFrom: Al Viro <[email protected]>
Date: Sat, 31 Jan 2015 03:55:13 +0000
Quoted 3 lines
->sendmsg() side of that business, now. By the end of it, weget all ->sendmsg() instances leaving iovec unchanged and ->msg_iter - drained.
...
Quoted 7 lines
The pile after that one will be dealing with the
kernel_sendmsgandkernel_recvmgcallers - at that point we can start reaping benefits of consistent way ->msg_iter is handled. Note that after these changes ifiov_iter_kvec()is used to initialize ->msg_iter, we don't need the games with get_fs()/set_fs() anymore; just sock_sendmsg()/sock_recvmsg() will do, so quite a few of those kernel_{send,recv}msg() callers will turn into sock_{send,recv}msg() ones.
The content of this series looks fine, but I really would like you to put proper "subsystem: " prefixes into the commit log header lines of these commits.
Patch 2 and 3 should use "ipv6: ", patch #4 should use whatever the name of that device driver "vmw_vmci: " or similar, etc.
Thanks.
Al Viro
maintainerQuoted 15 lines · David Miller
From: Al Viro <[email protected]>
Date: Sat, 31 Jan 2015 03:55:13 +0000Quoted 3 lines
->sendmsg() side of that business, now. By the end of it, weget all ->sendmsg() instances leaving iovec unchanged and ->msg_iter - drained.
...
Quoted 7 lines
The pile after that one will be dealing with the
kernel_sendmsgandkernel_recvmgcallers - at that point we can start reaping benefits of consistent way ->msg_iter is handled. Note that after these changes ifiov_iter_kvec()is used to initialize ->msg_iter, we don't need the games with get_fs()/set_fs() anymore; just sock_sendmsg()/sock_recvmsg() will do, so quite a few of those kernel_{send,recv}msg() callers will turn into sock_{send,recv}msg() ones.
Quoted 6 lines
The content of this series looks fine, but I really would like you to put proper "subsystem: " prefixes into the commit log header lines of these commits.
Patch 2 and 3 should use "ipv6: ", patch #4 should use whatever the name of that device driver "
vmw_vmci: " or similar, etc.
Point... Are you OK with tcp_send_syn_data() change in 8/18? Basically, tcp_sendmsg() treats short copy from userland as "send as much as we can, stop at the first point where copy_from_user() fails", same as write(), etc.; that much is unchanged, but the current mainline has a strange behaviour in case when short copy happens within what would be packed into SYN packet - if that happens, it still sends as much as possible, but it falls back to separate SYN. With this patch it simply sends shorter SYN+data packet instead. The reason I went that way is that I wanted to avoid copying the same data from userland twice and it was easy to do; I can preserve the current mainline behaviour, but it'll cost making a backup copy of ->msg_iter in tcp_send_syn_data(), only to never use it in normal case *and* do piles of extra work (extra packet to send, repeated copying from userland) in case of short copy. Is there any reason not to combine SYN+data in case of short copy? Again, we do send exact same data, return the same value, etc. - you need tcpdump to see the difference.
Al, off to figure out the proper Cc: for all those commits, so that git-send-email would DTRT - if I need to edit commit messages, might as well do that at the same time...
David Miller
maintainerFrom: Al Viro <[email protected]>
Date: Mon, 2 Feb 2015 06:53:39 +0000
Quoted 7 lines
Point... Are you OK with
tcp_send_syn_data()change in 8/18? Basically,tcp_sendmsg()treats short copy from userland as "send as much as we can, stop at the first point wherecopy_from_user()fails", same aswrite(), etc.; that much is unchanged, but the current mainline has a strange behaviour in case when short copy happens within what would be packed into SYN packet - if that happens, it still sends as much as possible, but it falls back to separate SYN. With this patch it simply sends shorter SYN+data packet instead.
Quoted 8 lines
The reason I went that way is that I wanted to avoid copying the same data from userland twice and it was easy to do; I can preserve the current mainline behaviour, but it'll cost making a backup copy of ->msg_iter in
tcp_send_syn_data(), only to never use it in normal case *and* do piles of extra work (extra packet to send, repeated copying from userland) in case of short copy. Is there any reason not to combine SYN+data in case of short copy? Again, we do send exact same data, return the same value, etc. - you need tcpdump to see the difference.
I think dropping down to plain SYN in the short copy case was just based upon a blanket decision to not do SYN+DATA if anything out of the ordinary happens, rathe than an explicit policy decision. So that change should be OK.
Al Viro
maintainerQuoted 3 lines · Al Viro
Al, off to figure out the proper Cc: for all those commits, so that git-send-email would DTRT - if I need to edit commit messages, might as well do that at the same time...
Done, vfs.git#for-davem force-pushed; same contents, all changes are in commit messages.
Al Viro
maintainerPATCH v2 1/18 netlink: make the check for "send from tx_ring" deterministic
In reply to Al ViroFrom: Al Viro <[email protected]>
As it is, zero msg_iovlen means that the first iovec in the kernel array of iovecs is left uninitialized, so checking if its ->iov_base is NULL is random. Since the real users of that thing are doing sendto(fd, NULL, 0, ...), they are getting msg_iovlen = 1 and msg_iov[0] = {NULL, 0}, which is what this test is trying to catch. As suggested by davem, let's just check that msg_iovlen was 1 and msg_iov[0].iov_base was NULL - _that_ is well-defined and it catches what we want to catch.
--- net/netlink/af_netlink.c | 4 ++++ 1 file changed, 4 insertions(+)
net/netlink/af_netlink.c +4 -0
@@ -2298,7 +2298,11 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, goto out; } +/* It's a really convoluted way for userland to ask for mmaped +* sendmsg(), but that's what we've got... */ if (netlink_tx_is_mmaped (sk) && + msg->msg_iter.type ==ITER_IOVEC && + msg->msg_iter.nr_segs ==1 && msg->msg_iter.iov->iov_base ==NULL ) { err =netlink_mmap_sendmsg (sk, msg, dst_portid, dst_group, &scm);
Signature · 1 line
2.1.4
Re: [PATCH v2 01/18] netlink: make the check for "send from tx_ring" deterministic
Hello.
Quoted 21 lines · Al Viro
From: Al Viro <[email protected]>
As it is, zero
msg_iovlenmeans that the first iovec in the kernel array of iovecs is left uninitialized, so checking if its ->iov_base is NULL is random. Since the real users of that thing are doingsendto(fd, NULL, 0, ...), they are gettingmsg_iovlen= 1 and msg_iov[0] = {NULL, 0}, which is what this test is trying to catch. As suggested by davem, let's just check thatmsg_iovlenwas 1 and msg_iov[0].iov_base was NULL - _that_ is well-defined and it catches what we want to catch.Signed-off-by Al Viro <[email protected]>--- net/netlink/af_netlink.c | 4 ++++ 1 file changed, 4 insertions(+)net/netlink/af_netlink.c +0
-0
net/netlink/af_netlink.c static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, · line 2302
Quoted 5 lines
net/netlink/af_netlink.c +2
-0@@ -2298,7 +2298,11 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, goto out; } +/* It's a really convoluted way for userland to ask for mmaped +* sendmsg(), but that's what we've got... */
Hmm, not sure why DaveM hasn't commented on this broken comment formatting
(perhaps he was going to fix it while applying?). The preferred comment style in the networking code is:
/* bla
* bla
*/
WBR, Sergei
David Miller
maintainerRe: [PATCH v2 01/18] netlink: make the check for "send from tx_ring" deterministic
From: Sergei Shtylyov <[email protected]>
Date: Mon, 02 Feb 2015 16:14:16 +0300
Quoted 11 lines · Al Viro
net/netlink/af_netlink.c static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, · line 2302
Quoted 5 lines
From: Al Viro <[email protected]>
+ /* It's a really convoluted way for userland to ask for mmaped
net/netlink/af_netlink.c +1
-0+* sendmsg(), but that's what we've got... */ Hmm, not sure why DaveM hasn't commented on this broken comment formatting (perhaps he was going to fix it while applying?). The preferred comment style in the networking code is:
Quoted 3 lines
/* bla
* bla
*/
Indeed, Al can you please audit your whole series for this issue and respin?
Please also explicitly give me the GIT url to pull from each time you post the series.
Thanks.
Al Viro
maintainerRe: [PATCH v2 01/18] netlink: make the check for "send from tx_ring" deterministic
Quoted 2 lines · David Miller
Indeed, Al can you please audit your whole series for this issue and respin?
Done, will repost in followups to this one.
Quoted 2 lines
Please also explicitly give me the GIT url to pull from each time you post the series.
OK, it's been force-pushed togit://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git for-davem
Shortlog:
Al Viro (18):
netlink: make the check for "send from tx_ring" deterministic
ipv4: raw_send_hdrinc(): pass msghdr
ipv6: rawv6_send_hdrinc(): pass msghdr
vmci: propagate msghdr all way down to __qp_memcpy_to_queue()
rxrpc: switch rxrpc_send_data() to iov_iter primitives
rxrpc: make the users of rxrpc_kernel_send_data() set kvec-backed msg_iter properly
ip: stash a pointer to msghdr in struct ping_fakehdr
ip: convert tcp_sendmsg() to iov_iter primitives
net: switch memcpy_fromiovec()/memcpy_fromiovecend() users to copy_from_iter()
tipc: tipc ->sendmsg() conversion
net: bury net/core/iovec.c - nothing in there is used anymore
crypto: switch af_alg_make_sg() to iov_iter
net/socket.c: fold do_sock_{read,write} into callers
net: switch sockets to ->read_iter/->write_iter
vhost: switch vhost get_indirect() to iov_iter, kill memcpy_fromiovec()
vhost: don't bother with copying iovec in handle_tx()
vhost: don't bother copying iovecs in handle_rx(), kill memcpy_toiovecend()
vhost: vhost_scsi_handle_vq() should just use copy_from_user()
Diffstat:
crypto/af_alg.c | 40 ++---- crypto/algif_hash.c | 45 +++--- crypto/algif_skcipher.c | 74 +++++----- drivers/misc/vmw_vmci/vmci_queue_pair.c | 16 +-- drivers/vhost/net.c | 91 ++++--------- drivers/vhost/scsi.c | 2 +- drivers/vhost/vhost.c | 6 +- fs/afs/rxrpc.c | 14 +- include/crypto/if_alg.h | 3 +- include/linux/skbuff.h | 14 +- include/linux/socket.h | 7 - include/linux/uio.h | 6 - include/linux/vmw_vmci_api.h | 2 +- include/net/ping.h | 2 +- include/net/sock.h | 18 ++- include/net/udplite.h | 3 +- lib/Makefile | 2 +- lib/iovec.c | 87 ------------ net/core/Makefile | 2 +- net/core/iovec.c | 137 ------------------- net/ipv4/ip_output.c | 6 +- net/ipv4/ping.c | 17 ++- net/ipv4/raw.c | 7 +- net/ipv4/tcp.c | 233 +++++++++++++++----------------- net/ipv4/tcp_output.c | 11 +- net/ipv6/ping.c | 3 +- net/ipv6/raw.c | 7 +- net/netlink/af_netlink.c | 5 + net/rxrpc/ar-output.c | 46 ++----- net/socket.c | 76 ++++------- net/tipc/msg.c | 7 +- net/tipc/socket.c | 14 +- net/vmw_vsock/vmci_transport.c | 3 +- 33 files changed, 320 insertions(+), 686 deletions(-) delete mode 100644 lib/iovec.c delete mode 100644 net/core/iovec.c
Al Viro
maintainerPATCH v3 1/18 netlink: make the check for "send from tx_ring" deterministic
From: Al Viro <[email protected]>
As it is, zero msg_iovlen means that the first iovec in the kernel array of iovecs is left uninitialized, so checking if its ->iov_base is NULL is random. Since the real users of that thing are doing sendto(fd, NULL, 0, ...), they are getting msg_iovlen = 1 and msg_iov[0] = {NULL, 0}, which is what this test is trying to catch. As suggested by davem, let's just check that msg_iovlen was 1 and msg_iov[0].iov_base was NULL - _that_ is well-defined and it catches what we want to catch.
--- net/netlink/af_netlink.c | 5 +++++ 1 file changed, 5 insertions(+)
net/netlink/af_netlink.c +5 -0
@@ -2298,7 +2298,12 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, goto out; } +/* It's a really convoluted way for userland to ask for mmaped +* sendmsg(), but that's what we've got... +*/ if (netlink_tx_is_mmaped (sk) && + msg->msg_iter.type ==ITER_IOVEC && + msg->msg_iter.nr_segs ==1 && msg->msg_iter.iov->iov_base ==NULL ) { err =netlink_mmap_sendmsg (sk, msg, dst_portid, dst_group, &scm);
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v3 2/18 ipv4: raw_send_hdrinc(): pass msghdr
In reply to Al ViroFrom: Al Viro <[email protected]>
Switch from passing msg->iov_iter.iov to passing msg itself
--- net/ipv4/raw.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
net/ipv4/raw.c +3 -4
@@ -337,7 +337,7 @@ int raw_rcv(struct sock *sk, struct sk_buff *skb) }static int raw_send_hdrinc (struct sock *sk,struct flowi4 *fl4, -void *from,size_t length, +struct msghdr *msg,size_t length,struct rtable **rtp,unsigned int flags) {
@@ -382,7 +382,7 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, skb->transport_header = skb->network_header; err = -EFAULT ; -if (memcpy_fromiovecend ((void *)iph, from,0 , length)) +if (memcpy_fromiovecend ((void *)iph, msg->msg_iter.iov,0 , length)) goto error_free; iphlen = iph->ihl *4 ;
@@ -625,8 +625,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, back_from_confirm:if (inet->hdrincl) -/* XXX: stripping const */ - err =raw_send_hdrinc (sk, &fl4, (struct iovec *)msg->msg_iter.iov, len, + err =raw_send_hdrinc (sk, &fl4, msg, len, &rt, msg->msg_flags);else {
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v3 3/18 ipv6: rawv6_send_hdrinc(): pass msghdr
In reply to Al ViroFrom: Al Viro <[email protected]>
Switch from passing msg->iov_iter.iov to passing msg itself
--- net/ipv6/raw.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
net/ipv6/raw.c +3 -4
@@ -609,7 +609,7 @@ out:return err; } -static int rawv6_send_hdrinc (struct sock *sk,void *from,int length, +static int rawv6_send_hdrinc (struct sock *sk,struct msghdr *msg,int length,struct flowi6 *fl6,struct dst_entry **dstp,unsigned int flags) {
@@ -648,7 +648,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, skb->ip_summed =CHECKSUM_NONE ; skb->transport_header = skb->network_header; - err =memcpy_fromiovecend ((void *)iph, from,0 , length); + err =memcpy_fromiovecend ((void *)iph, msg->msg_iter.iov,0 , length);if (err) goto error_fault;
@@ -886,8 +886,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, back_from_confirm:if (inet->hdrincl) -/* XXX: stripping const */ - err =rawv6_send_hdrinc (sk, (struct iovec *)msg->msg_iter.iov, len, &fl6, &dst, msg->msg_flags); + err =rawv6_send_hdrinc (sk, msg, len, &fl6, &dst, msg->msg_flags);else {lock_sock (sk); err = ip6_append_data(sk, raw6_getfrag, &rfv,
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v3 4/18 vmci: propagate msghdr all way down to __qp_memcpy_to_queue()
In reply to Al ViroFrom: Al Viro <[email protected]>
Switch from passing msg->iov_iter.iov to passing msg itself
--- drivers/misc/vmw_vmci/vmci_queue_pair.c | 16 ++++++++-------- include/linux/vmw_vmci_api.h | 2 +- net/vmw_vsock/vmci_transport.c | 3 +-- 3 files changed, 10 insertions(+), 11 deletions(-)
drivers/misc/vmw_vmci/vmci_queue_pair.c +8 -8
@@ -370,12 +370,12 @@ static int __qp_memcpy_to_queue(struct vmci_queue *queue, to_copy = size - bytes_copied;if (is_iovec) { -struct iovec *iov = (struct iovec *)src; +struct msghdr *msg = (struct msghdr *)src;int err;/* The iovec will track bytes_copied internally. */ - err =memcpy_fromiovec ((u8 *)va + page_offset, - iov, to_copy); + err =memcpy_from_msg ((u8 *)va + page_offset, + msg, to_copy);if (err !=0 ) {if (kernel_if->host)kunmap (kernel_if->u.h.page[page_index]);
@@ -580,7 +580,7 @@ static int qp_memcpy_from_queue(void *dest,*/ static int qp_memcpy_to_queue_iov (struct vmci_queue *queue,u64 queue_offset, -const void *src, +const void *msg,size_t src_offset,size_t size) {
@@ -588,7 +588,7 @@ static int qp_memcpy_to_queue_iov(struct vmci_queue *queue,* We ignore src_offset because src is really a struct iovec * and will * maintain offset internally. */ -return __qp_memcpy_to_queue (queue, queue_offset, src, size, true); +return __qp_memcpy_to_queue (queue, queue_offset, msg, size, true); }/*
@@ -3223,13 +3223,13 @@ EXPORT_SYMBOL_GPL(vmci_qpair_peek);* of bytes enqueued or < 0 on error. */ ssize_t vmci_qpair_enquev (struct vmci_qp *qpair, -void *iov, +struct msghdr *msg,size_t iov_size,int buf_type) {ssize_t result; -if (!qpair || !iov) +if (!qpair)return VMCI_ERROR_INVALID_ARGS ;qp_lock (qpair);
@@ -3238,7 +3238,7 @@ ssize_t vmci_qpair_enquev(struct vmci_qp *qpair, result =qp_enqueue_locked (qpair->produce_q, qpair->consume_q, qpair->produce_q_size, - iov, iov_size, + msg, iov_size, qp_memcpy_to_queue_iov); if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
include/linux/vmw_vmci_api.h +1 -1
@@ -74,7 +74,7 @@ ssize_t vmci_qpair_dequeue(struct vmci_qp *qpair,ssize_t vmci_qpair_peek (struct vmci_qp *qpair,void *buf,size_t buf_size,int mode);ssize_t vmci_qpair_enquev (struct vmci_qp *qpair, -void *iov,size_t iov_size,int mode); +struct msghdr *msg,size_t iov_size,int mode);ssize_t vmci_qpair_dequev (struct vmci_qp *qpair,struct msghdr *msg,size_t iov_size,int mode); ssize_t vmci_qpair_peekv(struct vmci_qp *qpair, struct msghdr *msg, size_t iov_size,
net/vmw_vsock/vmci_transport.c +1 -2
@@ -1850,8 +1850,7 @@ static ssize_t vmci_transport_stream_enqueue( struct msghdr *msg, size_t len) { -/* XXX: stripping const */ -return vmci_qpair_enquev (vmci_trans (vsk)->qpair, (struct iovec *)msg->msg_iter.iov, len,0 ); +return vmci_qpair_enquev (vmci_trans (vsk)->qpair, msg, len,0 ); }static s64 vmci_transport_stream_has_data (struct vsock_sock *vsk)
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v3 5/18 rxrpc: switch rxrpc_send_data() to iov_iter primitives
In reply to Al ViroFrom: Al Viro <[email protected]>
Convert skb_add_data() to iov_iter; allows to get rid of the explicit messing with iovec in its only caller - skb_add_data() will keep advancing ->msg_iter for us, so there's no need to similate that manually.
--- include/linux/skbuff.h | 11 +++++------ net/rxrpc/ar-output.c | 43 ++++++++++--------------------------------- 2 files changed, 15 insertions(+), 39 deletions(-)
include/linux/skbuff.h +5 -6
@@ -2484,19 +2484,18 @@ static inline int skb_put_padto(struct sk_buff *skb, unsigned int len) }static inline int skb_add_data (struct sk_buff *skb, -char __user *from,int copy) +struct iov_iter *from,int copy) {const int off = skb->len;if (skb->ip_summed ==CHECKSUM_NONE ) { -int err =0 ; -__wsum csum =csum_and_copy_from_user (from,skb_put (skb, copy), - copy,0 , &err); -if (!err) { +__wsum csum =0 ; +if (csum_and_copy_from_iter (skb_put (skb, copy), copy, + &csum, from) == copy) { skb->csum =csum_block_add (skb->csum, csum, off);return 0 ; } - }else if (!copy_from_user (skb_put (skb, copy), from, copy)) + }else if (copy_from_iter (skb_put (skb, copy), copy, from) == copy)return 0 ;__skb_trim (skb, off);
net/rxrpc/ar-output.c +10 -33
97 lines not on this page · raw message
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v3 6/18 rxrpc: make the users of rxrpc_kernel_send_data() set kvec-backed msg_iter properly
In reply to Al ViroFrom: Al Viro <[email protected]>
Use iov_iter_kvec() there, get rid of set_fs() games - now that rxrpc_send_data() uses iov_iter primitives, it'll handle ITER_KVEC just fine.
--- fs/afs/rxrpc.c | 14 +++++++------- net/rxrpc/ar-output.c | 3 --- 2 files changed, 7 insertions(+), 10 deletions(-)
fs/afs/rxrpc.c +7 -7
@@ -306,8 +306,8 @@ static int afs_send_pages(struct afs_call *call, struct msghdr *msg,_debug ("- range %u-%u%s" , offset, to, msg->msg_flags ?" [more]" :"" ); -iov_iter_init (&msg->msg_iter,WRITE , - (struct iovec *) iov,1 , to - offset); +iov_iter_kvec (&msg->msg_iter,WRITE |ITER_KVEC , + iov,1 , to - offset);/* have to change the state *before* sending the last * packet as RxRPC might give us the reply before it
@@ -384,7 +384,7 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, msg.msg_name =NULL ; msg.msg_namelen =0 ; -iov_iter_init (&msg.msg_iter,WRITE , (struct iovec *)iov,1 , +iov_iter_kvec (&msg.msg_iter,WRITE |ITER_KVEC , iov,1 , call->request_size); msg.msg_control =NULL ; msg.msg_controllen =0 ;
@@ -770,7 +770,7 @@ static int afs_deliver_cm_op_id(struct afs_call *call, struct sk_buff *skb,void afs_send_empty_reply (struct afs_call *call) {struct msghdr msg; -struct iovec iov[1 ]; +struct kvec iov[1 ];_enter ("" );
@@ -778,7 +778,7 @@ void afs_send_empty_reply(struct afs_call *call) iov[0 ].iov_len =0 ; msg.msg_name =NULL ; msg.msg_namelen =0 ; -iov_iter_init (&msg.msg_iter,WRITE , iov,0 ,0 );/* WTF? */ +iov_iter_kvec (&msg.msg_iter,WRITE |ITER_KVEC , iov,0 ,0 );/* WTF? */ msg.msg_control =NULL ; msg.msg_controllen =0 ; msg.msg_flags =0 ;
@@ -805,7 +805,7 @@ void afs_send_empty_reply(struct afs_call *call)void afs_send_simple_reply (struct afs_call *call,const void *buf,size_t len) {struct msghdr msg; -struct iovec iov[1 ]; +struct kvec iov[1 ];int n;_enter ("" );
@@ -814,7 +814,7 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len) iov[0 ].iov_len = len; msg.msg_name =NULL ; msg.msg_namelen =0 ; -iov_iter_init (&msg.msg_iter,WRITE , iov,1 , len); +iov_iter_kvec (&msg.msg_iter,WRITE |ITER_KVEC , iov,1 , len); msg.msg_control =NULL ; msg.msg_controllen =0 ; msg.msg_flags =0 ;
net/rxrpc/ar-output.c +0 -3
@@ -232,10 +232,7 @@ int rxrpc_kernel_send_data(struct rxrpc_call *call, struct msghdr *msg, call->state != RXRPC_CALL_SERVER_SEND_REPLY) { ret = -EPROTO; /* request phase complete for this client call */ } else { -mm_segment_t oldfs =get_fs (); -set_fs (KERNEL_DS ); ret =rxrpc_send_data (NULL , call->socket, call, msg, len); -set_fs (oldfs); }release_sock (&call->socket->sk);
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v3 7/18 ip: stash a pointer to msghdr in struct ping_fakehdr
In reply to Al ViroFrom: Al Viro <[email protected]>
... instead of storing its ->mgs_iter.iov there
--- include/net/ping.h | 2 +- net/ipv4/ping.c | 7 +++---- net/ipv6/ping.c | 3 +-- 3 files changed, 5 insertions(+), 7 deletions(-)
include/net/ping.h +1 -1
@@ -59,7 +59,7 @@ extern struct pingv6_ops pingv6_ops;struct pingfakehdr {struct icmphdr icmph; -struct iovec *iov; +struct msghdr *msg;sa_family_t family;__wsum wcheck; };
net/ipv4/ping.c +3 -4
@@ -602,14 +602,14 @@ int ping_getfrag(void *from, char *to,if (fraglen <sizeof (struct icmphdr ))BUG ();if (csum_partial_copy_fromiovecend (to +sizeof (struct icmphdr ), - pfh->iov,0 , fraglen -sizeof (struct icmphdr ), + pfh->msg->msg_iter.iov,0 , fraglen -sizeof (struct icmphdr ), &pfh->wcheck))return -EFAULT ; }else if (offset <sizeof (struct icmphdr )) {BUG (); }else {if (csum_partial_copy_fromiovecend - (to, pfh->iov, offset -sizeof (struct icmphdr ), + (to, pfh->msg->msg_iter.iov, offset -sizeof (struct icmphdr ), fraglen, &pfh->wcheck))return -EFAULT ; }
@@ -811,8 +811,7 @@ back_from_confirm: pfh.icmph.checksum =0 ; pfh.icmph.un.echo.id = inet->inet_sport; pfh.icmph.un.echo.sequence = user_icmph.un.echo.sequence; -/* XXX: stripping const */ - pfh.iov = (struct iovec *)msg->msg_iter.iov; + pfh.msg = msg; pfh.wcheck =0 ; pfh.family =AF_INET ;
net/ipv6/ping.c +1 -2
@@ -163,8 +163,7 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, pfh.icmph.checksum =0 ; pfh.icmph.un.echo.id = inet->inet_sport; pfh.icmph.un.echo.sequence = user_icmph.icmp6_sequence; -/* XXX: stripping const */ - pfh.iov = (struct iovec *)msg->msg_iter.iov; + pfh.msg = msg; pfh.wcheck =0 ; pfh.family =AF_INET6 ;
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v3 8/18 ip: convert tcp_sendmsg() to iov_iter primitives
In reply to Al ViroFrom: Al Viro <[email protected]>
patch is actually smaller than it seems to be - most of it is unindenting the inner loop body in tcp_sendmsg() itself...
the bit in tcp_input.c is going to get reverted very soon - that's what memcpy_from_msg() will become, but not in this commit; let's keep it reasonably contained...
There's one potentially subtle change here: in case of short copy from userland, mainline tcp_send_syn_data() discards the skb it has allocated and falls back to normal path, where we'll send as much as possible after rereading the same data again. This patch trims SYN+data skb instead - that way we don't need to copy from the same place twice.
--- include/net/sock.h | 18 ++-- net/ipv4/tcp.c | 233 +++++++++++++++++++++++--------------------------- net/ipv4/tcp_input.c | 2 +- net/ipv4/tcp_output.c | 11 ++- 4 files changed, 123 insertions(+), 141 deletions(-)
include/net/sock.h +8 -10
@@ -1803,27 +1803,25 @@ static inline void sk_nocaps_add(struct sock *sk, netdev_features_t flags) }static inline int skb_do_copy_data_nocache (struct sock *sk,struct sk_buff *skb, -char __user *from,char *to, +struct iov_iter *from,char *to,int copy,int offset) {if (skb->ip_summed ==CHECKSUM_NONE ) { -int err =0 ; -__wsum csum =csum_and_copy_from_user (from, to, copy,0 , &err); -if (err) -return err; +__wsum csum =0 ; +if (csum_and_copy_from_iter (to, copy, &csum, from) != copy) +return -EFAULT ; skb->csum =csum_block_add (skb->csum, csum, offset); }else if (sk->sk_route_caps &NETIF_F_NOCACHE_COPY ) { -if (!access_ok (VERIFY_READ , from, copy) || -__copy_from_user_nocache (to, from, copy)) +if (copy_from_iter_nocache (to, copy, from) != copy)return -EFAULT ; - }else if (copy_from_user (to, from, copy)) + }else if (copy_from_iter (to, copy, from) != copy)return -EFAULT ;return 0 ; }static inline int skb_add_data_nocache (struct sock *sk,struct sk_buff *skb, -char __user *from,int copy) +struct iov_iter *from,int copy) {int err, offset = skb->len;
@@ -1835,7 +1833,7 @@ static inline int skb_add_data_nocache(struct sock *sk, struct sk_buff *skb,return err; } -static inline int skb_copy_to_page_nocache (struct sock *sk,char __user *from, +static inline int skb_copy_to_page_nocache (struct sock *sk,struct iov_iter *from,struct sk_buff *skb,struct page *page,int off,int copy)
net/ipv4/tcp.c +106 -127
283 lines not on this page · raw message
net/ipv4/tcp_input.c +1 -1
@@ -4368,7 +4368,7 @@ int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)if (tcp_try_rmem_schedule (sk, skb, skb->truesize)) goto err_free; -if (memcpy_from_msg (skb_put (skb, size), msg, size)) +if (copy_from_iter (skb_put (skb, size), size, &msg->msg_iter) != size) goto err_free;TCP_SKB_CB (skb)->seq =tcp_sk (sk)->rcv_nxt;
net/ipv4/tcp_output.c +8 -3
@@ -3055,7 +3055,7 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) {struct tcp_sock *tp =tcp_sk (sk);struct tcp_fastopen_request *fo = tp->fastopen_req; -int syn_loss =0 , space, err =0 ; +int syn_loss =0 , space, err =0 , copied;unsigned long last_syn_loss =0 ;struct sk_buff *syn_data;
@@ -3093,11 +3093,16 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) goto fallback; syn_data->ip_summed =CHECKSUM_PARTIAL ;memcpy (syn_data->cb, syn->cb,sizeof (syn->cb)); -if (unlikely (memcpy_fromiovecend (skb_put (syn_data, space), - fo->data->msg_iter.iov,0 , space))) { + copied =copy_from_iter (skb_put (syn_data, space), space, + &fo->data->msg_iter); +if (unlikely (!copied)) {kfree_skb (syn_data); goto fallback; } +if (copied != space) { +skb_trim (syn_data, copied); + space = copied; + }/* No more data pending in inet_wait_for_connect() */ if (space == fo->size)
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v3 9/18 net: switch memcpy_fromiovec()/memcpy_fromiovecend() users to copy_from_iter()
In reply to Al ViroFrom: Al Viro <[email protected]>
That takes care of the majority of ->sendmsg() instances - most of them via memcpy_to_msg() or assorted getfrag() callbacks. One place where we still keep memcpy_fromiovecend() is tipc - there we potentially read the same data over and over; separate patch, that...
--- include/linux/skbuff.h | 3 +-- include/net/udplite.h | 3 +-- net/ipv4/ip_output.c | 6 ++---- net/ipv4/ping.c | 14 +++++++------- net/ipv4/raw.c | 2 +- net/ipv4/tcp_input.c | 2 +- net/ipv6/raw.c | 2 +- 7 files changed, 14 insertions(+), 18 deletions(-)
include/linux/skbuff.h +1 -2
@@ -2692,8 +2692,7 @@ int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci);static inline int memcpy_from_msg (void *data,struct msghdr *msg,int len) { -/* XXX: stripping const */ -return memcpy_fromiovec (data, (struct iovec *)msg->msg_iter.iov, len); +return copy_from_iter (data, len, &msg->msg_iter) == len ?0 : -EFAULT ; }static inline int memcpy_to_msg (struct msghdr *msg,void *data,int len)
include/net/udplite.h +1 -2
@@ -20,8 +20,7 @@ static __inline__ int udplite_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb) { struct msghdr *msg = from; -/* XXX: stripping const */ -return memcpy_fromiovecend (to, (struct iovec *)msg->msg_iter.iov, offset, len); +return copy_from_iter (to, len, &msg->msg_iter) != len ? -EFAULT :0 ; }/* Designate sk as UDP-Lite socket */
net/ipv4/ip_output.c +2 -4
@@ -755,13 +755,11 @@ ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct skstruct msghdr *msg = from;if (skb->ip_summed ==CHECKSUM_PARTIAL ) { -/* XXX: stripping const */ -if (memcpy_fromiovecend (to, (struct iovec *)msg->msg_iter.iov, offset, len) <0 ) +if (copy_from_iter (to, len, &msg->msg_iter) != len)return -EFAULT ; }else {__wsum csum =0 ; -/* XXX: stripping const */ -if (csum_partial_copy_fromiovecend (to, (struct iovec *)msg->msg_iter.iov, offset, len, &csum) <0 ) +if (csum_and_copy_from_iter (to, len, &csum, &msg->msg_iter) != len)return -EFAULT ; skb->csum =csum_block_add (skb->csum, csum, odd); }
net/ipv4/ping.c +7 -7
@@ -599,18 +599,18 @@ int ping_getfrag(void *from, char *to,struct pingfakehdr *pfh = (struct pingfakehdr *)from;if (offset ==0 ) { -if (fraglen <sizeof (struct icmphdr )) + fraglen -=sizeof (struct icmphdr ); +if (fraglen <0 )BUG (); -if (csum_partial_copy_fromiovecend (to +sizeof (struct icmphdr ), - pfh->msg->msg_iter.iov,0 , fraglen -sizeof (struct icmphdr ), - &pfh->wcheck)) +if (csum_and_copy_from_iter (to +sizeof (struct icmphdr ), + fraglen, &pfh->wcheck, + &pfh->msg->msg_iter) != fraglen)return -EFAULT ; }else if (offset <sizeof (struct icmphdr )) {BUG (); }else { -if (csum_partial_copy_fromiovecend - (to, pfh->msg->msg_iter.iov, offset -sizeof (struct icmphdr ), - fraglen, &pfh->wcheck)) +if (csum_and_copy_from_iter (to, fraglen, &pfh->wcheck, + &pfh->msg->msg_iter) != fraglen)return -EFAULT ; }
net/ipv4/raw.c +1 -1
@@ -382,7 +382,7 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, skb->transport_header = skb->network_header; err = -EFAULT ; -if (memcpy_fromiovecend ((void *)iph, msg->msg_iter.iov,0 , length)) +if (memcpy_from_msg (iph, msg, length)) goto error_free; iphlen = iph->ihl *4 ;
net/ipv4/tcp_input.c +1 -1
@@ -4368,7 +4368,7 @@ int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)if (tcp_try_rmem_schedule (sk, skb, skb->truesize)) goto err_free; -if (copy_from_iter (skb_put (skb, size), size, &msg->msg_iter) != size) +if (memcpy_from_msg (skb_put (skb, size), msg, size)) goto err_free;TCP_SKB_CB (skb)->seq =tcp_sk (sk)->rcv_nxt;
net/ipv6/raw.c +1 -1
@@ -648,7 +648,7 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, skb->ip_summed =CHECKSUM_NONE ; skb->transport_header = skb->network_header; - err =memcpy_fromiovecend ((void *)iph, msg->msg_iter.iov,0 , length); + err =memcpy_from_msg (iph, msg, length);if (err) goto error_fault;
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v3 10/18 tipc: tipc ->sendmsg() conversion
In reply to Al ViroFrom: Al Viro <[email protected]>
This one needs to copy the same data from user potentially more than once. Sadly, MTU changes can trigger that ;-/
--- net/tipc/msg.c | 7 ++----- net/tipc/socket.c | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 7 deletions(-)
net/tipc/msg.c +2 -5
@@ -189,7 +189,6 @@ err:* tipc_msg_build - create buffer chain containing specified header and data * @mhdr: Message header, to be prepended to data * @m: User message -* @offset: Posision in iov to start copying from * @dsz: Total length of user data * @pktmax: Max packet size that can be used * @list: Buffer or chain of buffers to be returned to caller
@@ -221,8 +220,7 @@ int tipc_msg_build(struct net *net, struct tipc_msg *mhdr, struct msghdr *m,__skb_queue_tail (list, skb);skb_copy_to_linear_data (skb, mhdr, mhsz); pktpos = skb->data + mhsz; -if (!dsz || !memcpy_fromiovecend (pktpos, m->msg_iter.iov, offset, - dsz)) +if (copy_from_iter (pktpos, dsz, &m->msg_iter) == dsz)return dsz; rc = -EFAULT ; goto error;
@@ -252,12 +250,11 @@ int tipc_msg_build(struct net *net, struct tipc_msg *mhdr, struct msghdr *m,if (drem < pktrem) pktrem = drem; -if (memcpy_fromiovecend (pktpos, m->msg_iter.iov, offset, pktrem)) { +if (copy_from_iter (pktpos, pktrem, &m->msg_iter) != pktrem) { rc = -EFAULT ; goto error; } drem -= pktrem; - offset += pktrem;if (!drem)break ;
net/tipc/socket.c +12 -2
@@ -733,6 +733,7 @@ static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq,struct net *net =sock_net (sk);struct tipc_msg *mhdr = &tipc_sk (sk)->phdr;struct sk_buff_head head; +struct iov_iter save = msg->msg_iter;uint mtu;int rc;
@@ -758,8 +759,10 @@ new_mtu: rc = dsz;break ; } -if (rc == -EMSGSIZE ) +if (rc == -EMSGSIZE ) { + msg->msg_iter = save; goto new_mtu; + }if (rc != -ELINKCONG )break ;tipc_sk (sk)->link_cong =1 ;
@@ -895,6 +898,7 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,struct sk_buff_head head;struct sk_buff *skb;struct tipc_name_seq *seq = &dest->addr.nameseq; +struct iov_iter save;u32 mtu;long timeo;int rc;
@@ -963,6 +967,7 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,msg_set_hdr_sz (mhdr,BASIC_H_SIZE ); } + save = m->msg_iter; new_mtu: mtu =tipc_node_get_mtu (net, dnode, tsk->portid);__skb_queue_head_init (&head);
@@ -980,8 +985,10 @@ new_mtu: rc = dsz;break ; } -if (rc == -EMSGSIZE ) +if (rc == -EMSGSIZE ) { + m->msg_iter = save; goto new_mtu; + }if (rc != -ELINKCONG )break ; tsk->link_cong =1 ;
@@ -1052,6 +1059,7 @@ static int tipc_send_stream(struct kiocb *iocb, struct socket *sock,long timeo;u32 dnode;uint mtu, send, sent =0 ; +struct iov_iter save;/* Handle implied connection establishment */ if (unlikely (dest)) {
@@ -1078,6 +1086,7 @@ static int tipc_send_stream(struct kiocb *iocb, struct socket *sock, dnode =tsk_peer_node (tsk); next: + save = m->msg_iter; mtu = tsk->max_pkt; send =min_t (uint, dsz - sent,TIPC_MAX_USER_MSG_SIZE );__skb_queue_head_init (&head);
@@ -1097,6 +1106,7 @@ next:if (rc == -EMSGSIZE ) { tsk->max_pkt =tipc_node_get_mtu (net, dnode, portid); + m->msg_iter = save; goto next; }if (rc != -ELINKCONG )
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v3 11/18 net: bury net/core/iovec.c - nothing in there is used anymore
In reply to Al ViroFrom: Al Viro <[email protected]>
--- include/linux/socket.h | 7 --- net/core/Makefile | 2 +- net/core/iovec.c | 137 ------------------------------------------------- 3 files changed, 1 insertion(+), 145 deletions(-) delete mode 100644 net/core/iovec.c
include/linux/socket.h +0 -7
@@ -318,13 +318,6 @@ struct ucred {/* IPX options */ #define IPX_TYPE 1 -extern int csum_partial_copy_fromiovecend (unsigned char *kdata, -struct iovec *iov, -int offset, -unsigned int len,__wsum *csump); -extern unsigned long iov_pages (const struct iovec *iov,int offset, -unsigned long nr_segs); -extern int move_addr_to_kernel (void __user *uaddr,int ulen,struct sockaddr_storage *kaddr);extern int put_cmsg (struct msghdr *,int level,int type,int len,void *data);
net/core/Makefile +1 -1
@@ -2,7 +2,7 @@ # Makefile for the Linux networking core. # -obj-y := sock.o request_sock.o skbuff.o iovec.o datagram.o stream.o scm.o \ +obj-y := sock.o request_sock.o skbuff.o datagram.o stream.o scm.o \ gen_stats.o gen_estimator.o net_namespace.o secure_seq.o flow_dissector.o obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
net/core/iovec.c deleted +0 -137
137 lines not on this page · raw message
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v3 12/18 crypto: switch af_alg_make_sg() to iov_iter
In reply to Al ViroFrom: Al Viro <[email protected]>
With that, all ->sendmsg() instances are converted to iov_iter primitives and are agnostic wrt the kind of iov_iter they are working with. So's the last remaining ->recvmsg() instance that wasn't kind-agnostic yet. All ->sendmsg() and ->recvmsg() advance ->msg_iter by the amount actually copied and none of them modifies the underlying iovec, etc.
--- crypto/af_alg.c | 40 ++++++++------------------ crypto/algif_hash.c | 45 ++++++++++++------------------ crypto/algif_skcipher.c | 74 ++++++++++++++++++++++--------------------------- include/crypto/if_alg.h | 3 +- 4 files changed, 62 insertions(+), 100 deletions(-)
crypto/af_alg.c +11 -29
@@ -338,49 +338,31 @@ static const struct net_proto_family alg_family = { .owner = THIS_MODULE, }; -int af_alg_make_sg (struct af_alg_sgl *sgl,void __user *addr,int len, -int write) +int af_alg_make_sg (struct af_alg_sgl *sgl,struct iov_iter *iter,int len) { -unsigned long from = (unsigned long )addr; -unsigned long npages; -unsigned off; -int err; -int i; - - err = -EFAULT ; -if (!access_ok (write ?VERIFY_READ :VERIFY_WRITE , addr, len)) - goto out; - - off = from & ~PAGE_MASK ; - npages = (off + len +PAGE_SIZE -1 ) >>PAGE_SHIFT ; -if (npages >ALG_MAX_PAGES ) - npages =ALG_MAX_PAGES ; +size_t off; +ssize_t n; +int npages, i; - err =get_user_pages_fast (from, npages, write, sgl->pages); -if (err <0 ) - goto out; + n =iov_iter_get_pages (iter, sgl->pages, len,ALG_MAX_PAGES , &off); +if (n <0 ) +return n; - npages = err; - err = -EINVAL ; + npages =PAGE_ALIGN (off + n);if (WARN_ON (npages ==0 )) - goto out; - - err =0 ; +return -EINVAL ;sg_init_table (sgl->sg, npages); -for (i =0 ; i < npages; i++) { +for (i =0 , len = n; i < npages; i++) {int plen =min_t (int, len,PAGE_SIZE - off);sg_set_page (sgl->sg + i, sgl->pages[i], plen, off); off =0 ; len -= plen; - err += plen; } - -out: -return err; +return n; }EXPORT_SYMBOL_GPL (af_alg_make_sg);
crypto/algif_hash.c +17 -28
62 lines not on this page · raw message
crypto/algif_skcipher.c +33 -41
100 lines not on this page · raw message
include/crypto/if_alg.h +1 -2
@@ -67,8 +67,7 @@ int af_alg_unregister_type(const struct af_alg_type *type);int af_alg_release (struct socket *sock);int af_alg_accept (struct sock *sk,struct socket *newsock); -int af_alg_make_sg (struct af_alg_sgl *sgl,void __user *addr,int len, -int write); +int af_alg_make_sg (struct af_alg_sgl *sgl,struct iov_iter *iter,int len);void af_alg_free_sg (struct af_alg_sgl *sgl);int af_alg_cmsg_send (struct msghdr *msg,struct af_alg_control *con);
Signature · 1 line
2.1.4
Re: [PATCH v3 12/18] crypto: switch af_alg_make_sg() to iov_iter
Am Mittwoch, 4. Februar 2015, 06:40:03 schrieb Al Viro:
Hi Al,
Quoted 23 lines
From: Al Viro <[email protected]>
With that, all ->sendmsg() instances are converted to
iov_iterprimitives and are agnostic wrt the kind ofiov_iterthey are working with. So's the last remaining ->recvmsg() instance that wasn't kind-agnostic yet. All ->sendmsg() and ->recvmsg() advance ->msg_iter by the amount actually copied and none of them modifies the underlying iovec, etc.Signed-off-by Al Viro <[email protected]>--- crypto/af_alg.c | 40 ++++++++------------------ crypto/algif_hash.c | 45 ++++++++++++------------------ crypto/algif_skcipher.c | 74 ++++++++++++++++++++++--------------------------- include/crypto/if_alg.h | 3 +- 4 files changed, 62 insertions(+), 100 deletions(-)crypto/af_alg.c +0
-0
crypto/af_alg.c static const struct net_proto_family alg_family = { · line 341
Quoted 6 lines
crypto/af_alg.c +1
-2@@ -338,49 +338,31 @@ static const struct net_proto_family alg_family = { .owner = THIS_MODULE, }; -int af_alg_make_sg (struct af_alg_sgl *sgl,void __user *addr,int len, -int write) +int af_alg_make_sg (struct af_alg_sgl *sgl,struct iov_iter *iter,int len)
Shouldn't len be size_t? iov_iter_get_pages wants a size_t. Also, the invocation of af_alg_make_sg uses an unsigned variable that is provided by userspace.
Quoted 68 lines
crypto/af_alg.c +10
-27{ -unsigned long from = (unsigned long )addr; -unsigned long npages; -unsigned off; -int err; -int i; - - err = -EFAULT ; -if (!access_ok (write ?VERIFY_READ :VERIFY_WRITE , addr, len)) - goto out; - - off = from & ~PAGE_MASK ; - npages = (off + len +PAGE_SIZE -1 ) >>PAGE_SHIFT ; -if (npages >ALG_MAX_PAGES ) - npages =ALG_MAX_PAGES ; +size_t off; +ssize_t n; +int npages, i; - err =get_user_pages_fast (from, npages, write, sgl->pages); -if (err <0 ) - goto out; + n =iov_iter_get_pages (iter, sgl->pages, len,ALG_MAX_PAGES , &off); +if (n <0 ) +return n; - npages = err; - err = -EINVAL ; + npages =PAGE_ALIGN (off + n);if (WARN_ON (npages ==0 )) - goto out; - - err =0 ; +return -EINVAL ;sg_init_table (sgl->sg, npages); -for (i =0 ; i < npages; i++) { +for (i =0 , len = n; i < npages; i++) {int plen =min_t (int, len,PAGE_SIZE - off);sg_set_page (sgl->sg + i, sgl->pages[i], plen, off); off =0 ; len -= plen; - err += plen; } - -out: -return err; +return n; }EXPORT_SYMBOL_GPL (af_alg_make_sg);crypto/algif_hash.c +0
-2@@ -41,8 +41,6 @@ static int hash_sendmsg(struct kiocb *unused, struct socket *sock, struct sock *sk = sock->sk;struct alg_sock *ask =alg_sk (sk);struct hash_ctx *ctx = ask->private; -unsigned long iovlen; -const struct iovec *iov;long copied =0 ;int err;
crypto/algif_hash.c static int hash_sendmsg(struct kiocb *unused, struct · line 62
Quoted 5 lines
crypto/algif_hash.c +0
-1@@ -58,37 +56,28 @@ static int hash_sendmsg(struct kiocb *unused, struct socket *sock, ctx->more =0 ; - for (iov = msg->msg_iter.iov, iovlen = msg->msg_iter.nr_segs; iovlen >
0;
crypto/algif_hash.c static int hash_sendmsg(struct kiocb *unused, struct socket *sock, · line 60
Quoted 5 lines
crypto/algif_hash.c +2
-3- iovlen--, iov++) { -unsigned long seglen = iov->iov_len; -char __user *from = iov->iov_base; +while (iov_iter_count (&msg->msg_iter)) { +int len =iov_iter_count (&msg->msg_iter);
size_t for len?
crypto/algif_hash.c static int hash_sendmsg(struct kiocb *unused, struct socket *sock, · line 63
Quoted 6 lines
crypto/algif_hash.c +2
-3-while (seglen) { - int len = min_t(unsigned long, seglen, limit); -int newlen; +if (len > limit) + len = limit;
If we leave int, do we have a wrap problem here?
Quoted 46 lines
crypto/algif_hash.c +13
-19- newlen =af_alg_make_sg (&ctx->sgl, from, len,0 ); -if (newlen <0 ) { - err = copied ?0 : newlen; - goto unlock; - } - -ahash_request_set_crypt (&ctx->req, ctx->sgl.sg,NULL , - newlen); - - err =af_alg_wait_for_completion ( -crypto_ahash_update (&ctx->req), - &ctx->completion); + len =af_alg_make_sg (&ctx->sgl, &msg->msg_iter, len); +if (len <0 ) { + err = copied ?0 : len; + goto unlock; + } -af_alg_free_sg (&ctx->sgl); +ahash_request_set_crypt (&ctx->req, ctx->sgl.sg,NULL , len); -if (err) - goto unlock; + err =af_alg_wait_for_completion (crypto_ahash_update (&ctx- req), + &ctx->completion); +af_alg_free_sg (&ctx->sgl); +if (err) + goto unlock; - seglen -= newlen; - from += newlen; - copied += newlen; - } + copied += len; +iov_iter_advance (&msg->msg_iter, len); } err =0 ;crypto/algif_skcipher.c +0
-0@@ -426,67 +426,59 @@ static int skcipher_recvmsg(struct kiocb *unused, struct socket *sock, &ctx->req));
crypto/algif_skcipher.c static int skcipher_recvmsg(struct kiocb *unused, · line 436
Quoted 10 lines
crypto/algif_skcipher.c +0
-3struct skcipher_sg_list *sgl;struct scatterlist *sg; -unsigned long iovlen; -const struct iovec *iov;int err = -EAGAIN ;int used;long copied =0 ;lock_sock (sk); - for (iov = msg->msg_iter.iov, iovlen = msg->msg_iter.nr_segs; iovlen >
0;
Quoted 21 lines
crypto/algif_skcipher.c +4
-17- iovlen--, iov++) { -unsigned long seglen = iov->iov_len; -char __user *from = iov->iov_base; - -while (seglen) { - sgl =list_first_entry (&ctx->tsgl, - struct skcipher_sg_list, list); - sg = sgl->sg; - -while (!sg->length) - sg++; - -if (!ctx->used) { - err =skcipher_wait_for_data (sk, flags); -if (err) - goto unlock; - } +while (iov_iter_count (&msg->msg_iter)) { + sgl =list_first_entry (&ctx->tsgl, + struct skcipher_sg_list, list); + sg = sgl->sg;
crypto/algif_skcipher.c static int skcipher_recvmsg(struct kiocb *unused, struct socket *sock, · line 443
Quoted 10 lines
crypto/algif_skcipher.c +4
-4- used = min_t(unsigned long, ctx->used, seglen); +while (!sg->length) + sg++; - used =af_alg_make_sg (&ctx->rsgl, from, used,1 ); - err = used; -if (err <0 ) + used = ctx->used; +if (!used) {
I do not think that this change is correct. The following skcipher_wait_for_data puts the recvmsg to sleep. That means, ctx->used may change due to a new sendmsg() while sleeping.
Hence, I would think that we should leave the code as it was:
if (!ctx->used)
and then in the following
crypto/algif_skcipher.c static int skcipher_recvmsg(struct kiocb *unused, struct socket *sock,
Quoted 7 lines
crypto/algif_skcipher.c +5
-0+ err =skcipher_wait_for_data (sk, flags); +if (err) goto unlock; + } + + used = min_t(unsigned long, used, iov_iter_count(&msg- msg_iter));
we use ctx->used here.
And shouldn't we use size_t here instead of unsigned long?
Quoted 66 lines
crypto/algif_skcipher.c +20
-17+ + used =af_alg_make_sg (&ctx->rsgl, &msg->msg_iter, used); + err = used; +if (err <0 ) + goto unlock; -if (ctx->more || used < ctx->used) - used -= used % bs; +if (ctx->more || used < ctx->used) + used -= used % bs; - err = -EINVAL ; -if (!used) - goto free; + err = -EINVAL ; +if (!used) + goto free; -ablkcipher_request_set_crypt (&ctx->req, sg, - ctx->rsgl.sg, used, - ctx->iv); +ablkcipher_request_set_crypt (&ctx->req, sg, + ctx->rsgl.sg, used, + ctx->iv); - err =af_alg_wait_for_completion ( + err =af_alg_wait_for_completion ( ctx->enc ?crypto_ablkcipher_encrypt (&ctx->req) :crypto_ablkcipher_decrypt (&ctx->req), &ctx->completion); free: -af_alg_free_sg (&ctx->rsgl); +af_alg_free_sg (&ctx->rsgl); -if (err) - goto unlock; +if (err) + goto unlock; - copied += used; - from += used; - seglen -= used; -skcipher_pull_sgl (sk, used); - } + copied += used; +skcipher_pull_sgl (sk, used); +iov_iter_advance (&msg->msg_iter, used); }crypto/algif_skcipher.c +0
-0err =0 ;include/crypto/if_alg.h +1
-2@@ -67,8 +67,7 @@ int af_alg_unregister_type(const struct af_alg_type *type); int af_alg_release(struct socket *sock);int af_alg_accept (struct sock *sk,struct socket *newsock); -int af_alg_make_sg (struct af_alg_sgl *sgl,void __user *addr,int len, -int write); +int af_alg_make_sg (struct af_alg_sgl *sgl,struct iov_iter *iter,int len);void af_alg_free_sg (struct af_alg_sgl *sgl);int af_alg_cmsg_send (struct msghdr *msg,struct af_alg_control *con);
Signature · 2 lines
Ciao Stephan
Al Viro
maintainerRe: [PATCH v3 12/18] crypto: switch af_alg_make_sg() to iov_iter
Quoted 8 lines · Stephan Mueller
crypto/af_alg.c static const struct net_proto_family alg_family = { · line 341
Quoted 4 lines
crypto/af_alg.c +1
-2-int af_alg_make_sg (struct af_alg_sgl *sgl,void __user *addr,int len, -int write) +int af_alg_make_sg (struct af_alg_sgl *sgl,struct iov_iter *iter,int len)Shouldn't len be
size_t?iov_iter_get_pageswants asize_t. Also, the invocation ofaf_alg_make_sguses an unsigned variable that is provided by userspace.
Keepo in mind that rw_copy_check_uvector() does, among other things, verify that total length is less than 2^31. So this code doesn't suffer from wraparounds; it might make sense to switch to size_t here, but that's a separate patch, IMO. For this conversion I just kept the type that used to be there.
Re: [PATCH v3 12/18] crypto: switch af_alg_make_sg() to iov_iter
In reply to Al ViroAm Mittwoch, 4. Februar 2015, 06:40:03 schrieb Al Viro:
Hi Al,
Quoted 7 lines
From: Al Viro <[email protected]>
With that, all ->sendmsg() instances are converted to
iov_iterprimitives and are agnostic wrt the kind ofiov_iterthey are working with. So's the last remaining ->recvmsg() instance that wasn't kind-agnostic yet. All ->sendmsg() and ->recvmsg() advance ->msg_iter by the amount actually copied and none of them modifies the underlying iovec, etc.
After testing this patch with the test application by simply executing [1]/test/test.sh, the hash and skcipher interface invocation hang in kernel space. Though, I am not sure where the problem is.
For individual invocations of the tests, you may look into [1]/test/kcapi- main.c in the comments above cavs_sym or cavs_hash.
[1] http://www.chronox.de/libkcapi.html
Signature · 2 lines
Ciao Stephan
Al Viro
maintainerRe: [PATCH v3 12/18] crypto: switch af_alg_make_sg() to iov_iter
Quoted 12 lines · Stephan Mueller
Am Mittwoch, 4. Februar 2015, 06:40:03 schrieb Al Viro:
Hi Al,
Quoted 7 lines
From: Al Viro <[email protected]>
With that, all ->sendmsg() instances are converted to
iov_iterprimitives and are agnostic wrt the kind ofiov_iterthey are working with. So's the last remaining ->recvmsg() instance that wasn't kind-agnostic yet. All ->sendmsg() and ->recvmsg() advance ->msg_iter by the amount actually copied and none of them modifies the underlying iovec, etc.
Quoted 8 lines
After testing this patch with the test application by simply executing [1]/test/test.sh, the hash and skcipher interface invocation hang in kernel space. Though, I am not sure where the problem is.
For individual invocations of the tests, you may look into [1]/test/kcapi-
main.cin the comments abovecavs_symorcavs_hash.
Very interesting; I'll try to reproduce it once I get some sleep (up since yesterday, and it's past noon here ;-/)
Al Viro
maintainerPATCH v3 13/18 net/socket.c: fold do_sock_{read,write} into callers
In reply to Al ViroFrom: Al Viro <[email protected]>
--- net/socket.c | 56 +++++++++++++++++++++----------------------------------- 1 file changed, 21 insertions(+), 35 deletions(-)
net/socket.c +21 -35
@@ -845,25 +845,11 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos,return sock->ops->splice_read (sock, ppos, pipe, len, flags); } -static ssize_t do_sock_read (struct msghdr *msg,struct kiocb *iocb, -struct file *file,const struct iovec *iov, -unsigned long nr_segs) -{ -struct socket *sock = file->private_data; - - msg->msg_name =NULL ; - msg->msg_namelen =0 ; - msg->msg_control =NULL ; - msg->msg_controllen =0 ; -iov_iter_init (&msg->msg_iter,READ , iov, nr_segs, iocb->ki_nbytes); - msg->msg_flags = (file->f_flags &O_NONBLOCK ) ?MSG_DONTWAIT :0 ; - -return __sock_recvmsg (iocb, sock, msg, iocb->ki_nbytes, msg->msg_flags); -} -static ssize_t sock_aio_read (struct kiocb *iocb,const struct iovec *iov,unsigned long nr_segs,loff_t pos) { +struct file *file = iocb->ki_filp; +struct socket *sock = file->private_data;struct msghdr msg;if (pos !=0 )
@@ -872,36 +858,36 @@ static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,if (iocb->ki_nbytes ==0 )/* Match SYS5 behaviour */ return 0 ; -return do_sock_read (&msg, iocb, iocb->ki_filp, iov, nr_segs); -} - -static ssize_t do_sock_write (struct msghdr *msg,struct kiocb *iocb, -struct file *file,const struct iovec *iov, -unsigned long nr_segs) -{ -struct socket *sock = file->private_data; - - msg->msg_name =NULL ; - msg->msg_namelen =0 ; - msg->msg_control =NULL ; - msg->msg_controllen =0 ; -iov_iter_init (&msg->msg_iter,WRITE , iov, nr_segs, iocb->ki_nbytes); - msg->msg_flags = (file->f_flags &O_NONBLOCK ) ?MSG_DONTWAIT :0 ; -if (sock->type ==SOCK_SEQPACKET ) - msg->msg_flags |=MSG_EOR ; + msg.msg_name =NULL ; + msg.msg_namelen =0 ; + msg.msg_control =NULL ; + msg.msg_controllen =0 ; +iov_iter_init (&msg.msg_iter,READ , iov, nr_segs, iocb->ki_nbytes); + msg.msg_flags = (file->f_flags &O_NONBLOCK ) ?MSG_DONTWAIT :0 ; -return __sock_sendmsg (iocb, sock, msg, iocb->ki_nbytes); +return __sock_recvmsg (iocb, sock, &msg, iocb->ki_nbytes, msg.msg_flags); }static ssize_t sock_aio_write (struct kiocb *iocb,const struct iovec *iov,unsigned long nr_segs,loff_t pos) { +struct file *file = iocb->ki_filp; +struct socket *sock = file->private_data;struct msghdr msg;if (pos !=0 )return -ESPIPE ; -return do_sock_write (&msg, iocb, iocb->ki_filp, iov, nr_segs); + msg.msg_name =NULL ; + msg.msg_namelen =0 ; + msg.msg_control =NULL ; + msg.msg_controllen =0 ; +iov_iter_init (&msg.msg_iter,WRITE , iov, nr_segs, iocb->ki_nbytes); + msg.msg_flags = (file->f_flags &O_NONBLOCK ) ?MSG_DONTWAIT :0 ; +if (sock->type ==SOCK_SEQPACKET ) + msg.msg_flags |=MSG_EOR ; + +return __sock_sendmsg (iocb, sock, &msg, iocb->ki_nbytes); }/*
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v3 14/18 net: switch sockets to ->read_iter/->write_iter
In reply to Al ViroFrom: Al Viro <[email protected]>
--- net/socket.c | 56 +++++++++++++++++++++++++++----------------------------- 1 file changed, 27 insertions(+), 29 deletions(-)
net/socket.c +27 -29
@@ -113,10 +113,8 @@ unsigned int sysctl_net_busy_read __read_mostly;unsigned int sysctl_net_busy_poll__read_mostly ;#endif -static ssize_t sock_aio_read (struct kiocb *iocb,const struct iovec *iov, -unsigned long nr_segs,loff_t pos); -static ssize_t sock_aio_write (struct kiocb *iocb,const struct iovec *iov, -unsigned long nr_segs,loff_t pos); +static ssize_t sock_read_iter (struct kiocb *iocb,struct iov_iter *to); +static ssize_t sock_write_iter (struct kiocb *iocb,struct iov_iter *from);static int sock_mmap (struct file *file,struct vm_area_struct *vma);static int sock_close (struct inode *inode,struct file *file);
@@ -142,8 +140,10 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos,static const struct file_operations socket_file_ops = { .owner =THIS_MODULE , .llseek = no_llseek, - .aio_read = sock_aio_read, - .aio_write = sock_aio_write, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = sock_read_iter, + .write_iter = sock_write_iter, .poll = sock_poll, .unlocked_ioctl = sock_ioctl, #ifdef CONFIG_COMPAT
@@ -845,49 +845,47 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos,return sock->ops->splice_read (sock, ppos, pipe, len, flags); } -static ssize_t sock_aio_read (struct kiocb *iocb,const struct iovec *iov, -unsigned long nr_segs,loff_t pos) +static ssize_t sock_read_iter (struct kiocb *iocb,struct iov_iter *to) {struct file *file = iocb->ki_filp;struct socket *sock = file->private_data; -struct msghdr msg; +struct msghdr msg = {.msg_iter = *to}; +ssize_t res; + +if (file->f_flags &O_NONBLOCK ) + msg.msg_flags =MSG_DONTWAIT ; -if (pos !=0 ) +if (iocb->ki_pos !=0 )return -ESPIPE ;if (iocb->ki_nbytes ==0 )/* Match SYS5 behaviour */ return 0 ; - msg.msg_name =NULL ; - msg.msg_namelen =0 ; - msg.msg_control =NULL ; - msg.msg_controllen =0 ; -iov_iter_init (&msg.msg_iter,READ , iov, nr_segs, iocb->ki_nbytes); - msg.msg_flags = (file->f_flags &O_NONBLOCK ) ?MSG_DONTWAIT :0 ; - -return __sock_recvmsg (iocb, sock, &msg, iocb->ki_nbytes, msg.msg_flags); + res =__sock_recvmsg (iocb, sock, &msg, + iocb->ki_nbytes, msg.msg_flags); + *to = msg.msg_iter; +return res; } -static ssize_t sock_aio_write (struct kiocb *iocb,const struct iovec *iov, -unsigned long nr_segs,loff_t pos) +static ssize_t sock_write_iter (struct kiocb *iocb,struct iov_iter *from) {struct file *file = iocb->ki_filp;struct socket *sock = file->private_data; -struct msghdr msg; +struct msghdr msg = {.msg_iter = *from}; +ssize_t res; -if (pos !=0 ) +if (iocb->ki_pos !=0 )return -ESPIPE ; - msg.msg_name =NULL ; - msg.msg_namelen =0 ; - msg.msg_control =NULL ; - msg.msg_controllen =0 ; -iov_iter_init (&msg.msg_iter,WRITE , iov, nr_segs, iocb->ki_nbytes); - msg.msg_flags = (file->f_flags &O_NONBLOCK ) ?MSG_DONTWAIT :0 ; +if (file->f_flags &O_NONBLOCK ) + msg.msg_flags =MSG_DONTWAIT ; +if (sock->type ==SOCK_SEQPACKET ) msg.msg_flags |=MSG_EOR ; -return __sock_sendmsg (iocb, sock, &msg, iocb->ki_nbytes); + res =__sock_sendmsg (iocb, sock, &msg, iocb->ki_nbytes); + *from = msg.msg_iter; +return res; }/*
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v3 15/18 vhost: switch vhost get_indirect() to iov_iter, kill memcpy_fromiovec()
In reply to Al ViroFrom: Al Viro <[email protected]>
--- drivers/vhost/vhost.c | 6 ++++-- include/linux/uio.h | 1 - lib/iovec.c | 25 ------------------------- 3 files changed, 4 insertions(+), 28 deletions(-)
drivers/vhost/vhost.c +4 -2
@@ -1125,6 +1125,7 @@ static int get_indirect(struct vhost_virtqueue *vq,struct vring_desc desc;unsigned int i =0 , count, found =0 ;u32 len =vhost32_to_cpu (vq, indirect->len); +struct iov_iter from;int ret;/* Sanity check */
@@ -1142,6 +1143,7 @@ static int get_indirect(struct vhost_virtqueue *vq,vq_err (vq,"Translation failure %d in indirect.\n" , ret);return ret; } +iov_iter_init (&from,READ , vq->indirect, ret, len);/* We will use the result as an address to read from, so most * architectures only need a compiler barrier here. */
@@ -1164,8 +1166,8 @@ static int get_indirect(struct vhost_virtqueue *vq, i, count);return -EINVAL ; } -if (unlikely (memcpy_fromiovec ((unsigned char *)&desc, - vq->indirect,sizeof desc))) { +if (unlikely (copy_from_iter (&desc,sizeof (desc), &from) != +sizeof (desc))) {vq_err (vq,"Failed indirect descriptor: idx %d, %zx\n" , i, (size_t )vhost64_to_cpu (vq, indirect->addr) + i *sizeof desc);return -EINVAL ;
include/linux/uio.h +0 -1
@@ -135,7 +135,6 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count)size_t csum_and_copy_to_iter (void *addr,size_t bytes,__wsum *csum,struct iov_iter *i);size_t csum_and_copy_from_iter (void *addr,size_t bytes,__wsum *csum,struct iov_iter *i); -int memcpy_fromiovec (unsigned char *kdata,struct iovec *iov,int len);int memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov,int offset,int len); int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata,
lib/iovec.c +0 -25
@@ -3,31 +3,6 @@#include <linux/uio.h> /* -* Copy iovec to kernel. Returns -EFAULT on error. -* -* Note: this modifies the original iovec. -*/ - -int memcpy_fromiovec (unsigned char *kdata,struct iovec *iov,int len) -{ -while (len >0 ) { -if (iov->iov_len) { - int copy = min_t(unsigned int, len, iov->iov_len); -if (copy_from_user (kdata, iov->iov_base, copy)) -return -EFAULT ; - len -= copy; - kdata += copy; - iov->iov_base += copy; - iov->iov_len -= copy; - } - iov++; - } - -return 0 ; -} -EXPORT_SYMBOL (memcpy_fromiovec); - -/* * Copy kernel to iovec. Returns -EFAULT on error. */
Signature · 1 line
2.1.4
Re: [PATCH v3 15/18] vhost: switch vhost get_indirect() to iov_iter, kill memcpy_fromiovec()
Quoted 6 lines · Al Viro
From: Al Viro <[email protected]>
Cc Michael S. Tsirkin <[email protected]>Signed-off-by Al Viro <[email protected]>
Quoted 87 lines
--- drivers/vhost/vhost.c | 6 ++++-- include/linux/uio.h | 1 - lib/iovec.c | 25 ------------------------- 3 files changed, 4 insertions(+), 28 deletions(-)drivers/vhost/vhost.c +4
-2@@ -1125,6 +1125,7 @@ static int get_indirect(struct vhost_virtqueue *vq,struct vring_desc desc;unsigned int i =0 , count, found =0 ;u32 len =vhost32_to_cpu (vq, indirect->len); +struct iov_iter from;int ret;/* Sanity check */ @@ -1142,6 +1143,7 @@ static int get_indirect(struct vhost_virtqueue *vq,vq_err (vq,"Translation failure %d in indirect.\n" , ret);return ret; } +iov_iter_init (&from,READ , vq->indirect, ret, len);/* We will use the result as an address to read from, so most * architectures only need a compiler barrier here. */ @@ -1164,8 +1166,8 @@ static int get_indirect(struct vhost_virtqueue *vq, i, count);return -EINVAL ; } -if (unlikely (memcpy_fromiovec ((unsigned char *)&desc, - vq->indirect,sizeof desc))) { +if (unlikely (copy_from_iter (&desc,sizeof (desc), &from) != +sizeof (desc))) {vq_err (vq,"Failed indirect descriptor: idx %d, %zx\n" , i, (size_t )vhost64_to_cpu (vq, indirect->addr) + i *sizeof desc);return -EINVAL ;include/linux/uio.h +0
-1@@ -135,7 +135,6 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count)size_t csum_and_copy_to_iter (void *addr,size_t bytes,__wsum *csum,struct iov_iter *i);size_t csum_and_copy_from_iter (void *addr,size_t bytes,__wsum *csum,struct iov_iter *i); -int memcpy_fromiovec (unsigned char *kdata,struct iovec *iov,int len);int memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov,int offset,int len); int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata,lib/iovec.c +0
-25@@ -3,31 +3,6 @@#include <linux/uio.h> /* -* Copy iovec to kernel. Returns -EFAULT on error. -* -* Note: this modifies the original iovec. -*/ - -int memcpy_fromiovec (unsigned char *kdata,struct iovec *iov,int len) -{ -while (len >0 ) { -if (iov->iov_len) { - int copy = min_t(unsigned int, len, iov->iov_len); -if (copy_from_user (kdata, iov->iov_base, copy)) -return -EFAULT ; - len -= copy; - kdata += copy; - iov->iov_base += copy; - iov->iov_len -= copy; - } - iov++; - } - -return 0 ; -} -EXPORT_SYMBOL (memcpy_fromiovec); - -/* * Copy kernel to iovec. Returns -EFAULT on error. */ Signature · 1 line
2.1.4
Re: [PATCH v3 15/18] vhost: switch vhost get_indirect() to iov_iter, kill memcpy_fromiovec()
In reply to Al ViroQuoted 6 lines · Al Viro
From: Al Viro <[email protected]>
Cc Michael S. Tsirkin <[email protected]>Signed-off-by Al Viro <[email protected]>
Quoted 87 lines
--- drivers/vhost/vhost.c | 6 ++++-- include/linux/uio.h | 1 - lib/iovec.c | 25 ------------------------- 3 files changed, 4 insertions(+), 28 deletions(-)drivers/vhost/vhost.c +4
-2@@ -1125,6 +1125,7 @@ static int get_indirect(struct vhost_virtqueue *vq,struct vring_desc desc;unsigned int i =0 , count, found =0 ;u32 len =vhost32_to_cpu (vq, indirect->len); +struct iov_iter from;int ret;/* Sanity check */ @@ -1142,6 +1143,7 @@ static int get_indirect(struct vhost_virtqueue *vq,vq_err (vq,"Translation failure %d in indirect.\n" , ret);return ret; } +iov_iter_init (&from,READ , vq->indirect, ret, len);/* We will use the result as an address to read from, so most * architectures only need a compiler barrier here. */ @@ -1164,8 +1166,8 @@ static int get_indirect(struct vhost_virtqueue *vq, i, count);return -EINVAL ; } -if (unlikely (memcpy_fromiovec ((unsigned char *)&desc, - vq->indirect,sizeof desc))) { +if (unlikely (copy_from_iter (&desc,sizeof (desc), &from) != +sizeof (desc))) {vq_err (vq,"Failed indirect descriptor: idx %d, %zx\n" , i, (size_t )vhost64_to_cpu (vq, indirect->addr) + i *sizeof desc);return -EINVAL ;include/linux/uio.h +0
-1@@ -135,7 +135,6 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count)size_t csum_and_copy_to_iter (void *addr,size_t bytes,__wsum *csum,struct iov_iter *i);size_t csum_and_copy_from_iter (void *addr,size_t bytes,__wsum *csum,struct iov_iter *i); -int memcpy_fromiovec (unsigned char *kdata,struct iovec *iov,int len);int memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov,int offset,int len); int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata,lib/iovec.c +0
-25@@ -3,31 +3,6 @@#include <linux/uio.h> /* -* Copy iovec to kernel. Returns -EFAULT on error. -* -* Note: this modifies the original iovec. -*/ - -int memcpy_fromiovec (unsigned char *kdata,struct iovec *iov,int len) -{ -while (len >0 ) { -if (iov->iov_len) { - int copy = min_t(unsigned int, len, iov->iov_len); -if (copy_from_user (kdata, iov->iov_base, copy)) -return -EFAULT ; - len -= copy; - kdata += copy; - iov->iov_base += copy; - iov->iov_len -= copy; - } - iov++; - } - -return 0 ; -} -EXPORT_SYMBOL (memcpy_fromiovec); - -/* * Copy kernel to iovec. Returns -EFAULT on error. */ Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v3 16/18 vhost: don't bother with copying iovec in handle_tx()
In reply to Al ViroFrom: Al Viro <[email protected]>
just advance the msg.msg_iter and be done with that.
--- drivers/vhost/net.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/vhost/net.c +5 -4
@@ -336,7 +336,7 @@ static void handle_tx(struct vhost_net *net) {struct vhost_net_virtqueue *nvq = &net->vqs[VHOST_NET_VQ_TX ];struct vhost_virtqueue *vq = &nvq->vq; -unsigned out, in, s; +unsigned out, in;int head;struct msghdr msg = { .msg_name =NULL ,
@@ -395,16 +395,17 @@ static void handle_tx(struct vhost_net *net)break ; }/* Skip header. TODO: support TSO. */ - s =move_iovec_hdr (vq->iov, nvq->hdr, hdr_size, out); len =iov_length (vq->iov, out);iov_iter_init (&msg.msg_iter,WRITE , vq->iov, out, len); +iov_iter_advance (&msg.msg_iter, hdr_size);/* Sanity check */ -if (!len) { +if (!iov_iter_count (&msg.msg_iter)) {vq_err (vq,"Unexpected header len for TX: " "%zd expected %zd\n" , -iov_length (nvq->hdr, s), hdr_size); + len, hdr_size);break ; } + len =iov_iter_count (&msg.msg_iter); zcopy_used = zcopy && len >=VHOST_GOODCOPY_LEN && (nvq->upend_idx + 1) % UIO_MAXIOV !=
Signature · 1 line
2.1.4
Re: [PATCH v3 16/18] vhost: don't bother with copying iovec in handle_tx()
Quoted 8 lines · Al Viro
From: Al Viro <[email protected]>
just advance the msg.msg_iter and be done with that.
Cc Michael S. Tsirkin <[email protected]>Signed-off-by Al Viro <[email protected]>
Quoted 40 lines
--- drivers/vhost/net.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)drivers/vhost/net.c +5
-4@@ -336,7 +336,7 @@ static void handle_tx(struct vhost_net *net) {struct vhost_net_virtqueue *nvq = &net->vqs[VHOST_NET_VQ_TX ];struct vhost_virtqueue *vq = &nvq->vq; -unsigned out, in, s; +unsigned out, in;int head;struct msghdr msg = { .msg_name =NULL ,@@ -395,16 +395,17 @@ static void handle_tx(struct vhost_net *net)break ; }/* Skip header. TODO: support TSO. */ - s =move_iovec_hdr (vq->iov, nvq->hdr, hdr_size, out); len =iov_length (vq->iov, out);iov_iter_init (&msg.msg_iter,WRITE , vq->iov, out, len); +iov_iter_advance (&msg.msg_iter, hdr_size);/* Sanity check */ -if (!len) { +if (!iov_iter_count (&msg.msg_iter)) {vq_err (vq,"Unexpected header len for TX: " "%zd expected %zd\n" , -iov_length (nvq->hdr, s), hdr_size); + len, hdr_size);break ; } + len =iov_iter_count (&msg.msg_iter); zcopy_used = zcopy && len >=VHOST_GOODCOPY_LEN && (nvq->upend_idx + 1) % UIO_MAXIOV !=Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v3 17/18 vhost: don't bother copying iovecs in handle_rx(), kill memcpy_toiovecend()
In reply to Al ViroFrom: Al Viro <[email protected]>
--- drivers/vhost/net.c | 82 +++++++++++++++-------------------------------------- include/linux/uio.h | 3 -- lib/iovec.c | 26 ----------------- 3 files changed, 23 insertions(+), 88 deletions(-)
drivers/vhost/net.c +23 -59
@@ -84,10 +84,6 @@ struct vhost_net_ubuf_ref {struct vhost_net_virtqueue {struct vhost_virtqueue vq; -/* hdr is used to store the virtio header. -* Since each iovec has >= 1 byte length, we never need more than -* header length entries to store the header. */ -struct iovec hdr[sizeof (struct virtio_net_hdr_mrg_rxbuf )];size_t vhost_hlen;size_t sock_hlen;/* vhost zerocopy support fields below: */
@@ -235,44 +231,6 @@ static bool vhost_sock_zcopy(struct socket *sock)sock_flag (sock->sk,SOCK_ZEROCOPY ); } -/* Pop first len bytes from iovec. Return number of segments used. */ -static int move_iovec_hdr (struct iovec *from,struct iovec *to, -size_t len,int iov_count) -{ -int seg =0 ; -size_t size; - -while (len && seg < iov_count) { - size =min (from->iov_len, len); - to->iov_base = from->iov_base; - to->iov_len = size; - from->iov_len -= size; - from->iov_base += size; - len -= size; - ++from; - ++to; - ++seg; - } -return seg; -} -/* Copy iovec entries for len bytes from iovec. */ -static void copy_iovec_hdr (const struct iovec *from,struct iovec *to, -size_t len,int iovcount) -{ -int seg =0 ; -size_t size; - -while (len && seg < iovcount) { - size =min (from->iov_len, len); - to->iov_base = from->iov_base; - to->iov_len = size; - len -= size; - ++from; - ++to; - ++seg; - } -} -/* In case of DMA done not in order in lower device driver for some reason. * upend_idx is used to track end of used idx, done_idx is used to track head * of used idx. Once lower device DMA done contiguously, we will signal KVM
@@ -570,9 +528,9 @@ static void handle_rx(struct vhost_net *net) .msg_controllen = 0, .msg_flags = MSG_DONTWAIT, }; -struct virtio_net_hdr_mrg_rxbuf hdr = { - .hdr.flags =0 , - .hdr.gso_type =VIRTIO_NET_HDR_GSO_NONE +struct virtio_net_hdr hdr = { + .flags =0 , + .gso_type =VIRTIO_NET_HDR_GSO_NONE };size_t total_len =0 ;int err, mergeable;
@@ -580,6 +538,7 @@ static void handle_rx(struct vhost_net *net)size_t vhost_hlen, sock_hlen;size_t vhost_len, sock_len;struct socket *sock; +struct iov_iter fixup;mutex_lock (&vq->mutex); sock = vq->private_data;
@@ -624,14 +583,19 @@ static void handle_rx(struct vhost_net *net)break ; }/* We don't need to be notified again. */ -if (unlikely ((vhost_hlen))) -/* Skip header. TODO: support TSO. */ -move_iovec_hdr (vq->iov, nvq->hdr, vhost_hlen, in); -else -/* Copy the header for use in VIRTIO_NET_F_MRG_RXBUF: -* needed because recvmsg can modify msg_iov. */ -copy_iovec_hdr (vq->iov, nvq->hdr, sock_hlen, in); -iov_iter_init (&msg.msg_iter,READ , vq->iov, in, sock_len); +iov_iter_init (&msg.msg_iter,READ , vq->iov, in, vhost_len); + fixup = msg.msg_iter; +if (unlikely ((vhost_hlen))) { +/* We will supply the header ourselves +* TODO: support TSO. +*/ +iov_iter_advance (&msg.msg_iter, vhost_hlen); + }else { +/* It'll come from socket; we'll need to patch +* ->num_buffers over if VIRTIO_NET_F_MRG_RXBUF +*/ +iov_iter_advance (&fixup,sizeof (hdr)); + } err = sock->ops->recvmsg (NULL , sock, &msg, sock_len,MSG_DONTWAIT |MSG_TRUNC );/* Userspace might have consumed the packet meanwhile:
@@ -643,18 +607,18 @@ static void handle_rx(struct vhost_net *net)vhost_discard_vq_desc (vq, headcount);continue ; } +/* Supply virtio_net_hdr if VHOST_NET_F_VIRTIO_NET_HDR */ if (unlikely (vhost_hlen) && -memcpy_toiovecend (nvq->hdr, (unsigned char *)&hdr,0 , - vhost_hlen)) { +copy_to_iter (&hdr,sizeof (hdr), &fixup) !=sizeof (hdr)) {vq_err (vq,"Unable to write vnet_hdr at addr %p\n" , vq->iov->iov_base);break ; } -/* TODO: Should check and handle checksum. */ +/* Supply (or replace) ->num_buffers if VIRTIO_NET_F_MRG_RXBUF +* TODO: Should check and handle checksum. +*/ if (likely (mergeable) && -memcpy_toiovecend (nvq->hdr, (unsigned char *)&headcount, - offsetof(typeof (hdr ), num_buffers), -sizeof hdr.num_buffers)) { +copy_to_iter (&headcount,2 , &fixup) !=2 ) {vq_err (vq,"Failed num_buffers write" );vhost_discard_vq_desc (vq, headcount);break ;
include/linux/uio.h +0 -3
@@ -137,7 +137,4 @@ size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct ioint memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov,int offset,int len); -int memcpy_toiovecend (const struct iovec *v,unsigned char *kdata, -int offset,int len); -#endif
lib/iovec.c +0 -26
@@ -3,32 +3,6 @@#include <linux/uio.h> /* -* Copy kernel to iovec. Returns -EFAULT on error. -*/ - -int memcpy_toiovecend (const struct iovec *iov,unsigned char *kdata, -int offset,int len) -{ -int copy; -for (; len >0 ; ++iov) { -/* Skip over the finished iovecs */ -if (unlikely (offset >= iov->iov_len)) { - offset -= iov->iov_len; -continue ; - } - copy = min_t(unsigned int, iov->iov_len - offset, len); -if (copy_to_user (iov->iov_base + offset, kdata, copy)) -return -EFAULT ; - offset =0 ; - kdata += copy; - len -= copy; - } - -return 0 ; -} -EXPORT_SYMBOL (memcpy_toiovecend); - -/* * Copy iovec to kernel. Returns -EFAULT on error. */
Signature · 1 line
2.1.4
Re: [PATCH v3 17/18] vhost: don't bother copying iovecs in handle_rx(), kill memcpy_toiovecend()
Quoted 6 lines · Al Viro
From: Al Viro <[email protected]>
Cc Michael S. Tsirkin <[email protected]>Signed-off-by Al Viro <[email protected]>
Quoted 191 lines
--- drivers/vhost/net.c | 82 +++++++++++++++-------------------------------------- include/linux/uio.h | 3 -- lib/iovec.c | 26 ----------------- 3 files changed, 23 insertions(+), 88 deletions(-)drivers/vhost/net.c +23
-59@@ -84,10 +84,6 @@ struct vhost_net_ubuf_ref {struct vhost_net_virtqueue {struct vhost_virtqueue vq; -/* hdr is used to store the virtio header. -* Since each iovec has >= 1 byte length, we never need more than -* header length entries to store the header. */ -struct iovec hdr[sizeof (struct virtio_net_hdr_mrg_rxbuf )];size_t vhost_hlen;size_t sock_hlen;/* vhost zerocopy support fields below: */ @@ -235,44 +231,6 @@ static bool vhost_sock_zcopy(struct socket *sock)sock_flag (sock->sk,SOCK_ZEROCOPY ); } -/* Pop first len bytes from iovec. Return number of segments used. */ -static int move_iovec_hdr (struct iovec *from,struct iovec *to, -size_t len,int iov_count) -{ -int seg =0 ; -size_t size; - -while (len && seg < iov_count) { - size =min (from->iov_len, len); - to->iov_base = from->iov_base; - to->iov_len = size; - from->iov_len -= size; - from->iov_base += size; - len -= size; - ++from; - ++to; - ++seg; - } -return seg; -} -/* Copy iovec entries for len bytes from iovec. */ -static void copy_iovec_hdr (const struct iovec *from,struct iovec *to, -size_t len,int iovcount) -{ -int seg =0 ; -size_t size; - -while (len && seg < iovcount) { - size =min (from->iov_len, len); - to->iov_base = from->iov_base; - to->iov_len = size; - len -= size; - ++from; - ++to; - ++seg; - } -} -/* In case of DMA done not in order in lower device driver for some reason. * upend_idx is used to track end of used idx, done_idx is used to track head * of used idx. Once lower device DMA done contiguously, we will signal KVM @@ -570,9 +528,9 @@ static void handle_rx(struct vhost_net *net) .msg_controllen = 0, .msg_flags = MSG_DONTWAIT, }; -struct virtio_net_hdr_mrg_rxbuf hdr = { - .hdr.flags =0 , - .hdr.gso_type =VIRTIO_NET_HDR_GSO_NONE +struct virtio_net_hdr hdr = { + .flags =0 , + .gso_type =VIRTIO_NET_HDR_GSO_NONE };size_t total_len =0 ;int err, mergeable;@@ -580,6 +538,7 @@ static void handle_rx(struct vhost_net *net)size_t vhost_hlen, sock_hlen;size_t vhost_len, sock_len;struct socket *sock; +struct iov_iter fixup;mutex_lock (&vq->mutex); sock = vq->private_data;@@ -624,14 +583,19 @@ static void handle_rx(struct vhost_net *net)break ; }/* We don't need to be notified again. */ -if (unlikely ((vhost_hlen))) -/* Skip header. TODO: support TSO. */ -move_iovec_hdr (vq->iov, nvq->hdr, vhost_hlen, in); -else -/* Copy the header for use in VIRTIO_NET_F_MRG_RXBUF: -* needed because recvmsg can modify msg_iov. */ -copy_iovec_hdr (vq->iov, nvq->hdr, sock_hlen, in); -iov_iter_init (&msg.msg_iter,READ , vq->iov, in, sock_len); +iov_iter_init (&msg.msg_iter,READ , vq->iov, in, vhost_len); + fixup = msg.msg_iter; +if (unlikely ((vhost_hlen))) { +/* We will supply the header ourselves +* TODO: support TSO. +*/ +iov_iter_advance (&msg.msg_iter, vhost_hlen); + }else { +/* It'll come from socket; we'll need to patch +* ->num_buffers over if VIRTIO_NET_F_MRG_RXBUF +*/ +iov_iter_advance (&fixup,sizeof (hdr)); + } err = sock->ops->recvmsg (NULL , sock, &msg, sock_len,MSG_DONTWAIT |MSG_TRUNC );/* Userspace might have consumed the packet meanwhile: @@ -643,18 +607,18 @@ static void handle_rx(struct vhost_net *net)vhost_discard_vq_desc (vq, headcount);continue ; } +/* Supply virtio_net_hdr if VHOST_NET_F_VIRTIO_NET_HDR */ if (unlikely (vhost_hlen) && -memcpy_toiovecend (nvq->hdr, (unsigned char *)&hdr,0 , - vhost_hlen)) { +copy_to_iter (&hdr,sizeof (hdr), &fixup) !=sizeof (hdr)) {vq_err (vq,"Unable to write vnet_hdr at addr %p\n" , vq->iov->iov_base);break ; } -/* TODO: Should check and handle checksum. */ +/* Supply (or replace) ->num_buffers if VIRTIO_NET_F_MRG_RXBUF +* TODO: Should check and handle checksum. +*/ if (likely (mergeable) && -memcpy_toiovecend (nvq->hdr, (unsigned char *)&headcount, - offsetof(typeof (hdr ), num_buffers), -sizeof hdr.num_buffers)) { +copy_to_iter (&headcount,2 , &fixup) !=2 ) {vq_err (vq,"Failed num_buffers write" );vhost_discard_vq_desc (vq, headcount);break ;include/linux/uio.h +0
-3@@ -137,7 +137,4 @@ size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct ioint memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov,int offset,int len); -int memcpy_toiovecend (const struct iovec *v,unsigned char *kdata, -int offset,int len); -#endif lib/iovec.c +0
-26@@ -3,32 +3,6 @@#include <linux/uio.h> /* -* Copy kernel to iovec. Returns -EFAULT on error. -*/ - -int memcpy_toiovecend (const struct iovec *iov,unsigned char *kdata, -int offset,int len) -{ -int copy; -for (; len >0 ; ++iov) { -/* Skip over the finished iovecs */ -if (unlikely (offset >= iov->iov_len)) { - offset -= iov->iov_len; -continue ; - } - copy = min_t(unsigned int, iov->iov_len - offset, len); -if (copy_to_user (iov->iov_base + offset, kdata, copy)) -return -EFAULT ; - offset =0 ; - kdata += copy; - len -= copy; - } - -return 0 ; -} -EXPORT_SYMBOL (memcpy_toiovecend); - -/* * Copy iovec to kernel. Returns -EFAULT on error. */ Signature · 1 line
2.1.4
Re: [PATCH v3 17/18] vhost: don't bother copying iovecs in handle_rx(), kill memcpy_toiovecend()
In reply to Al ViroQuoted 6 lines · Al Viro
From: Al Viro <[email protected]>
Cc Michael S. Tsirkin <[email protected]>Signed-off-by Al Viro <[email protected]>
Quoted 191 lines
--- drivers/vhost/net.c | 82 +++++++++++++++-------------------------------------- include/linux/uio.h | 3 -- lib/iovec.c | 26 ----------------- 3 files changed, 23 insertions(+), 88 deletions(-)drivers/vhost/net.c +23
-59@@ -84,10 +84,6 @@ struct vhost_net_ubuf_ref {struct vhost_net_virtqueue {struct vhost_virtqueue vq; -/* hdr is used to store the virtio header. -* Since each iovec has >= 1 byte length, we never need more than -* header length entries to store the header. */ -struct iovec hdr[sizeof (struct virtio_net_hdr_mrg_rxbuf )];size_t vhost_hlen;size_t sock_hlen;/* vhost zerocopy support fields below: */ @@ -235,44 +231,6 @@ static bool vhost_sock_zcopy(struct socket *sock)sock_flag (sock->sk,SOCK_ZEROCOPY ); } -/* Pop first len bytes from iovec. Return number of segments used. */ -static int move_iovec_hdr (struct iovec *from,struct iovec *to, -size_t len,int iov_count) -{ -int seg =0 ; -size_t size; - -while (len && seg < iov_count) { - size =min (from->iov_len, len); - to->iov_base = from->iov_base; - to->iov_len = size; - from->iov_len -= size; - from->iov_base += size; - len -= size; - ++from; - ++to; - ++seg; - } -return seg; -} -/* Copy iovec entries for len bytes from iovec. */ -static void copy_iovec_hdr (const struct iovec *from,struct iovec *to, -size_t len,int iovcount) -{ -int seg =0 ; -size_t size; - -while (len && seg < iovcount) { - size =min (from->iov_len, len); - to->iov_base = from->iov_base; - to->iov_len = size; - len -= size; - ++from; - ++to; - ++seg; - } -} -/* In case of DMA done not in order in lower device driver for some reason. * upend_idx is used to track end of used idx, done_idx is used to track head * of used idx. Once lower device DMA done contiguously, we will signal KVM @@ -570,9 +528,9 @@ static void handle_rx(struct vhost_net *net) .msg_controllen = 0, .msg_flags = MSG_DONTWAIT, }; -struct virtio_net_hdr_mrg_rxbuf hdr = { - .hdr.flags =0 , - .hdr.gso_type =VIRTIO_NET_HDR_GSO_NONE +struct virtio_net_hdr hdr = { + .flags =0 , + .gso_type =VIRTIO_NET_HDR_GSO_NONE };size_t total_len =0 ;int err, mergeable;@@ -580,6 +538,7 @@ static void handle_rx(struct vhost_net *net)size_t vhost_hlen, sock_hlen;size_t vhost_len, sock_len;struct socket *sock; +struct iov_iter fixup;mutex_lock (&vq->mutex); sock = vq->private_data;@@ -624,14 +583,19 @@ static void handle_rx(struct vhost_net *net)break ; }/* We don't need to be notified again. */ -if (unlikely ((vhost_hlen))) -/* Skip header. TODO: support TSO. */ -move_iovec_hdr (vq->iov, nvq->hdr, vhost_hlen, in); -else -/* Copy the header for use in VIRTIO_NET_F_MRG_RXBUF: -* needed because recvmsg can modify msg_iov. */ -copy_iovec_hdr (vq->iov, nvq->hdr, sock_hlen, in); -iov_iter_init (&msg.msg_iter,READ , vq->iov, in, sock_len); +iov_iter_init (&msg.msg_iter,READ , vq->iov, in, vhost_len); + fixup = msg.msg_iter; +if (unlikely ((vhost_hlen))) { +/* We will supply the header ourselves +* TODO: support TSO. +*/ +iov_iter_advance (&msg.msg_iter, vhost_hlen); + }else { +/* It'll come from socket; we'll need to patch +* ->num_buffers over if VIRTIO_NET_F_MRG_RXBUF +*/ +iov_iter_advance (&fixup,sizeof (hdr)); + } err = sock->ops->recvmsg (NULL , sock, &msg, sock_len,MSG_DONTWAIT |MSG_TRUNC );/* Userspace might have consumed the packet meanwhile: @@ -643,18 +607,18 @@ static void handle_rx(struct vhost_net *net)vhost_discard_vq_desc (vq, headcount);continue ; } +/* Supply virtio_net_hdr if VHOST_NET_F_VIRTIO_NET_HDR */ if (unlikely (vhost_hlen) && -memcpy_toiovecend (nvq->hdr, (unsigned char *)&hdr,0 , - vhost_hlen)) { +copy_to_iter (&hdr,sizeof (hdr), &fixup) !=sizeof (hdr)) {vq_err (vq,"Unable to write vnet_hdr at addr %p\n" , vq->iov->iov_base);break ; } -/* TODO: Should check and handle checksum. */ +/* Supply (or replace) ->num_buffers if VIRTIO_NET_F_MRG_RXBUF +* TODO: Should check and handle checksum. +*/ if (likely (mergeable) && -memcpy_toiovecend (nvq->hdr, (unsigned char *)&headcount, - offsetof(typeof (hdr ), num_buffers), -sizeof hdr.num_buffers)) { +copy_to_iter (&headcount,2 , &fixup) !=2 ) {vq_err (vq,"Failed num_buffers write" );vhost_discard_vq_desc (vq, headcount);break ;include/linux/uio.h +0
-3@@ -137,7 +137,4 @@ size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct ioint memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov,int offset,int len); -int memcpy_toiovecend (const struct iovec *v,unsigned char *kdata, -int offset,int len); -#endif lib/iovec.c +0
-26@@ -3,32 +3,6 @@#include <linux/uio.h> /* -* Copy kernel to iovec. Returns -EFAULT on error. -*/ - -int memcpy_toiovecend (const struct iovec *iov,unsigned char *kdata, -int offset,int len) -{ -int copy; -for (; len >0 ; ++iov) { -/* Skip over the finished iovecs */ -if (unlikely (offset >= iov->iov_len)) { - offset -= iov->iov_len; -continue ; - } - copy = min_t(unsigned int, iov->iov_len - offset, len); -if (copy_to_user (iov->iov_base + offset, kdata, copy)) -return -EFAULT ; - offset =0 ; - kdata += copy; - len -= copy; - } - -return 0 ; -} -EXPORT_SYMBOL (memcpy_toiovecend); - -/* * Copy iovec to kernel. Returns -EFAULT on error. */ Signature · 1 line
2.1.4
Michael S. Tsirkin
maintainerRe: [PATCH v3 17/18] vhost: don't bother copying iovecs in handle_rx(), kill memcpy_toiovecend()
In reply to Al Virodrivers/vhost/net.c static void handle_rx(struct vhost_net *net) · line 624
Quoted 8 lines
drivers/vhost/net.c +1
-3if (likely (mergeable) && -memcpy_toiovecend (nvq->hdr, (unsigned char *)&headcount, - offsetof(typeof (hdr ), num_buffers), -sizeof hdr.num_buffers)) { +copy_to_iter (&headcount,2 , &fixup) !=2 ) {vq_err (vq,"Failed num_buffers write" );vhost_discard_vq_desc (vq, headcount);break ;
BTW this will have to be re-based on top of
http://mid.gmane.org/[email protected]
taking byte-swap into account.
Al Viro
maintainerPATCH v3 18/18 vhost: vhost_scsi_handle_vq() should just use copy_from_user()
In reply to Al ViroFrom: Al Viro <[email protected]>
it has just verified that it asks no more than the length of the first segment of iovec.
And with that the last user of stuff in lib/iovec.c is gone. RIP.
--- drivers/vhost/scsi.c | 2 +- include/linux/uio.h | 2 -- lib/Makefile | 2 +- lib/iovec.c | 36 ------------------------------------ 4 files changed, 2 insertions(+), 40 deletions(-) delete mode 100644 lib/iovec.c
drivers/vhost/scsi.c +1 -1
@@ -1079,7 +1079,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) req_size, vq->iov[0].iov_len);break ; } - ret =memcpy_fromiovecend (req, &vq->iov[0 ],0 , req_size); + ret =copy_from_user (req, vq->iov[0 ].iov_base, req_size);if (unlikely (ret)) {vq_err (vq,"Faulted on virtio_scsi_cmd_req\n" );break ;
include/linux/uio.h +0 -2
@@ -135,6 +135,4 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count)size_t csum_and_copy_to_iter (void *addr,size_t bytes,__wsum *csum,struct iov_iter *i);size_t csum_and_copy_from_iter (void *addr,size_t bytes,__wsum *csum,struct iov_iter *i); -int memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov, -int offset,int len);#endif
lib/Makefile +1 -1
@@ -24,7 +24,7 @@ obj-y += lockref.o obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \ - gcd.o lcm.o list_sort.o uuid.o flex_array.o iovec.o clz_ctz.o \ + gcd.o lcm.o list_sort.o uuid.o flex_array.o clz_ctz.o \ bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o \ percpu-refcount.o percpu_ida.o rhashtable.o reciprocal_div.o obj-y += string_helpers.o
lib/iovec.c deleted +0 -36
@@ -1,36 +0,0 @@ -#include <linux/uaccess.h> -#include <linux/export.h> -#include <linux/uio.h> - -/* -* Copy iovec to kernel. Returns -EFAULT on error. -*/ - -int memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov, -int offset,int len) -{ -/* No data? Done! */ -if (len ==0 ) -return 0 ; - -/* Skip over the finished iovecs */ -while (offset >= iov->iov_len) { - offset -= iov->iov_len; - iov++; - } - -while (len >0 ) { -u8 __user *base = iov->iov_base + offset; - int copy = min_t(unsigned int, len, iov->iov_len - offset); - - offset =0 ; -if (copy_from_user (kdata, base, copy)) -return -EFAULT ; - len -= copy; - kdata += copy; - iov++; - } - -return 0 ; -} -EXPORT_SYMBOL (memcpy_fromiovecend);
Signature · 1 line
2.1.4
Re: [PATCH v3 18/18] vhost: vhost_scsi_handle_vq() should just use copy_from_user()
Quoted 5 lines · Al Viro
From: Al Viro <[email protected]>
it has just verified that it asks no more than the length of the first segment of iovec.
Quoted 8 lines
And with that the last user of stuff in
lib/iovec.cis gone. RIP.Cc Michael S. Tsirkin <[email protected]>Cc Nicholas A. Bellinger <[email protected]>Signed-off-by Al Viro <[email protected]>
Quoted 89 lines
--- drivers/vhost/scsi.c | 2 +- include/linux/uio.h | 2 -- lib/Makefile | 2 +- lib/iovec.c | 36 ------------------------------------ 4 files changed, 2 insertions(+), 40 deletions(-) delete mode 100644 lib/iovec.cdrivers/vhost/scsi.c +1
-1@@ -1079,7 +1079,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) req_size, vq->iov[0].iov_len);break ; } - ret =memcpy_fromiovecend (req, &vq->iov[0 ],0 , req_size); + ret =copy_from_user (req, vq->iov[0 ].iov_base, req_size);if (unlikely (ret)) {vq_err (vq,"Faulted on virtio_scsi_cmd_req\n" );break ;include/linux/uio.h +0
-2@@ -135,6 +135,4 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count)size_t csum_and_copy_to_iter (void *addr,size_t bytes,__wsum *csum,struct iov_iter *i);size_t csum_and_copy_from_iter (void *addr,size_t bytes,__wsum *csum,struct iov_iter *i); -int memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov, -int offset,int len);#endif lib/Makefile +1
-1@@ -24,7 +24,7 @@ obj-y += lockref.o obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \ - gcd.o lcm.o list_sort.o uuid.o flex_array.o iovec.o clz_ctz.o \ + gcd.o lcm.o list_sort.o uuid.o flex_array.o clz_ctz.o \ bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o \ percpu-refcount.o percpu_ida.o rhashtable.o reciprocal_div.o obj-y += string_helpers.olib/iovec.c deleted +0
-36@@ -1,36 +0,0 @@ -#include <linux/uaccess.h> -#include <linux/export.h> -#include <linux/uio.h> - -/* -* Copy iovec to kernel. Returns -EFAULT on error. -*/ - -int memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov, -int offset,int len) -{ -/* No data? Done! */ -if (len ==0 ) -return 0 ; - -/* Skip over the finished iovecs */ -while (offset >= iov->iov_len) { - offset -= iov->iov_len; - iov++; - } - -while (len >0 ) { -u8 __user *base = iov->iov_base + offset; - int copy = min_t(unsigned int, len, iov->iov_len - offset); - - offset =0 ; -if (copy_from_user (kdata, base, copy)) -return -EFAULT ; - len -= copy; - kdata += copy; - iov++; - } - -return 0 ; -} -EXPORT_SYMBOL (memcpy_fromiovecend);Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v2 2/18 ipv4: raw_send_hdrinc(): pass msghdr
In reply to Al ViroFrom: Al Viro <[email protected]>
Switch from passing msg->iov_iter.iov to passing msg itself
--- net/ipv4/raw.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
net/ipv4/raw.c +3 -4
@@ -337,7 +337,7 @@ int raw_rcv(struct sock *sk, struct sk_buff *skb) }static int raw_send_hdrinc (struct sock *sk,struct flowi4 *fl4, -void *from,size_t length, +struct msghdr *msg,size_t length,struct rtable **rtp,unsigned int flags) {
@@ -382,7 +382,7 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, skb->transport_header = skb->network_header; err = -EFAULT ; -if (memcpy_fromiovecend ((void *)iph, from,0 , length)) +if (memcpy_fromiovecend ((void *)iph, msg->msg_iter.iov,0 , length)) goto error_free; iphlen = iph->ihl *4 ;
@@ -625,8 +625,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, back_from_confirm:if (inet->hdrincl) -/* XXX: stripping const */ - err =raw_send_hdrinc (sk, &fl4, (struct iovec *)msg->msg_iter.iov, len, + err =raw_send_hdrinc (sk, &fl4, msg, len, &rt, msg->msg_flags);else {
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v2 3/18 ipv6: rawv6_send_hdrinc(): pass msghdr
In reply to Al ViroFrom: Al Viro <[email protected]>
Switch from passing msg->iov_iter.iov to passing msg itself
--- net/ipv6/raw.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
net/ipv6/raw.c +3 -4
@@ -609,7 +609,7 @@ out:return err; } -static int rawv6_send_hdrinc (struct sock *sk,void *from,int length, +static int rawv6_send_hdrinc (struct sock *sk,struct msghdr *msg,int length,struct flowi6 *fl6,struct dst_entry **dstp,unsigned int flags) {
@@ -648,7 +648,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, skb->ip_summed =CHECKSUM_NONE ; skb->transport_header = skb->network_header; - err =memcpy_fromiovecend ((void *)iph, from,0 , length); + err =memcpy_fromiovecend ((void *)iph, msg->msg_iter.iov,0 , length);if (err) goto error_fault;
@@ -886,8 +886,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, back_from_confirm:if (inet->hdrincl) -/* XXX: stripping const */ - err =rawv6_send_hdrinc (sk, (struct iovec *)msg->msg_iter.iov, len, &fl6, &dst, msg->msg_flags); + err =rawv6_send_hdrinc (sk, msg, len, &fl6, &dst, msg->msg_flags);else {lock_sock (sk); err = ip6_append_data(sk, raw6_getfrag, &rfv,
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v2 4/18 vmci: propagate msghdr all way down to __qp_memcpy_to_queue()
In reply to Al ViroFrom: Al Viro <[email protected]>
Switch from passing msg->iov_iter.iov to passing msg itself
--- drivers/misc/vmw_vmci/vmci_queue_pair.c | 16 ++++++++-------- include/linux/vmw_vmci_api.h | 2 +- net/vmw_vsock/vmci_transport.c | 3 +-- 3 files changed, 10 insertions(+), 11 deletions(-)
drivers/misc/vmw_vmci/vmci_queue_pair.c +8 -8
@@ -370,12 +370,12 @@ static int __qp_memcpy_to_queue(struct vmci_queue *queue, to_copy = size - bytes_copied;if (is_iovec) { -struct iovec *iov = (struct iovec *)src; +struct msghdr *msg = (struct msghdr *)src;int err;/* The iovec will track bytes_copied internally. */ - err =memcpy_fromiovec ((u8 *)va + page_offset, - iov, to_copy); + err =memcpy_from_msg ((u8 *)va + page_offset, + msg, to_copy);if (err !=0 ) {if (kernel_if->host)kunmap (kernel_if->u.h.page[page_index]);
@@ -580,7 +580,7 @@ static int qp_memcpy_from_queue(void *dest,*/ static int qp_memcpy_to_queue_iov (struct vmci_queue *queue,u64 queue_offset, -const void *src, +const void *msg,size_t src_offset,size_t size) {
@@ -588,7 +588,7 @@ static int qp_memcpy_to_queue_iov(struct vmci_queue *queue,* We ignore src_offset because src is really a struct iovec * and will * maintain offset internally. */ -return __qp_memcpy_to_queue (queue, queue_offset, src, size, true); +return __qp_memcpy_to_queue (queue, queue_offset, msg, size, true); }/*
@@ -3223,13 +3223,13 @@ EXPORT_SYMBOL_GPL(vmci_qpair_peek);* of bytes enqueued or < 0 on error. */ ssize_t vmci_qpair_enquev (struct vmci_qp *qpair, -void *iov, +struct msghdr *msg,size_t iov_size,int buf_type) {ssize_t result; -if (!qpair || !iov) +if (!qpair)return VMCI_ERROR_INVALID_ARGS ;qp_lock (qpair);
@@ -3238,7 +3238,7 @@ ssize_t vmci_qpair_enquev(struct vmci_qp *qpair, result =qp_enqueue_locked (qpair->produce_q, qpair->consume_q, qpair->produce_q_size, - iov, iov_size, + msg, iov_size, qp_memcpy_to_queue_iov); if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
include/linux/vmw_vmci_api.h +1 -1
@@ -74,7 +74,7 @@ ssize_t vmci_qpair_dequeue(struct vmci_qp *qpair,ssize_t vmci_qpair_peek (struct vmci_qp *qpair,void *buf,size_t buf_size,int mode);ssize_t vmci_qpair_enquev (struct vmci_qp *qpair, -void *iov,size_t iov_size,int mode); +struct msghdr *msg,size_t iov_size,int mode);ssize_t vmci_qpair_dequev (struct vmci_qp *qpair,struct msghdr *msg,size_t iov_size,int mode); ssize_t vmci_qpair_peekv(struct vmci_qp *qpair, struct msghdr *msg, size_t iov_size,
net/vmw_vsock/vmci_transport.c +1 -2
@@ -1850,8 +1850,7 @@ static ssize_t vmci_transport_stream_enqueue( struct msghdr *msg, size_t len) { -/* XXX: stripping const */ -return vmci_qpair_enquev (vmci_trans (vsk)->qpair, (struct iovec *)msg->msg_iter.iov, len,0 ); +return vmci_qpair_enquev (vmci_trans (vsk)->qpair, msg, len,0 ); }static s64 vmci_transport_stream_has_data (struct vsock_sock *vsk)
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v2 5/18 rxrpc: switch rxrpc_send_data() to iov_iter primitives
In reply to Al ViroFrom: Al Viro <[email protected]>
Convert skb_add_data() to iov_iter; allows to get rid of the explicit messing with iovec in its only caller - skb_add_data() will keep advancing ->msg_iter for us, so there's no need to similate that manually.
--- include/linux/skbuff.h | 11 +++++------ net/rxrpc/ar-output.c | 43 ++++++++++--------------------------------- 2 files changed, 15 insertions(+), 39 deletions(-)
include/linux/skbuff.h +5 -6
@@ -2484,19 +2484,18 @@ static inline int skb_put_padto(struct sk_buff *skb, unsigned int len) }static inline int skb_add_data (struct sk_buff *skb, -char __user *from,int copy) +struct iov_iter *from,int copy) {const int off = skb->len;if (skb->ip_summed ==CHECKSUM_NONE ) { -int err =0 ; -__wsum csum =csum_and_copy_from_user (from,skb_put (skb, copy), - copy,0 , &err); -if (!err) { +__wsum csum =0 ; +if (csum_and_copy_from_iter (skb_put (skb, copy), copy, + &csum, from) == copy) { skb->csum =csum_block_add (skb->csum, csum, off);return 0 ; } - }else if (!copy_from_user (skb_put (skb, copy), from, copy)) + }else if (copy_from_iter (skb_put (skb, copy), copy, from) == copy)return 0 ;__skb_trim (skb, off);
net/rxrpc/ar-output.c +10 -33
97 lines not on this page · raw message
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v2 6/18 rxrpc: make the users of rxrpc_kernel_send_data() set kvec-backed msg_iter properly
In reply to Al ViroFrom: Al Viro <[email protected]>
Use iov_iter_kvec() there, get rid of set_fs() games - now that rxrpc_send_data() uses iov_iter primitives, it'll handle ITER_KVEC just fine.
--- fs/afs/rxrpc.c | 14 +++++++------- net/rxrpc/ar-output.c | 3 --- 2 files changed, 7 insertions(+), 10 deletions(-)
fs/afs/rxrpc.c +7 -7
@@ -306,8 +306,8 @@ static int afs_send_pages(struct afs_call *call, struct msghdr *msg,_debug ("- range %u-%u%s" , offset, to, msg->msg_flags ?" [more]" :"" ); -iov_iter_init (&msg->msg_iter,WRITE , - (struct iovec *) iov,1 , to - offset); +iov_iter_kvec (&msg->msg_iter,WRITE |ITER_KVEC , + iov,1 , to - offset);/* have to change the state *before* sending the last * packet as RxRPC might give us the reply before it
@@ -384,7 +384,7 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, msg.msg_name =NULL ; msg.msg_namelen =0 ; -iov_iter_init (&msg.msg_iter,WRITE , (struct iovec *)iov,1 , +iov_iter_kvec (&msg.msg_iter,WRITE |ITER_KVEC , iov,1 , call->request_size); msg.msg_control =NULL ; msg.msg_controllen =0 ;
@@ -770,7 +770,7 @@ static int afs_deliver_cm_op_id(struct afs_call *call, struct sk_buff *skb,void afs_send_empty_reply (struct afs_call *call) {struct msghdr msg; -struct iovec iov[1 ]; +struct kvec iov[1 ];_enter ("" );
@@ -778,7 +778,7 @@ void afs_send_empty_reply(struct afs_call *call) iov[0 ].iov_len =0 ; msg.msg_name =NULL ; msg.msg_namelen =0 ; -iov_iter_init (&msg.msg_iter,WRITE , iov,0 ,0 );/* WTF? */ +iov_iter_kvec (&msg.msg_iter,WRITE |ITER_KVEC , iov,0 ,0 );/* WTF? */ msg.msg_control =NULL ; msg.msg_controllen =0 ; msg.msg_flags =0 ;
@@ -805,7 +805,7 @@ void afs_send_empty_reply(struct afs_call *call)void afs_send_simple_reply (struct afs_call *call,const void *buf,size_t len) {struct msghdr msg; -struct iovec iov[1 ]; +struct kvec iov[1 ];int n;_enter ("" );
@@ -814,7 +814,7 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len) iov[0 ].iov_len = len; msg.msg_name =NULL ; msg.msg_namelen =0 ; -iov_iter_init (&msg.msg_iter,WRITE , iov,1 , len); +iov_iter_kvec (&msg.msg_iter,WRITE |ITER_KVEC , iov,1 , len); msg.msg_control =NULL ; msg.msg_controllen =0 ; msg.msg_flags =0 ;
net/rxrpc/ar-output.c +0 -3
@@ -232,10 +232,7 @@ int rxrpc_kernel_send_data(struct rxrpc_call *call, struct msghdr *msg, call->state != RXRPC_CALL_SERVER_SEND_REPLY) { ret = -EPROTO; /* request phase complete for this client call */ } else { -mm_segment_t oldfs =get_fs (); -set_fs (KERNEL_DS ); ret =rxrpc_send_data (NULL , call->socket, call, msg, len); -set_fs (oldfs); }release_sock (&call->socket->sk);
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v2 7/18 ip: stash a pointer to msghdr in struct ping_fakehdr
In reply to Al ViroFrom: Al Viro <[email protected]>
... instead of storing its ->mgs_iter.iov there
--- include/net/ping.h | 2 +- net/ipv4/ping.c | 7 +++---- net/ipv6/ping.c | 3 +-- 3 files changed, 5 insertions(+), 7 deletions(-)
include/net/ping.h +1 -1
@@ -59,7 +59,7 @@ extern struct pingv6_ops pingv6_ops;struct pingfakehdr {struct icmphdr icmph; -struct iovec *iov; +struct msghdr *msg;sa_family_t family;__wsum wcheck; };
net/ipv4/ping.c +3 -4
@@ -602,14 +602,14 @@ int ping_getfrag(void *from, char *to,if (fraglen <sizeof (struct icmphdr ))BUG ();if (csum_partial_copy_fromiovecend (to +sizeof (struct icmphdr ), - pfh->iov,0 , fraglen -sizeof (struct icmphdr ), + pfh->msg->msg_iter.iov,0 , fraglen -sizeof (struct icmphdr ), &pfh->wcheck))return -EFAULT ; }else if (offset <sizeof (struct icmphdr )) {BUG (); }else {if (csum_partial_copy_fromiovecend - (to, pfh->iov, offset -sizeof (struct icmphdr ), + (to, pfh->msg->msg_iter.iov, offset -sizeof (struct icmphdr ), fraglen, &pfh->wcheck))return -EFAULT ; }
@@ -811,8 +811,7 @@ back_from_confirm: pfh.icmph.checksum =0 ; pfh.icmph.un.echo.id = inet->inet_sport; pfh.icmph.un.echo.sequence = user_icmph.un.echo.sequence; -/* XXX: stripping const */ - pfh.iov = (struct iovec *)msg->msg_iter.iov; + pfh.msg = msg; pfh.wcheck =0 ; pfh.family =AF_INET ;
net/ipv6/ping.c +1 -2
@@ -163,8 +163,7 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, pfh.icmph.checksum =0 ; pfh.icmph.un.echo.id = inet->inet_sport; pfh.icmph.un.echo.sequence = user_icmph.icmp6_sequence; -/* XXX: stripping const */ - pfh.iov = (struct iovec *)msg->msg_iter.iov; + pfh.msg = msg; pfh.wcheck =0 ; pfh.family =AF_INET6 ;
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v2 8/18 ip: convert tcp_sendmsg() to iov_iter primitives
In reply to Al ViroFrom: Al Viro <[email protected]>
patch is actually smaller than it seems to be - most of it is unindenting the inner loop body in tcp_sendmsg() itself...
the bit in tcp_input.c is going to get reverted very soon - that's what memcpy_from_msg() will become, but not in this commit; let's keep it reasonably contained...
There's one potentially subtle change here: in case of short copy from userland, mainline tcp_send_syn_data() discards the skb it has allocated and falls back to normal path, where we'll send as much as possible after rereading the same data again. This patch trims SYN+data skb instead - that way we don't need to copy from the same place twice.
--- include/net/sock.h | 18 ++-- net/ipv4/tcp.c | 233 +++++++++++++++++++++++--------------------------- net/ipv4/tcp_input.c | 2 +- net/ipv4/tcp_output.c | 11 ++- 4 files changed, 123 insertions(+), 141 deletions(-)
include/net/sock.h +8 -10
@@ -1803,27 +1803,25 @@ static inline void sk_nocaps_add(struct sock *sk, netdev_features_t flags) }static inline int skb_do_copy_data_nocache (struct sock *sk,struct sk_buff *skb, -char __user *from,char *to, +struct iov_iter *from,char *to,int copy,int offset) {if (skb->ip_summed ==CHECKSUM_NONE ) { -int err =0 ; -__wsum csum =csum_and_copy_from_user (from, to, copy,0 , &err); -if (err) -return err; +__wsum csum =0 ; +if (csum_and_copy_from_iter (to, copy, &csum, from) != copy) +return -EFAULT ; skb->csum =csum_block_add (skb->csum, csum, offset); }else if (sk->sk_route_caps &NETIF_F_NOCACHE_COPY ) { -if (!access_ok (VERIFY_READ , from, copy) || -__copy_from_user_nocache (to, from, copy)) +if (copy_from_iter_nocache (to, copy, from) != copy)return -EFAULT ; - }else if (copy_from_user (to, from, copy)) + }else if (copy_from_iter (to, copy, from) != copy)return -EFAULT ;return 0 ; }static inline int skb_add_data_nocache (struct sock *sk,struct sk_buff *skb, -char __user *from,int copy) +struct iov_iter *from,int copy) {int err, offset = skb->len;
@@ -1835,7 +1833,7 @@ static inline int skb_add_data_nocache(struct sock *sk, struct sk_buff *skb,return err; } -static inline int skb_copy_to_page_nocache (struct sock *sk,char __user *from, +static inline int skb_copy_to_page_nocache (struct sock *sk,struct iov_iter *from,struct sk_buff *skb,struct page *page,int off,int copy)
net/ipv4/tcp.c +106 -127
283 lines not on this page · raw message
net/ipv4/tcp_input.c +1 -1
@@ -4368,7 +4368,7 @@ int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)if (tcp_try_rmem_schedule (sk, skb, skb->truesize)) goto err_free; -if (memcpy_from_msg (skb_put (skb, size), msg, size)) +if (copy_from_iter (skb_put (skb, size), size, &msg->msg_iter) != size) goto err_free;TCP_SKB_CB (skb)->seq =tcp_sk (sk)->rcv_nxt;
net/ipv4/tcp_output.c +8 -3
@@ -3055,7 +3055,7 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) {struct tcp_sock *tp =tcp_sk (sk);struct tcp_fastopen_request *fo = tp->fastopen_req; -int syn_loss =0 , space, err =0 ; +int syn_loss =0 , space, err =0 , copied;unsigned long last_syn_loss =0 ;struct sk_buff *syn_data;
@@ -3093,11 +3093,16 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) goto fallback; syn_data->ip_summed =CHECKSUM_PARTIAL ;memcpy (syn_data->cb, syn->cb,sizeof (syn->cb)); -if (unlikely (memcpy_fromiovecend (skb_put (syn_data, space), - fo->data->msg_iter.iov,0 , space))) { + copied =copy_from_iter (skb_put (syn_data, space), space, + &fo->data->msg_iter); +if (unlikely (!copied)) {kfree_skb (syn_data); goto fallback; } +if (copied != space) { +skb_trim (syn_data, copied); + space = copied; + }/* No more data pending in inet_wait_for_connect() */ if (space == fo->size)
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v2 9/18 net: switch memcpy_fromiovec()/memcpy_fromiovecend() users to copy_from_iter()
In reply to Al ViroFrom: Al Viro <[email protected]>
That takes care of the majority of ->sendmsg() instances - most of them via memcpy_to_msg() or assorted getfrag() callbacks. One place where we still keep memcpy_fromiovecend() is tipc - there we potentially read the same data over and over; separate patch, that...
--- include/linux/skbuff.h | 3 +-- include/net/udplite.h | 3 +-- net/ipv4/ip_output.c | 6 ++---- net/ipv4/ping.c | 14 +++++++------- net/ipv4/raw.c | 2 +- net/ipv4/tcp_input.c | 2 +- net/ipv6/raw.c | 2 +- 7 files changed, 14 insertions(+), 18 deletions(-)
include/linux/skbuff.h +1 -2
@@ -2692,8 +2692,7 @@ int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci);static inline int memcpy_from_msg (void *data,struct msghdr *msg,int len) { -/* XXX: stripping const */ -return memcpy_fromiovec (data, (struct iovec *)msg->msg_iter.iov, len); +return copy_from_iter (data, len, &msg->msg_iter) == len ?0 : -EFAULT ; }static inline int memcpy_to_msg (struct msghdr *msg,void *data,int len)
include/net/udplite.h +1 -2
@@ -20,8 +20,7 @@ static __inline__ int udplite_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb) { struct msghdr *msg = from; -/* XXX: stripping const */ -return memcpy_fromiovecend (to, (struct iovec *)msg->msg_iter.iov, offset, len); +return copy_from_iter (to, len, &msg->msg_iter) != len ? -EFAULT :0 ; }/* Designate sk as UDP-Lite socket */
net/ipv4/ip_output.c +2 -4
@@ -755,13 +755,11 @@ ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct skstruct msghdr *msg = from;if (skb->ip_summed ==CHECKSUM_PARTIAL ) { -/* XXX: stripping const */ -if (memcpy_fromiovecend (to, (struct iovec *)msg->msg_iter.iov, offset, len) <0 ) +if (copy_from_iter (to, len, &msg->msg_iter) != len)return -EFAULT ; }else {__wsum csum =0 ; -/* XXX: stripping const */ -if (csum_partial_copy_fromiovecend (to, (struct iovec *)msg->msg_iter.iov, offset, len, &csum) <0 ) +if (csum_and_copy_from_iter (to, len, &csum, &msg->msg_iter) != len)return -EFAULT ; skb->csum =csum_block_add (skb->csum, csum, odd); }
net/ipv4/ping.c +7 -7
@@ -599,18 +599,18 @@ int ping_getfrag(void *from, char *to,struct pingfakehdr *pfh = (struct pingfakehdr *)from;if (offset ==0 ) { -if (fraglen <sizeof (struct icmphdr )) + fraglen -=sizeof (struct icmphdr ); +if (fraglen <0 )BUG (); -if (csum_partial_copy_fromiovecend (to +sizeof (struct icmphdr ), - pfh->msg->msg_iter.iov,0 , fraglen -sizeof (struct icmphdr ), - &pfh->wcheck)) +if (csum_and_copy_from_iter (to +sizeof (struct icmphdr ), + fraglen, &pfh->wcheck, + &pfh->msg->msg_iter) != fraglen)return -EFAULT ; }else if (offset <sizeof (struct icmphdr )) {BUG (); }else { -if (csum_partial_copy_fromiovecend - (to, pfh->msg->msg_iter.iov, offset -sizeof (struct icmphdr ), - fraglen, &pfh->wcheck)) +if (csum_and_copy_from_iter (to, fraglen, &pfh->wcheck, + &pfh->msg->msg_iter) != fraglen)return -EFAULT ; }
net/ipv4/raw.c +1 -1
@@ -382,7 +382,7 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, skb->transport_header = skb->network_header; err = -EFAULT ; -if (memcpy_fromiovecend ((void *)iph, msg->msg_iter.iov,0 , length)) +if (memcpy_from_msg (iph, msg, length)) goto error_free; iphlen = iph->ihl *4 ;
net/ipv4/tcp_input.c +1 -1
@@ -4368,7 +4368,7 @@ int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)if (tcp_try_rmem_schedule (sk, skb, skb->truesize)) goto err_free; -if (copy_from_iter (skb_put (skb, size), size, &msg->msg_iter) != size) +if (memcpy_from_msg (skb_put (skb, size), msg, size)) goto err_free;TCP_SKB_CB (skb)->seq =tcp_sk (sk)->rcv_nxt;
net/ipv6/raw.c +1 -1
@@ -648,7 +648,7 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, skb->ip_summed =CHECKSUM_NONE ; skb->transport_header = skb->network_header; - err =memcpy_fromiovecend ((void *)iph, msg->msg_iter.iov,0 , length); + err =memcpy_from_msg (iph, msg, length);if (err) goto error_fault;
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v2 10/18 tipc: tipc ->sendmsg() conversion
In reply to Al ViroFrom: Al Viro <[email protected]>
This one needs to copy the same data from user potentially more than once. Sadly, MTU changes can trigger that ;-/
--- net/tipc/msg.c | 7 ++----- net/tipc/socket.c | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 7 deletions(-)
net/tipc/msg.c +2 -5
@@ -189,7 +189,6 @@ err:* tipc_msg_build - create buffer chain containing specified header and data * @mhdr: Message header, to be prepended to data * @m: User message -* @offset: Posision in iov to start copying from * @dsz: Total length of user data * @pktmax: Max packet size that can be used * @list: Buffer or chain of buffers to be returned to caller
@@ -221,8 +220,7 @@ int tipc_msg_build(struct net *net, struct tipc_msg *mhdr, struct msghdr *m,__skb_queue_tail (list, skb);skb_copy_to_linear_data (skb, mhdr, mhsz); pktpos = skb->data + mhsz; -if (!dsz || !memcpy_fromiovecend (pktpos, m->msg_iter.iov, offset, - dsz)) +if (copy_from_iter (pktpos, dsz, &m->msg_iter) == dsz)return dsz; rc = -EFAULT ; goto error;
@@ -252,12 +250,11 @@ int tipc_msg_build(struct net *net, struct tipc_msg *mhdr, struct msghdr *m,if (drem < pktrem) pktrem = drem; -if (memcpy_fromiovecend (pktpos, m->msg_iter.iov, offset, pktrem)) { +if (copy_from_iter (pktpos, pktrem, &m->msg_iter) != pktrem) { rc = -EFAULT ; goto error; } drem -= pktrem; - offset += pktrem;if (!drem)break ;
net/tipc/socket.c +12 -2
@@ -733,6 +733,7 @@ static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq,struct net *net =sock_net (sk);struct tipc_msg *mhdr = &tipc_sk (sk)->phdr;struct sk_buff_head head; +struct iov_iter save = msg->msg_iter;uint mtu;int rc;
@@ -758,8 +759,10 @@ new_mtu: rc = dsz;break ; } -if (rc == -EMSGSIZE ) +if (rc == -EMSGSIZE ) { + msg->msg_iter = save; goto new_mtu; + }if (rc != -ELINKCONG )break ;tipc_sk (sk)->link_cong =1 ;
@@ -895,6 +898,7 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,struct sk_buff_head head;struct sk_buff *skb;struct tipc_name_seq *seq = &dest->addr.nameseq; +struct iov_iter save;u32 mtu;long timeo;int rc;
@@ -963,6 +967,7 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,msg_set_hdr_sz (mhdr,BASIC_H_SIZE ); } + save = m->msg_iter; new_mtu: mtu =tipc_node_get_mtu (net, dnode, tsk->portid);__skb_queue_head_init (&head);
@@ -980,8 +985,10 @@ new_mtu: rc = dsz;break ; } -if (rc == -EMSGSIZE ) +if (rc == -EMSGSIZE ) { + m->msg_iter = save; goto new_mtu; + }if (rc != -ELINKCONG )break ; tsk->link_cong =1 ;
@@ -1052,6 +1059,7 @@ static int tipc_send_stream(struct kiocb *iocb, struct socket *sock,long timeo;u32 dnode;uint mtu, send, sent =0 ; +struct iov_iter save;/* Handle implied connection establishment */ if (unlikely (dest)) {
@@ -1078,6 +1086,7 @@ static int tipc_send_stream(struct kiocb *iocb, struct socket *sock, dnode =tsk_peer_node (tsk); next: + save = m->msg_iter; mtu = tsk->max_pkt; send =min_t (uint, dsz - sent,TIPC_MAX_USER_MSG_SIZE );__skb_queue_head_init (&head);
@@ -1097,6 +1106,7 @@ next:if (rc == -EMSGSIZE ) { tsk->max_pkt =tipc_node_get_mtu (net, dnode, portid); + m->msg_iter = save; goto next; }if (rc != -ELINKCONG )
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v2 11/18 net: bury net/core/iovec.c - nothing in there is used anymore
In reply to Al ViroFrom: Al Viro <[email protected]>
--- include/linux/socket.h | 7 --- net/core/Makefile | 2 +- net/core/iovec.c | 137 ------------------------------------------------- 3 files changed, 1 insertion(+), 145 deletions(-) delete mode 100644 net/core/iovec.c
include/linux/socket.h +0 -7
@@ -318,13 +318,6 @@ struct ucred {/* IPX options */ #define IPX_TYPE 1 -extern int csum_partial_copy_fromiovecend (unsigned char *kdata, -struct iovec *iov, -int offset, -unsigned int len,__wsum *csump); -extern unsigned long iov_pages (const struct iovec *iov,int offset, -unsigned long nr_segs); -extern int move_addr_to_kernel (void __user *uaddr,int ulen,struct sockaddr_storage *kaddr);extern int put_cmsg (struct msghdr *,int level,int type,int len,void *data);
net/core/Makefile +1 -1
@@ -2,7 +2,7 @@ # Makefile for the Linux networking core. # -obj-y := sock.o request_sock.o skbuff.o iovec.o datagram.o stream.o scm.o \ +obj-y := sock.o request_sock.o skbuff.o datagram.o stream.o scm.o \ gen_stats.o gen_estimator.o net_namespace.o secure_seq.o flow_dissector.o obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
net/core/iovec.c deleted +0 -137
137 lines not on this page · raw message
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v2 12/18 crypto: switch af_alg_make_sg() to iov_iter
In reply to Al ViroFrom: Al Viro <[email protected]>
With that, all ->sendmsg() instances are converted to iov_iter primitives and are agnostic wrt the kind of iov_iter they are working with. So's the last remaining ->recvmsg() instance that wasn't kind-agnostic yet. All ->sendmsg() and ->recvmsg() advance ->msg_iter by the amount actually copied and none of them modifies the underlying iovec, etc.
--- crypto/af_alg.c | 40 ++++++++------------------ crypto/algif_hash.c | 45 ++++++++++++------------------ crypto/algif_skcipher.c | 74 ++++++++++++++++++++++--------------------------- include/crypto/if_alg.h | 3 +- 4 files changed, 62 insertions(+), 100 deletions(-)
crypto/af_alg.c +11 -29
@@ -338,49 +338,31 @@ static const struct net_proto_family alg_family = { .owner = THIS_MODULE, }; -int af_alg_make_sg (struct af_alg_sgl *sgl,void __user *addr,int len, -int write) +int af_alg_make_sg (struct af_alg_sgl *sgl,struct iov_iter *iter,int len) { -unsigned long from = (unsigned long )addr; -unsigned long npages; -unsigned off; -int err; -int i; - - err = -EFAULT ; -if (!access_ok (write ?VERIFY_READ :VERIFY_WRITE , addr, len)) - goto out; - - off = from & ~PAGE_MASK ; - npages = (off + len +PAGE_SIZE -1 ) >>PAGE_SHIFT ; -if (npages >ALG_MAX_PAGES ) - npages =ALG_MAX_PAGES ; +size_t off; +ssize_t n; +int npages, i; - err =get_user_pages_fast (from, npages, write, sgl->pages); -if (err <0 ) - goto out; + n =iov_iter_get_pages (iter, sgl->pages, len,ALG_MAX_PAGES , &off); +if (n <0 ) +return n; - npages = err; - err = -EINVAL ; + npages =PAGE_ALIGN (off + n);if (WARN_ON (npages ==0 )) - goto out; - - err =0 ; +return -EINVAL ;sg_init_table (sgl->sg, npages); -for (i =0 ; i < npages; i++) { +for (i =0 , len = n; i < npages; i++) {int plen =min_t (int, len,PAGE_SIZE - off);sg_set_page (sgl->sg + i, sgl->pages[i], plen, off); off =0 ; len -= plen; - err += plen; } - -out: -return err; +return n; }EXPORT_SYMBOL_GPL (af_alg_make_sg);
crypto/algif_hash.c +17 -28
62 lines not on this page · raw message
crypto/algif_skcipher.c +33 -41
100 lines not on this page · raw message
include/crypto/if_alg.h +1 -2
@@ -67,8 +67,7 @@ int af_alg_unregister_type(const struct af_alg_type *type);int af_alg_release (struct socket *sock);int af_alg_accept (struct sock *sk,struct socket *newsock); -int af_alg_make_sg (struct af_alg_sgl *sgl,void __user *addr,int len, -int write); +int af_alg_make_sg (struct af_alg_sgl *sgl,struct iov_iter *iter,int len);void af_alg_free_sg (struct af_alg_sgl *sgl);int af_alg_cmsg_send (struct msghdr *msg,struct af_alg_control *con);
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v2 13/18 net/socket.c: fold do_sock_{read,write} into callers
In reply to Al ViroFrom: Al Viro <[email protected]>
--- net/socket.c | 56 +++++++++++++++++++++----------------------------------- 1 file changed, 21 insertions(+), 35 deletions(-)
net/socket.c +21 -35
@@ -845,25 +845,11 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos,return sock->ops->splice_read (sock, ppos, pipe, len, flags); } -static ssize_t do_sock_read (struct msghdr *msg,struct kiocb *iocb, -struct file *file,const struct iovec *iov, -unsigned long nr_segs) -{ -struct socket *sock = file->private_data; - - msg->msg_name =NULL ; - msg->msg_namelen =0 ; - msg->msg_control =NULL ; - msg->msg_controllen =0 ; -iov_iter_init (&msg->msg_iter,READ , iov, nr_segs, iocb->ki_nbytes); - msg->msg_flags = (file->f_flags &O_NONBLOCK ) ?MSG_DONTWAIT :0 ; - -return __sock_recvmsg (iocb, sock, msg, iocb->ki_nbytes, msg->msg_flags); -} -static ssize_t sock_aio_read (struct kiocb *iocb,const struct iovec *iov,unsigned long nr_segs,loff_t pos) { +struct file *file = iocb->ki_filp; +struct socket *sock = file->private_data;struct msghdr msg;if (pos !=0 )
@@ -872,36 +858,36 @@ static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,if (iocb->ki_nbytes ==0 )/* Match SYS5 behaviour */ return 0 ; -return do_sock_read (&msg, iocb, iocb->ki_filp, iov, nr_segs); -} - -static ssize_t do_sock_write (struct msghdr *msg,struct kiocb *iocb, -struct file *file,const struct iovec *iov, -unsigned long nr_segs) -{ -struct socket *sock = file->private_data; - - msg->msg_name =NULL ; - msg->msg_namelen =0 ; - msg->msg_control =NULL ; - msg->msg_controllen =0 ; -iov_iter_init (&msg->msg_iter,WRITE , iov, nr_segs, iocb->ki_nbytes); - msg->msg_flags = (file->f_flags &O_NONBLOCK ) ?MSG_DONTWAIT :0 ; -if (sock->type ==SOCK_SEQPACKET ) - msg->msg_flags |=MSG_EOR ; + msg.msg_name =NULL ; + msg.msg_namelen =0 ; + msg.msg_control =NULL ; + msg.msg_controllen =0 ; +iov_iter_init (&msg.msg_iter,READ , iov, nr_segs, iocb->ki_nbytes); + msg.msg_flags = (file->f_flags &O_NONBLOCK ) ?MSG_DONTWAIT :0 ; -return __sock_sendmsg (iocb, sock, msg, iocb->ki_nbytes); +return __sock_recvmsg (iocb, sock, &msg, iocb->ki_nbytes, msg.msg_flags); }static ssize_t sock_aio_write (struct kiocb *iocb,const struct iovec *iov,unsigned long nr_segs,loff_t pos) { +struct file *file = iocb->ki_filp; +struct socket *sock = file->private_data;struct msghdr msg;if (pos !=0 )return -ESPIPE ; -return do_sock_write (&msg, iocb, iocb->ki_filp, iov, nr_segs); + msg.msg_name =NULL ; + msg.msg_namelen =0 ; + msg.msg_control =NULL ; + msg.msg_controllen =0 ; +iov_iter_init (&msg.msg_iter,WRITE , iov, nr_segs, iocb->ki_nbytes); + msg.msg_flags = (file->f_flags &O_NONBLOCK ) ?MSG_DONTWAIT :0 ; +if (sock->type ==SOCK_SEQPACKET ) + msg.msg_flags |=MSG_EOR ; + +return __sock_sendmsg (iocb, sock, &msg, iocb->ki_nbytes); }/*
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v2 14/18 net: switch sockets to ->read_iter/->write_iter
In reply to Al ViroFrom: Al Viro <[email protected]>
--- net/socket.c | 56 +++++++++++++++++++++++++++----------------------------- 1 file changed, 27 insertions(+), 29 deletions(-)
net/socket.c +27 -29
@@ -113,10 +113,8 @@ unsigned int sysctl_net_busy_read __read_mostly;unsigned int sysctl_net_busy_poll__read_mostly ;#endif -static ssize_t sock_aio_read (struct kiocb *iocb,const struct iovec *iov, -unsigned long nr_segs,loff_t pos); -static ssize_t sock_aio_write (struct kiocb *iocb,const struct iovec *iov, -unsigned long nr_segs,loff_t pos); +static ssize_t sock_read_iter (struct kiocb *iocb,struct iov_iter *to); +static ssize_t sock_write_iter (struct kiocb *iocb,struct iov_iter *from);static int sock_mmap (struct file *file,struct vm_area_struct *vma);static int sock_close (struct inode *inode,struct file *file);
@@ -142,8 +140,10 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos,static const struct file_operations socket_file_ops = { .owner =THIS_MODULE , .llseek = no_llseek, - .aio_read = sock_aio_read, - .aio_write = sock_aio_write, + .read = new_sync_read, + .write = new_sync_write, + .read_iter = sock_read_iter, + .write_iter = sock_write_iter, .poll = sock_poll, .unlocked_ioctl = sock_ioctl, #ifdef CONFIG_COMPAT
@@ -845,49 +845,47 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos,return sock->ops->splice_read (sock, ppos, pipe, len, flags); } -static ssize_t sock_aio_read (struct kiocb *iocb,const struct iovec *iov, -unsigned long nr_segs,loff_t pos) +static ssize_t sock_read_iter (struct kiocb *iocb,struct iov_iter *to) {struct file *file = iocb->ki_filp;struct socket *sock = file->private_data; -struct msghdr msg; +struct msghdr msg = {.msg_iter = *to}; +ssize_t res; + +if (file->f_flags &O_NONBLOCK ) + msg.msg_flags =MSG_DONTWAIT ; -if (pos !=0 ) +if (iocb->ki_pos !=0 )return -ESPIPE ;if (iocb->ki_nbytes ==0 )/* Match SYS5 behaviour */ return 0 ; - msg.msg_name =NULL ; - msg.msg_namelen =0 ; - msg.msg_control =NULL ; - msg.msg_controllen =0 ; -iov_iter_init (&msg.msg_iter,READ , iov, nr_segs, iocb->ki_nbytes); - msg.msg_flags = (file->f_flags &O_NONBLOCK ) ?MSG_DONTWAIT :0 ; - -return __sock_recvmsg (iocb, sock, &msg, iocb->ki_nbytes, msg.msg_flags); + res =__sock_recvmsg (iocb, sock, &msg, + iocb->ki_nbytes, msg.msg_flags); + *to = msg.msg_iter; +return res; } -static ssize_t sock_aio_write (struct kiocb *iocb,const struct iovec *iov, -unsigned long nr_segs,loff_t pos) +static ssize_t sock_write_iter (struct kiocb *iocb,struct iov_iter *from) {struct file *file = iocb->ki_filp;struct socket *sock = file->private_data; -struct msghdr msg; +struct msghdr msg = {.msg_iter = *from}; +ssize_t res; -if (pos !=0 ) +if (iocb->ki_pos !=0 )return -ESPIPE ; - msg.msg_name =NULL ; - msg.msg_namelen =0 ; - msg.msg_control =NULL ; - msg.msg_controllen =0 ; -iov_iter_init (&msg.msg_iter,WRITE , iov, nr_segs, iocb->ki_nbytes); - msg.msg_flags = (file->f_flags &O_NONBLOCK ) ?MSG_DONTWAIT :0 ; +if (file->f_flags &O_NONBLOCK ) + msg.msg_flags =MSG_DONTWAIT ; +if (sock->type ==SOCK_SEQPACKET ) msg.msg_flags |=MSG_EOR ; -return __sock_sendmsg (iocb, sock, &msg, iocb->ki_nbytes); + res =__sock_sendmsg (iocb, sock, &msg, iocb->ki_nbytes); + *from = msg.msg_iter; +return res; }/*
Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v2 15/18 vhost: switch vhost get_indirect() to iov_iter, kill memcpy_fromiovec()
In reply to Al ViroFrom: Al Viro <[email protected]>
--- drivers/vhost/vhost.c | 6 ++++-- include/linux/uio.h | 1 - lib/iovec.c | 25 ------------------------- 3 files changed, 4 insertions(+), 28 deletions(-)
drivers/vhost/vhost.c +4 -2
@@ -1125,6 +1125,7 @@ static int get_indirect(struct vhost_virtqueue *vq,struct vring_desc desc;unsigned int i =0 , count, found =0 ;u32 len =vhost32_to_cpu (vq, indirect->len); +struct iov_iter from;int ret;/* Sanity check */
@@ -1142,6 +1143,7 @@ static int get_indirect(struct vhost_virtqueue *vq,vq_err (vq,"Translation failure %d in indirect.\n" , ret);return ret; } +iov_iter_init (&from,READ , vq->indirect, ret, len);/* We will use the result as an address to read from, so most * architectures only need a compiler barrier here. */
@@ -1164,8 +1166,8 @@ static int get_indirect(struct vhost_virtqueue *vq, i, count);return -EINVAL ; } -if (unlikely (memcpy_fromiovec ((unsigned char *)&desc, - vq->indirect,sizeof desc))) { +if (unlikely (copy_from_iter (&desc,sizeof (desc), &from) != +sizeof (desc))) {vq_err (vq,"Failed indirect descriptor: idx %d, %zx\n" , i, (size_t )vhost64_to_cpu (vq, indirect->addr) + i *sizeof desc);return -EINVAL ;
include/linux/uio.h +0 -1
@@ -135,7 +135,6 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count)size_t csum_and_copy_to_iter (void *addr,size_t bytes,__wsum *csum,struct iov_iter *i);size_t csum_and_copy_from_iter (void *addr,size_t bytes,__wsum *csum,struct iov_iter *i); -int memcpy_fromiovec (unsigned char *kdata,struct iovec *iov,int len);int memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov,int offset,int len); int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata,
lib/iovec.c +0 -25
@@ -3,31 +3,6 @@#include <linux/uio.h> /* -* Copy iovec to kernel. Returns -EFAULT on error. -* -* Note: this modifies the original iovec. -*/ - -int memcpy_fromiovec (unsigned char *kdata,struct iovec *iov,int len) -{ -while (len >0 ) { -if (iov->iov_len) { - int copy = min_t(unsigned int, len, iov->iov_len); -if (copy_from_user (kdata, iov->iov_base, copy)) -return -EFAULT ; - len -= copy; - kdata += copy; - iov->iov_base += copy; - iov->iov_len -= copy; - } - iov++; - } - -return 0 ; -} -EXPORT_SYMBOL (memcpy_fromiovec); - -/* * Copy kernel to iovec. Returns -EFAULT on error. */
Signature · 1 line
2.1.4
Re: [PATCH v2 15/18] vhost: switch vhost get_indirect() to iov_iter, kill memcpy_fromiovec()
Quoted 5 lines · Al Viro
From: Al Viro <[email protected]>
Cc Michael S. Tsirkin <[email protected]>Signed-off-by Al Viro <[email protected]>
But, can you pls copy [email protected] ? I think some guys working on virtio might only hang out there.
Quoted 87 lines
--- drivers/vhost/vhost.c | 6 ++++-- include/linux/uio.h | 1 - lib/iovec.c | 25 ------------------------- 3 files changed, 4 insertions(+), 28 deletions(-)drivers/vhost/vhost.c +4
-2@@ -1125,6 +1125,7 @@ static int get_indirect(struct vhost_virtqueue *vq,struct vring_desc desc;unsigned int i =0 , count, found =0 ;u32 len =vhost32_to_cpu (vq, indirect->len); +struct iov_iter from;int ret;/* Sanity check */ @@ -1142,6 +1143,7 @@ static int get_indirect(struct vhost_virtqueue *vq,vq_err (vq,"Translation failure %d in indirect.\n" , ret);return ret; } +iov_iter_init (&from,READ , vq->indirect, ret, len);/* We will use the result as an address to read from, so most * architectures only need a compiler barrier here. */ @@ -1164,8 +1166,8 @@ static int get_indirect(struct vhost_virtqueue *vq, i, count);return -EINVAL ; } -if (unlikely (memcpy_fromiovec ((unsigned char *)&desc, - vq->indirect,sizeof desc))) { +if (unlikely (copy_from_iter (&desc,sizeof (desc), &from) != +sizeof (desc))) {vq_err (vq,"Failed indirect descriptor: idx %d, %zx\n" , i, (size_t )vhost64_to_cpu (vq, indirect->addr) + i *sizeof desc);return -EINVAL ;include/linux/uio.h +0
-1@@ -135,7 +135,6 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count)size_t csum_and_copy_to_iter (void *addr,size_t bytes,__wsum *csum,struct iov_iter *i);size_t csum_and_copy_from_iter (void *addr,size_t bytes,__wsum *csum,struct iov_iter *i); -int memcpy_fromiovec (unsigned char *kdata,struct iovec *iov,int len);int memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov,int offset,int len); int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata,lib/iovec.c +0
-25@@ -3,31 +3,6 @@#include <linux/uio.h> /* -* Copy iovec to kernel. Returns -EFAULT on error. -* -* Note: this modifies the original iovec. -*/ - -int memcpy_fromiovec (unsigned char *kdata,struct iovec *iov,int len) -{ -while (len >0 ) { -if (iov->iov_len) { - int copy = min_t(unsigned int, len, iov->iov_len); -if (copy_from_user (kdata, iov->iov_base, copy)) -return -EFAULT ; - len -= copy; - kdata += copy; - iov->iov_base += copy; - iov->iov_len -= copy; - } - iov++; - } - -return 0 ; -} -EXPORT_SYMBOL (memcpy_fromiovec); - -/* * Copy kernel to iovec. Returns -EFAULT on error. */ Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v2 16/18 vhost: don't bother with copying iovec in handle_tx()
In reply to Al ViroFrom: Al Viro <[email protected]>
just advance the msg.msg_iter and be done with that.
--- drivers/vhost/net.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/vhost/net.c +5 -4
@@ -336,7 +336,7 @@ static void handle_tx(struct vhost_net *net) {struct vhost_net_virtqueue *nvq = &net->vqs[VHOST_NET_VQ_TX ];struct vhost_virtqueue *vq = &nvq->vq; -unsigned out, in, s; +unsigned out, in;int head;struct msghdr msg = { .msg_name =NULL ,
@@ -395,16 +395,17 @@ static void handle_tx(struct vhost_net *net)break ; }/* Skip header. TODO: support TSO. */ - s =move_iovec_hdr (vq->iov, nvq->hdr, hdr_size, out); len =iov_length (vq->iov, out);iov_iter_init (&msg.msg_iter,WRITE , vq->iov, out, len); +iov_iter_advance (&msg.msg_iter, hdr_size);/* Sanity check */ -if (!len) { +if (!iov_iter_count (&msg.msg_iter)) {vq_err (vq,"Unexpected header len for TX: " "%zd expected %zd\n" , -iov_length (nvq->hdr, s), hdr_size); + len, hdr_size);break ; } + len =iov_iter_count (&msg.msg_iter); zcopy_used = zcopy && len >=VHOST_GOODCOPY_LEN && (nvq->upend_idx + 1) % UIO_MAXIOV !=
Signature · 1 line
2.1.4
Re: [PATCH v2 16/18] vhost: don't bother with copying iovec in handle_tx()
Quoted 7 lines · Al Viro
From: Al Viro <[email protected]>
just advance the msg.msg_iter and be done with that.
Cc Michael S. Tsirkin <[email protected]>Signed-off-by Al Viro <[email protected]>
Nice.
But, can you pls copy [email protected] ? I think some guys working on virtio might only hang out there.
Quoted 40 lines
--- drivers/vhost/net.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)drivers/vhost/net.c +5
-4@@ -336,7 +336,7 @@ static void handle_tx(struct vhost_net *net) {struct vhost_net_virtqueue *nvq = &net->vqs[VHOST_NET_VQ_TX ];struct vhost_virtqueue *vq = &nvq->vq; -unsigned out, in, s; +unsigned out, in;int head;struct msghdr msg = { .msg_name =NULL ,@@ -395,16 +395,17 @@ static void handle_tx(struct vhost_net *net)break ; }/* Skip header. TODO: support TSO. */ - s =move_iovec_hdr (vq->iov, nvq->hdr, hdr_size, out); len =iov_length (vq->iov, out);iov_iter_init (&msg.msg_iter,WRITE , vq->iov, out, len); +iov_iter_advance (&msg.msg_iter, hdr_size);/* Sanity check */ -if (!len) { +if (!iov_iter_count (&msg.msg_iter)) {vq_err (vq,"Unexpected header len for TX: " "%zd expected %zd\n" , -iov_length (nvq->hdr, s), hdr_size); + len, hdr_size);break ; } + len =iov_iter_count (&msg.msg_iter); zcopy_used = zcopy && len >=VHOST_GOODCOPY_LEN && (nvq->upend_idx + 1) % UIO_MAXIOV !=Signature · 1 line
2.1.4
Al Viro
maintainerPATCH v2 17/18 vhost: don't bother copying iovecs in handle_rx(), kill memcpy_toiovecend()
In reply to Al ViroFrom: Al Viro <[email protected]>
--- drivers/vhost/net.c | 79 ++++++++++++++--------------------------------------- include/linux/uio.h | 3 -- lib/iovec.c | 26 ------------------ 3 files changed, 20 insertions(+), 88 deletions(-)
drivers/vhost/net.c +20 -59
@@ -84,10 +84,6 @@ struct vhost_net_ubuf_ref {struct vhost_net_virtqueue {struct vhost_virtqueue vq; -/* hdr is used to store the virtio header. -* Since each iovec has >= 1 byte length, we never need more than -* header length entries to store the header. */ -struct iovec hdr[sizeof (struct virtio_net_hdr_mrg_rxbuf )];size_t vhost_hlen;size_t sock_hlen;/* vhost zerocopy support fields below: */
@@ -235,44 +231,6 @@ static bool vhost_sock_zcopy(struct socket *sock)sock_flag (sock->sk,SOCK_ZEROCOPY ); } -/* Pop first len bytes from iovec. Return number of segments used. */ -static int move_iovec_hdr (struct iovec *from,struct iovec *to, -size_t len,int iov_count) -{ -int seg =0 ; -size_t size; - -while (len && seg < iov_count) { - size =min (from->iov_len, len); - to->iov_base = from->iov_base; - to->iov_len = size; - from->iov_len -= size; - from->iov_base += size; - len -= size; - ++from; - ++to; - ++seg; - } -return seg; -} -/* Copy iovec entries for len bytes from iovec. */ -static void copy_iovec_hdr (const struct iovec *from,struct iovec *to, -size_t len,int iovcount) -{ -int seg =0 ; -size_t size; - -while (len && seg < iovcount) { - size =min (from->iov_len, len); - to->iov_base = from->iov_base; - to->iov_len = size; - len -= size; - ++from; - ++to; - ++seg; - } -} -/* In case of DMA done not in order in lower device driver for some reason. * upend_idx is used to track end of used idx, done_idx is used to track head * of used idx. Once lower device DMA done contiguously, we will signal KVM
@@ -570,9 +528,9 @@ static void handle_rx(struct vhost_net *net) .msg_controllen = 0, .msg_flags = MSG_DONTWAIT, }; -struct virtio_net_hdr_mrg_rxbuf hdr = { - .hdr.flags =0 , - .hdr.gso_type =VIRTIO_NET_HDR_GSO_NONE +struct virtio_net_hdr hdr = { + .flags =0 , + .gso_type =VIRTIO_NET_HDR_GSO_NONE };size_t total_len =0 ;int err, mergeable;
@@ -580,6 +538,7 @@ static void handle_rx(struct vhost_net *net)size_t vhost_hlen, sock_hlen;size_t vhost_len, sock_len;struct socket *sock; +struct iov_iter fixup;mutex_lock (&vq->mutex); sock = vq->private_data;
@@ -624,14 +583,17 @@ static void handle_rx(struct vhost_net *net)break ; }/* We don't need to be notified again. */ -if (unlikely ((vhost_hlen))) -/* Skip header. TODO: support TSO. */ -move_iovec_hdr (vq->iov, nvq->hdr, vhost_hlen, in); -else -/* Copy the header for use in VIRTIO_NET_F_MRG_RXBUF: -* needed because recvmsg can modify msg_iov. */ -copy_iovec_hdr (vq->iov, nvq->hdr, sock_hlen, in); -iov_iter_init (&msg.msg_iter,READ , vq->iov, in, sock_len); +iov_iter_init (&msg.msg_iter,READ , vq->iov, in, vhost_len); + fixup = msg.msg_iter; +if (unlikely ((vhost_hlen))) { +/* We will supply the header ourselves +* TODO: support TSO. */ +iov_iter_advance (&msg.msg_iter, vhost_hlen); + }else { +/* It'll come from socket; we'll need to patch +* ->num_buffers over if VIRTIO_NET_F_MRG_RXBUF */ +iov_iter_advance (&fixup,sizeof (hdr)); + } err = sock->ops->recvmsg (NULL , sock, &msg, sock_len,MSG_DONTWAIT |MSG_TRUNC );/* Userspace might have consumed the packet meanwhile:
@@ -643,18 +605,17 @@ static void handle_rx(struct vhost_net *net)vhost_discard_vq_desc (vq, headcount);continue ; } +/* Supply virtio_net_hdr if VHOST_NET_F_VIRTIO_NET_HDR */ if (unlikely (vhost_hlen) && -memcpy_toiovecend (nvq->hdr, (unsigned char *)&hdr,0 , - vhost_hlen)) { +copy_to_iter (&hdr,sizeof (hdr), &fixup) !=sizeof (hdr)) {vq_err (vq,"Unable to write vnet_hdr at addr %p\n" , vq->iov->iov_base);break ; } -/* TODO: Should check and handle checksum. */ +/* Supply (or replace) ->num_buffers if VIRTIO_NET_F_MRG_RXBUF +* TODO: Should check and handle checksum. */ if (likely (mergeable) && -memcpy_toiovecend (nvq->hdr, (unsigned char *)&headcount, - offsetof(typeof (hdr ), num_buffers), -sizeof hdr.num_buffers)) { +copy_to_iter (&headcount,2 , &fixup) !=2 ) {vq_err (vq,"Failed num_buffers write" );vhost_discard_vq_desc (vq, headcount);break ;
include/linux/uio.h +0 -3
@@ -137,7 +137,4 @@ size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct ioint memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov,int offset,int len); -int memcpy_toiovecend (const struct iovec *v,unsigned char *kdata, -int offset,int len); -#endif
lib/iovec.c +0 -26
@@ -3,32 +3,6 @@#include <linux/uio.h> /* -* Copy kernel to iovec. Returns -EFAULT on error. -*/ - -int memcpy_toiovecend (const struct iovec *iov,unsigned char *kdata, -int offset,int len) -{ -int copy; -for (; len >0 ; ++iov) { -/* Skip over the finished iovecs */ -if (unlikely (offset >= iov->iov_len)) { - offset -= iov->iov_len; -continue ; - } - copy = min_t(unsigned int, iov->iov_len - offset, len); -if (copy_to_user (iov->iov_base + offset, kdata, copy)) -return -EFAULT ; - offset =0 ; - kdata += copy; - len -= copy; - } - -return 0 ; -} -EXPORT_SYMBOL (memcpy_toiovecend); - -/* * Copy iovec to kernel. Returns -EFAULT on error. */
Signature · 1 line
2.1.4
Re: [PATCH v2 17/18] vhost: don't bother copying iovecs in handle_rx(), kill memcpy_toiovecend()
Quoted 6 lines · Al Viro
From: Al Viro <[email protected]>
Cc Michael S. Tsirkin <[email protected]>Signed-off-by Al Viro <[email protected]>---
So this made me notice a bug in vhost introduced in 3.19. I sent a patch for that, this one will have to be rebased on top. Otherwise:
But, can you pls copy [email protected] ? I think some guys working on virtio might only hang out there.
Quoted 113 lines
drivers/vhost/net.c | 79 ++++++++++++++--------------------------------------- include/linux/uio.h | 3 -- lib/iovec.c | 26 ------------------ 3 files changed, 20 insertions(+), 88 deletions(-)drivers/vhost/net.c +15
-53@@ -84,10 +84,6 @@ struct vhost_net_ubuf_ref {struct vhost_net_virtqueue {struct vhost_virtqueue vq; -/* hdr is used to store the virtio header. -* Since each iovec has >= 1 byte length, we never need more than -* header length entries to store the header. */ -struct iovec hdr[sizeof (struct virtio_net_hdr_mrg_rxbuf )];size_t vhost_hlen;size_t sock_hlen;/* vhost zerocopy support fields below: */ @@ -235,44 +231,6 @@ static bool vhost_sock_zcopy(struct socket *sock)sock_flag (sock->sk,SOCK_ZEROCOPY ); } -/* Pop first len bytes from iovec. Return number of segments used. */ -static int move_iovec_hdr (struct iovec *from,struct iovec *to, -size_t len,int iov_count) -{ -int seg =0 ; -size_t size; - -while (len && seg < iov_count) { - size =min (from->iov_len, len); - to->iov_base = from->iov_base; - to->iov_len = size; - from->iov_len -= size; - from->iov_base += size; - len -= size; - ++from; - ++to; - ++seg; - } -return seg; -} -/* Copy iovec entries for len bytes from iovec. */ -static void copy_iovec_hdr (const struct iovec *from,struct iovec *to, -size_t len,int iovcount) -{ -int seg =0 ; -size_t size; - -while (len && seg < iovcount) { - size =min (from->iov_len, len); - to->iov_base = from->iov_base; - to->iov_len = size; - len -= size; - ++from; - ++to; - ++seg; - } -} -/* In case of DMA done not in order in lower device driver for some reason. * upend_idx is used to track end of used idx, done_idx is used to track head * of used idx. Once lower device DMA done contiguously, we will signal KVM @@ -570,9 +528,9 @@ static void handle_rx(struct vhost_net *net) .msg_controllen = 0, .msg_flags = MSG_DONTWAIT, }; -struct virtio_net_hdr_mrg_rxbuf hdr = { - .hdr.flags =0 , - .hdr.gso_type =VIRTIO_NET_HDR_GSO_NONE +struct virtio_net_hdr hdr = { + .flags =0 , + .gso_type =VIRTIO_NET_HDR_GSO_NONE };size_t total_len =0 ;int err, mergeable;@@ -580,6 +538,7 @@ static void handle_rx(struct vhost_net *net)size_t vhost_hlen, sock_hlen;size_t vhost_len, sock_len;struct socket *sock; +struct iov_iter fixup;mutex_lock (&vq->mutex); sock = vq->private_data;@@ -624,14 +583,17 @@ static void handle_rx(struct vhost_net *net)break ; }/* We don't need to be notified again. */ -if (unlikely ((vhost_hlen))) -/* Skip header. TODO: support TSO. */ -move_iovec_hdr (vq->iov, nvq->hdr, vhost_hlen, in); -else -/* Copy the header for use in VIRTIO_NET_F_MRG_RXBUF: -* needed because recvmsg can modify msg_iov. */ -copy_iovec_hdr (vq->iov, nvq->hdr, sock_hlen, in); -iov_iter_init (&msg.msg_iter,READ , vq->iov, in, sock_len); +iov_iter_init (&msg.msg_iter,READ , vq->iov, in, vhost_len); + fixup = msg.msg_iter; +if (unlikely ((vhost_hlen))) { +/* We will supply the header ourselves +* TODO: support TSO. */ +iov_iter_advance (&msg.msg_iter, vhost_hlen); + }else { +/* It'll come from socket; we'll need to patch +* ->num_buffers over if VIRTIO_NET_F_MRG_RXBUF */ +iov_iter_advance (&fixup,sizeof (hdr)); + } err = sock->ops->recvmsg (NULL , sock, &msg, sock_len,MSG_DONTWAIT |MSG_TRUNC );/* Userspace might have consumed the packet meanwhile:
drivers/vhost/net.c static void handle_rx(struct vhost_net *net) · line 610
Quoted 8 lines
drivers/vhost/net.c +2
-2@@ -643,18 +605,17 @@ static void handle_rx(struct vhost_net *net)vhost_discard_vq_desc (vq, headcount);continue ; } +/* Supply virtio_net_hdr if VHOST_NET_F_VIRTIO_NET_HDR */ if (unlikely (vhost_hlen) && -memcpy_toiovecend (nvq->hdr, (unsigned char *)&hdr,0 , - vhost_hlen)) { +copy_to_iter (&hdr,sizeof (hdr), &fixup) !=sizeof (hdr)) {
BTW, all iovecs are pre-validated in vhost core.
I'd like to add __copy_to_iter and __copy_from_iter that are the same but skip the extra checks, and use that everywhere in vhost (shouln't matter here specifically, because we don't hit this path).
Quoted 1 line
From experience, this helps gcc optimize the code resulting
in measureable performance gains.
Comments? Will you be ok with a patch like this?
Quoted 5 lines
drivers/vhost/net.c +0
-1vq_err (vq,"Unable to write vnet_hdr at addr %p\n" , vq->iov->iov_base);break ; } -/* TODO: Should check and handle checksum. */
drivers/vhost/net.c static void handle_rx(struct vhost_net *net) · line 621
Quoted 10 lines
drivers/vhost/net.c +3
-3+/* Supply (or replace) ->num_buffers if VIRTIO_NET_F_MRG_RXBUF +* TODO: Should check and handle checksum. */ if (likely (mergeable) && -memcpy_toiovecend (nvq->hdr, (unsigned char *)&headcount, - offsetof(typeof (hdr ), num_buffers), -sizeof hdr.num_buffers)) { +copy_to_iter (&headcount,2 , &fixup) !=2 ) {vq_err (vq,"Failed num_buffers write" );vhost_discard_vq_desc (vq, headcount);break ;
This made me notice we have a bug: native-endianness integer is copied out to guest. I sent a patch, hope it'll make it in 3.19.
Quoted 51 lines
include/linux/uio.h +0
-3@@ -137,7 +137,4 @@ size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct ioint memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov,int offset,int len); -int memcpy_toiovecend (const struct iovec *v,unsigned char *kdata, -int offset,int len); -#endif lib/iovec.c +0
-26@@ -3,32 +3,6 @@#include <linux/uio.h> /* -* Copy kernel to iovec. Returns -EFAULT on error. -*/ - -int memcpy_toiovecend (const struct iovec *iov,unsigned char *kdata, -int offset,int len) -{ -int copy; -for (; len >0 ; ++iov) { -/* Skip over the finished iovecs */ -if (unlikely (offset >= iov->iov_len)) { - offset -= iov->iov_len; -continue ; - } - copy = min_t(unsigned int, iov->iov_len - offset, len); -if (copy_to_user (iov->iov_base + offset, kdata, copy)) -return -EFAULT ; - offset =0 ; - kdata += copy; - len -= copy; - } - -return 0 ; -} -EXPORT_SYMBOL (memcpy_toiovecend); - -/* * Copy iovec to kernel. Returns -EFAULT on error. */ Signature · 1 line
2.1.4
Michael S. Tsirkin
maintainerRe: [PATCH v2 17/18] vhost: don't bother copying iovecs in handle_rx(), kill memcpy_toiovecend()
In reply to Al ViroQuoted 108 lines · Al Viro
From: Al Viro <[email protected]>
Cc Michael S. Tsirkin <[email protected]>Signed-off-by Al Viro <[email protected]>--- drivers/vhost/net.c | 79 ++++++++++++++--------------------------------------- include/linux/uio.h | 3 -- lib/iovec.c | 26 ------------------ 3 files changed, 20 insertions(+), 88 deletions(-)drivers/vhost/net.c +8
-53@@ -84,10 +84,6 @@ struct vhost_net_ubuf_ref {struct vhost_net_virtqueue {struct vhost_virtqueue vq; -/* hdr is used to store the virtio header. -* Since each iovec has >= 1 byte length, we never need more than -* header length entries to store the header. */ -struct iovec hdr[sizeof (struct virtio_net_hdr_mrg_rxbuf )];size_t vhost_hlen;size_t sock_hlen;/* vhost zerocopy support fields below: */ @@ -235,44 +231,6 @@ static bool vhost_sock_zcopy(struct socket *sock)sock_flag (sock->sk,SOCK_ZEROCOPY ); } -/* Pop first len bytes from iovec. Return number of segments used. */ -static int move_iovec_hdr (struct iovec *from,struct iovec *to, -size_t len,int iov_count) -{ -int seg =0 ; -size_t size; - -while (len && seg < iov_count) { - size =min (from->iov_len, len); - to->iov_base = from->iov_base; - to->iov_len = size; - from->iov_len -= size; - from->iov_base += size; - len -= size; - ++from; - ++to; - ++seg; - } -return seg; -} -/* Copy iovec entries for len bytes from iovec. */ -static void copy_iovec_hdr (const struct iovec *from,struct iovec *to, -size_t len,int iovcount) -{ -int seg =0 ; -size_t size; - -while (len && seg < iovcount) { - size =min (from->iov_len, len); - to->iov_base = from->iov_base; - to->iov_len = size; - len -= size; - ++from; - ++to; - ++seg; - } -} -/* In case of DMA done not in order in lower device driver for some reason. * upend_idx is used to track end of used idx, done_idx is used to track head * of used idx. Once lower device DMA done contiguously, we will signal KVM @@ -570,9 +528,9 @@ static void handle_rx(struct vhost_net *net) .msg_controllen = 0, .msg_flags = MSG_DONTWAIT, }; -struct virtio_net_hdr_mrg_rxbuf hdr = { - .hdr.flags =0 , - .hdr.gso_type =VIRTIO_NET_HDR_GSO_NONE +struct virtio_net_hdr hdr = { + .flags =0 , + .gso_type =VIRTIO_NET_HDR_GSO_NONE };size_t total_len =0 ;int err, mergeable;@@ -580,6 +538,7 @@ static void handle_rx(struct vhost_net *net)size_t vhost_hlen, sock_hlen;size_t vhost_len, sock_len;struct socket *sock; +struct iov_iter fixup;mutex_lock (&vq->mutex); sock = vq->private_data;@@ -624,14 +583,17 @@ static void handle_rx(struct vhost_net *net)break ; }/* We don't need to be notified again. */ -if (unlikely ((vhost_hlen))) -/* Skip header. TODO: support TSO. */ -move_iovec_hdr (vq->iov, nvq->hdr, vhost_hlen, in); -else -/* Copy the header for use in VIRTIO_NET_F_MRG_RXBUF: -* needed because recvmsg can modify msg_iov. */ -copy_iovec_hdr (vq->iov, nvq->hdr, sock_hlen, in); -iov_iter_init (&msg.msg_iter,READ , vq->iov, in, sock_len); +iov_iter_init (&msg.msg_iter,READ , vq->iov, in, vhost_len); + fixup = msg.msg_iter; +if (unlikely ((vhost_hlen))) { +/* We will supply the header ourselves
drivers/vhost/net.c static void handle_rx(struct vhost_net *net) · line 599
Quoted 10 lines
drivers/vhost/net.c +7
-0+* TODO: support TSO. */ +iov_iter_advance (&msg.msg_iter, vhost_hlen); + }else { +/* It'll come from socket; we'll need to patch +* ->num_buffers over if VIRTIO_NET_F_MRG_RXBUF */ +iov_iter_advance (&fixup,sizeof (hdr)); + } err = sock->ops->recvmsg (NULL , sock, &msg, sock_len,MSG_DONTWAIT |MSG_TRUNC );/* Userspace might have consumed the packet meanwhile:
Hmm having second thoughts here.
Will this modify the iov in vq->iov?
If yes, how will recvmsg fill it?
Quoted 14 lines
drivers/vhost/net.c +2
-3@@ -643,18 +605,17 @@ static void handle_rx(struct vhost_net *net)vhost_discard_vq_desc (vq, headcount);continue ; } +/* Supply virtio_net_hdr if VHOST_NET_F_VIRTIO_NET_HDR */ if (unlikely (vhost_hlen) && -memcpy_toiovecend (nvq->hdr, (unsigned char *)&hdr,0 , - vhost_hlen)) { +copy_to_iter (&hdr,sizeof (hdr), &fixup) !=sizeof (hdr)) {vq_err (vq,"Unable to write vnet_hdr at addr %p\n" , vq->iov->iov_base);break ; } -/* TODO: Should check and handle checksum. */
drivers/vhost/net.c static void handle_rx(struct vhost_net *net) · line 621
Quoted 10 lines
drivers/vhost/net.c +3
-3+/* Supply (or replace) ->num_buffers if VIRTIO_NET_F_MRG_RXBUF +* TODO: Should check and handle checksum. */ if (likely (mergeable) && -memcpy_toiovecend (nvq->hdr, (unsigned char *)&headcount, - offsetof(typeof (hdr ), num_buffers), -sizeof hdr.num_buffers)) { +copy_to_iter (&headcount,2 , &fixup) !=2 ) {vq_err (vq,"Failed num_buffers write" );vhost_discard_vq_desc (vq, headcount);break ;
Here, if recvmsg modified the iov, how does copy_to_iter see the header?
Quoted 51 lines
include/linux/uio.h +0
-3@@ -137,7 +137,4 @@ size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct ioint memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov,int offset,int len); -int memcpy_toiovecend (const struct iovec *v,unsigned char *kdata, -int offset,int len); -#endif lib/iovec.c +0
-26@@ -3,32 +3,6 @@#include <linux/uio.h> /* -* Copy kernel to iovec. Returns -EFAULT on error. -*/ - -int memcpy_toiovecend (const struct iovec *iov,unsigned char *kdata, -int offset,int len) -{ -int copy; -for (; len >0 ; ++iov) { -/* Skip over the finished iovecs */ -if (unlikely (offset >= iov->iov_len)) { - offset -= iov->iov_len; -continue ; - } - copy = min_t(unsigned int, iov->iov_len - offset, len); -if (copy_to_user (iov->iov_base + offset, kdata, copy)) -return -EFAULT ; - offset =0 ; - kdata += copy; - len -= copy; - } - -return 0 ; -} -EXPORT_SYMBOL (memcpy_toiovecend); - -/* * Copy iovec to kernel. Returns -EFAULT on error. */ Signature · 1 line
2.1.4
Michael S. Tsirkin
maintainerRe: [PATCH v2 17/18] vhost: don't bother copying iovecs in handle_rx(), kill memcpy_toiovecend()
Quoted 3 lines
Hmm having second thoughts here.
Will this modify the iov invq->iov?
If yes, how will recvmsg fill it?
OK that was just me misunderstanding what the function does. As it doesn't modify the iovec itself, I think there's no issue, my ack stands.
Al Viro
maintainerRe: [PATCH v2 17/18] vhost: don't bother copying iovecs in handle_rx(), kill memcpy_toiovecend()
Quoted 7 lines · Michael S. Tsirkin
Quoted 3 lines
Hmm having second thoughts here.
Will this modify the iov invq->iov?
If yes, how will recvmsg fill it?OK that was just me misunderstanding what the function does. As it doesn't modify the iovec itself, I think there's no issue, my ack stands.
That, BTW, was the point of switching ->sendmsg() and ->recvmsg() to iov_iter primitives - not only do memcpy_toiovec() et.al. change the iovec, the way it's done was protocol-dependent, up to and including the things like "have sent 60 caller-supplied bytes, iovec modified with only 6 bytes consumed". What's worse, on TCP sendmsg we usually left iovec unchanged, but sometimes it got drained. Granted, that happened only after setsockopt() playing caller with TCP_REPAIR (i.e. checkpoint/restart stuff), but...
Al Viro
maintainerPATCH v2 18/18 vhost: vhost_scsi_handle_vq() should just use copy_from_user()
In reply to Al ViroFrom: Al Viro <[email protected]>
it has just verified that it asks no more than the length of the first segment of iovec.
And with that the last user of stuff in lib/iovec.c is gone. RIP.
--- drivers/vhost/scsi.c | 2 +- include/linux/uio.h | 2 -- lib/Makefile | 2 +- lib/iovec.c | 36 ------------------------------------ 4 files changed, 2 insertions(+), 40 deletions(-) delete mode 100644 lib/iovec.c
drivers/vhost/scsi.c +1 -1
@@ -1079,7 +1079,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) req_size, vq->iov[0].iov_len);break ; } - ret =memcpy_fromiovecend (req, &vq->iov[0 ],0 , req_size); + ret =copy_from_user (req, vq->iov[0 ].iov_base, req_size);if (unlikely (ret)) {vq_err (vq,"Faulted on virtio_scsi_cmd_req\n" );break ;
include/linux/uio.h +0 -2
@@ -135,6 +135,4 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count)size_t csum_and_copy_to_iter (void *addr,size_t bytes,__wsum *csum,struct iov_iter *i);size_t csum_and_copy_from_iter (void *addr,size_t bytes,__wsum *csum,struct iov_iter *i); -int memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov, -int offset,int len);#endif
lib/Makefile +1 -1
@@ -24,7 +24,7 @@ obj-y += lockref.o obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \ - gcd.o lcm.o list_sort.o uuid.o flex_array.o iovec.o clz_ctz.o \ + gcd.o lcm.o list_sort.o uuid.o flex_array.o clz_ctz.o \ bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o \ percpu-refcount.o percpu_ida.o rhashtable.o reciprocal_div.o obj-y += string_helpers.o
lib/iovec.c deleted +0 -36
@@ -1,36 +0,0 @@ -#include <linux/uaccess.h> -#include <linux/export.h> -#include <linux/uio.h> - -/* -* Copy iovec to kernel. Returns -EFAULT on error. -*/ - -int memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov, -int offset,int len) -{ -/* No data? Done! */ -if (len ==0 ) -return 0 ; - -/* Skip over the finished iovecs */ -while (offset >= iov->iov_len) { - offset -= iov->iov_len; - iov++; - } - -while (len >0 ) { -u8 __user *base = iov->iov_base + offset; - int copy = min_t(unsigned int, len, iov->iov_len - offset); - - offset =0 ; -if (copy_from_user (kdata, base, copy)) -return -EFAULT ; - len -= copy; - kdata += copy; - iov++; - } - -return 0 ; -} -EXPORT_SYMBOL (memcpy_fromiovecend);
Signature · 1 line
2.1.4
Re: [PATCH v2 18/18] vhost: vhost_scsi_handle_vq() should just use copy_from_user()
Hi Al,
Quoted 25 lines · Al Viro
From: Al Viro <[email protected]>
it has just verified that it asks no more than the length of the first segment of iovec.
And with that the last user of stuff in
lib/iovec.cis gone. RIP.Cc Michael S. Tsirkin <[email protected]>Cc Nicholas A. Bellinger <[email protected]>Signed-off-by Al Viro <[email protected]>--- drivers/vhost/scsi.c | 2 +- include/linux/uio.h | 2 -- lib/Makefile | 2 +- lib/iovec.c | 36 ------------------------------------ 4 files changed, 2 insertions(+), 40 deletions(-) delete mode 100644 lib/iovec.cdrivers/vhost/scsi.c +0
-0
drivers/vhost/scsi.c vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) · line 1085
Quoted 8 lines
drivers/vhost/scsi.c +1
-1@@ -1079,7 +1079,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) req_size, vq->iov[0].iov_len);break ; } - ret =memcpy_fromiovecend (req, &vq->iov[0 ],0 , req_size); + ret =copy_from_user (req, vq->iov[0 ].iov_base, req_size);if (unlikely (ret)) {vq_err (vq,"Faulted on virtio_scsi_cmd_req\n" );break ;
Is this in for-next yet..?
If not, please push out ASAP so SFR can hit the conflict between target-pending/for-next as a heads up for Linus..
--nab
Re: [PATCH v2 18/18] vhost: vhost_scsi_handle_vq() should just use copy_from_user()
In reply to Al ViroQuoted 5 lines · Al Viro
From: Al Viro <[email protected]>
it has just verified that it asks no more than the length of the first segment of iovec.
Quoted 7 lines
And with that the last user of stuff in
lib/iovec.cis gone. RIP.Cc Michael S. Tsirkin <[email protected]>Cc Nicholas A. Bellinger <[email protected]>Signed-off-by Al Viro <[email protected]>
BTW it should really be __copy_from_user since the iovec is pre-validated by vhost core.
Still Nicholas is rewriting it all anyway, so not worth the time to optimize it, so
But, can you pls copy [email protected] ? I think some guys working on virtio might only hang out there.
Quoted 89 lines
--- drivers/vhost/scsi.c | 2 +- include/linux/uio.h | 2 -- lib/Makefile | 2 +- lib/iovec.c | 36 ------------------------------------ 4 files changed, 2 insertions(+), 40 deletions(-) delete mode 100644 lib/iovec.cdrivers/vhost/scsi.c +1
-1@@ -1079,7 +1079,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) req_size, vq->iov[0].iov_len);break ; } - ret =memcpy_fromiovecend (req, &vq->iov[0 ],0 , req_size); + ret =copy_from_user (req, vq->iov[0 ].iov_base, req_size);if (unlikely (ret)) {vq_err (vq,"Faulted on virtio_scsi_cmd_req\n" );break ;include/linux/uio.h +0
-2@@ -135,6 +135,4 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count)size_t csum_and_copy_to_iter (void *addr,size_t bytes,__wsum *csum,struct iov_iter *i);size_t csum_and_copy_from_iter (void *addr,size_t bytes,__wsum *csum,struct iov_iter *i); -int memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov, -int offset,int len);#endif lib/Makefile +1
-1@@ -24,7 +24,7 @@ obj-y += lockref.o obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \ - gcd.o lcm.o list_sort.o uuid.o flex_array.o iovec.o clz_ctz.o \ + gcd.o lcm.o list_sort.o uuid.o flex_array.o clz_ctz.o \ bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o \ percpu-refcount.o percpu_ida.o rhashtable.o reciprocal_div.o obj-y += string_helpers.olib/iovec.c deleted +0
-36@@ -1,36 +0,0 @@ -#include <linux/uaccess.h> -#include <linux/export.h> -#include <linux/uio.h> - -/* -* Copy iovec to kernel. Returns -EFAULT on error. -*/ - -int memcpy_fromiovecend (unsigned char *kdata,const struct iovec *iov, -int offset,int len) -{ -/* No data? Done! */ -if (len ==0 ) -return 0 ; - -/* Skip over the finished iovecs */ -while (offset >= iov->iov_len) { - offset -= iov->iov_len; - iov++; - } - -while (len >0 ) { -u8 __user *base = iov->iov_base + offset; - int copy = min_t(unsigned int, len, iov->iov_len - offset); - - offset =0 ; -if (copy_from_user (kdata, base, copy)) -return -EFAULT ; - len -= copy; - kdata += copy; - iov++; - } - -return 0 ; -} -EXPORT_SYMBOL (memcpy_fromiovecend);Signature · 1 line
2.1.4