]> git.karo-electronics.de Git - linux-beck.git/commitdiff
Merge branch 'for-davem-2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorDavid S. Miller <davem@davemloft.net>
Wed, 10 Dec 2014 18:17:23 +0000 (13:17 -0500)
committerDavid S. Miller <davem@davemloft.net>
Wed, 10 Dec 2014 18:17:23 +0000 (13:17 -0500)
More iov_iter work for the networking from Al Viro.

Signed-off-by: David S. Miller <davem@davemloft.net>
48 files changed:
crypto/algif_hash.c
crypto/algif_skcipher.c
drivers/misc/vmw_vmci/vmci_queue_pair.c
drivers/net/macvtap.c
drivers/net/ppp/ppp_generic.c
drivers/net/tun.c
drivers/target/iscsi/iscsi_target_util.c
drivers/vhost/net.c
fs/afs/rxrpc.c
include/linux/skbuff.h
include/linux/socket.h
include/linux/tcp.h
include/linux/uio.h
include/linux/vmw_vmci_api.h
include/net/bluetooth/l2cap.h
include/net/udplite.h
lib/iovec.c
mm/iov_iter.c
net/atm/common.c
net/bluetooth/6lowpan.c
net/bluetooth/a2mp.c
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_sock.c
net/bluetooth/smp.c
net/caif/caif_socket.c
net/compat.c
net/core/datagram.c
net/ipv4/ip_output.c
net/ipv4/ping.c
net/ipv4/raw.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_output.c
net/ipv4/udp.c
net/ipv6/ping.c
net/ipv6/raw.c
net/ipv6/udp.c
net/l2tp/l2tp_ip6.c
net/netlink/af_netlink.c
net/packet/af_packet.c
net/rds/recv.c
net/rds/send.c
net/rxrpc/ar-output.c
net/sctp/socket.c
net/socket.c
net/tipc/msg.c
net/unix/af_unix.c
net/vmw_vsock/vmci_transport.c

