fs: Use non-const iov in aio_read/aio_write

From: Herbert Xu
Date: Sun Nov 02 2014 - 18:06:08 EST


Currently the functions aio_read/aio_write use a const iov as
input. This is unnecessary as all their callers supply a
stack-based or kmalloced iov which is never reused. Conceptually
this is fine because iovs supplied to aio_read/aio_write ultimately
come from user-space so we always have to make a copy of them for
the kernel.

This is also a joke because for as long (since 2.1.15) as we've
had the const iov, the network stack (currently through do_sock_read
and do_sock_write) has been casting the const away. IOW if anybody
did supply a const iov they would crash and burn if they ever
entered the network stack.

The network stack needs a non-const iov because it iterates through
the iov as it reads/writes data.

So we have two alternatives, either change the network stack to
not touch the iovs or make the iovs non-const.

As there is no reason for the iovs to be const in the first place,
I have taken the second choice and changed all aio_read/aio_write
functions to use non-const iovs.

Signed-off-by: Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx>

diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index b30753c..dfefc79 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -434,8 +434,8 @@ prototypes:
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
- ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
- ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
+ ssize_t (*aio_read) (struct kiocb *, struct iovec *, unsigned long, loff_t);
+ ssize_t (*aio_write) (struct kiocb *, struct iovec *, unsigned long, loff_t);
ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
int (*iterate) (struct file *, struct dir_context *);
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index 20bf204..a2ba142 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -811,8 +811,8 @@ struct file_operations {
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
- ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
- ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
+ ssize_t (*aio_read) (struct kiocb *, struct iovec *, unsigned long, loff_t);
+ ssize_t (*aio_write) (struct kiocb *, struct iovec *, unsigned long, loff_t);
ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
int (*iterate) (struct file *, struct dir_context *);
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index c952b98..c7490bd 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -144,7 +144,7 @@ static int hypfs_open(struct inode *inode, struct file *filp)
return nonseekable_open(inode, filp);
}

