[iov_iter] new primitives - copy_from_iter_full() and friends
authorAl Viro <viro@zeniv.linux.org.uk>
Wed, 2 Nov 2016 02:09:04 +0000 (22:09 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 5 Dec 2016 19:33:36 +0000 (14:33 -0500)
copy_from_iter_full(), copy_from_iter_full_nocache() and
csum_and_copy_from_iter_full() - counterparts of copy_from_iter()
et.al., advancing iterator only in case of successful full copy
and returning whether it had been successful or not.

Convert some obvious users.  *NOTE* - do not blindly assume that
something is a good candidate for those unless you are sure that
not advancing iov_iter in failure case is the right thing in
this case.  Anything that does short read/short write kind of
stuff (or is in a loop, etc.) is unlikely to be a good one.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
17 files changed:
drivers/bluetooth/hci_vhci.c
drivers/net/macvtap.c
drivers/net/tun.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/legacy/inode.c
drivers/vhost/scsi.c
drivers/vhost/vhost.c
fs/ncpfs/file.c
fs/orangefs/devorangefs-req.c
include/linux/uio.h
kernel/printk/printk.c
lib/iov_iter.c
net/atm/common.c
net/bluetooth/l2cap_core.c
net/packet/af_packet.c
net/tipc/msg.c
security/keys/keyctl.c

index c4a75a18dcae5e8d4d1d7778b356a4a4a17e0bf4..233e850fdac75763a78731f1687e07936ad58660 100644 (file)
@@ -181,7 +181,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *data,
        if (!skb)
                return -ENOMEM;
 
-       if (copy_from_iter(skb_put(skb, len), len, from) != len) {
+       if (!copy_from_iter_full(skb_put(skb, len), len, from)) {
                kfree_skb(skb);
                return -EFAULT;
        }
index 070e3290aa6efea6fcb505cdf0860a4dce676b74..19d81ca3fb49be1aa4a843d68797b229aecb2006 100644 (file)
@@ -673,7 +673,6 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
        int depth;
        bool zerocopy = false;
        size_t linear;
-       ssize_t n;
 
        if (q->flags & IFF_VNET_HDR) {
                vnet_hdr_len = q->vnet_hdr_sz;
@@ -684,8 +683,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
                len -= vnet_hdr_len;
 
                err = -EFAULT;
-               n = copy_from_iter(&vnet_hdr, sizeof(vnet_hdr), from);
-               if (n != sizeof(vnet_hdr))
+               if (!copy_from_iter_full(&vnet_hdr, sizeof(vnet_hdr), from))
                        goto err;
                iov_iter_advance(from, vnet_hdr_len - sizeof(vnet_hdr));
                if ((vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
index 8093e39ae263a7bd954682125221189499206b7c..4fa2d756548ac465c04e7ba74390a03722ce1085 100644 (file)
@@ -1171,7 +1171,6 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
        bool zerocopy = false;
        int err;
        u32 rxhash;
-       ssize_t n;
 
        if (!(tun->dev->flags & IFF_UP))
                return -EIO;
@@ -1181,8 +1180,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
                        return -EINVAL;
                len -= sizeof(pi);
 
-               n = copy_from_iter(&pi, sizeof(pi), from);
-               if (n != sizeof(pi))
+               if (!copy_from_iter_full(&pi, sizeof(pi), from))
                        return -EFAULT;
        }
 
@@ -1191,8 +1189,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
                        return -EINVAL;
                len -= tun->vnet_hdr_sz;
 
-               n = copy_from_iter(&gso, sizeof(gso), from);
-               if (n != sizeof(gso))
+               if (!copy_from_iter_full(&gso, sizeof(gso), from))
                        return -EFAULT;
 
                if ((gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
index 17989b72cdaec18dbf55d0709897fc75d1842ab7..0bfd1e25b431ed8cc8f84e18635cd649f1641c7c 100644 (file)
@@ -949,7 +949,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
                        goto error_mutex;
                }
                if (!io_data->read &&
-                   copy_from_iter(data, data_len, &io_data->data) != data_len) {
+                   !copy_from_iter_full(data, data_len, &io_data->data)) {
                        ret = -EFAULT;
                        goto error_mutex;
                }
index bd82dd12deffd25aa9ae8528d60a898bdfa7551b..10b2576f8b6a9fdd4dbd55847b600a1bf5a1154b 100644 (file)
@@ -667,7 +667,7 @@ ep_write_iter(struct kiocb *iocb, struct iov_iter *from)
                return -ENOMEM;
        }
 
-       if (unlikely(copy_from_iter(buf, len, from) != len)) {
+       if (unlikely(!copy_from_iter_full(buf, len, from))) {
                value = -EFAULT;
                goto out;
        }
index 6e29d053843d0b7f29a1aed672ac88ef8150b9d7..b296985fda0d3514d3fd5146ea8c37da00437929 100644 (file)
@@ -922,8 +922,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
                 */
                iov_iter_init(&out_iter, WRITE, vq->iov, out, out_size);
 
-               ret = copy_from_iter(req, req_size, &out_iter);
-               if (unlikely(ret != req_size)) {
+               if (unlikely(!copy_from_iter_full(req, req_size, &out_iter))) {
                        vq_err(vq, "Faulted on copy_from_iter\n");
                        vhost_scsi_send_bad_target(vs, vq, head, out);
                        continue;
index c6f2d89c0e97cd4c184e615be6e3d86aca722a0d..06e8b81b62531194d7b2cb6aa77b195d7ddfe3e0 100644 (file)
@@ -1862,8 +1862,7 @@ static int get_indirect(struct vhost_virtqueue *vq,
                               i, count);
                        return -EINVAL;
                }
-               if (unlikely(copy_from_iter(&desc, sizeof(desc), &from) !=
-                            sizeof(desc))) {
+               if (unlikely(!copy_from_iter_full(&desc, sizeof(desc), &from))) {
                        vq_err(vq, "Failed indirect descriptor: idx %d, %zx\n",
                               i, (size_t)vhost64_to_cpu(vq, indirect->addr) + i * sizeof desc);
                        return -EINVAL;
index dd38ca1f2ecb9a181668496cc056653e1e470be2..83ca77231707184cea82475ff2f2199a25bf1919 100644 (file)
@@ -203,7 +203,7 @@ ncp_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
                                      bufsize - (pos % bufsize),
                                      iov_iter_count(from));
 
-               if (copy_from_iter(bouncebuffer, to_write, from) != to_write) {
+               if (!copy_from_iter_full(bouncebuffer, to_write, from)) {
                        errno = -EFAULT;
                        break;
                }
index 516ffb4dc9a0ad8f6d06b04f25610a445b325ef2..b0ced669427e154cc67c7b4b4f9e4630f934919f 100644 (file)
@@ -355,7 +355,6 @@ static ssize_t orangefs_devreq_write_iter(struct kiocb *iocb,
                __u64 tag;
        } head;
        int total = ret = iov_iter_count(iter);
-       int n;
        int downcall_size = sizeof(struct orangefs_downcall_s);
        int head_size = sizeof(head);
 
@@ -372,8 +371,7 @@ static ssize_t orangefs_devreq_write_iter(struct kiocb *iocb,
                return -EFAULT;
        }
      
-       n = copy_from_iter(&head, head_size, iter);
-       if (n < head_size) {
+       if (!copy_from_iter_full(&head, head_size, iter)) {
                gossip_err("%s: failed to copy head.\n", __func__);
                return -EFAULT;
        }
@@ -407,8 +405,7 @@ static ssize_t orangefs_devreq_write_iter(struct kiocb *iocb,
                return ret;
        }
 
-       n = copy_from_iter(&op->downcall, downcall_size, iter);
-       if (n != downcall_size) {
+       if (!copy_from_iter_full(&op->downcall, downcall_size, iter)) {
                gossip_err("%s: failed to copy downcall.\n", __func__);
                goto Efault;
        }
@@ -462,10 +459,8 @@ static ssize_t orangefs_devreq_write_iter(struct kiocb *iocb,
                goto Enomem;
        }
        memset(op->downcall.trailer_buf, 0, op->downcall.trailer_size);
-       n = copy_from_iter(op->downcall.trailer_buf,
-                          op->downcall.trailer_size,
-                          iter);
-       if (n != op->downcall.trailer_size) {
+       if (!copy_from_iter_full(op->downcall.trailer_buf,
+                                op->downcall.trailer_size, iter)) {
                gossip_err("%s: failed to copy trailer.\n", __func__);
                vfree(op->downcall.trailer_buf);
                goto Efault;
index 6e22b544d03913746e3190c21b9a1094f6e9f28a..e57c0ccd61c6b98186d02524b36ad7bcbd28bc4a 100644 (file)
@@ -89,7 +89,9 @@ size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes,
                         struct iov_iter *i);
 size_t copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i);
 size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i);
+bool copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i);
 size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i);
+bool copy_from_iter_full_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);
 unsigned long iov_iter_gap_alignment(const struct iov_iter *i);
@@ -155,6 +157,7 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count)
 }
 size_t csum_and_copy_to_iter(const 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);
+bool csum_and_copy_from_iter_full(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i);
 
 int import_iovec(int type, const struct iovec __user * uvector,
                 unsigned nr_segs, unsigned fast_segs,
index f7a55e9ff2f7621c2403d6bf28c6f8b88d1120f2..f6bda15396dfc6c0c998c2bd49ed2131ee081532 100644 (file)
@@ -748,7 +748,7 @@ static ssize_t devkmsg_write(struct kiocb *iocb, struct iov_iter *from)
                return -ENOMEM;
 
        buf[len] = '\0';
-       if (copy_from_iter(buf, len, from) != len) {
+       if (!copy_from_iter_full(buf, len, from)) {
                kfree(buf);
                return -EFAULT;
        }
index f2bd21b93dfca464ae24bb18c6492bd8c7f1eb88..83c00b7f59b5b52d92525d5f52a6709caae1cf2d 100644 (file)
@@ -568,6 +568,31 @@ size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i)
 }
 EXPORT_SYMBOL(copy_from_iter);
 
+bool copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i)
+{
+       char *to = addr;
+       if (unlikely(i->type & ITER_PIPE)) {
+               WARN_ON(1);
+               return false;
+       }
+       if (unlikely(i->count < bytes))                         \
+               return false;
+
+       iterate_all_kinds(i, bytes, v, ({
+               if (__copy_from_user((to += v.iov_len) - v.iov_len,
+                                     v.iov_base, v.iov_len))
+                       return false;
+               0;}),
+               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)
+       )
+
+       iov_iter_advance(i, bytes);
+       return true;
+}
+EXPORT_SYMBOL(copy_from_iter_full);
+
 size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i)
 {
        char *to = addr;
@@ -587,6 +612,30 @@ size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i)
 }
 EXPORT_SYMBOL(copy_from_iter_nocache);
 