index 35c93ff11f35b4e097279cdc3805e46d40ec285b..83cd2cc49c9f2647755282a2ba1cf4b5f2e122b9 100644 (file)
@@ -42,7 +42,7 @@ static int hash_sendmsg(struct kiocb *unused, struct socket *sock,
        struct alg_sock *ask = alg_sk(sk);
        struct hash_ctx *ctx = ask->private;
        unsigned long iovlen;
-       struct iovec *iov;
+       const struct iovec *iov;
        long copied = 0;
        int err;
 
@@ -58,7 +58,7 @@ static int hash_sendmsg(struct kiocb *unused, struct socket *sock,
 
        ctx->more = 0;
 
-       for (iov = msg->msg_iov, iovlen = msg->msg_iovlen; iovlen > 0;
+       for (iov = msg->msg_iter.iov, iovlen = msg->msg_iter.nr_segs; iovlen > 0;
             iovlen--, iov++) {
                unsigned long seglen = iov->iov_len;
                char __user *from = iov->iov_base;
index c3b482bee2081262a56a6698fbede2ae3f39906a..4f45dab24648f267ae562dc2a6d266475ec11a14 100644 (file)
@@ -429,13 +429,13 @@ static int skcipher_recvmsg(struct kiocb *unused, struct socket *sock,
        struct skcipher_sg_list *sgl;
        struct scatterlist *sg;
        unsigned long iovlen;
-       struct iovec *iov;
+       const struct iovec *iov;
        int err = -EAGAIN;
        int used;
        long copied = 0;
 
        lock_sock(sk);
-       for (iov = msg->msg_iov, iovlen = msg->msg_iovlen; iovlen > 0;
+       for (iov = msg->msg_iter.iov, iovlen = msg->msg_iter.nr_segs; iovlen > 0;
             iovlen--, iov++) {
                unsigned long seglen = iov->iov_len;
                char __user *from = iov->iov_base;
index 1b7b303085d28d459c2595776fd82b15cf9a0dc5..7aaaf51e1596c5dc399cfa096040822275a05bae 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/uio.h>
 #include <linux/wait.h>
 #include <linux/vmalloc.h>
+#include <linux/skbuff.h>
 
 #include "vmci_handle_array.h"
 #include "vmci_queue_pair.h"
@@ -429,11 +430,11 @@ static int __qp_memcpy_from_queue(void *dest,
                        to_copy = size - bytes_copied;
 
                if (is_iovec) {
-                       struct iovec *iov = (struct iovec *)dest;
+                       struct msghdr *msg = dest;
                        int err;
 
                        /* The iovec will track bytes_copied internally. */
-                       err = memcpy_toiovec(iov, (u8 *)va + page_offset,
+                       err = memcpy_to_msg(msg, (u8 *)va + page_offset,
                                             to_copy);
                        if (err != 0) {
                                if (kernel_if->host)
@@ -3264,13 +3265,13 @@ EXPORT_SYMBOL_GPL(vmci_qpair_enquev);
  * of bytes dequeued or < 0 on error.
  */
 ssize_t vmci_qpair_dequev(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);
@@ -3279,7 +3280,7 @@ ssize_t vmci_qpair_dequev(struct vmci_qp *qpair,
                result = qp_dequeue_locked(qpair->produce_q,
                                           qpair->consume_q,
                                           qpair->consume_q_size,
-                                          iov, iov_size,
+                                          msg, iov_size,
                                           qp_memcpy_from_queue_iov,
                                           true);
 
@@ -3308,13 +3309,13 @@ EXPORT_SYMBOL_GPL(vmci_qpair_dequev);
  * of bytes peeked or < 0 on error.
  */
 ssize_t vmci_qpair_peekv(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);
@@ -3323,7 +3324,7 @@ ssize_t vmci_qpair_peekv(struct vmci_qp *qpair,
                result = qp_dequeue_locked(qpair->produce_q,
                                           qpair->consume_q,
                                           qpair->consume_q_size,
-                                          iov, iov_size,
+                                          msg, iov_size,
                                           qp_memcpy_from_queue_iov,
                                           false);
 
index ba1e5db2152e5519f644338bb170398d91853128..2c157cced81ffef7e82f30e45b7dd3da17c961c5 100644 (file)
@@ -1095,9 +1095,7 @@ static int macvtap_sendmsg(struct kiocb *iocb, struct socket *sock,
                           struct msghdr *m, size_t total_len)
 {
        struct macvtap_queue *q = container_of(sock, struct macvtap_queue, sock);
-       struct iov_iter from;
-       iov_iter_init(&from, WRITE, m->msg_iov, m->msg_iovlen, total_len);
-       return macvtap_get_user(q, m, &from, m->msg_flags & MSG_DONTWAIT);
+       return macvtap_get_user(q, m, &m->msg_iter, m->msg_flags & MSG_DONTWAIT);
 }
 
 static int macvtap_recvmsg(struct kiocb *iocb, struct socket *sock,
@@ -1105,12 +1103,10 @@ static int macvtap_recvmsg(struct kiocb *iocb, struct socket *sock,
                           int flags)
 {
        struct macvtap_queue *q = container_of(sock, struct macvtap_queue, sock);
-       struct iov_iter to;
        int ret;
        if (flags & ~(MSG_DONTWAIT|MSG_TRUNC))
                return -EINVAL;
-       iov_iter_init(&to, READ, m->msg_iov, m->msg_iovlen, total_len);
-       ret = macvtap_do_read(q, &to, flags & MSG_DONTWAIT);
+       ret = macvtap_do_read(q, &m->msg_iter, flags & MSG_DONTWAIT);
        if (ret > total_len) {
                m->msg_flags |= MSG_TRUNC;
                ret = flags & MSG_TRUNC ? ret : total_len;
index 794a4732936883c662212e0769e62993e67d96b0..af034dba9bd62a693ba81dd04479cd11ffc7f10e 100644 (file)
@@ -417,6 +417,7 @@ static ssize_t ppp_read(struct file *file, char __user *buf,
        ssize_t ret;
        struct sk_buff *skb = NULL;
        struct iovec iov;
+       struct iov_iter to;
 
        ret = count;
 
@@ -462,7 +463,8 @@ static ssize_t ppp_read(struct file *file, char __user *buf,
        ret = -EFAULT;
        iov.iov_base = buf;
        iov.iov_len = count;
-       if (skb_copy_datagram_iovec(skb, 0, &iov, skb->len))
+       iov_iter_init(&to, READ, &iov, 1, count);
+       if (skb_copy_datagram_iter(skb, 0, &to, skb->len))
                goto outf;
        ret = skb->len;
 
index 9c58286b8a42d20189f34801fca3e4a21e7c10e7..f3e992ed87ac69a1e91c79c146a3befcf4efe0ec 100644 (file)
@@ -1449,13 +1449,11 @@ static int tun_sendmsg(struct kiocb *iocb, struct socket *sock,
        int ret;
        struct tun_file *tfile = container_of(sock, struct tun_file, socket);
        struct tun_struct *tun = __tun_get(tfile);
-       struct iov_iter from;
 
        if (!tun)
                return -EBADFD;
 
-       iov_iter_init(&from, WRITE, m->msg_iov, m->msg_iovlen, total_len);
-       ret = tun_get_user(tun, tfile, m->msg_control, &from,
+       ret = tun_get_user(tun, tfile, m->msg_control, &m->msg_iter,
                           m->msg_flags & MSG_DONTWAIT);
        tun_put(tun);
        return ret;
@@ -1467,7 +1465,6 @@ static int tun_recvmsg(struct kiocb *iocb, struct socket *sock,
 {
        struct tun_file *tfile = container_of(sock, struct tun_file, socket);
        struct tun_struct *tun = __tun_get(tfile);
-       struct iov_iter to;
        int ret;
 
        if (!tun)
@@ -1482,8 +1479,7 @@ static int tun_recvmsg(struct kiocb *iocb, struct socket *sock,
                                         SOL_PACKET, TUN_TX_TIMESTAMP);
                goto out;
        }
-       iov_iter_init(&to, READ, m->msg_iov, m->msg_iovlen, total_len);
-       ret = tun_do_read(tun, tfile, &to, flags & MSG_DONTWAIT);
+       ret = tun_do_read(tun, tfile, &m->msg_iter, flags & MSG_DONTWAIT);
        if (ret > total_len) {
                m->msg_flags |= MSG_TRUNC;
                ret = flags & MSG_TRUNC ? ret : total_len;
index ce87ce9bdb9c59fd0d5d5eaf886acb7fc4c2b799..7c6a95bcb35e4ec043679338211f2435f98ccd33 100644 (file)
@@ -1326,21 +1326,19 @@ static int iscsit_do_rx_data(
        struct iscsi_conn *conn,
        struct iscsi_data_count *count)
 {
-       int data = count->data_length, rx_loop = 0, total_rx = 0, iov_len;
-       struct kvec *iov_p;
+       int data = count->data_length, rx_loop = 0, total_rx = 0;
        struct msghdr msg;
 
        if (!conn || !conn->sock || !conn->conn_ops)
                return -1;
 
        memset(&msg, 0, sizeof(struct msghdr));
-
-       iov_p = count->iov;
-       iov_len = count->iov_count;
+       iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC,
+                     count->iov, count->iov_count, data);
 
        while (total_rx < data) {
-               rx_loop = kernel_recvmsg(conn->sock, &msg, iov_p, iov_len,
-                                       (data - total_rx), MSG_WAITALL);
+               rx_loop = sock_recvmsg(conn->sock, &msg,
+                                     (data - total_rx), MSG_WAITALL);
                if (rx_loop <= 0) {
                        pr_debug("rx_loop: %d total_rx: %d\n",
                                rx_loop, total_rx);
index 8dae2f724a35ebfe811864a8c5c428280cfd2a76..9f06e70a26312b2e0e0cf9054e5cd854905f48f9 100644 (file)
@@ -342,7 +342,6 @@ static void handle_tx(struct vhost_net *net)
                .msg_namelen = 0,
                .msg_control = NULL,
                .msg_controllen = 0,
-               .msg_iov = vq->iov,
                .msg_flags = MSG_DONTWAIT,
        };
        size_t len, total_len = 0;
@@ -396,8 +395,8 @@ static void handle_tx(struct vhost_net *net)
                }
                /* Skip header. TODO: support TSO. */
                s = move_iovec_hdr(vq->iov, nvq->hdr, hdr_size, out);
-               msg.msg_iovlen = out;
                len = iov_length(vq->iov, out);
+               iov_iter_init(&msg.msg_iter, WRITE, vq->iov, out, len);
                /* Sanity check */
                if (!len) {
                        vq_err(vq, "Unexpected header len for TX: "
@@ -562,7 +561,6 @@ static void handle_rx(struct vhost_net *net)
                .msg_namelen = 0,
                .msg_control = NULL, /* FIXME: get and handle RX aux data. */
                .msg_controllen = 0,
-               .msg_iov = vq->iov,
                .msg_flags = MSG_DONTWAIT,
        };
        struct virtio_net_hdr_mrg_rxbuf hdr = {
@@ -600,7 +598,7 @@ static void handle_rx(struct vhost_net *net)
                        break;
                /* On overrun, truncate and discard */
                if (unlikely(headcount > UIO_MAXIOV)) {
-                       msg.msg_iovlen = 1;
+                       iov_iter_init(&msg.msg_iter, READ, vq->iov, 1, 1);
                        err = sock->ops->recvmsg(NULL, sock, &msg,
                                                 1, MSG_DONTWAIT | MSG_TRUNC);
                        pr_debug("Discarded rx packet: len %zd\n", sock_len);
@@ -626,7 +624,7 @@ static void handle_rx(struct vhost_net *net)
                        /* 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);
-               msg.msg_iovlen = in;
+               iov_iter_init(&msg.msg_iter, READ, vq->iov, in, sock_len);
                err = sock->ops->recvmsg(NULL, sock, &msg,
                                         sock_len, MSG_DONTWAIT | MSG_TRUNC);
                /* Userspace might have consumed the packet meanwhile:
index 03a3beb170048df40c436dff51c41373104cf9e7..06e14bfb3496c9d9aab923243c104addfbff7196 100644 (file)
@@ -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]" : "");
-                       msg->msg_iov = (struct iovec *) iov;
-                       msg->msg_iovlen = 1;
+                       iov_iter_init(&msg->msg_iter, WRITE,
+                                     (struct iovec *) iov, 1, to - offset);
 
                        /* have to change the state *before* sending the last
                         * packet as RxRPC might give us the reply before it
@@ -384,8 +384,8 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp,
 
        msg.msg_name            = NULL;
        msg.msg_namelen         = 0;
-       msg.msg_iov             = (struct iovec *) iov;
-       msg.msg_iovlen          = 1;
+       iov_iter_init(&msg.msg_iter, WRITE, (struct iovec *)iov, 1,
+                     call->request_size);
        msg.msg_control         = NULL;
        msg.msg_controllen      = 0;
        msg.msg_flags           = (call->send_pages ? MSG_MORE : 0);
@@ -778,8 +778,7 @@ void afs_send_empty_reply(struct afs_call *call)
        iov[0].iov_len          = 0;
        msg.msg_name            = NULL;
        msg.msg_namelen         = 0;
-       msg.msg_iov             = iov;
-       msg.msg_iovlen          = 0;
+       iov_iter_init(&msg.msg_iter, WRITE, iov, 0, 0); /* WTF? */
        msg.msg_control         = NULL;
        msg.msg_controllen      = 0;
        msg.msg_flags           = 0;
@@ -815,8 +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;
-       msg.msg_iov             = iov;
-       msg.msg_iovlen          = 1;
+       iov_iter_init(&msg.msg_iter, WRITE, iov, 1, len);
        msg.msg_control         = NULL;
        msg.msg_controllen      = 0;
        msg.msg_flags           = 0;
index ef64cec42804d8bde1dd081825908f119ba347c9..ab0bc43c82a4965b354d966d3a0db7ef82a00009 100644 (file)
@@ -2644,24 +2644,17 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock,
                                  int *err);
 unsigned int datagram_poll(struct file *file, struct socket *sock,
                           struct poll_table_struct *wait);
-int skb_copy_datagram_iovec(const struct sk_buff *from, int offset,
-                           struct iovec *to, int size);
+int skb_copy_datagram_iter(const struct sk_buff *from, int offset,
+                          struct iov_iter *to, int size);
 static inline int skb_copy_datagram_msg(const struct sk_buff *from, int offset,
                                        struct msghdr *msg, int size)
 {
-       return skb_copy_datagram_iovec(from, offset, msg->msg_iov, size);
-}
-int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb, int hlen,
-                                    struct iovec *iov);
-static inline int skb_copy_and_csum_datagram_msg(struct sk_buff *skb, int hlen,
-                           struct msghdr *msg)
-{
-       return skb_copy_and_csum_datagram_iovec(skb, hlen, msg->msg_iov);
+       return skb_copy_datagram_iter(from, offset, &msg->msg_iter, size);
 }
+int skb_copy_and_csum_datagram_msg(struct sk_buff *skb, int hlen,
+                                  struct msghdr *msg);
 int skb_copy_datagram_from_iter(struct sk_buff *skb, int offset,
                                 struct iov_iter *from, int len);
-int skb_copy_datagram_iter(const struct sk_buff *from, int offset,
-                          struct iov_iter *to, int size);
 int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *frm);
 void skb_free_datagram(struct sock *sk, struct sk_buff *skb);
 void skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb);
@@ -2689,12 +2682,13 @@ 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)
 {
-       return memcpy_fromiovec(data, msg->msg_iov, len);
+       /* XXX: stripping const */
+       return memcpy_fromiovec(data, (struct iovec *)msg->msg_iter.iov, len);
 }
 
 static inline int memcpy_to_msg(struct msghdr *msg, void *data, int len)
 {
-       return memcpy_toiovec(msg->msg_iov, data, len);
+       return copy_to_iter(data, len, &msg->msg_iter) == len ? 0 : -EFAULT;
 }
 
 struct skb_checksum_ops {
index de5222832be4e51663ef6f233eb21068a570a711..048d6d6eed6d1284a735960c9b05cf61ff1c6bf3 100644 (file)
@@ -47,8 +47,7 @@ struct linger {
 struct msghdr {
        void            *msg_name;      /* ptr to socket address structure */
        int             msg_namelen;    /* size of socket address structure */
-       struct iovec    *msg_iov;       /* scatter/gather array */
-       __kernel_size_t msg_iovlen;     /* # elements in msg_iov */
+       struct iov_iter msg_iter;       /* data */
        void            *msg_control;   /* ancillary data */
        __kernel_size_t msg_controllen; /* ancillary data buffer length */
        unsigned int    msg_flags;      /* flags on received message */
index 3fa0a9669a3a662be81d4b04f7d117b11012257c..67309ece0772b9a28e054af553c9aabd76021699 100644 (file)
@@ -162,7 +162,7 @@ struct tcp_sock {
        struct {
                struct sk_buff_head     prequeue;
                struct task_struct      *task;
-               struct iovec            *iov;
+               struct msghdr           *msg;
                int                     memory;
                int                     len;
        } ucopy;
index 9b1581414cd4ab1606574b01f617ec6a5583f663..a41e252396c0a4d58910858db78a7c6e5e800973 100644 (file)
@@ -31,6 +31,7 @@ struct iov_iter {
        size_t count;
        union {
                const struct iovec *iov;
+               const struct kvec *kvec;
                const struct bio_vec *bvec;
        };
        unsigned long nr_segs;
@@ -82,10 +83,13 @@ size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes,
                         struct iov_iter *i);
 size_t copy_to_iter(void *addr, size_t bytes, struct iov_iter *i);
 size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i);
+size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i);
 size_t iov_iter_zero(size_t bytes, struct iov_iter *);
 unsigned long iov_iter_alignment(const struct iov_iter *i);
 void iov_iter_init(struct iov_iter *i, int direction, const struct iovec *iov,
                        unsigned long nr_segs, size_t count);
+void iov_iter_kvec(struct iov_iter *i, int direction, const struct kvec *iov,
+                       unsigned long nr_segs, size_t count);
 ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages,
                        size_t maxsize, unsigned maxpages, size_t *start);
 ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages,
@@ -123,9 +127,10 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count)
 {
        i->count = 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_toiovec(struct iovec *iov, unsigned char *kdata, 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,
index 023430e265fe983f3e1192ccd8093985ee69e053..5691f752ce8f0b6fdd83f43502621f0ca06eebca 100644 (file)
@@ -24,6 +24,7 @@
 #define VMCI_KERNEL_API_VERSION_2 2
 #define VMCI_KERNEL_API_VERSION   VMCI_KERNEL_API_VERSION_2
 
+struct msghdr;
 typedef void (vmci_device_shutdown_fn) (void *device_registration,
                                        void *user_data);
 
@@ -75,8 +76,8 @@ ssize_t vmci_qpair_peek(struct vmci_qp *qpair, void *buf, size_t buf_size,
 ssize_t vmci_qpair_enquev(struct vmci_qp *qpair,
                          void *iov, size_t iov_size, int mode);
 ssize_t vmci_qpair_dequev(struct vmci_qp *qpair,
-                         void *iov, size_t iov_size, int mode);
-ssize_t vmci_qpair_peekv(struct vmci_qp *qpair, void *iov, size_t iov_size,
+                         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,
                         int mode);
 
 #endif /* !__VMW_VMCI_API_H__ */
index eee3ef530e79310dcaa5a216c132b37aa600bec2..d1bb342d083f14efc11ba4992e8c7509a67deac1 100644 (file)
@@ -608,10 +608,6 @@ struct l2cap_ops {
        struct sk_buff          *(*alloc_skb) (struct l2cap_chan *chan,
                                               unsigned long hdr_len,
                                               unsigned long len, int nb);
-       int                     (*memcpy_fromiovec) (struct l2cap_chan *chan,
-                                                    unsigned char *kdata,
-                                                    struct iovec *iov,
-                                                    int len);
 };
 
 struct l2cap_conn {
@@ -905,31 +901,6 @@ static inline long l2cap_chan_no_get_sndtimeo(struct l2cap_chan *chan)
        return 0;
 }
 
-static inline int l2cap_chan_no_memcpy_fromiovec(struct l2cap_chan *chan,
-                                                unsigned char *kdata,
-                                                struct iovec *iov,
-                                                int len)
-{
-       /* Following is safe since for compiler definitions of kvec and
-        * iovec are identical, yielding the same in-core layout and alignment
-        */
-       struct kvec *vec = (struct kvec *)iov;
-
-       while (len > 0) {
-               if (vec->iov_len) {
-                       int copy = min_t(unsigned int, len, vec->iov_len);
-                       memcpy(kdata, vec->iov_base, copy);
-                       len -= copy;
-                       kdata += copy;
-                       vec->iov_base += copy;
-                       vec->iov_len -= copy;
-               }
-               vec++;
-       }
-
-       return 0;
-}
-
 extern bool disable_ertm;
 
 int l2cap_init_sockets(void);
index 9a28a51794009a83d172949cbc5844b917ee5e66..ae7c8d1fbcadbccd635edc56a54dba6d94563170 100644 (file)
@@ -19,7 +19,9 @@ extern struct udp_table               udplite_table;
 static __inline__ int udplite_getfrag(void *from, char *to, int  offset,
                                      int len, int odd, struct sk_buff *skb)
 {
-       return memcpy_fromiovecend(to, (struct iovec *) from, offset, len);
+       struct msghdr *msg = from;
+       /* XXX: stripping const */
+       return memcpy_fromiovecend(to, (struct iovec *)msg->msg_iter.iov, offset, len);
 }
 
 /* Designate sk as UDP-Lite socket */
index df3abd1eaa4a52da47f806ffa7f4d93867366637..2d99cb4a500634b43fad5fe176c4951795b60721 100644 (file)
@@ -27,31 +27,6 @@ int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len)
 }
 EXPORT_SYMBOL(memcpy_fromiovec);
 
-/*
- *     Copy kernel to iovec. Returns -EFAULT on error.
- *
- *     Note: this modifies the original iovec.
- */
-
-int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len)
-{
-       while (len > 0) {
-               if (iov->iov_len) {
-                       int copy = min_t(unsigned int, iov->iov_len, len);
-                       if (copy_to_user(iov->iov_base, kdata, copy))
-                               return -EFAULT;
-                       kdata += copy;
-                       len -= copy;
-                       iov->iov_len -= copy;
-                       iov->iov_base += copy;
-               }
-               iov++;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL(memcpy_toiovec);
-
 /*
  *     Copy kernel to iovec. Returns -EFAULT on error.
  */
index e34a3cb6aad6cb078c0801efc6891ba83f5db155..a1599ca4ab0ed0e27917276102612d2877038b08 100644 (file)
 #include <linux/pagemap.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
-
-static size_t copy_to_iter_iovec(void *from, size_t bytes, struct iov_iter *i)
-{
-       size_t skip, copy, left, wanted;
-       const struct iovec *iov;
-       char __user *buf;
-
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       wanted = bytes;
-       iov = i->iov;
-       skip = i->iov_offset;
-       buf = iov->iov_base + skip;
-       copy = min(bytes, iov->iov_len - skip);
-
-       left = __copy_to_user(buf, from, copy);
-       copy -= left;
-       skip += copy;
-       from += copy;
-       bytes -= copy;
-       while (unlikely(!left && bytes)) {
-               iov++;
-               buf = iov->iov_base;
-               copy = min(bytes, iov->iov_len);
-               left = __copy_to_user(buf, from, copy);
-               copy -= left;
-               skip = copy;
-               from += copy;
-               bytes -= copy;
-       }
-
-       if (skip == iov->iov_len) {
-               iov++;
-               skip = 0;
-       }
-       i->count -= wanted - bytes;
-       i->nr_segs -= iov - i->iov;
-       i->iov = iov;
-       i->iov_offset = skip;
-       return wanted - bytes;
-}
-
-static size_t copy_from_iter_iovec(void *to, size_t bytes, struct iov_iter *i)
-{
-       size_t skip, copy, left, wanted;
-       const struct iovec *iov;
-       char __user *buf;
-
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       wanted = bytes;
-       iov = i->iov;
-       skip = i->iov_offset;
-       buf = iov->iov_base + skip;
-       copy = min(bytes, iov->iov_len - skip);
-
-       left = __copy_from_user(to, buf, copy);
-       copy -= left;
-       skip += copy;
-       to += copy;
-       bytes -= copy;
-       while (unlikely(!left && bytes)) {
-               iov++;
-               buf = iov->iov_base;
-               copy = min(bytes, iov->iov_len);
-               left = __copy_from_user(to, buf, copy);
-               copy -= left;
-               skip = copy;
-               to += copy;
-               bytes -= copy;
-       }
-
-       if (skip == iov->iov_len) {
-               iov++;
-               skip = 0;
-       }
-       i->count -= wanted - bytes;
-       i->nr_segs -= iov - i->iov;
-       i->iov = iov;
-       i->iov_offset = skip;
-       return wanted - bytes;
+#include <net/checksum.h>
+
+#define iterate_iovec(i, n, __v, __p, skip, STEP) {    \
+       size_t left;                                    \
+       size_t wanted = n;                              \
+       __p = i->iov;                                   \
+       __v.iov_len = min(n, __p->iov_len - skip);      \
+       if (likely(__v.iov_len)) {                      \
+               __v.iov_base = __p->iov_base + skip;    \
+               left = (STEP);                          \
+               __v.iov_len -= left;                    \
+               skip += __v.iov_len;                    \
+               n -= __v.iov_len;                       \
+       } else {                                        \
+               left = 0;                               \
+       }                                               \
+       while (unlikely(!left && n)) {                  \
+               __p++;                                  \
+               __v.iov_len = min(n, __p->iov_len);     \
+               if (unlikely(!__v.iov_len))             \
+                       continue;                       \
+               __v.iov_base = __p->iov_base;           \
+               left = (STEP);                          \
+               __v.iov_len -= left;                    \
+               skip = __v.iov_len;                     \
+               n -= __v.iov_len;                       \
+       }                                               \
+       n = wanted - n;                                 \
+}
+
+#define iterate_kvec(i, n, __v, __p, skip, STEP) {     \
+       size_t wanted = n;                              \
+       __p = i->kvec;                                  \
+       __v.iov_len = min(n, __p->iov_len - skip);      \
+       if (likely(__v.iov_len)) {                      \
+               __v.iov_base = __p->iov_base + skip;    \
+               (void)(STEP);                           \
+               skip += __v.iov_len;                    \
+               n -= __v.iov_len;                       \
+       }                                               \
+       while (unlikely(n)) {                           \
+               __p++;                                  \
+               __v.iov_len = min(n, __p->iov_len);     \
+               if (unlikely(!__v.iov_len))             \
+                       continue;                       \
+               __v.iov_base = __p->iov_base;           \
+               (void)(STEP);                           \
+               skip = __v.iov_len;                     \
+               n -= __v.iov_len;                       \
+       }                                               \
+       n = wanted;                                     \
+}
+
+#define iterate_bvec(i, n, __v, __p, skip, STEP) {     \
+       size_t wanted = n;                              \
+       __p = i->bvec;                                  \
+       __v.bv_len = min_t(size_t, n, __p->bv_len - skip);      \
+       if (likely(__v.bv_len)) {                       \
+               __v.bv_page = __p->bv_page;             \
+               __v.bv_offset = __p->bv_offset + skip;  \
+               (void)(STEP);                           \
+               skip += __v.bv_len;                     \
+               n -= __v.bv_len;                        \
+       }                                               \
+       while (unlikely(n)) {                           \
+               __p++;                                  \
+               __v.bv_len = min_t(size_t, n, __p->bv_len);     \
+               if (unlikely(!__v.bv_len))              \
+                       continue;                       \
+               __v.bv_page = __p->bv_page;             \
+               __v.bv_offset = __p->bv_offset;         \
+               (void)(STEP);                           \
+               skip = __v.bv_len;                      \
+               n -= __v.bv_len;                        \
+       }                                               \
+       n = wanted;                                     \
+}
+
+#define iterate_all_kinds(i, n, v, I, B, K) {                  \
+       size_t skip = i->iov_offset;                            \
+       if (unlikely(i->type & ITER_BVEC)) {                    \
+               const struct bio_vec *bvec;                     \
+               struct bio_vec v;                               \
+               iterate_bvec(i, n, v, bvec, skip, (B))          \
+       } else if (unlikely(i->type & ITER_KVEC)) {             \
+               const struct kvec *kvec;                        \
+               struct kvec v;                                  \
+               iterate_kvec(i, n, v, kvec, skip, (K))          \
+       } else {                                                \
+               const struct iovec *iov;                        \
+               struct iovec v;                                 \
+               iterate_iovec(i, n, v, iov, skip, (I))          \
+       }                                                       \
+}
+
+#define iterate_and_advance(i, n, v, I, B, K) {                        \
+       size_t skip = i->iov_offset;                            \
+       if (unlikely(i->type & ITER_BVEC)) {                    \
+               const struct bio_vec *bvec;                     \
+               struct bio_vec v;                               \
+               iterate_bvec(i, n, v, bvec, skip, (B))          \
+               if (skip == bvec->bv_len) {                     \
+                       bvec++;                                 \
+                       skip = 0;                               \
+               }                                               \
+               i->nr_segs -= bvec - i->bvec;                   \
+               i->bvec = bvec;                                 \
+       } else if (unlikely(i->type & ITER_KVEC)) {             \
+               const struct kvec *kvec;                        \
+               struct kvec v;                                  \
+               iterate_kvec(i, n, v, kvec, skip, (K))          \
+               if (skip == kvec->iov_len) {                    \
+                       kvec++;                                 \
+                       skip = 0;                               \
+               }                                               \
+               i->nr_segs -= kvec - i->kvec;                   \
+               i->kvec = kvec;                                 \
+       } else {                                                \
+               const struct iovec *iov;                        \
+               struct iovec v;                                 \
+               iterate_iovec(i, n, v, iov, skip, (I))          \
+               if (skip == iov->iov_len) {                     \
+                       iov++;                                  \
+                       skip = 0;                               \
+               }                                               \
+               i->nr_segs -= iov - i->iov;                     \
+               i->iov = iov;                                   \
+       }                                                       \
+       i->count -= n;                                          \
+       i->iov_offset = skip;                                   \
 }
 
 static size_t copy_page_to_iter_iovec(struct page *page, size_t offset, size_t bytes,
@@ -256,134 +297,6 @@ done:
        return wanted - bytes;
 }
 
-static size_t zero_iovec(size_t bytes, struct iov_iter *i)
-{
-       size_t skip, copy, left, wanted;
-       const struct iovec *iov;
-       char __user *buf;
-
-       if (unlikely(bytes > i->count))
-               bytes = i->count;
-
-       if (unlikely(!bytes))
-               return 0;
-
-       wanted = bytes;
-       iov = i->iov;
-       skip = i->iov_offset;
-       buf = iov->iov_base + skip;
-       copy = min(bytes, iov->iov_len - skip);
-
-       left = __clear_user(buf, copy);
-       copy -= left;
-       skip += copy;
-       bytes -= copy;
-
-       while (unlikely(!left && bytes)) {
-               iov++;
-               buf = iov->iov_base;
-               copy = min(bytes, iov->iov_len);
-               left = __clear_user(buf, copy);
-               copy -= left;
-               skip = copy;
-               bytes -= copy;
-       }
-
-       if (skip == iov->iov_len) {
-               iov++;
-               skip = 0;
-       }
-       i->count -= wanted - bytes;
-       i->nr_segs -= iov - i->iov;
-       i->iov = iov;
-       i->iov_offset = skip;
-       return wanted - bytes;
-}
-
-static size_t __iovec_copy_from_user_inatomic(char *vaddr,
-                       const struct iovec *iov, size_t base, size_t bytes)
-{
-       size_t copied = 0, left = 0;
-
-       while (bytes) {
-               char __user *buf = iov->iov_base + base;
-               int copy = min(bytes, iov->iov_len - base);
-
-               base = 0;
-               left = __copy_from_user_inatomic(vaddr, buf, copy);
-               copied += copy;
-               bytes -= copy;
-               vaddr += copy;
-               iov++;
-
-               if (unlikely(left))
-                       break;
-       }
-       return copied - left;
-}
-
-/*
- * Copy as much as we can into the page and return the number of bytes which
- * were successfully copied.  If a fault is encountered then return the number of
- * bytes which were copied.
- */
-static size_t copy_from_user_atomic_iovec(struct page *page,
-               struct iov_iter *i, unsigned long offset, size_t bytes)
-{
-       char *kaddr;
-       size_t copied;
-
-       kaddr = kmap_atomic(page);
-       if (likely(i->nr_segs == 1)) {
-               int left;
-               char __user *buf = i->iov->iov_base + i->iov_offset;
-               left = __copy_from_user_inatomic(kaddr + offset, buf, bytes);
-               copied = bytes - left;
-       } else {
-               copied = __iovec_copy_from_user_inatomic(kaddr + offset,
-                                               i->iov, i->iov_offset, bytes);
-       }
-       kunmap_atomic(kaddr);
-
-       return copied;
-}
-
-static void advance_iovec(struct iov_iter *i, size_t bytes)
-{
-       BUG_ON(i->count < bytes);
-
-       if (likely(i->nr_segs == 1)) {
-               i->iov_offset += bytes;
-               i->count -= bytes;
-       } else {
-               const struct iovec *iov = i->iov;
-               size_t base = i->iov_offset;
-               unsigned long nr_segs = i->nr_segs;
-
-               /*
-                * The !iov->iov_len check ensures we skip over unlikely
-                * zero-length segments (without overruning the iovec).
-                */
-               while (bytes || unlikely(i->count && !iov->iov_len)) {
-                       int copy;
-
-                       copy = min(bytes, iov->iov_len - base);
-                       BUG_ON(!i->count || i->count < copy);
-                       i->count -= copy;
-                       bytes -= copy;
-                       base += copy;
-                       if (iov->iov_len == base) {
-                               iov++;
-                               nr_segs--;
-                               base = 0;
-                       }
-               }
-               i->iov = iov;
-               i->iov_offset = base;
-               i->nr_segs = nr_segs;
-       }
-}
-
 /*
  * Fault in the first iovec of the given iov_iter, to a maximum length
  * of bytes. Returns 0 on success, or non-zero if the memory could not be
@@ -395,7 +308,7 @@ static void advance_iovec(struct iov_iter *i, size_t bytes)
  */
 int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes)
 {
-       if (!(i->type & ITER_BVEC)) {
+       if (!(i->type & (ITER_BVEC|ITER_KVEC))) {
                char __user *buf = i->iov->iov_base + i->iov_offset;
                bytes = min(bytes, i->iov->iov_len - i->iov_offset);
                return fault_in_pages_readable(buf, bytes);
@@ -404,136 +317,25 @@ int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes)
 }
 EXPORT_SYMBOL(iov_iter_fault_in_readable);
 
-static unsigned long alignment_iovec(const struct iov_iter *i)
-{
-       const struct iovec *iov = i->iov;
-       unsigned long res;
-       size_t size = i->count;
-       size_t n;
-
-       if (!size)
-               return 0;
-
-       res = (unsigned long)iov->iov_base + i->iov_offset;
-       n = iov->iov_len - i->iov_offset;
-       if (n >= size)
-               return res | size;
-       size -= n;
-       res |= n;
-       while (size > (++iov)->iov_len) {
-               res |= (unsigned long)iov->iov_base | iov->iov_len;
-               size -= iov->iov_len;
-       }
-       res |= (unsigned long)iov->iov_base | size;
-       return res;
-}
-
 void iov_iter_init(struct iov_iter *i, int direction,
                        const struct iovec *iov, unsigned long nr_segs,
                        size_t count)
 {
        /* It will get better.  Eventually... */
-       if (segment_eq(get_fs(), KERNEL_DS))
+       if (segment_eq(get_fs(), KERNEL_DS)) {
                direction |= ITER_KVEC;
-       i->type = direction;
-       i->iov = iov;
+               i->type = direction;
+               i->kvec = (struct kvec *)iov;
+       } else {
+               i->type = direction;
+               i->iov = iov;
+       }
        i->nr_segs = nr_segs;
        i->iov_offset = 0;
        i->count = count;
 }
 EXPORT_SYMBOL(iov_iter_init);
 
-static ssize_t get_pages_iovec(struct iov_iter *i,
-                  struct page **pages, size_t maxsize, unsigned maxpages,
-                  size_t *start)
-{
-       size_t offset = i->iov_offset;
-       const struct iovec *iov = i->iov;
-       size_t len;
-       unsigned long addr;
-       int n;
-       int res;
-
-       len = iov->iov_len - offset;
-       if (len > i->count)
-               len = i->count;
-       if (len > maxsize)
-               len = maxsize;
-       addr = (unsigned long)iov->iov_base + offset;
-       len += *start = addr & (PAGE_SIZE - 1);
-       if (len > maxpages * PAGE_SIZE)
-               len = maxpages * PAGE_SIZE;
-       addr &= ~(PAGE_SIZE - 1);
-       n = (len + PAGE_SIZE - 1) / PAGE_SIZE;
-       res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, pages);
-       if (unlikely(res < 0))
-               return res;
-       return (res == n ? len : res * PAGE_SIZE) - *start;
-}
-
-static ssize_t get_pages_alloc_iovec(struct iov_iter *i,
-                  struct page ***pages, size_t maxsize,
-                  size_t *start)
-{
-       size_t offset = i->iov_offset;
-       const struct iovec *iov = i->iov;
-       size_t len;
-       unsigned long addr;
-       void *p;
-       int n;
-       int res;
-
-       len = iov->iov_len - offset;
-       if (len > i->count)
-               len = i->count;
-       if (len > maxsize)
-               len = maxsize;
-       addr = (unsigned long)iov->iov_base + offset;
-       len += *start = addr & (PAGE_SIZE - 1);
-       addr &= ~(PAGE_SIZE - 1);
-       n = (len + PAGE_SIZE - 1) / PAGE_SIZE;
-       
-       p = kmalloc(n * sizeof(struct page *), GFP_KERNEL);
-       if (!p)
-               p = vmalloc(n * sizeof(struct page *));
-       if (!p)
-               return -ENOMEM;
-
-       res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, p);
-       if (unlikely(res < 0)) {
-               kvfree(p);
-               return res;
-       }
-       *pages = p;
-       return (res == n ? len : res * PAGE_SIZE) - *start;
-}
-
-static int iov_iter_npages_iovec(const struct iov_iter *i, int maxpages)
-{
-       size_t offset = i->iov_offset;
-       size_t size = i->count;
-       const struct iovec *iov = i->iov;
-       int npages = 0;
-       int n;
-
-       for (n = 0; size && n < i->nr_segs; n++, iov++) {
-               unsigned long addr = (unsigned long)iov->iov_base + offset;
-               size_t len = iov->iov_len - offset;
-               offset = 0;
-               if (unlikely(!len))     /* empty segment */
-                       continue;
-               if (len > size)
-                       len = size;
-               npages += (addr + len + PAGE_SIZE - 1) / PAGE_SIZE
-                         - addr / PAGE_SIZE;
-               if (npages >= maxpages) /* don't bother going further */
-                       return maxpages;
-               size -= len;
-               offset = 0;
-       }
-       return min(npages, maxpages);
-}
-
 static void memcpy_from_page(char *to, struct page *page, size_t offset, size_t len)
 {
        char *from = kmap_atomic(page);
@@ -555,293 +357,78 @@ static void memzero_page(struct page *page, size_t offset, size_t len)
        kunmap_atomic(addr);
 }
 
-static size_t copy_to_iter_bvec(void *from, size_t bytes, struct iov_iter *i)
+size_t copy_to_iter(void *addr, size_t bytes, struct iov_iter *i)
 {
-       size_t skip, copy, wanted;
-       const struct bio_vec *bvec;
-
+       char *from = addr;
        if (unlikely(bytes > i->count))
                bytes = i->count;
 
        if (unlikely(!bytes))
                return 0;
 
-       wanted = bytes;
-       bvec = i->bvec;
-       skip = i->iov_offset;
-       copy = min_t(size_t, bytes, bvec->bv_len - skip);
+       iterate_and_advance(i, bytes, v,
+               __copy_to_user(v.iov_base, (from += v.iov_len) - v.iov_len,
+                              v.iov_len),
+               memcpy_to_page(v.bv_page, v.bv_offset,
+                              (from += v.bv_len) - v.bv_len, v.bv_len),
+               memcpy(v.iov_base, (from += v.iov_len) - v.iov_len, v.iov_len)
+       )
 
-       memcpy_to_page(bvec->bv_page, skip + bvec->bv_offset, from, copy);
-       skip += copy;
-       from += copy;
-       bytes -= copy;
-       while (bytes) {
-               bvec++;
-               copy = min(bytes, (size_t)bvec->bv_len);
-               memcpy_to_page(bvec->bv_page, bvec->bv_offset, from, copy);
-               skip = copy;
-               from += copy;
-               bytes -= copy;
-       }
-       if (skip == bvec->bv_len) {
-               bvec++;
-               skip = 0;
-       }
-       i->count -= wanted - bytes;
-       i->nr_segs -= bvec - i->bvec;
-       i->bvec = bvec;
-       i->iov_offset = skip;
-       return wanted - bytes;
+       return bytes;
 }
+EXPORT_SYMBOL(copy_to_iter);
 
-static size_t copy_from_iter_bvec(void *to, size_t bytes, struct iov_iter *i)
+size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i)
 {
-       size_t skip, copy, wanted;
-       const struct bio_vec *bvec;
-
+       char *to = addr;
        if (unlikely(bytes > i->count))
                bytes = i->count;
 
        if (unlikely(!bytes))
                return 0;
 
-       wanted = bytes;
-       bvec = i->bvec;
-       skip = i->iov_offset;
-
-       copy = min(bytes, bvec->bv_len - skip);
+       iterate_and_advance(i, bytes, v,
+               __copy_from_user((to += v.iov_len) - v.iov_len, v.iov_base,
+                                v.iov_len),
+               memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page,
+                                v.bv_offset, v.bv_len),
+               memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
+       )
 
-       memcpy_from_page(to, bvec->bv_page, bvec->bv_offset + skip, copy);
-
-       to += copy;
-       skip += copy;
-       bytes -= copy;
-
-       while (bytes) {
-               bvec++;
-               copy = min(bytes, (size_t)bvec->bv_len);
-               memcpy_from_page(to, bvec->bv_page, bvec->bv_offset, copy);
-               skip = copy;
-               to += copy;
-               bytes -= copy;
-       }
-       if (skip == bvec->bv_len) {
-               bvec++;
-               skip = 0;
-       }
-       i->count -= wanted;
-       i->nr_segs -= bvec - i->bvec;
-       i->bvec = bvec;
-       i->iov_offset = skip;
-       return wanted;
-}
-
-static size_t copy_page_to_iter_bvec(struct page *page, size_t offset,
-                                       size_t bytes, struct iov_iter *i)
-{
-       void *kaddr = kmap_atomic(page);
-       size_t wanted = copy_to_iter_bvec(kaddr + offset, bytes, i);
-       kunmap_atomic(kaddr);
-       return wanted;
-}
-
-static size_t copy_page_from_iter_bvec(struct page *page, size_t offset,
-                                       size_t bytes, struct iov_iter *i)
-{
-       void *kaddr = kmap_atomic(page);
-       size_t wanted = copy_from_iter_bvec(kaddr + offset, bytes, i);
-       kunmap_atomic(kaddr);
-       return wanted;
+       return bytes;
 }
+EXPORT_SYMBOL(copy_from_iter);
 
-static size_t zero_bvec(size_t bytes, struct iov_iter *i)
+size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i)
 {
-       size_t skip, copy, wanted;
-       const struct bio_vec *bvec;
-
+       char *to = addr;
        if (unlikely(bytes > i->count))
                bytes = i->count;
 
        if (unlikely(!bytes))
                return 0;
 
-       wanted = bytes;
-       bvec = i->bvec;
-       skip = i->iov_offset;
-       copy = min_t(size_t, bytes, bvec->bv_len - skip);
-
-       memzero_page(bvec->bv_page, skip + bvec->bv_offset, copy);
-       skip += copy;
-       bytes -= copy;
-       while (bytes) {
-               bvec++;
-               copy = min(bytes, (size_t)bvec->bv_len);
-               memzero_page(bvec->bv_page, bvec->bv_offset, copy);
-               skip = copy;
-               bytes -= copy;
-       }
-       if (skip == bvec->bv_len) {
-               bvec++;
-               skip = 0;
-       }
-       i->count -= wanted - bytes;
-       i->nr_segs -= bvec - i->bvec;
-       i->bvec = bvec;
-       i->iov_offset = skip;
-       return wanted - bytes;
-}
+       iterate_and_advance(i, bytes, v,
+               __copy_from_user_nocache((to += v.iov_len) - v.iov_len,
+                                        v.iov_base, v.iov_len),
+               memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page,
+                                v.bv_offset, v.bv_len),
+               memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
+       )
 
-static size_t copy_from_user_bvec(struct page *page,
-               struct iov_iter *i, unsigned long offset, size_t bytes)
-{
-       char *kaddr;
-       size_t left;
-       const struct bio_vec *bvec;
-       size_t base = i->iov_offset;
-
-       kaddr = kmap_atomic(page);
-       for (left = bytes, bvec = i->bvec; left; bvec++, base = 0) {
-               size_t copy = min(left, bvec->bv_len - base);
-               if (!bvec->bv_len)
-                       continue;
-               memcpy_from_page(kaddr + offset, bvec->bv_page,
-                                bvec->bv_offset + base, copy);
-               offset += copy;
-               left -= copy;
-       }
-       kunmap_atomic(kaddr);
        return bytes;
 }
-
-static void advance_bvec(struct iov_iter *i, size_t bytes)
-{
-       BUG_ON(i->count < bytes);
-
-       if (likely(i->nr_segs == 1)) {
-               i->iov_offset += bytes;
-               i->count -= bytes;
-       } else {
-               const struct bio_vec *bvec = i->bvec;
-               size_t base = i->iov_offset;
-               unsigned long nr_segs = i->nr_segs;
-
-               /*
-                * The !iov->iov_len check ensures we skip over unlikely
-                * zero-length segments (without overruning the iovec).
-                */
-               while (bytes || unlikely(i->count && !bvec->bv_len)) {
-                       int copy;
-
-                       copy = min(bytes, bvec->bv_len - base);
-                       BUG_ON(!i->count || i->count < copy);
-                       i->count -= copy;
-                       bytes -= copy;
-                       base += copy;
-                       if (bvec->bv_len == base) {
-                               bvec++;
-                               nr_segs--;
-                               base = 0;
-                       }
-               }
-               i->bvec = bvec;
-               i->iov_offset = base;
-               i->nr_segs = nr_segs;
-       }
-}
-
-static unsigned long alignment_bvec(const struct iov_iter *i)
-{
-       const struct bio_vec *bvec = i->bvec;
-       unsigned long res;
-       size_t size = i->count;
-       size_t n;
-
-       if (!size)
-               return 0;
-
-       res = bvec->bv_offset + i->iov_offset;
-       n = bvec->bv_len - i->iov_offset;
-       if (n >= size)
-               return res | size;
-       size -= n;
-       res |= n;
-       while (size > (++bvec)->bv_len) {
-               res |= bvec->bv_offset | bvec->bv_len;
-               size -= bvec->bv_len;
-       }
-       res |= bvec->bv_offset | size;
-       return res;
-}
-
-static ssize_t get_pages_bvec(struct iov_iter *i,
-                  struct page **pages, size_t maxsize, unsigned maxpages,
-                  size_t *start)
-{
-       const struct bio_vec *bvec = i->bvec;
-       size_t len = bvec->bv_len - i->iov_offset;
-       if (len > i->count)
-               len = i->count;
-       if (len > maxsize)
-               len = maxsize;
-       /* can't be more than PAGE_SIZE */
-       *start = bvec->bv_offset + i->iov_offset;
-
-       get_page(*pages = bvec->bv_page);
-
-       return len;
-}
-
-static ssize_t get_pages_alloc_bvec(struct iov_iter *i,
-                  struct page ***pages, size_t maxsize,
-                  size_t *start)
-{
-       const struct bio_vec *bvec = i->bvec;
-       size_t len = bvec->bv_len - i->iov_offset;
-       if (len > i->count)
-               len = i->count;
-       if (len > maxsize)
-               len = maxsize;
-       *start = bvec->bv_offset + i->iov_offset;
-
-       *pages = kmalloc(sizeof(struct page *), GFP_KERNEL);
-       if (!*pages)
-               return -ENOMEM;
-
-       get_page(**pages = bvec->bv_page);
-
-       return len;
-}
-
-static int iov_iter_npages_bvec(const struct iov_iter *i, int maxpages)
-{
-       size_t offset = i->iov_offset;
-       size_t size = i->count;
-       const struct bio_vec *bvec = i->bvec;
-       int npages = 0;
-       int n;
-
-       for (n = 0; size && n < i->nr_segs; n++, bvec++) {
-               size_t len = bvec->bv_len - offset;
-               offset = 0;
-               if (unlikely(!len))     /* empty segment */
-                       continue;
-               if (len > size)
-                       len = size;
-               npages++;
-               if (npages >= maxpages) /* don't bother going further */
-                       return maxpages;
-               size -= len;
-               offset = 0;
-       }
-       return min(npages, maxpages);
-}
+EXPORT_SYMBOL(copy_from_iter_nocache);
 
 size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
                         struct iov_iter *i)
 {
-       if (i->type & ITER_BVEC)
-               return copy_page_to_iter_bvec(page, offset, bytes, i);
-       else
+       if (i->type & (ITER_BVEC|ITER_KVEC)) {
+               void *kaddr = kmap_atomic(page);
+               size_t wanted = copy_to_iter(kaddr + offset, bytes, i);
+               kunmap_atomic(kaddr);
+               return wanted;
+       } else
                return copy_page_to_iter_iovec(page, offset, bytes, i);
 }
 EXPORT_SYMBOL(copy_page_to_iter);
@@ -849,57 +436,53 @@ EXPORT_SYMBOL(copy_page_to_iter);
 size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes,
                         struct iov_iter *i)
 {
-       if (i->type & ITER_BVEC)
-               return copy_page_from_iter_bvec(page, offset, bytes, i);
-       else
+       if (i->type & (ITER_BVEC|ITER_KVEC)) {
+               void *kaddr = kmap_atomic(page);
+               size_t wanted = copy_from_iter(kaddr + offset, bytes, i);
+               kunmap_atomic(kaddr);
+               return wanted;
+       } else
                return copy_page_from_iter_iovec(page, offset, bytes, i);
 }
 EXPORT_SYMBOL(copy_page_from_iter);
 
-size_t copy_to_iter(void *addr, size_t bytes, struct iov_iter *i)
+size_t iov_iter_zero(size_t bytes, struct iov_iter *i)
 {
-       if (i->type & ITER_BVEC)
-               return copy_to_iter_bvec(addr, bytes, i);
-       else
-               return copy_to_iter_iovec(addr, bytes, i);
-}
-EXPORT_SYMBOL(copy_to_iter);
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
 
-size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i)
-{
-       if (i->type & ITER_BVEC)
-               return copy_from_iter_bvec(addr, bytes, i);
-       else
-               return copy_from_iter_iovec(addr, bytes, i);
-}
-EXPORT_SYMBOL(copy_from_iter);
+       if (unlikely(!bytes))
+               return 0;
 
-size_t iov_iter_zero(size_t bytes, struct iov_iter *i)
-{
-       if (i->type & ITER_BVEC) {
-               return zero_bvec(bytes, i);
-       } else {
-               return zero_iovec(bytes, i);
-       }
+       iterate_and_advance(i, bytes, v,
+               __clear_user(v.iov_base, v.iov_len),
+               memzero_page(v.bv_page, v.bv_offset, v.bv_len),
+               memset(v.iov_base, 0, v.iov_len)
+       )
+
+       return bytes;
 }
 EXPORT_SYMBOL(iov_iter_zero);
 
 size_t iov_iter_copy_from_user_atomic(struct page *page,
                struct iov_iter *i, unsigned long offset, size_t bytes)
 {
-       if (i->type & ITER_BVEC)
-               return copy_from_user_bvec(page, i, offset, bytes);
-       else
-               return copy_from_user_atomic_iovec(page, i, offset, bytes);
+       char *kaddr = kmap_atomic(page), *p = kaddr + offset;
+       iterate_all_kinds(i, bytes, v,
+               __copy_from_user_inatomic((p += v.iov_len) - v.iov_len,
+                                         v.iov_base, v.iov_len),
+               memcpy_from_page((p += v.bv_len) - v.bv_len, v.bv_page,
+                                v.bv_offset, v.bv_len),
+               memcpy((p += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
+       )
+       kunmap_atomic(kaddr);
+       return bytes;
 }
 EXPORT_SYMBOL(iov_iter_copy_from_user_atomic);
 
 void iov_iter_advance(struct iov_iter *i, size_t size)
 {
-       if (i->type & ITER_BVEC)
-               advance_bvec(i, size);
-       else
-               advance_iovec(i, size);
+       iterate_and_advance(i, size, v, 0, 0, 0)
 }
 EXPORT_SYMBOL(iov_iter_advance);
 
@@ -917,12 +500,33 @@ size_t iov_iter_single_seg_count(const struct iov_iter *i)
 }
 EXPORT_SYMBOL(iov_iter_single_seg_count);
 
+void iov_iter_kvec(struct iov_iter *i, int direction,
+                       const struct kvec *iov, unsigned long nr_segs,
+                       size_t count)
+{
+       BUG_ON(!(direction & ITER_KVEC));
+       i->type = direction;
+       i->kvec = (struct kvec *)iov;
+       i->nr_segs = nr_segs;
+       i->iov_offset = 0;
+       i->count = count;
+}
+EXPORT_SYMBOL(iov_iter_kvec);
+
 unsigned long iov_iter_alignment(const struct iov_iter *i)
 {
-       if (i->type & ITER_BVEC)
-               return alignment_bvec(i);
-       else
-               return alignment_iovec(i);
+       unsigned long res = 0;
+       size_t size = i->count;
+
+       if (!size)
+               return 0;
+
+       iterate_all_kinds(i, size, v,
+               (res |= (unsigned long)v.iov_base | v.iov_len, 0),
+               res |= v.bv_offset | v.bv_len,
+               res |= (unsigned long)v.iov_base | v.iov_len
+       )
+       return res;
 }
 EXPORT_SYMBOL(iov_iter_alignment);
 
@@ -930,29 +534,207 @@ ssize_t iov_iter_get_pages(struct iov_iter *i,
                   struct page **pages, size_t maxsize, unsigned maxpages,
                   size_t *start)
 {
-       if (i->type & ITER_BVEC)
-               return get_pages_bvec(i, pages, maxsize, maxpages, start);
-       else
-               return get_pages_iovec(i, pages, maxsize, maxpages, start);
+       if (maxsize > i->count)
+               maxsize = i->count;
+
+       if (!maxsize)
+               return 0;
+
+       iterate_all_kinds(i, maxsize, v, ({
+               unsigned long addr = (unsigned long)v.iov_base;
+               size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
+               int n;
+               int res;
+
+               if (len > maxpages * PAGE_SIZE)
+                       len = maxpages * PAGE_SIZE;
+               addr &= ~(PAGE_SIZE - 1);
+               n = DIV_ROUND_UP(len, PAGE_SIZE);
+               res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, pages);
+               if (unlikely(res < 0))
+                       return res;
+               return (res == n ? len : res * PAGE_SIZE) - *start;
+       0;}),({
+               /* can't be more than PAGE_SIZE */
+               *start = v.bv_offset;
+               get_page(*pages = v.bv_page);
+               return v.bv_len;
+       }),({
+               return -EFAULT;
+       })
+       )
+       return 0;
 }
 EXPORT_SYMBOL(iov_iter_get_pages);
 
+static struct page **get_pages_array(size_t n)
+{
+       struct page **p = kmalloc(n * sizeof(struct page *), GFP_KERNEL);
+       if (!p)
+               p = vmalloc(n * sizeof(struct page *));
+       return p;
+}
+
 ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
                   struct page ***pages, size_t maxsize,
                   size_t *start)
 {
-       if (i->type & ITER_BVEC)
-               return get_pages_alloc_bvec(i, pages, maxsize, start);
-       else
-               return get_pages_alloc_iovec(i, pages, maxsize, start);
+       struct page **p;
+
+       if (maxsize > i->count)
+               maxsize = i->count;
+
+       if (!maxsize)
+               return 0;
+
+       iterate_all_kinds(i, maxsize, v, ({
+               unsigned long addr = (unsigned long)v.iov_base;
+               size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
+               int n;
+               int res;
+
+               addr &= ~(PAGE_SIZE - 1);
+               n = DIV_ROUND_UP(len, PAGE_SIZE);
+               p = get_pages_array(n);
+               if (!p)
+                       return -ENOMEM;
+               res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, p);
+               if (unlikely(res < 0)) {
+                       kvfree(p);
+                       return res;
+               }
+               *pages = p;
+               return (res == n ? len : res * PAGE_SIZE) - *start;
+       0;}),({
+               /* can't be more than PAGE_SIZE */
+               *start = v.bv_offset;
+               *pages = p = get_pages_array(1);
+               if (!p)
+                       return -ENOMEM;
+               get_page(*p = v.bv_page);
+               return v.bv_len;
+       }),({
+               return -EFAULT;
+       })
+       )
+       return 0;
 }
 EXPORT_SYMBOL(iov_iter_get_pages_alloc);
 
+size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum,
+                              struct iov_iter *i)
+{
+       char *to = addr;
+       __wsum sum, next;
+       size_t off = 0;
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       sum = *csum;
+       iterate_and_advance(i, bytes, v, ({
+               int err = 0;
+               next = csum_and_copy_from_user(v.iov_base, 
+                                              (to += v.iov_len) - v.iov_len,
+                                              v.iov_len, 0, &err);
+               if (!err) {
+                       sum = csum_block_add(sum, next, off);
+                       off += v.iov_len;
+               }
+               err ? v.iov_len : 0;
+       }), ({
+               char *p = kmap_atomic(v.bv_page);
+               next = csum_partial_copy_nocheck(p + v.bv_offset,
+                                                (to += v.bv_len) - v.bv_len,
+                                                v.bv_len, 0);
+               kunmap_atomic(p);
+               sum = csum_block_add(sum, next, off);
+               off += v.bv_len;
+       }),({
+               next = csum_partial_copy_nocheck(v.iov_base,
+                                                (to += v.iov_len) - v.iov_len,
+                                                v.iov_len, 0);
+               sum = csum_block_add(sum, next, off);
+               off += v.iov_len;
+       })
+       )
+       *csum = sum;
+       return bytes;
+}
+EXPORT_SYMBOL(csum_and_copy_from_iter);
+
+size_t csum_and_copy_to_iter(void *addr, size_t bytes, __wsum *csum,
+                            struct iov_iter *i)
+{
+       char *from = addr;
+       __wsum sum, next;
+       size_t off = 0;
+       if (unlikely(bytes > i->count))
+               bytes = i->count;
+
+       if (unlikely(!bytes))
+               return 0;
+
+       sum = *csum;
+       iterate_and_advance(i, bytes, v, ({
+               int err = 0;
+               next = csum_and_copy_to_user((from += v.iov_len) - v.iov_len,
+                                            v.iov_base, 
+                                            v.iov_len, 0, &err);
+               if (!err) {
+                       sum = csum_block_add(sum, next, off);
+                       off += v.iov_len;
+               }
+               err ? v.iov_len : 0;
+       }), ({
+               char *p = kmap_atomic(v.bv_page);
+               next = csum_partial_copy_nocheck((from += v.bv_len) - v.bv_len,
+                                                p + v.bv_offset,
+                                                v.bv_len, 0);
+               kunmap_atomic(p);
+               sum = csum_block_add(sum, next, off);
+               off += v.bv_len;
+       }),({
+               next = csum_partial_copy_nocheck((from += v.iov_len) - v.iov_len,
+                                                v.iov_base,
+                                                v.iov_len, 0);
+               sum = csum_block_add(sum, next, off);
+               off += v.iov_len;
+       })
+       )
+       *csum = sum;
+       return bytes;
+}
+EXPORT_SYMBOL(csum_and_copy_to_iter);
+
 int iov_iter_npages(const struct iov_iter *i, int maxpages)
 {
-       if (i->type & ITER_BVEC)
-               return iov_iter_npages_bvec(i, maxpages);
-       else
-               return iov_iter_npages_iovec(i, maxpages);
+       size_t size = i->count;
+       int npages = 0;
+
+       if (!size)
+               return 0;
+
+       iterate_all_kinds(i, size, v, ({
+               unsigned long p = (unsigned long)v.iov_base;
+               npages += DIV_ROUND_UP(p + v.iov_len, PAGE_SIZE)
+                       - p / PAGE_SIZE;
+               if (npages >= maxpages)
+                       return maxpages;
+       0;}),({
+               npages++;
+               if (npages >= maxpages)
+                       return maxpages;
+       }),({
+               unsigned long p = (unsigned long)v.iov_base;
+               npages += DIV_ROUND_UP(p + v.iov_len, PAGE_SIZE)
+                       - p / PAGE_SIZE;
+               if (npages >= maxpages)
+                       return maxpages;
+       })
+       )
+       return npages;
 }
 EXPORT_SYMBOL(iov_iter_npages);
index f59112944c917e845c919b90449098aa7a3a1a7e..b84057e41bd6a364281ea85f24e60b82e4ec6cfd 100644 (file)
@@ -577,9 +577,6 @@ int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
        struct atm_vcc *vcc;
        struct sk_buff *skb;
        int eff, error;
-       struct iov_iter from;
-
-       iov_iter_init(&from, WRITE, m->msg_iov, m->msg_iovlen, size);
 
        lock_sock(sk);
        if (sock->state != SS_CONNECTED) {
@@ -634,7 +631,7 @@ int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
                goto out;
        skb->dev = NULL; /* for paths shared with net_device interfaces */
        ATM_SKB(skb)->atm_options = vcc->atm_options;
-       if (copy_from_iter(skb_put(skb, size), size, &from) != size) {
+       if (copy_from_iter(skb_put(skb, size), size, &m->msg_iter) != size) {
                kfree_skb(skb);
                error = -EFAULT;
                goto out;
index bdcaefd2db127c97b6d0e4556dd3494835f01d89..76617be1e797ba6d41c72fbc8f582d5a5614ff3e 100644 (file)
@@ -537,12 +537,12 @@ static int send_pkt(struct l2cap_chan *chan, struct sk_buff *skb,
         */
        chan->data = skb;
 
-       memset(&msg, 0, sizeof(msg));
-       msg.msg_iov = (struct iovec *) &iv;
-       msg.msg_iovlen = 1;
        iv.iov_base = skb->data;
        iv.iov_len = skb->len;
 
+       memset(&msg, 0, sizeof(msg));
+       iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, &iv, 1, skb->len);
+
        err = l2cap_chan_send(chan, &msg, skb->len);
        if (err > 0) {
                netdev->stats.tx_bytes += err;
@@ -1050,7 +1050,6 @@ static const struct l2cap_ops bt_6lowpan_chan_ops = {
        .suspend                = chan_suspend_cb,
        .get_sndtimeo           = chan_get_sndtimeo_cb,
        .alloc_skb              = chan_alloc_skb_cb,
-       .memcpy_fromiovec       = l2cap_chan_no_memcpy_fromiovec,
 
        .teardown               = l2cap_chan_no_teardown,
        .defer                  = l2cap_chan_no_defer,
index 5dcade511fdbf7da80995ac2c8218171663b339f..cedfbda15dad8514b606d3f62c86c81352f6c09d 100644 (file)
@@ -60,8 +60,7 @@ void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data)
 
        memset(&msg, 0, sizeof(msg));
 
-       msg.msg_iov = (struct iovec *) &iv;
-       msg.msg_iovlen = 1;
+       iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, &iv, 1, total_len);
 
        l2cap_chan_send(chan, &msg, total_len);
 
@@ -720,7 +719,6 @@ static const struct l2cap_ops a2mp_chan_ops = {
        .resume = l2cap_chan_no_resume,
        .set_shutdown = l2cap_chan_no_set_shutdown,
        .get_sndtimeo = l2cap_chan_no_get_sndtimeo,
-       .memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec,
 };
 
 static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked)
index a8da7ea9c2c04bfe6b39d3daf6540c94c362ee0f..a2b6dfa38a0cfd7f020c9d6f5a1584a92ae5c6e6 100644 (file)
@@ -2103,8 +2103,7 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
        struct sk_buff **frag;
        int sent = 0;
 
-       if (chan->ops->memcpy_fromiovec(chan, skb_put(skb, count),
-                                       msg->msg_iov, count))
+       if (copy_from_iter(skb_put(skb, count), count, &msg->msg_iter) != count)
                return -EFAULT;
 
        sent += count;
@@ -2124,8 +2123,8 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
 
                *frag = tmp;
 
-               if (chan->ops->memcpy_fromiovec(chan, skb_put(*frag, count),
-                                               msg->msg_iov, count))
+               if (copy_from_iter(skb_put(*frag, count), count,
+                                  &msg->msg_iter) != count)
                        return -EFAULT;
 
                sent += count;
index b0efb7202957cc4ae61781fb8642e1b30c9dd1f8..f65caf41953f866fdea55b8eb342fafc9dc8a1c7 100644 (file)
@@ -1336,13 +1336,6 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan,
        return skb;
 }
 
-static int l2cap_sock_memcpy_fromiovec_cb(struct l2cap_chan *chan,
-                                         unsigned char *kdata,
-                                         struct iovec *iov, int len)
-{
-       return memcpy_fromiovec(kdata, iov, len);
-}
-
 static void l2cap_sock_ready_cb(struct l2cap_chan *chan)
 {
        struct sock *sk = chan->data;
@@ -1427,7 +1420,6 @@ static const struct l2cap_ops l2cap_chan_ops = {
        .set_shutdown           = l2cap_sock_set_shutdown_cb,
        .get_sndtimeo           = l2cap_sock_get_sndtimeo_cb,
        .alloc_skb              = l2cap_sock_alloc_skb_cb,
-       .memcpy_fromiovec       = l2cap_sock_memcpy_fromiovec_cb,
 };
 
 static void l2cap_sock_destruct(struct sock *sk)
index 96bf16dcd9e9382e2ed6add599b2a05d63233fba..6a46252fe66f39fb1cc490987d6c14d2ec955dfa 100644 (file)
@@ -539,8 +539,7 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
 
        memset(&msg, 0, sizeof(msg));
 
-       msg.msg_iov = (struct iovec *) &iv;
-       msg.msg_iovlen = 2;
+       iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, iv, 2, 1 + len);
 
        l2cap_chan_send(chan, &msg, 1 + len);
 
@@ -2865,7 +2864,6 @@ static const struct l2cap_ops smp_chan_ops = {
        .suspend                = l2cap_chan_no_suspend,
        .set_shutdown           = l2cap_chan_no_set_shutdown,
        .get_sndtimeo           = l2cap_chan_no_get_sndtimeo,
-       .memcpy_fromiovec       = l2cap_chan_no_memcpy_fromiovec,
 };
 
 static inline struct l2cap_chan *smp_new_conn_cb(struct l2cap_chan *pchan)
@@ -2914,7 +2912,6 @@ static const struct l2cap_ops smp_root_chan_ops = {
        .resume                 = l2cap_chan_no_resume,
        .set_shutdown           = l2cap_chan_no_set_shutdown,
        .get_sndtimeo           = l2cap_chan_no_get_sndtimeo,
-       .memcpy_fromiovec       = l2cap_chan_no_memcpy_fromiovec,
 };
 
 static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid)
index ac618b0b8a4f52933a238b83234fc09c1187b310..769b185fefbd5f6bb6d4e68c1bcb0caeafa23d25 100644 (file)
@@ -535,7 +535,7 @@ static int caif_seqpkt_sendmsg(struct kiocb *kiocb, struct socket *sock,
                goto err;
 
        ret = -EINVAL;
-       if (unlikely(msg->msg_iov->iov_base == NULL))
+       if (unlikely(msg->msg_iter.iov->iov_base == NULL))
                goto err;
        noblock = msg->msg_flags & MSG_DONTWAIT;
 
index 062f157d2a6b9726ae888cea7b0b1af6f69e4082..3236b4167a32109b91b1eb28ae8bdf522c8db3f5 100644 (file)
@@ -37,13 +37,14 @@ ssize_t get_compat_msghdr(struct msghdr *kmsg,
                          struct iovec **iov)
 {
        compat_uptr_t uaddr, uiov, tmp3;
+       compat_size_t nr_segs;
        ssize_t err;
 
        if (!access_ok(VERIFY_READ, umsg, sizeof(*umsg)) ||
            __get_user(uaddr, &umsg->msg_name) ||
            __get_user(kmsg->msg_namelen, &umsg->msg_namelen) ||
            __get_user(uiov, &umsg->msg_iov) ||
-           __get_user(kmsg->msg_iovlen, &umsg->msg_iovlen) ||
+           __get_user(nr_segs, &umsg->msg_iovlen) ||
            __get_user(tmp3, &umsg->msg_control) ||
            __get_user(kmsg->msg_controllen, &umsg->msg_controllen) ||
            __get_user(kmsg->msg_flags, &umsg->msg_flags))
@@ -68,14 +69,15 @@ ssize_t get_compat_msghdr(struct msghdr *kmsg,
                kmsg->msg_namelen = 0;
        }
 
-       if (kmsg->msg_iovlen > UIO_MAXIOV)
+       if (nr_segs > UIO_MAXIOV)
                return -EMSGSIZE;
 
        err = compat_rw_copy_check_uvector(save_addr ? READ : WRITE,
-                                          compat_ptr(uiov), kmsg->msg_iovlen,
+                                          compat_ptr(uiov), nr_segs,
                                           UIO_FASTIOV, *iov, iov);
        if (err >= 0)
-               kmsg->msg_iov = *iov;
+               iov_iter_init(&kmsg->msg_iter, save_addr ? READ : WRITE,
+                             *iov, nr_segs, err);
        return err;
 }
 
index b6e303b0f01fa818e507ef442c87fc4c5803dbd5..df493d68330c03d1cb5b59e40d31294d7f45b3f8 100644 (file)
@@ -309,90 +309,6 @@ int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags)
 }
 EXPORT_SYMBOL(skb_kill_datagram);
 
-/**
- *     skb_copy_datagram_iovec - Copy a datagram to an iovec.
- *     @skb: buffer to copy
- *     @offset: offset in the buffer to start copying from
- *     @to: io vector to copy to
- *     @len: amount of data to copy from buffer to iovec
- *
- *     Note: the iovec is modified during the copy.
- */
-int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset,
-                           struct iovec *to, int len)
-{
-       int start = skb_headlen(skb);
-       int i, copy = start - offset;
-       struct sk_buff *frag_iter;
-
-       trace_skb_copy_datagram_iovec(skb, len);
-
-       /* Copy header. */
-       if (copy > 0) {
-               if (copy > len)
-                       copy = len;
-               if (memcpy_toiovec(to, skb->data + offset, copy))
-                       goto fault;
-               if ((len -= copy) == 0)
-                       return 0;
-               offset += copy;
-       }
-
-       /* Copy paged appendix. Hmm... why does this look so complicated? */
-       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-               int end;
-               const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-
-               WARN_ON(start > offset + len);
-
-               end = start + skb_frag_size(frag);
-               if ((copy = end - offset) > 0) {
-                       int err;
-                       u8  *vaddr;
-                       struct page *page = skb_frag_page(frag);
-
-                       if (copy > len)
-                               copy = len;
-                       vaddr = kmap(page);
-                       err = memcpy_toiovec(to, vaddr + frag->page_offset +
-                                            offset - start, copy);
-                       kunmap(page);
-                       if (err)
-                               goto fault;
-                       if (!(len -= copy))
-                               return 0;
-                       offset += copy;
-               }
-               start = end;
-       }
-
-       skb_walk_frags(skb, frag_iter) {
-               int end;
-
-               WARN_ON(start > offset + len);
-
-               end = start + frag_iter->len;
-               if ((copy = end - offset) > 0) {
-                       if (copy > len)
-                               copy = len;
-                       if (skb_copy_datagram_iovec(frag_iter,
-                                                   offset - start,
-                                                   to, copy))
-                               goto fault;
-                       if ((len -= copy) == 0)
-                               return 0;
-                       offset += copy;
-               }
-               start = end;
-       }
-       if (!len)
-               return 0;
-
-fault:
-       return -EFAULT;
-}
-EXPORT_SYMBOL(skb_copy_datagram_iovec);
-
 /**
  *     skb_copy_datagram_iter - Copy a datagram to an iovec iterator.
  *     @skb: buffer to copy
@@ -615,27 +531,25 @@ int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *from)
 EXPORT_SYMBOL(zerocopy_sg_from_iter);
 
 static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
-                                     u8 __user *to, int len,
+                                     struct iov_iter *to, int len,
                                      __wsum *csump)
 {
        int start = skb_headlen(skb);
        int i, copy = start - offset;
        struct sk_buff *frag_iter;
        int pos = 0;
+       int n;
 
        /* Copy header. */
        if (copy > 0) {
-               int err = 0;
                if (copy > len)
                        copy = len;
-               *csump = csum_and_copy_to_user(skb->data + offset, to, copy,
-                                              *csump, &err);
-               if (err)
+               n = csum_and_copy_to_iter(skb->data + offset, copy, csump, to);
+               if (n != copy)
                        goto fault;
                if ((len -= copy) == 0)
                        return 0;
                offset += copy;
-               to += copy;
                pos = copy;
        }
 
@@ -647,26 +561,22 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
 
                end = start + skb_frag_size(frag);
                if ((copy = end - offset) > 0) {
-                       __wsum csum2;
-                       int err = 0;
-                       u8  *vaddr;
+                       __wsum csum2 = 0;
                        struct page *page = skb_frag_page(frag);
+                       u8  *vaddr = kmap(page);
 
                        if (copy > len)
                                copy = len;
-                       vaddr = kmap(page);
-                       csum2 = csum_and_copy_to_user(vaddr +
-                                                       frag->page_offset +
-                                                       offset - start,
-                                                     to, copy, 0, &err);
+                       n = csum_and_copy_to_iter(vaddr + frag->page_offset +
+                                                 offset - start, copy,
+                                                 &csum2, to);
                        kunmap(page);
-                       if (err)
+                       if (n != copy)
                                goto fault;
                        *csump = csum_block_add(*csump, csum2, pos);
                        if (!(len -= copy))
                                return 0;
                        offset += copy;
-                       to += copy;
                        pos += copy;
                }
                start = end;
@@ -691,7 +601,6 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
                        if ((len -= copy) == 0)
                                return 0;
                        offset += copy;
-                       to += copy;
                        pos += copy;
                }
                start = end;
@@ -744,20 +653,19 @@ __sum16 __skb_checksum_complete(struct sk_buff *skb)
 EXPORT_SYMBOL(__skb_checksum_complete);
 
 /**
- *     skb_copy_and_csum_datagram_iovec - Copy and checksum skb to user iovec.
+ *     skb_copy_and_csum_datagram_msg - Copy and checksum skb to user iovec.
  *     @skb: skbuff
  *     @hlen: hardware length
- *     @iov: io vector
+ *     @msg: destination
  *
  *     Caller _must_ check that skb will fit to this iovec.
  *
  *     Returns: 0       - success.
  *              -EINVAL - checksum failure.
- *              -EFAULT - fault during copy. Beware, in this case iovec
- *                        can be modified!
+ *              -EFAULT - fault during copy.
  */
-int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb,
-                                    int hlen, struct iovec *iov)
+int skb_copy_and_csum_datagram_msg(struct sk_buff *skb,
+                                  int hlen, struct msghdr *msg)
 {
        __wsum csum;
        int chunk = skb->len - hlen;
@@ -765,28 +673,20 @@ int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb,
        if (!chunk)
                return 0;
 
-       /* Skip filled elements.
-        * Pretty silly, look at memcpy_toiovec, though 8)
-        */
-       while (!iov->iov_len)
-               iov++;
-
-       if (iov->iov_len < chunk) {
+       if (iov_iter_count(&msg->msg_iter) < chunk) {
                if (__skb_checksum_complete(skb))
                        goto csum_error;
-               if (skb_copy_datagram_iovec(skb, hlen, iov, chunk))
+               if (skb_copy_datagram_msg(skb, hlen, msg, chunk))
                        goto fault;
        } else {
                csum = csum_partial(skb->data, hlen, skb->csum);
-               if (skb_copy_and_csum_datagram(skb, hlen, iov->iov_base,
+               if (skb_copy_and_csum_datagram(skb, hlen, &msg->msg_iter,
                                               chunk, &csum))
                        goto fault;
                if (csum_fold(csum))
                        goto csum_error;
                if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE))
                        netdev_rx_csum_fault(skb->dev);
-               iov->iov_len -= chunk;
-               iov->iov_base += chunk;
        }
        return 0;
 csum_error:
@@ -794,7 +694,7 @@ csum_error:
 fault:
        return -EFAULT;
 }
-EXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec);
+EXPORT_SYMBOL(skb_copy_and_csum_datagram_msg);
 
 /**
  *     datagram_poll - generic datagram poll
index 4a929adf2ab7a5ef6923ffe504ae33669ee97242..b50861b22b6bea036b1a99ddf141d7ed2d6cf6cd 100644 (file)
@@ -752,14 +752,16 @@ EXPORT_SYMBOL(ip_fragment);
 int
 ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
 {
-       struct iovec *iov = from;
+       struct msghdr *msg = from;
 
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               if (memcpy_fromiovecend(to, iov, offset, len) < 0)
+               /* XXX: stripping const */
+               if (memcpy_fromiovecend(to, (struct iovec *)msg->msg_iter.iov, offset, len) < 0)
                        return -EFAULT;
        } else {
                __wsum csum = 0;
-               if (csum_partial_copy_fromiovecend(to, iov, offset, len, &csum) < 0)
+               /* XXX: stripping const */
+               if (csum_partial_copy_fromiovecend(to, (struct iovec *)msg->msg_iter.iov, offset, len, &csum) < 0)
                        return -EFAULT;
                skb->csum = csum_block_add(skb->csum, csum, odd);
        }