-static ssize_t hypfs_aio_read(struct kiocb *iocb, const struct iovec *iov,
+static ssize_t hypfs_aio_read(struct kiocb *iocb, struct iovec *iov,
unsigned long nr_segs, loff_t offset)
{
char *data;
@@ -167,7 +167,7 @@ static ssize_t hypfs_aio_read(struct kiocb *iocb, const struct iovec *iov,

return ret;
}
-static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov,
+static ssize_t hypfs_aio_write(struct kiocb *iocb, struct iovec *iov,
unsigned long nr_segs, loff_t offset)
{
int rc;
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 524b707..d94e5b0 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -598,13 +598,13 @@ static ssize_t write_null(struct file *file, const char __user *buf,
return count;
}

-static ssize_t aio_read_null(struct kiocb *iocb, const struct iovec *iov,
+static ssize_t aio_read_null(struct kiocb *iocb, struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
return 0;
}

-static ssize_t aio_write_null(struct kiocb *iocb, const struct iovec *iov,
+static ssize_t aio_write_null(struct kiocb *iocb, struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
return iov_length(iov, nr_segs);
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
index 6d7f453..8b75de4f 100644
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
@@ -53,7 +53,7 @@ static int ipath_open(struct inode *, struct file *);
static int ipath_close(struct inode *, struct file *);
static ssize_t ipath_write(struct file *, const char __user *, size_t,
loff_t *);
-static ssize_t ipath_writev(struct kiocb *, const struct iovec *,
+static ssize_t ipath_writev(struct kiocb *, struct iovec *,
unsigned long , loff_t);
static unsigned int ipath_poll(struct file *, struct poll_table_struct *);
static int ipath_mmap(struct file *, struct vm_area_struct *);
@@ -2414,7 +2414,7 @@ bail:
return ret;
}

-static ssize_t ipath_writev(struct kiocb *iocb, const struct iovec *iov,
+static ssize_t ipath_writev(struct kiocb *iocb, struct iovec *iov,
unsigned long dim, loff_t off)
{
struct file *filp = iocb->ki_filp;
diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c
index b15e34e..8872924 100644
--- a/drivers/infiniband/hw/qib/qib_file_ops.c
+++ b/drivers/infiniband/hw/qib/qib_file_ops.c
@@ -55,7 +55,7 @@
static int qib_open(struct inode *, struct file *);
static int qib_close(struct inode *, struct file *);
static ssize_t qib_write(struct file *, const char __user *, size_t, loff_t *);
-static ssize_t qib_aio_write(struct kiocb *, const struct iovec *,
+static ssize_t qib_aio_write(struct kiocb *, struct iovec *,
unsigned long, loff_t);
static unsigned int qib_poll(struct file *, struct poll_table_struct *);
static int qib_mmapf(struct file *, struct vm_area_struct *);
@@ -2245,7 +2245,7 @@ bail:
return ret;
}

-static ssize_t qib_aio_write(struct kiocb *iocb, const struct iovec *iov,
+static ssize_t qib_aio_write(struct kiocb *iocb, struct iovec *iov,
unsigned long dim, loff_t off)
{
struct qib_filedata *fp = iocb->ki_filp->private_data;
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index 6f226de..823522e 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -761,7 +761,7 @@ err:
return err;
}

-static ssize_t macvtap_aio_write(struct kiocb *iocb, const struct iovec *iv,
+static ssize_t macvtap_aio_write(struct kiocb *iocb, struct iovec *iv,
unsigned long count, loff_t pos)
{
struct file *file = iocb->ki_filp;
@@ -871,7 +871,7 @@ static ssize_t macvtap_do_read(struct macvtap_queue *q,
return ret;
}

-static ssize_t macvtap_aio_read(struct kiocb *iocb, const struct iovec *iv,
+static ssize_t macvtap_aio_read(struct kiocb *iocb, struct iovec *iv,
unsigned long count, loff_t pos)
{
struct file *file = iocb->ki_filp;
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 9dd3746..8d06816 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1206,7 +1206,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
return total_len;
}

-static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv,
+static ssize_t tun_chr_aio_write(struct kiocb *iocb, struct iovec *iv,
unsigned long count, loff_t pos)
{
struct file *file = iocb->ki_filp;
@@ -1371,7 +1371,7 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile,
return ret;
}

-static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
+static ssize_t tun_chr_aio_read(struct kiocb *iocb, struct iovec *iv,
unsigned long count, loff_t pos)
{
struct file *file = iocb->ki_filp;
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 63314ed..47fec3fd 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -958,7 +958,7 @@ static int ffs_aio_cancel(struct kiocb *kiocb)
}

static ssize_t ffs_epfile_aio_write(struct kiocb *kiocb,
- const struct iovec *iovec,
+ struct iovec *iovec,
unsigned long nr_segs, loff_t loff)
{
struct ffs_io_data *io_data;
@@ -985,7 +985,7 @@ static ssize_t ffs_epfile_aio_write(struct kiocb *kiocb,
}

static ssize_t ffs_epfile_aio_read(struct kiocb *kiocb,
- const struct iovec *iovec,
+ struct iovec *iovec,
unsigned long nr_segs, loff_t loff)
{
struct ffs_io_data *io_data;
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
index c744e49..211ab83 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -695,7 +695,7 @@ fail:
}

static ssize_t
-ep_aio_read(struct kiocb *iocb, const struct iovec *iov,
+ep_aio_read(struct kiocb *iocb, struct iovec *iov,
unsigned long nr_segs, loff_t o)
{
struct ep_data *epdata = iocb->ki_filp->private_data;
@@ -712,7 +712,7 @@ ep_aio_read(struct kiocb *iocb, const struct iovec *iov,
}

static ssize_t
-ep_aio_write(struct kiocb *iocb, const struct iovec *iov,
+ep_aio_write(struct kiocb *iocb, struct iovec *iov,
unsigned long nr_segs, loff_t o)
{
struct ep_data *epdata = iocb->ki_filp->private_data;
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index afd2b44..ca3db8d 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -33,13 +33,13 @@ static ssize_t bad_file_write(struct file *filp, const char __user *buf,
return -EIO;
}

-static ssize_t bad_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
+static ssize_t bad_file_aio_read(struct kiocb *iocb, struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
return -EIO;
}

-static ssize_t bad_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
+static ssize_t bad_file_aio_write(struct kiocb *iocb, struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
return -EIO;
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index ca88731..88ce708 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1277,7 +1277,7 @@ static ssize_t fuse_dev_do_read(struct fuse_conn *fc, struct file *file,
return err;
}

-static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov,
+static ssize_t fuse_dev_read(struct kiocb *iocb, struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
struct fuse_copy_state cs;
@@ -1881,7 +1881,7 @@ static ssize_t fuse_dev_do_write(struct fuse_conn *fc,
return err;
}

-static ssize_t fuse_dev_write(struct kiocb *iocb, const struct iovec *iov,
+static ssize_t fuse_dev_write(struct kiocb *iocb, struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
struct fuse_copy_state cs;
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index 643faa4..2617860 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -2114,7 +2114,7 @@ out:
/**
* ntfs_file_aio_write -
*/
-static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
+static ssize_t ntfs_file_aio_write(struct kiocb *iocb, struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
struct file *file = iocb->ki_filp;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 4e41a4a..2585428 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1485,8 +1485,8 @@ struct file_operations {
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
- ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
- ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
+ ssize_t (*aio_read) (struct kiocb *, struct iovec *, unsigned long, loff_t);
+ ssize_t (*aio_write) (struct kiocb *, struct iovec *, unsigned long, loff_t);
ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
int (*iterate) (struct file *, struct dir_context *);
diff --git a/net/socket.c b/net/socket.c
index fe20c31..3c6fbab 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -114,9 +114,9 @@ unsigned int sysctl_net_busy_poll __read_mostly;
#endif

static int sock_no_open(struct inode *irrelevant, struct file *dontcare);
-static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
+static ssize_t sock_aio_read(struct kiocb *iocb, struct iovec *iov,
unsigned long nr_segs, loff_t pos);
-static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov,
+static ssize_t sock_aio_write(struct kiocb *iocb, struct iovec *iov,
unsigned long nr_segs, loff_t pos);
static int sock_mmap(struct file *file, struct vm_area_struct *vma);

@@ -901,7 +901,7 @@ static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb,
}

static ssize_t do_sock_read(struct msghdr *msg, struct kiocb *iocb,
- struct file *file, const struct iovec *iov,
+ struct file *file, struct iovec *iov,
unsigned long nr_segs)
{
struct socket *sock = file->private_data;
@@ -915,14 +915,14 @@ 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_iov = iov;
msg->msg_iovlen = nr_segs;
msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0;

return __sock_recvmsg(iocb, sock, msg, size, msg->msg_flags);
}

-static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
+static ssize_t sock_aio_read(struct kiocb *iocb, struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
struct sock_iocb siocb, *x;
@@ -941,7 +941,7 @@ static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
}

static ssize_t do_sock_write(struct msghdr *msg, struct kiocb *iocb,
- struct file *file, const struct iovec *iov,
+ struct file *file, struct iovec *iov,
unsigned long nr_segs)
{
struct socket *sock = file->private_data;
@@ -955,7 +955,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_iov = iov;
msg->msg_iovlen = nr_segs;
msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0;
if (sock->type == SOCK_SEQPACKET)
@@ -964,7 +964,7 @@ static ssize_t do_sock_write(struct msghdr *msg, struct kiocb *iocb,
return __sock_sendmsg(iocb, sock, msg, size);
}

-static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov,
+static ssize_t sock_aio_write(struct kiocb *iocb, struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
struct sock_iocb siocb, *x;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 166d59c..229b5a9 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -2995,7 +2995,7 @@ static ssize_t snd_pcm_write(struct file *file, const char __user *buf,
return result;
}

-static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov,
+static ssize_t snd_pcm_aio_read(struct kiocb *iocb, struct iovec *iov,
unsigned long nr_segs, loff_t pos)

{
@@ -3031,7 +3031,7 @@ static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov,
return result;
}

-static ssize_t snd_pcm_aio_write(struct kiocb *iocb, const struct iovec *iov,
+static ssize_t snd_pcm_aio_write(struct kiocb *iocb, struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
struct snd_pcm_file *pcm_file;

Cheers,
--
Email: Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/