+bool copy_from_iter_full_nocache(void *addr, size_t bytes, struct iov_iter *i)
+{
+       char *to = addr;
+       if (unlikely(i->type & ITER_PIPE)) {
+               WARN_ON(1);
+               return false;
+       }
+       if (unlikely(i->count < bytes))                         \
+               return false;
+       iterate_all_kinds(i, bytes, v, ({
+               if (__copy_from_user_nocache((to += v.iov_len) - v.iov_len,
+                                            v.iov_base, v.iov_len))
+                       return false;
+               0;}),
+               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)
+       )
+
+       iov_iter_advance(i, bytes);
+       return true;
+}
+EXPORT_SYMBOL(copy_from_iter_full_nocache);
+
 size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
                         struct iov_iter *i)
 {
@@ -1008,7 +1057,7 @@ size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum,
        }
        iterate_and_advance(i, bytes, v, ({
                int err = 0;
-               next = csum_and_copy_from_user(v.iov_base, 
+               next = csum_and_copy_from_user(v.iov_base,
                                               (to += v.iov_len) - v.iov_len,
                                               v.iov_len, 0, &err);
                if (!err) {
@@ -1037,6 +1086,51 @@ size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum,
 }
 EXPORT_SYMBOL(csum_and_copy_from_iter);
 
+bool csum_and_copy_from_iter_full(void *addr, size_t bytes, __wsum *csum,
+                              struct iov_iter *i)
+{
+       char *to = addr;
+       __wsum sum, next;
+       size_t off = 0;
+       sum = *csum;
+       if (unlikely(i->type & ITER_PIPE)) {
+               WARN_ON(1);
+               return false;
+       }
+       if (unlikely(i->count < bytes))
+               return false;
+       iterate_all_kinds(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)
+                       return false;
+               sum = csum_block_add(sum, next, off);
+               off += 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;
+       iov_iter_advance(i, bytes);
+       return true;
+}
+EXPORT_SYMBOL(csum_and_copy_from_iter_full);
+
 size_t csum_and_copy_to_iter(const void *addr, size_t bytes, __wsum *csum,
                             struct iov_iter *i)
 {
@@ -1051,7 +1145,7 @@ size_t csum_and_copy_to_iter(const void *addr, size_t bytes, __wsum *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_base,
                                             v.iov_len, 0, &err);
                if (!err) {
                        sum = csum_block_add(sum, next, off);
index 6dc12305799e45180bc8091ee2a99f11e3400fa7..a3ca922d307b0a9d3d12e7ef6b14a9e02a2741fc 100644 (file)
@@ -630,7 +630,7 @@ int vcc_sendmsg(struct socket *sock, struct msghdr *m, size_t size)
                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, &m->msg_iter) != size) {
+       if (!copy_from_iter_full(skb_put(skb, size), size, &m->msg_iter)) {
                kfree_skb(skb);
                error = -EFAULT;
                goto out;
index 577f1c01454a566cc63431ff8bb76f08785431ca..ce0b5dd01953694ffdcff246b8c3ab47ee689c03 100644 (file)
@@ -2127,7 +2127,7 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
        struct sk_buff **frag;
        int sent = 0;
 
-       if (copy_from_iter(skb_put(skb, count), count, &msg->msg_iter) != count)
+       if (!copy_from_iter_full(skb_put(skb, count), count, &msg->msg_iter))
                return -EFAULT;
 
        sent += count;
@@ -2147,8 +2147,8 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
 
                *frag = tmp;
 
-               if (copy_from_iter(skb_put(*frag, count), count,
-                                  &msg->msg_iter) != count)
+               if (!copy_from_iter_full(skb_put(*frag, count), count,
+                                  &msg->msg_iter))
                        return -EFAULT;
 
                sent += count;
index d2238b204691b8e4f2e3acb9bc167b553ba32d50..588ec202d5ba15a8a554b34d02b2795097bfadc0 100644 (file)
@@ -2432,14 +2432,11 @@ static int __packet_snd_vnet_parse(struct virtio_net_hdr *vnet_hdr, size_t len)
 static int packet_snd_vnet_parse(struct msghdr *msg, size_t *len,
                                 struct virtio_net_hdr *vnet_hdr)
 {
-       int n;
-
        if (*len < sizeof(*vnet_hdr))
                return -EINVAL;
        *len -= sizeof(*vnet_hdr);
 
-       n = copy_from_iter(vnet_hdr, sizeof(*vnet_hdr), &msg->msg_iter);
-       if (n != sizeof(*vnet_hdr))
+       if (!copy_from_iter_full(vnet_hdr, sizeof(*vnet_hdr), &msg->msg_iter))
                return -EFAULT;
 
        return __packet_snd_vnet_parse(vnet_hdr, *len);
index 17201aa8423ddd816a4792621e289dbeee8d4928..a22be502f1bd06dc8ec23ab44e56d32f4c3dd469 100644 (file)
@@ -268,7 +268,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m,
                __skb_queue_tail(list, skb);
                skb_copy_to_linear_data(skb, mhdr, mhsz);
                pktpos = skb->data + mhsz;
-               if (copy_from_iter(pktpos, dsz, &m->msg_iter) == dsz)
+               if (copy_from_iter_full(pktpos, dsz, &m->msg_iter))
                        return dsz;
                rc = -EFAULT;
                goto error;
@@ -299,7 +299,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m,
                if (drem < pktrem)
                        pktrem = drem;
 
-               if (copy_from_iter(pktpos, pktrem, &m->msg_iter) != pktrem) {
+               if (!copy_from_iter_full(pktpos, pktrem, &m->msg_iter)) {
                        rc = -EFAULT;
                        goto error;
                }
index d580ad06b792ff539f124a620a4c8791740f22dd..f89f1900e58d09b38ba4dc640f0a48c784e09e93 100644 (file)
@@ -1074,7 +1074,7 @@ long keyctl_instantiate_key_common(key_serial_t id,
                }
 
                ret = -EFAULT;
-               if (copy_from_iter(payload, plen, from) != plen)
+               if (!copy_from_iter_full(payload, plen, from))
                        goto error2;
        }