index 8dd4ae0424fcd75269b3dfb4950aff0723f22155..c0d82f78d364fe5561f819f953e3eb48d2f134da 100644 (file)
@@ -811,7 +811,8 @@ 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;
-       pfh.iov = msg->msg_iov;
+       /* XXX: stripping const */
+       pfh.iov = (struct iovec *)msg->msg_iter.iov;
        pfh.wcheck = 0;
        pfh.family = AF_INET;
 
index 43385a9fa44196bd54be66416413c5c7eb03057a..0bb68df5055d2d3f92cb06e829a997b44b512d65 100644 (file)
@@ -82,7 +82,7 @@
 #include <linux/uio.h>
 
 struct raw_frag_vec {
-       struct iovec *iov;
+       struct msghdr *msg;
        union {
                struct icmphdr icmph;
                char c[1];
@@ -440,7 +440,7 @@ static int raw_probe_proto_opt(struct raw_frag_vec *rfv, struct flowi4 *fl4)
        /* We only need the first two bytes. */
        rfv->hlen = 2;
 
-       err = memcpy_fromiovec(rfv->hdr.c, rfv->iov, rfv->hlen);
+       err = memcpy_from_msg(rfv->hdr.c, rfv->msg, rfv->hlen);
        if (err)
                return err;
 
@@ -478,7 +478,7 @@ static int raw_getfrag(void *from, char *to, int offset, int len, int odd,
 
        offset -= rfv->hlen;
 
-       return ip_generic_getfrag(rfv->iov, to, offset, len, odd, skb);
+       return ip_generic_getfrag(rfv->msg, to, offset, len, odd, skb);
 }
 
 static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
@@ -600,7 +600,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                           daddr, saddr, 0, 0);
 
        if (!inet->hdrincl) {
-               rfv.iov = msg->msg_iov;
+               rfv.msg = msg;
                rfv.hlen = 0;
 
                err = raw_probe_proto_opt(&rfv, &fl4);
@@ -625,7 +625,8 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 back_from_confirm:
 
        if (inet->hdrincl)
-               err = raw_send_hdrinc(sk, &fl4, msg->msg_iov, len,
+               /* XXX: stripping const */
+               err = raw_send_hdrinc(sk, &fl4, (struct iovec *)msg->msg_iter.iov, len,
                                      &rt, msg->msg_flags);
 
         else {
index 427aee33ffc04ad189d9d0ec24ab8004c25961ec..3075723c729bc98edf3a15eb0d0fbe172c300bbc 100644 (file)
@@ -1067,7 +1067,7 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg,
 int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                size_t size)
 {
-       struct iovec *iov;
+       const struct iovec *iov;
        struct tcp_sock *tp = tcp_sk(sk);
        struct sk_buff *skb;
        int iovlen, flags, err, copied = 0;
@@ -1118,8 +1118,8 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        mss_now = tcp_send_mss(sk, &size_goal, flags);
 
        /* Ok commence sending. */
-       iovlen = msg->msg_iovlen;
-       iov = msg->msg_iov;
+       iovlen = msg->msg_iter.nr_segs;
+       iov = msg->msg_iter.iov;
        copied = 0;
 
        err = -EPIPE;
@@ -1711,7 +1711,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                        if (!user_recv && !(flags & (MSG_TRUNC | MSG_PEEK))) {
                                user_recv = current;
                                tp->ucopy.task = user_recv;
-                               tp->ucopy.iov = msg->msg_iov;
+                               tp->ucopy.msg = msg;
                        }
 
                        tp->ucopy.len = len;
index 69de1a1c05c9fc575b171f85711a1e3c5aede8c0..075ab4d5af5e46e7a5a177a324228df592cbe5e3 100644 (file)
@@ -4421,7 +4421,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
                        __set_current_state(TASK_RUNNING);
 
                        local_bh_enable();
-                       if (!skb_copy_datagram_iovec(skb, 0, tp->ucopy.iov, chunk)) {
+                       if (!skb_copy_datagram_msg(skb, 0, tp->ucopy.msg, chunk)) {
                                tp->ucopy.len -= chunk;
                                tp->copied_seq += chunk;
                                eaten = (chunk == skb->len);
@@ -4941,10 +4941,9 @@ static int tcp_copy_to_iovec(struct sock *sk, struct sk_buff *skb, int hlen)
 
        local_bh_enable();
        if (skb_csum_unnecessary(skb))
-               err = skb_copy_datagram_iovec(skb, hlen, tp->ucopy.iov, chunk);
+               err = skb_copy_datagram_msg(skb, hlen, tp->ucopy.msg, chunk);
        else
-               err = skb_copy_and_csum_datagram_iovec(skb, hlen,
-                                                      tp->ucopy.iov);
+               err = skb_copy_and_csum_datagram_msg(skb, hlen, tp->ucopy.msg);
 
        if (!err) {
                tp->ucopy.len -= chunk;
index f37ecf53ee8a96827fc08bd203b0ca8857f8fc34..7f18262e2326ac4d7963347d7458273a325caa64 100644 (file)
@@ -3073,7 +3073,7 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn)
        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_iov, 0, space))) {
+                                        fo->data->msg_iter.iov, 0, space))) {
                kfree_skb(syn_data);
                goto fallback;
        }
index dd8e0063456397d263ac096fce8a8d8abd3152a7..13b4dcf86ef610d1fcc1b26f7f69f5a6bbd31686 100644 (file)
@@ -1049,7 +1049,7 @@ back_from_confirm:
 
        /* Lockless fast path for the non-corking case. */
        if (!corkreq) {
-               skb = ip_make_skb(sk, fl4, getfrag, msg->msg_iov, ulen,
+               skb = ip_make_skb(sk, fl4, getfrag, msg, ulen,
                                  sizeof(struct udphdr), &ipc, &rt,
                                  msg->msg_flags);
                err = PTR_ERR(skb);
@@ -1080,7 +1080,7 @@ back_from_confirm:
 
 do_append_data:
        up->len += ulen;
-       err = ip_append_data(sk, fl4, getfrag, msg->msg_iov, ulen,
+       err = ip_append_data(sk, fl4, getfrag, msg, ulen,
                             sizeof(struct udphdr), &ipc, &rt,
                             corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
        if (err)
index 5b7a1ed2aba95a837a0063b96cb9803ff8925f0c..2d3148378a1f6a7315b135090bf1fed57f181a3b 100644 (file)
@@ -163,7 +163,8 @@ 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;
-       pfh.iov = msg->msg_iov;
+       /* XXX: stripping const */
+       pfh.iov = (struct iovec *)msg->msg_iter.iov;
        pfh.wcheck = 0;
        pfh.family = AF_INET6;
 
index 8baa53e17a3044031417976feca82a183eb9cdb7..ee25631f8c293db3db95a0992fa2b319872afb30 100644 (file)
@@ -672,65 +672,62 @@ error:
        return err;
 }
 
-static int rawv6_probe_proto_opt(struct flowi6 *fl6, struct msghdr *msg)
+struct raw6_frag_vec {
+       struct msghdr *msg;
+       int hlen;
+       char c[4];
+};
+
+static int rawv6_probe_proto_opt(struct raw6_frag_vec *rfv, struct flowi6 *fl6)
 {
-       struct iovec *iov;
-       u8 __user *type = NULL;
-       u8 __user *code = NULL;
-       u8 len = 0;
-       int probed = 0;
-       int i;
-
-       if (!msg->msg_iov)
-               return 0;
+       int err = 0;
+       switch (fl6->flowi6_proto) {
+       case IPPROTO_ICMPV6:
+               rfv->hlen = 2;
+               err = memcpy_from_msg(rfv->c, rfv->msg, rfv->hlen);
+               if (!err) {
+                       fl6->fl6_icmp_type = rfv->c[0];
+                       fl6->fl6_icmp_code = rfv->c[1];
+               }
+               break;
+       case IPPROTO_MH:
+               rfv->hlen = 4;
+               err = memcpy_from_msg(rfv->c, rfv->msg, rfv->hlen);
+               if (!err)
+                       fl6->fl6_mh_type = rfv->c[2];
+       }
+       return err;
+}
 
-       for (i = 0; i < msg->msg_iovlen; i++) {
-               iov = &msg->msg_iov[i];
-               if (!iov)
-                       continue;
+static int raw6_getfrag(void *from, char *to, int offset, int len, int odd,
+                      struct sk_buff *skb)
+{
+       struct raw6_frag_vec *rfv = from;
 
-               switch (fl6->flowi6_proto) {
-               case IPPROTO_ICMPV6:
-                       /* check if one-byte field is readable or not. */
-                       if (iov->iov_base && iov->iov_len < 1)
-                               break;
-
-                       if (!type) {
-                               type = iov->iov_base;
-                               /* check if code field is readable or not. */
-                               if (iov->iov_len > 1)
-                                       code = type + 1;
-                       } else if (!code)
-                               code = iov->iov_base;
-
-                       if (type && code) {
-                               if (get_user(fl6->fl6_icmp_type, type) ||
-                                   get_user(fl6->fl6_icmp_code, code))
-                                       return -EFAULT;
-                               probed = 1;
-                       }
-                       break;
-               case IPPROTO_MH:
-                       if (iov->iov_base && iov->iov_len < 1)
-                               break;
-                       /* check if type field is readable or not. */
-                       if (iov->iov_len > 2 - len) {
-                               u8 __user *p = iov->iov_base;
-                               if (get_user(fl6->fl6_mh_type, &p[2 - len]))
-                                       return -EFAULT;
-                               probed = 1;
-                       } else
-                               len += iov->iov_len;
+       if (offset < rfv->hlen) {
+               int copy = min(rfv->hlen - offset, len);
 
-                       break;
-               default:
-                       probed = 1;
-                       break;
-               }
-               if (probed)
-                       break;
+               if (skb->ip_summed == CHECKSUM_PARTIAL)
+                       memcpy(to, rfv->c + offset, copy);
+               else
+                       skb->csum = csum_block_add(
+                               skb->csum,
+                               csum_partial_copy_nocheck(rfv->c + offset,
+                                                         to, copy, 0),
+                               odd);
+
+               odd = 0;
+               offset += copy;
+               to += copy;
+               len -= copy;
+
+               if (!len)
+                       return 0;
        }
-       return 0;
+
+       offset -= rfv->hlen;
+
+       return ip_generic_getfrag(rfv->msg, to, offset, len, odd, skb);
 }
 
 static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
@@ -745,6 +742,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
        struct ipv6_txoptions *opt = NULL;
        struct ip6_flowlabel *flowlabel = NULL;
        struct dst_entry *dst = NULL;
+       struct raw6_frag_vec rfv;
        struct flowi6 fl6;
        int addr_len = msg->msg_namelen;
        int hlimit = -1;
@@ -848,7 +846,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
        opt = ipv6_fixup_options(&opt_space, opt);
 
        fl6.flowi6_proto = proto;
-       err = rawv6_probe_proto_opt(&fl6, msg);
+       rfv.msg = msg;
+       rfv.hlen = 0;
+       err = rawv6_probe_proto_opt(&rfv, &fl6);
        if (err)
                goto out;
 
@@ -886,10 +886,11 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
 
 back_from_confirm:
        if (inet->hdrincl)
-               err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl6, &dst, msg->msg_flags);
+               /* XXX: stripping const */
+               err = rawv6_send_hdrinc(sk, (struct iovec *)msg->msg_iter.iov, len, &fl6, &dst, msg->msg_flags);
        else {
                lock_sock(sk);
-               err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov,
+               err = ip6_append_data(sk, raw6_getfrag, &rfv,
                        len, 0, hlimit, tclass, opt, &fl6, (struct rt6_info *)dst,
                        msg->msg_flags, dontfrag);
 
index 7f96432292ce4c583a50b25e771f3eee926ccc9b..189dc4ae3ecac1b140a7208c4b6de0b956e0b710 100644 (file)
@@ -1312,7 +1312,7 @@ do_append_data:
                dontfrag = np->dontfrag;
        up->len += ulen;
        getfrag  =  is_udplite ?  udplite_getfrag : ip_generic_getfrag;
-       err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen,
+       err = ip6_append_data(sk, getfrag, msg, ulen,
                sizeof(struct udphdr), hlimit, tclass, opt, &fl6,
                (struct rt6_info *)dst,
                corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags, dontfrag);
index 2177b960da870faf6e611b205532e7447e4384ed..8611f1b6314161d4df90c4969b3b9cb9066a446d 100644 (file)
@@ -619,7 +619,7 @@ static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk,
 
 back_from_confirm:
        lock_sock(sk);
-       err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov,
+       err = ip6_append_data(sk, ip_generic_getfrag, msg,
                              ulen, transhdrlen, hlimit, tclass, opt,
                              &fl6, (struct rt6_info *)dst,
                              msg->msg_flags, dontfrag);
index 63aa5c8acf1285f6864a11dcf572eb022d7fe624..cc9bcf008b0337a7082eefe6f6278cf5d59a6804 100644 (file)
@@ -2305,7 +2305,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
        }
 
        if (netlink_tx_is_mmaped(sk) &&
-           msg->msg_iov->iov_base == NULL) {
+           msg->msg_iter.iov->iov_base == NULL) {
                err = netlink_mmap_sendmsg(sk, msg, dst_portid, dst_group,
                                           siocb);
                goto out;
index efa84450113698a4aa36f29704569afe0d11f126..ed2e620b61df51e0333d7ca78b4d82f9ae613210 100644 (file)
@@ -2408,11 +2408,8 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
        unsigned short gso_type = 0;
        int hlen, tlen;
        int extra_len = 0;
-       struct iov_iter from;
        ssize_t n;
 
-       iov_iter_init(&from, WRITE, msg->msg_iov, msg->msg_iovlen, len);
-
        /*
         *      Get and verify the address.
         */
@@ -2451,7 +2448,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
                len -= vnet_hdr_len;
 
                err = -EFAULT;
-               n = copy_from_iter(&vnet_hdr, vnet_hdr_len, &from);
+               n = copy_from_iter(&vnet_hdr, vnet_hdr_len, &msg->msg_iter);
                if (n != vnet_hdr_len)
                        goto out_unlock;
 
@@ -2522,7 +2519,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
        }
 
        /* Returns -EFAULT on error */
-       err = skb_copy_datagram_from_iter(skb, offset, &from, len);
+       err = skb_copy_datagram_from_iter(skb, offset, &msg->msg_iter, len);
        if (err)
                goto out_free;
 
index 47d7b1029b33cc7d6a630f42ec1ff65d4fdd42db..f9ec1acd801cb182372e38a6f3c26d1dbe535137 100644 (file)
@@ -404,7 +404,6 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
        int ret = 0, nonblock = msg_flags & MSG_DONTWAIT;
        DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name);
        struct rds_incoming *inc = NULL;
-       struct iov_iter to;
 
        /* udp_recvmsg()->sock_recvtimeo() gets away without locking too.. */
        timeo = sock_rcvtimeo(sk, nonblock);
@@ -415,6 +414,7 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
                goto out;
 
        while (1) {
+               struct iov_iter save;
                /* If there are pending notifications, do those - and nothing else */
                if (!list_empty(&rs->rs_notify_queue)) {
                        ret = rds_notify_queue_get(rs, msg);
@@ -450,8 +450,8 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
                rdsdebug("copying inc %p from %pI4:%u to user\n", inc,
                         &inc->i_conn->c_faddr,
                         ntohs(inc->i_hdr.h_sport));
-               iov_iter_init(&to, READ, msg->msg_iov, msg->msg_iovlen, size);
-               ret = inc->i_conn->c_trans->inc_copy_to_user(inc, &to);
+               save = msg->msg_iter;
+               ret = inc->i_conn->c_trans->inc_copy_to_user(inc, &msg->msg_iter);
                if (ret < 0)
                        break;
 
@@ -464,6 +464,7 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
                        rds_inc_put(inc);
                        inc = NULL;
                        rds_stats_inc(s_recv_deliver_raced);
+                       msg->msg_iter = save;
                        continue;
                }
 
index 4de62ead1c711f75f225cd484a13437baa73b87e..40a5629a0a13c6a1eebe7afa11afafd29097afc2 100644 (file)
@@ -934,9 +934,7 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
        int queued = 0, allocated_mr = 0;
        int nonblock = msg->msg_flags & MSG_DONTWAIT;
        long timeo = sock_sndtimeo(sk, nonblock);
-       struct iov_iter from;
 
-       iov_iter_init(&from, WRITE, msg->msg_iov, msg->msg_iovlen, payload_len);
        /* Mirror Linux UDP mirror of BSD error message compatibility */
        /* XXX: Perhaps MSG_MORE someday */
        if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_CMSG_COMPAT)) {
@@ -984,7 +982,7 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
                        ret = -ENOMEM;
                        goto out;
                }
-               ret = rds_message_copy_from_user(rm, &from);
+               ret = rds_message_copy_from_user(rm, &msg->msg_iter);
                if (ret)
                        goto out;
        }
index 0b4b9a79f5abd0fb24e413551550aba25e7ce8e4..86e0f10aa2c0b35ef4d3290f7afbbd53f31215a3 100644 (file)
@@ -531,14 +531,12 @@ static int rxrpc_send_data(struct kiocb *iocb,
        struct rxrpc_skb_priv *sp;
        unsigned char __user *from;
        struct sk_buff *skb;
-       struct iovec *iov;
+       const struct iovec *iov;
        struct sock *sk = &rx->sk;
        long timeo;
        bool more;
        int ret, ioc, segment, copied;
 
-       _enter(",,,{%zu},%zu", msg->msg_iovlen, len);
-
        timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
 
        /* this should be in poll */
@@ -547,8 +545,8 @@ static int rxrpc_send_data(struct kiocb *iocb,
        if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
                return -EPIPE;
 
-       iov = msg->msg_iov;
-       ioc = msg->msg_iovlen - 1;
+       iov = msg->msg_iter.iov;
+       ioc = msg->msg_iter.nr_segs - 1;
        from = iov->iov_base;
        segment = iov->iov_len;
        iov++;
index 0397ac9fd98c2601da7c15822599607235cae14c..c92f96cda6994418a8543b7951ad73ed48e0000e 100644 (file)
@@ -1609,9 +1609,6 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
        __u16 sinfo_flags = 0;
        long timeo;
        int err;
-       struct iov_iter from;
-
-       iov_iter_init(&from, WRITE, msg->msg_iov, msg->msg_iovlen, msg_len);
 
        err = 0;
        sp = sctp_sk(sk);
@@ -1950,7 +1947,7 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
        }
 
        /* Break the message into multiple chunks of maximum size. */
-       datamsg = sctp_datamsg_from_user(asoc, sinfo, &from);
+       datamsg = sctp_datamsg_from_user(asoc, sinfo, &msg->msg_iter);
        if (IS_ERR(datamsg)) {
                err = PTR_ERR(datamsg);
                goto out_free;
index f676ac4a370122f9d36d9193fdedda3bc3f4c0a6..8809afccf7fadc1b43db802aa3160c03e3c473fa 100644 (file)
@@ -689,8 +689,7 @@ int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
         * the following is safe, since for compiler definitions of kvec and
         * iovec are identical, yielding the same in-core layout and alignment
         */
-       msg->msg_iov = (struct iovec *)vec;
-       msg->msg_iovlen = num;
+       iov_iter_init(&msg->msg_iter, WRITE, (struct iovec *)vec, num, size);
        result = sock_sendmsg(sock, msg, size);
        set_fs(oldfs);
        return result;
@@ -853,7 +852,7 @@ int kernel_recvmsg(struct socket *sock, struct msghdr *msg,
         * the following is safe, since for compiler definitions of kvec and
         * iovec are identical, yielding the same in-core layout and alignment
         */
-       msg->msg_iov = (struct iovec *)vec, msg->msg_iovlen = num;
+       iov_iter_init(&msg->msg_iter, READ, (struct iovec *)vec, num, size);
        result = sock_recvmsg(sock, msg, size, flags);
        set_fs(oldfs);
        return result;
@@ -913,8 +912,7 @@ static ssize_t do_sock_read(struct msghdr *msg, struct kiocb *iocb,
        msg->msg_namelen = 0;
        msg->msg_control = NULL;
        msg->msg_controllen = 0;
-       msg->msg_iov = (struct iovec *)iov;
-       msg->msg_iovlen = nr_segs;
+       iov_iter_init(&msg->msg_iter, READ, iov, nr_segs, size);
        msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0;
 
        return __sock_recvmsg(iocb, sock, msg, size, msg->msg_flags);
@@ -953,8 +951,7 @@ static ssize_t do_sock_write(struct msghdr *msg, struct kiocb *iocb,
        msg->msg_namelen = 0;
        msg->msg_control = NULL;
        msg->msg_controllen = 0;
-       msg->msg_iov = (struct iovec *)iov;
-       msg->msg_iovlen = nr_segs;
+       iov_iter_init(&msg->msg_iter, WRITE, iov, nr_segs, size);
        msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0;
        if (sock->type == SOCK_SEQPACKET)
                msg->msg_flags |= MSG_EOR;
@@ -1798,8 +1795,7 @@ SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len,
        iov.iov_base = buff;
        iov.iov_len = len;
        msg.msg_name = NULL;
-       msg.msg_iov = &iov;
-       msg.msg_iovlen = 1;
+       iov_iter_init(&msg.msg_iter, WRITE, &iov, 1, len);
        msg.msg_control = NULL;
        msg.msg_controllen = 0;
        msg.msg_namelen = 0;
@@ -1856,10 +1852,9 @@ SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,
 
        msg.msg_control = NULL;
        msg.msg_controllen = 0;
-       msg.msg_iovlen = 1;
-       msg.msg_iov = &iov;
        iov.iov_len = size;
        iov.iov_base = ubuf;
+       iov_iter_init(&msg.msg_iter, READ, &iov, 1, size);
        /* Save some cycles and don't copy the address if not needed */
        msg.msg_name = addr ? (struct sockaddr *)&address : NULL;
        /* We assume all kernel code knows the size of sockaddr_storage */
@@ -1993,13 +1988,14 @@ static ssize_t copy_msghdr_from_user(struct msghdr *kmsg,
 {
        struct sockaddr __user *uaddr;
        struct iovec __user *uiov;
+       size_t nr_segs;
        ssize_t err;
 
        if (!access_ok(VERIFY_READ, umsg, sizeof(*umsg)) ||
            __get_user(uaddr, &umsg->msg_name) ||
            __get_user(kmsg->msg_namelen, &umsg->msg_namelen) ||
            __get_user(uiov, &umsg->msg_iov) ||
-           __get_user(kmsg->msg_iovlen, &umsg->msg_iovlen) ||
+           __get_user(nr_segs, &umsg->msg_iovlen) ||
            __get_user(kmsg->msg_control, &umsg->msg_control) ||
            __get_user(kmsg->msg_controllen, &umsg->msg_controllen) ||
            __get_user(kmsg->msg_flags, &umsg->msg_flags))
@@ -2029,14 +2025,15 @@ static ssize_t copy_msghdr_from_user(struct msghdr *kmsg,
                kmsg->msg_namelen = 0;
        }
 
-       if (kmsg->msg_iovlen > UIO_MAXIOV)
+       if (nr_segs > UIO_MAXIOV)
                return -EMSGSIZE;
 
        err = rw_copy_check_uvector(save_addr ? READ : WRITE,
-                                   uiov, kmsg->msg_iovlen,
+                                   uiov, nr_segs,
                                    UIO_FASTIOV, *iov, iov);
        if (err >= 0)
-               kmsg->msg_iov = *iov;
+               iov_iter_init(&kmsg->msg_iter, save_addr ? READ : WRITE,
+                             *iov, nr_segs, err);
        return err;
 }
 
index 5b0659791c0769f0b6bf4519634d117ef6fa5903..a687b30a699cb651eaf7dd5f1c7d5fa3459bf9b5 100644 (file)
@@ -194,7 +194,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, int offset,
                __skb_queue_tail(list, skb);
                skb_copy_to_linear_data(skb, mhdr, mhsz);
                pktpos = skb->data + mhsz;
-               if (!dsz || !memcpy_fromiovecend(pktpos, m->msg_iov, offset,
+               if (!dsz || !memcpy_fromiovecend(pktpos, m->msg_iter.iov, offset,
                                                 dsz))
                        return dsz;
                rc = -EFAULT;
@@ -224,7 +224,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, int offset,
                if (drem < pktrem)
                        pktrem = drem;
 
-               if (memcpy_fromiovecend(pktpos, m->msg_iov, offset, pktrem)) {
+               if (memcpy_fromiovecend(pktpos, m->msg_iter.iov, offset, pktrem)) {
                        rc = -EFAULT;
                        goto error;
                }
index 4450d62266023de0697edfe82cc55db9693ee230..8e1b10274b02702345abba0b4b458d8319f2f841 100644 (file)
@@ -1459,9 +1459,6 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
        struct scm_cookie tmp_scm;
        int max_level;
        int data_len = 0;
-       struct iov_iter from;
-
-       iov_iter_init(&from, WRITE, msg->msg_iov, msg->msg_iovlen, len);
 
        if (NULL == siocb->scm)
                siocb->scm = &tmp_scm;
@@ -1519,7 +1516,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
        skb_put(skb, len - data_len);
        skb->data_len = data_len;
        skb->len = len;
-       err = skb_copy_datagram_from_iter(skb, 0, &from, len);
+       err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, len);
        if (err)
                goto out_free;
 
@@ -1641,9 +1638,6 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
        bool fds_sent = false;
        int max_level;
        int data_len;
-       struct iov_iter from;
-
-       iov_iter_init(&from, WRITE, msg->msg_iov, msg->msg_iovlen, len);
 
        if (NULL == siocb->scm)
                siocb->scm = &tmp_scm;
@@ -1700,7 +1694,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
                skb_put(skb, size - data_len);
                skb->data_len = data_len;
                skb->len = size;
-               err = skb_copy_datagram_from_iter(skb, 0, &from, size);
+               err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, size);
                if (err) {
                        kfree_skb(skb);
                        goto out_err;
index c1c03895297369089ca1eb765803518cfb55aceb..02d2e5229240dd635dfc3eb7b6f81e8aa970bf01 100644 (file)
@@ -1840,9 +1840,9 @@ static ssize_t vmci_transport_stream_dequeue(
        int flags)
 {
        if (flags & MSG_PEEK)
-               return vmci_qpair_peekv(vmci_trans(vsk)->qpair, msg->msg_iov, len, 0);
+               return vmci_qpair_peekv(vmci_trans(vsk)->qpair, msg, len, 0);
        else
-               return vmci_qpair_dequev(vmci_trans(vsk)->qpair, msg->msg_iov, len, 0);
+               return vmci_qpair_dequev(vmci_trans(vsk)->qpair, msg, len, 0);
 }
 
 static ssize_t vmci_transport_stream_enqueue(
@@ -1850,7 +1850,8 @@ static ssize_t vmci_transport_stream_enqueue(
        struct msghdr *msg,
        size_t len)
 {
-       return vmci_qpair_enquev(vmci_trans(vsk)->qpair, msg->msg_iov, len, 0);
+       /* XXX: stripping const */
+       return vmci_qpair_enquev(vmci_trans(vsk)->qpair, (struct iovec *)msg->msg_iter.iov, len, 0);
 }
 
 static s64 vmci_transport_stream_has_data(struct vsock_sock *vsk)