[PATCH] Vectorize aio_read/aio_write fileop methods
Badari Pulavarty [Sun, 1 Oct 2006 06:28:46 +0000 (23:28 -0700)]
This patch vectorizes aio_read() and aio_write() methods to prepare for
collapsing all aio & vectored operations into one interface - which is
aio_read()/aio_write().

Signed-off-by: Badari Pulavarty <pbadari@us.ibm.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Cc: Michael Holzheu <HOLZHEU@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

22 files changed:
Documentation/filesystems/Locking
Documentation/filesystems/vfs.txt
arch/s390/hypfs/inode.c
drivers/char/raw.c
drivers/usb/gadget/inode.c
fs/aio.c
fs/block_dev.c
fs/cifs/cifsfs.c
fs/ext3/file.c
fs/nfs/direct.c
fs/nfs/file.c
fs/ntfs/file.c
fs/ocfs2/file.c
fs/read_write.c
fs/reiserfs/file.c
fs/xfs/linux-2.6/xfs_file.c
include/linux/aio.h
include/linux/fs.h
include/linux/nfs_fs.h
include/net/sock.h
mm/filemap.c
net/socket.c

index 247d7f6..eb1a6ca 100644 (file)
@@ -356,10 +356,9 @@ The last two are called only from check_disk_change().
 prototypes:
        loff_t (*llseek) (struct file *, loff_t, int);
        ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
-       ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
        ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
-       ssize_t (*aio_write) (struct kiocb *, 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);
        int (*readdir) (struct file *, void *, filldir_t);
        unsigned int (*poll) (struct file *, struct poll_table_struct *);
        int (*ioctl) (struct inode *, struct file *, unsigned int,
index 1cb7e8b..cd07c21 100644 (file)
@@ -699,9 +699,9 @@ This describes how the VFS can manipulate an open file. As of kernel
 struct file_operations {
        loff_t (*llseek) (struct file *, loff_t, int);
        ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
-       ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
        ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
-       ssize_t (*aio_write) (struct kiocb *, 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);
        int (*readdir) (struct file *, void *, filldir_t);
        unsigned int (*poll) (struct file *, struct poll_table_struct *);
        int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
index 813fc21..cd702ae 100644 (file)
@@ -134,12 +134,20 @@ static int hypfs_open(struct inode *inode, struct file *filp)
        return 0;
 }
 
-static ssize_t hypfs_aio_read(struct kiocb *iocb, __user char *buf,
-                             size_t count, loff_t offset)
+static ssize_t hypfs_aio_read(struct kiocb *iocb, const struct iovec *iov,
+                             unsigned long nr_segs, loff_t offset)
 {
        char *data;
        size_t len;
        struct file *filp = iocb->ki_filp;
+       /* XXX: temporary */
+       char __user *buf = iov[0].iov_base;
+       size_t count = iov[0].iov_len;
+
+       if (nr_segs != 1) {
+               count = -EINVAL;
+               goto out;
+       }
 
        data = filp->private_data;
        len = strlen(data);
@@ -158,12 +166,13 @@ static ssize_t hypfs_aio_read(struct kiocb *iocb, __user char *buf,
 out:
        return count;
 }
-static ssize_t hypfs_aio_write(struct kiocb *iocb, const char __user *buf,
-                              size_t count, loff_t pos)
+static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov,
+                             unsigned long nr_segs, loff_t offset)
 {
        int rc;
        struct super_block *sb;
        struct hypfs_sb_info *fs_info;
+       size_t count = iov_length(iov, nr_segs);
 
        sb = iocb->ki_filp->f_dentry->d_inode->i_sb;
        fs_info = sb->s_fs_info;
index c596a08..173fb08 100644 (file)
@@ -249,23 +249,11 @@ static ssize_t raw_file_write(struct file *file, const char __user *buf,
        return generic_file_write_nolock(file, &local_iov, 1, ppos);
 }
 
-static ssize_t raw_file_aio_write(struct kiocb *iocb, const char __user *buf,
-                                       size_t count, loff_t pos)
-{
-       struct iovec local_iov = {
-               .iov_base = (char __user *)buf,
-               .iov_len = count
-       };
-
-       return generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos);
-}
-
-
 static const struct file_operations raw_fops = {
        .read   =       generic_file_read,
        .aio_read =     generic_file_aio_read,
        .write  =       raw_file_write,
-       .aio_write =    raw_file_aio_write,
+       .aio_write =    generic_file_aio_write_nolock,
        .open   =       raw_open,
        .release=       raw_release,
        .ioctl  =       raw_ioctl,
index 4a000d8..86924f9 100644 (file)
@@ -533,7 +533,8 @@ struct kiocb_priv {
        struct usb_request      *req;
        struct ep_data          *epdata;
        void                    *buf;
-       char __user             *ubuf;          /* NULL for writes */
+       const struct iovec      *iv;
+       unsigned long           nr_segs;
        unsigned                actual;
 };
 
@@ -561,17 +562,32 @@ static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e)
 static ssize_t ep_aio_read_retry(struct kiocb *iocb)
 {
        struct kiocb_priv       *priv = iocb->private;
-       ssize_t                 status = priv->actual;
-
-       /* we "retry" to get the right mm context for this: */
-       status = copy_to_user(priv->ubuf, priv->buf, priv->actual);
-       if (unlikely(0 != status))
-               status = -EFAULT;
-       else
-               status = priv->actual;
-       kfree(priv->buf);
-       kfree(priv);
-       return status;
+       ssize_t                 len, total;
+       int                     i;
+
+       /* we "retry" to get the right mm context for this: */
+
+       /* copy stuff into user buffers */
+       total = priv->actual;
+       len = 0;
+       for (i=0; i < priv->nr_segs; i++) {
+               ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
+
+               if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) {
+                       if (len == 0)
+                               len = -EFAULT;
+                       break;
+               }
+
+               total -= this;
+               len += this;
+               if (total == 0)
+                       break;
+       }
+       kfree(priv->buf);
+       kfree(priv);
+       aio_put_req(iocb);
+       return len;
 }
 
 static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
@@ -584,7 +600,7 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
        spin_lock(&epdata->dev->lock);
        priv->req = NULL;
        priv->epdata = NULL;
-       if (priv->ubuf == NULL
+       if (priv->iv == NULL
                        || unlikely(req->actual == 0)
                        || unlikely(kiocbIsCancelled(iocb))) {
                kfree(req->buf);
@@ -619,7 +635,8 @@ ep_aio_rwtail(
        char            *buf,
        size_t          len,
        struct ep_data  *epdata,
-       char __user     *ubuf
+       const struct iovec *iv,
+       unsigned long   nr_segs
 )
 {
        struct kiocb_priv       *priv;
@@ -634,7 +651,8 @@ fail:
                return value;
        }
        iocb->private = priv;
-       priv->ubuf = ubuf;
+       priv->iv = iv;
+       priv->nr_segs = nr_segs;
 
        value = get_ready_ep(iocb->ki_filp->f_flags, epdata);
        if (unlikely(value < 0)) {
@@ -674,41 +692,53 @@ fail:
                kfree(priv);
                put_ep(epdata);
        } else
-               value = (ubuf ? -EIOCBRETRY : -EIOCBQUEUED);
+               value = (iv ? -EIOCBRETRY : -EIOCBQUEUED);
        return value;
 }
 
 static ssize_t
-ep_aio_read(struct kiocb *iocb, char __user *ubuf, size_t len, loff_t o)
+ep_aio_read(struct kiocb *iocb, const struct iovec *iov,
+               unsigned long nr_segs, loff_t o)
 {
        struct ep_data          *epdata = iocb->ki_filp->private_data;
        char                    *buf;
 
        if (unlikely(epdata->desc.bEndpointAddress & USB_DIR_IN))
                return -EINVAL;
-       buf = kmalloc(len, GFP_KERNEL);
+
+       buf = kmalloc(iocb->ki_left, GFP_KERNEL);
        if (unlikely(!buf))
                return -ENOMEM;
+
        iocb->ki_retry = ep_aio_read_retry;
-       return ep_aio_rwtail(iocb, buf, len, epdata, ubuf);
+       return ep_aio_rwtail(iocb, buf, iocb->ki_left, epdata, iov, nr_segs);
 }
 
 static ssize_t
-ep_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t len, loff_t o)
+ep_aio_write(struct kiocb *iocb, const struct iovec *iov,
+               unsigned long nr_segs, loff_t o)
 {
        struct ep_data          *epdata = iocb->ki_filp->private_data;
        char                    *buf;
+       size_t                  len = 0;
+       int                     i = 0;
 
        if (unlikely(!(epdata->desc.bEndpointAddress & USB_DIR_IN)))
                return -EINVAL;
-       buf = kmalloc(len, GFP_KERNEL);
+
+       buf = kmalloc(iocb->ki_left, GFP_KERNEL);
        if (unlikely(!buf))
                return -ENOMEM;
-       if (unlikely(copy_from_user(buf, ubuf, len) != 0)) {
-               kfree(buf);
-               return -EFAULT;
+
+       for (i=0; i < nr_segs; i++) {
+               if (unlikely(copy_from_user(&buf[len], iov[i].iov_base,
+                               iov[i].iov_len) != 0)) {
+                       kfree(buf);
+                       return -EFAULT;
+               }
+               len += iov[i].iov_len;
        }
-       return ep_aio_rwtail(iocb, buf, len, epdata, NULL);
+       return ep_aio_rwtail(iocb, buf, len, epdata, NULL, 0);
 }
 
 /*----------------------------------------------------------------------*/
index 9506301..27ff565 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -15,6 +15,7 @@
 #include <linux/aio_abi.h>
 #include <linux/module.h>
 #include <linux/syscalls.h>
+#include <linux/uio.h>
 
 #define DEBUG 0
 
@@ -1315,8 +1316,11 @@ static ssize_t aio_pread(struct kiocb *iocb)
        ssize_t ret = 0;
 
        do {
-               ret = file->f_op->aio_read(iocb, iocb->ki_buf,
-                       iocb->ki_left, iocb->ki_pos);
+               iocb->ki_inline_vec.iov_base = iocb->ki_buf;
+               iocb->ki_inline_vec.iov_len = iocb->ki_left;
+
+               ret = file->f_op->aio_read(iocb, &iocb->ki_inline_vec,
+                                               1, iocb->ki_pos);
                /*
                 * Can't just depend on iocb->ki_left to determine
                 * whether we are done. This may have been a short read.
@@ -1349,8 +1353,11 @@ static ssize_t aio_pwrite(struct kiocb *iocb)
        ssize_t ret = 0;
 
        do {
-               ret = file->f_op->aio_write(iocb, iocb->ki_buf,
-                       iocb->ki_left, iocb->ki_pos);
+               iocb->ki_inline_vec.iov_base = iocb->ki_buf;
+               iocb->ki_inline_vec.iov_len = iocb->ki_left;
+
+               ret = file->f_op->aio_write(iocb, &iocb->ki_inline_vec,
+                                               1, iocb->ki_pos);
                if (ret > 0) {
                        iocb->ki_buf += ret;
                        iocb->ki_left -= ret;
index 0c361ea..8c81911 100644 (file)
@@ -1162,14 +1162,6 @@ static ssize_t blkdev_file_write(struct file *file, const char __user *buf,
        return generic_file_write_nolock(file, &local_iov, 1, ppos);
 }
 
-static ssize_t blkdev_file_aio_write(struct kiocb *iocb, const char __user *buf,
-                                  size_t count, loff_t pos)
-{
-       struct iovec local_iov = { .iov_base = (void __user *)buf, .iov_len = count };
-
-       return generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos);
-}
-
 static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 {
        return blkdev_ioctl(file->f_mapping->host, file, cmd, arg);
@@ -1192,7 +1184,7 @@ const struct file_operations def_blk_fops = {
        .read           = generic_file_read,
        .write          = blkdev_file_write,
        .aio_read       = generic_file_aio_read,
-       .aio_write      = blkdev_file_aio_write, 
+       .aio_write      = generic_file_aio_write_nolock,
        .mmap           = generic_file_mmap,
        .fsync          = block_fsync,
        .unlocked_ioctl = block_ioctl,
index 22bcf4d..5abb42a 100644 (file)
@@ -492,13 +492,13 @@ static ssize_t cifs_file_writev(struct file *file, const struct iovec *iov,
        return written;
 }
 
-static ssize_t cifs_file_aio_write(struct kiocb *iocb, const char __user *buf,
-                                  size_t count, loff_t pos)
+static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
+                                  unsigned long nr_segs, loff_t pos)
 {
        struct inode *inode = iocb->ki_filp->f_dentry->d_inode;
        ssize_t written;
 
-       written = generic_file_aio_write(iocb, buf, count, pos);
+       written = generic_file_aio_write(iocb, iov, nr_segs, pos);
        if (!CIFS_I(inode)->clientCanCacheAll)
                filemap_fdatawrite(inode->i_mapping);
        return written;
index 74ff20f..5c76245 100644 (file)
@@ -48,14 +48,15 @@ static int ext3_release_file (struct inode * inode, struct file * filp)
 }
 
 static ssize_t
-ext3_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos)
+ext3_file_write(struct kiocb *iocb, const struct iovec *iov,
+               unsigned long nr_segs, loff_t pos)
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_dentry->d_inode;
        ssize_t ret;
        int err;
 
-       ret = generic_file_aio_write(iocb, buf, count, pos);
+       ret = generic_file_aio_write(iocb, iov, nr_segs, pos);
 
        /*
         * Skip flushing if there was an error, or if nothing was written.
index 377839b..9f7f8b9 100644 (file)
@@ -707,8 +707,8 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
 /**
  * nfs_file_direct_read - file direct read operation for NFS files
  * @iocb: target I/O control block
- * @buf: user's buffer into which to read data
- * @count: number of bytes to read
+ * @iov: vector of user buffers into which to read data
+ * @nr_segs: size of iov vector
  * @pos: byte offset in file where reading starts
  *
  * We use this function for direct reads instead of calling
@@ -725,17 +725,24 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
  * client must read the updated atime from the server back into its
  * cache.
  */
-ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos)
+ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
+                               unsigned long nr_segs, loff_t pos)
 {
        ssize_t retval = -EINVAL;
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
+       /* XXX: temporary */
+       const char __user *buf = iov[0].iov_base;
+       size_t count = iov[0].iov_len;
 
        dprintk("nfs: direct read(%s/%s, %lu@%Ld)\n",
                file->f_dentry->d_parent->d_name.name,
                file->f_dentry->d_name.name,
                (unsigned long) count, (long long) pos);
 
+       if (nr_segs != 1)
+               return -EINVAL;
+
        if (count < 0)
                goto out;
        retval = -EFAULT;
@@ -760,8 +767,8 @@ out:
 /**
  * nfs_file_direct_write - file direct write operation for NFS files
  * @iocb: target I/O control block
- * @buf: user's buffer from which to write data
- * @count: number of bytes to write
+ * @iov: vector of user buffers from which to write data
+ * @nr_segs: size of iov vector
  * @pos: byte offset in file where writing starts
  *
  * We use this function for direct writes instead of calling
@@ -782,17 +789,24 @@ out:
  * Note that O_APPEND is not supported for NFS direct writes, as there
  * is no atomic O_APPEND write facility in the NFS protocol.
  */
-ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos)
+ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
+                               unsigned long nr_segs, loff_t pos)
 {
        ssize_t retval;
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
+       /* XXX: temporary */
+       const char __user *buf = iov[0].iov_base;
+       size_t count = iov[0].iov_len;
 
        dfprintk(VFS, "nfs: direct write(%s/%s, %lu@%Ld)\n",
                file->f_dentry->d_parent->d_name.name,
                file->f_dentry->d_name.name,
                (unsigned long) count, (long long) pos);
 
+       if (nr_segs != 1)
+               return -EINVAL;
+
        retval = generic_write_checks(file, &pos, &count, 0);
        if (retval)
                goto out;
index be997d6..cc93865 100644 (file)
@@ -41,8 +41,10 @@ static int nfs_file_release(struct inode *, struct file *);
 static loff_t nfs_file_llseek(struct file *file, loff_t offset, int origin);
 static int  nfs_file_mmap(struct file *, struct vm_area_struct *);
 static ssize_t nfs_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *);
-static ssize_t nfs_file_read(struct kiocb *, char __user *, size_t, loff_t);
-static ssize_t nfs_file_write(struct kiocb *, const char __user *, size_t, loff_t);
+static ssize_t nfs_file_read(struct kiocb *, const struct iovec *iov,
+                               unsigned long nr_segs, loff_t pos);
+static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov,
+                               unsigned long nr_segs, loff_t pos);
 static int  nfs_file_flush(struct file *, fl_owner_t id);
 static int  nfs_fsync(struct file *, struct dentry *dentry, int datasync);
 static int nfs_check_flags(int flags);
@@ -53,8 +55,8 @@ const struct file_operations nfs_file_operations = {
        .llseek         = nfs_file_llseek,
        .read           = do_sync_read,
        .write          = do_sync_write,
-       .aio_read               = nfs_file_read,
-       .aio_write              = nfs_file_write,
+       .aio_read       = nfs_file_read,
+       .aio_write      = nfs_file_write,
        .mmap           = nfs_file_mmap,
        .open           = nfs_file_open,
        .flush          = nfs_file_flush,
@@ -196,15 +198,17 @@ nfs_file_flush(struct file *file, fl_owner_t id)
 }
 
 static ssize_t
-nfs_file_read(struct kiocb *iocb, char __user * buf, size_t count, loff_t pos)
+nfs_file_read(struct kiocb *iocb, const struct iovec *iov,
+               unsigned long nr_segs, loff_t pos)
 {
        struct dentry * dentry = iocb->ki_filp->f_dentry;
        struct inode * inode = dentry->d_inode;
        ssize_t result;
+       size_t count = iov_length(iov, nr_segs);
 
 #ifdef CONFIG_NFS_DIRECTIO
        if (iocb->ki_filp->f_flags & O_DIRECT)
-               return nfs_file_direct_read(iocb, buf, count, pos);
+               return nfs_file_direct_read(iocb, iov, nr_segs, pos);
 #endif
 
        dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n",
@@ -214,7 +218,7 @@ nfs_file_read(struct kiocb *iocb, char __user * buf, size_t count, loff_t pos)
        result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
        nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, count);
        if (!result)
-               result = generic_file_aio_read(iocb, buf, count, pos);
+               result = generic_file_aio_read(iocb, iov, nr_segs, pos);
        return result;
 }
 
@@ -336,24 +340,22 @@ const struct address_space_operations nfs_file_aops = {
 #endif
 };
 
-/* 
- * Write to a file (through the page cache).
- */
-static ssize_t
-nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos)
+static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,
+                               unsigned long nr_segs, loff_t pos)
 {
        struct dentry * dentry = iocb->ki_filp->f_dentry;
        struct inode * inode = dentry->d_inode;
        ssize_t result;
+       size_t count = iov_length(iov, nr_segs);
 
 #ifdef CONFIG_NFS_DIRECTIO
        if (iocb->ki_filp->f_flags & O_DIRECT)
-               return nfs_file_direct_write(iocb, buf, count, pos);
+               return nfs_file_direct_write(iocb, iov, nr_segs, pos);
 #endif
 
-       dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%lu)\n",
+       dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%Ld)\n",
                dentry->d_parent->d_name.name, dentry->d_name.name,
-               inode->i_ino, (unsigned long) count, (unsigned long) pos);
+               inode->i_ino, (unsigned long) count, (long long) pos);
 
        result = -EBUSY;
        if (IS_SWAPFILE(inode))
@@ -372,7 +374,7 @@ nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t
                goto out;
 
        nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count);
-       result = generic_file_aio_write(iocb, buf, count, pos);
+       result = generic_file_aio_write(iocb, iov, nr_segs, pos);
 out:
        return result;
 
index 585a79d..0c46f5c 100644 (file)
@@ -2176,20 +2176,18 @@ out:
 /**
  * ntfs_file_aio_write -
  */
-static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const char __user *buf,
-               size_t count, loff_t pos)
+static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
+               unsigned long nr_segs, loff_t pos)
 {
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
        struct inode *inode = mapping->host;
        ssize_t ret;
-       struct iovec local_iov = { .iov_base = (void __user *)buf,
-                                  .iov_len = count };
 
        BUG_ON(iocb->ki_pos != pos);
 
        mutex_lock(&inode->i_mutex);
-       ret = ntfs_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos);
+       ret = ntfs_file_aio_write_nolock(iocb, iov, nr_segs, &iocb->ki_pos);
        mutex_unlock(&inode->i_mutex);
        if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
                int err = sync_page_range(inode, mapping, pos, ret);
index 2bbfa17..d9ba0a9 100644 (file)
@@ -961,25 +961,23 @@ static inline int ocfs2_write_should_remove_suid(struct inode *inode)
 }
 
 static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
-                                   const char __user *buf,
-                                   size_t count,
+                                   const struct iovec *iov,
+                                   unsigned long nr_segs,
                                    loff_t pos)
 {
-       struct iovec local_iov = { .iov_base = (void __user *)buf,
-                                  .iov_len = count };
        int ret, rw_level = -1, meta_level = -1, have_alloc_sem = 0;
        u32 clusters;
        struct file *filp = iocb->ki_filp;
        struct inode *inode = filp->f_dentry->d_inode;
        loff_t newsize, saved_pos;
 
-       mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", filp, buf,
-                  (unsigned int)count,
+       mlog_entry("(0x%p, %u, '%.*s')\n", filp,
+                  (unsigned int)nr_segs,
                   filp->f_dentry->d_name.len,
                   filp->f_dentry->d_name.name);
 
        /* happy write of zero bytes */
-       if (count == 0)
+       if (iocb->ki_left == 0)
                return 0;
 
        if (!inode) {
@@ -1048,7 +1046,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
                } else {
                        saved_pos = iocb->ki_pos;
                }
-               newsize = count + saved_pos;
+               newsize = iocb->ki_left + saved_pos;
 
                mlog(0, "pos=%lld newsize=%lld cursize=%lld\n",
                     (long long) saved_pos, (long long) newsize,
@@ -1081,7 +1079,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
                if (!clusters)
                        break;
 
-               ret = ocfs2_extend_file(inode, NULL, newsize, count);
+               ret = ocfs2_extend_file(inode, NULL, newsize, iocb->ki_left);
                if (ret < 0) {
                        if (ret != -ENOSPC)
                                mlog_errno(ret);
@@ -1098,7 +1096,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
        /* communicate with ocfs2_dio_end_io */
        ocfs2_iocb_set_rw_locked(iocb);
 
-       ret = generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos);
+       ret = generic_file_aio_write_nolock(iocb, iov, nr_segs, iocb->ki_pos);
 
        /* buffered aio wouldn't have proper lock coverage today */
        BUG_ON(ret == -EIOCBQUEUED && !(filp->f_flags & O_DIRECT));
@@ -1132,16 +1130,16 @@ out:
 }
 
 static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
-                                  char __user *buf,
-                                  size_t count,
+                                  const struct iovec *iov,
+                                  unsigned long nr_segs,
                                   loff_t pos)
 {
        int ret = 0, rw_level = -1, have_alloc_sem = 0;
        struct file *filp = iocb->ki_filp;
        struct inode *inode = filp->f_dentry->d_inode;
 
-       mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", filp, buf,
-                  (unsigned int)count,
+       mlog_entry("(0x%p, %u, '%.*s')\n", filp,
+                  (unsigned int)nr_segs,
                   filp->f_dentry->d_name.len,
                   filp->f_dentry->d_name.name);
 
@@ -1185,7 +1183,7 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
        }
        ocfs2_meta_unlock(inode, 0);
 
-       ret = generic_file_aio_read(iocb, buf, count, iocb->ki_pos);
+       ret = generic_file_aio_read(iocb, iov, nr_segs, iocb->ki_pos);
        if (ret == -EINVAL)
                mlog(ML_ERROR, "generic_file_aio_read returned -EINVAL\n");
 
index d4cb318..679dd53 100644 (file)
@@ -227,14 +227,20 @@ static void wait_on_retry_sync_kiocb(struct kiocb *iocb)
 
 ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
 {
+       struct iovec iov = { .iov_base = buf, .iov_len = len };
        struct kiocb kiocb;
        ssize_t ret;
 
        init_sync_kiocb(&kiocb, filp);
        kiocb.ki_pos = *ppos;
-       while (-EIOCBRETRY ==
-               (ret = filp->f_op->aio_read(&kiocb, buf, len, kiocb.ki_pos)))
+       kiocb.ki_left = len;
+
+       for (;;) {
+               ret = filp->f_op->aio_read(&kiocb, &iov, 1, kiocb.ki_pos);
+               if (ret != -EIOCBRETRY)
+                       break;
                wait_on_retry_sync_kiocb(&kiocb);
+       }
 
        if (-EIOCBQUEUED == ret)
                ret = wait_on_sync_kiocb(&kiocb);
@@ -279,14 +285,20 @@ EXPORT_SYMBOL(vfs_read);
 
 ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
 {
+       struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };
        struct kiocb kiocb;
        ssize_t ret;
 
        init_sync_kiocb(&kiocb, filp);
        kiocb.ki_pos = *ppos;
-       while (-EIOCBRETRY ==
-              (ret = filp->f_op->aio_write(&kiocb, buf, len, kiocb.ki_pos)))
+       kiocb.ki_left = len;
+
+       for (;;) {
+               ret = filp->f_op->aio_write(&kiocb, &iov, 1, kiocb.ki_pos);
+               if (ret != -EIOCBRETRY)
+                       break;
                wait_on_retry_sync_kiocb(&kiocb);
+       }
 
        if (-EIOCBQUEUED == ret)
                ret = wait_on_sync_kiocb(&kiocb);
index c11f611..41f2436 100644 (file)
@@ -1334,7 +1334,7 @@ static ssize_t reiserfs_file_write(struct file *file,     /* the file we are going t
                        if (err)
                                return err;
                }
-               result = generic_file_write(file, buf, count, ppos);
+               result = do_sync_write(file, buf, count, ppos);
 
                if (after_file_end) {   /* Now update i_size and remove the savelink */
                        struct reiserfs_transaction_handle th;
@@ -1566,7 +1566,7 @@ static ssize_t reiserfs_file_write(struct file *file,     /* the file we are going t
 }
 
 const struct file_operations reiserfs_file_operations = {
-       .read = generic_file_read,
+       .read = do_sync_read,
        .write = reiserfs_file_write,
        .ioctl = reiserfs_ioctl,
 #ifdef CONFIG_COMPAT
index 41cfcba..4737971 100644 (file)
@@ -49,50 +49,49 @@ static struct vm_operations_struct xfs_dmapi_file_vm_ops;
 STATIC inline ssize_t
 __xfs_file_read(
        struct kiocb            *iocb,
-       char                    __user *buf,
+       const struct iovec      *iov,
+       unsigned long           nr_segs,
        int                     ioflags,
-       size_t                  count,
        loff_t                  pos)
 {
-       struct iovec            iov = {buf, count};
        struct file             *file = iocb->ki_filp;
        bhv_vnode_t             *vp = vn_from_inode(file->f_dentry->d_inode);
 
        BUG_ON(iocb->ki_pos != pos);
        if (unlikely(file->f_flags & O_DIRECT))
                ioflags |= IO_ISDIRECT;
-       return bhv_vop_read(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL);
+       return bhv_vop_read(vp, iocb, iov, nr_segs, &iocb->ki_pos,
+                               ioflags, NULL);
 }
 
 STATIC ssize_t
 xfs_file_aio_read(
        struct kiocb            *iocb,
-       char                    __user *buf,
-       size_t                  count,
+       const struct iovec      *iov,
+       unsigned long           nr_segs,
        loff_t                  pos)
 {
-       return __xfs_file_read(iocb, buf, IO_ISAIO, count, pos);
+       return __xfs_file_read(iocb, iov, nr_segs, IO_ISAIO, pos);
 }
 
 STATIC ssize_t
 xfs_file_aio_read_invis(
        struct kiocb            *iocb,
-       char                    __user *buf,
-       size_t                  count,
+       const struct iovec      *iov,
+       unsigned long           nr_segs,
        loff_t                  pos)
 {
-       return __xfs_file_read(iocb, buf, IO_ISAIO|IO_INVIS, count, pos);
+       return __xfs_file_read(iocb, iov, nr_segs, IO_ISAIO|IO_INVIS, pos);
 }
 
 STATIC inline ssize_t
 __xfs_file_write(
-       struct kiocb    *iocb,
-       const char      __user *buf,
-       int             ioflags,
-       size_t          count,
-       loff_t          pos)
+       struct kiocb            *iocb,
+       const struct iovec      *iov,
+       unsigned long           nr_segs,
+       int                     ioflags,
+       loff_t                  pos)
 {
-       struct iovec    iov = {(void __user *)buf, count};
        struct file     *file = iocb->ki_filp;
        struct inode    *inode = file->f_mapping->host;
        bhv_vnode_t     *vp = vn_from_inode(inode);
@@ -100,27 +99,28 @@ __xfs_file_write(
        BUG_ON(iocb->ki_pos != pos);
        if (unlikely(file->f_flags & O_DIRECT))
                ioflags |= IO_ISDIRECT;
-       return bhv_vop_write(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL);
+       return bhv_vop_write(vp, iocb, iov, nr_segs, &iocb->ki_pos,
+                               ioflags, NULL);
 }
 
 STATIC ssize_t
 xfs_file_aio_write(
        struct kiocb            *iocb,
-       const char              __user *buf,
-       size_t                  count,
+       const struct iovec      *iov,
+       unsigned long           nr_segs,
        loff_t                  pos)
 {
-       return __xfs_file_write(iocb, buf, IO_ISAIO, count, pos);
+       return __xfs_file_write(iocb, iov, nr_segs, IO_ISAIO, pos);
 }
 
 STATIC ssize_t
 xfs_file_aio_write_invis(
        struct kiocb            *iocb,
-       const char              __user *buf,
-       size_t                  count,
+       const struct iovec      *iov,
+       unsigned long           nr_segs,
        loff_t                  pos)
 {
-       return __xfs_file_write(iocb, buf, IO_ISAIO|IO_INVIS, count, pos);
+       return __xfs_file_write(iocb, iov, nr_segs, IO_ISAIO|IO_INVIS, pos);
 }
 
 STATIC inline ssize_t
index 8a01933..58349e5 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/list.h>
 #include <linux/workqueue.h>
 #include <linux/aio_abi.h>
+#include <linux/uio.h>
 
 #include <asm/atomic.h>
 
@@ -112,6 +113,7 @@ struct kiocb {
        long                    ki_retried;     /* just for testing */
        long                    ki_kicked;      /* just for testing */
        long                    ki_queued;      /* just for testing */
+       struct iovec            ki_inline_vec;  /* inline vector */
 
        struct list_head        ki_list;        /* the aio core uses this
                                                 * for cancellation */
index 5baf3a1..257bae1 100644 (file)
@@ -1097,9 +1097,9 @@ struct file_operations {
        struct module *owner;
        loff_t (*llseek) (struct file *, loff_t, int);
        ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
-       ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
        ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
-       ssize_t (*aio_write) (struct kiocb *, 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);
        int (*readdir) (struct file *, void *, filldir_t);
        unsigned int (*poll) (struct file *, struct poll_table_struct *);
        int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
@@ -1704,11 +1704,11 @@ extern int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned
 extern ssize_t generic_file_read(struct file *, char __user *, size_t, loff_t *);
 int generic_write_checks(struct file *file, loff_t *pos, size_t *count, int isblk);
 extern ssize_t generic_file_write(struct file *, const char __user *, size_t, loff_t *);
-extern ssize_t generic_file_aio_read(struct kiocb *, char __user *, size_t, loff_t);
+extern ssize_t generic_file_aio_read(struct kiocb *, const struct iovec *, unsigned long, loff_t);
 extern ssize_t __generic_file_aio_read(struct kiocb *, const struct iovec *, unsigned long, loff_t *);
-extern ssize_t generic_file_aio_write(struct kiocb *, const char __user *, size_t, loff_t);
+extern ssize_t generic_file_aio_write(struct kiocb *, const struct iovec *, unsigned long, loff_t);
 extern ssize_t generic_file_aio_write_nolock(struct kiocb *, const struct iovec *,
-               unsigned long, loff_t *);
+               unsigned long, loff_t);
 extern ssize_t generic_file_direct_write(struct kiocb *, const struct iovec *,
                unsigned long *, loff_t, loff_t *, size_t, size_t);
 extern ssize_t generic_file_buffered_write(struct kiocb *, const struct iovec *,
index 98c9b9f..76ff548 100644 (file)
@@ -367,10 +367,12 @@ extern int nfs3_removexattr (struct dentry *, const char *name);
  */
 extern ssize_t nfs_direct_IO(int, struct kiocb *, const struct iovec *, loff_t,
                        unsigned long);
-extern ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf,
-                       size_t count, loff_t pos);
-extern ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf,
-                       size_t count, loff_t pos);
+extern ssize_t nfs_file_direct_read(struct kiocb *iocb,
+                       const struct iovec *iov, unsigned long nr_segs,
+                       loff_t pos);
+extern ssize_t nfs_file_direct_write(struct kiocb *iocb,
+                       const struct iovec *iov, unsigned long nr_segs,
+                       loff_t pos);
 
 /*
  * linux/fs/nfs/dir.c
index edd4d73..40bb90e 100644 (file)
@@ -665,7 +665,6 @@ struct sock_iocb {
        struct sock             *sk;
        struct scm_cookie       *scm;
        struct msghdr           *msg, async_msg;
-       struct iovec            async_iov;
        struct kiocb            *kiocb;
 };
 
index c4fe97f..f6c1d22 100644 (file)
@@ -1226,12 +1226,11 @@ out:
 EXPORT_SYMBOL(__generic_file_aio_read);
 
 ssize_t
-generic_file_aio_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos)
+generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
+               unsigned long nr_segs, loff_t pos)
 {
-       struct iovec local_iov = { .iov_base = buf, .iov_len = count };
-
        BUG_ON(iocb->ki_pos != pos);
-       return __generic_file_aio_read(iocb, &local_iov, 1, &iocb->ki_pos);
+       return __generic_file_aio_read(iocb, iov, nr_segs, &iocb->ki_pos);
 }
 EXPORT_SYMBOL(generic_file_aio_read);
 
@@ -2315,22 +2314,22 @@ out:
        current->backing_dev_info = NULL;
        return written ? written : err;
 }
-EXPORT_SYMBOL(generic_file_aio_write_nolock);
 
-ssize_t
-generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
-                               unsigned long nr_segs, loff_t *ppos)
+ssize_t generic_file_aio_write_nolock(struct kiocb *iocb,
+               const struct iovec *iov, unsigned long nr_segs, loff_t pos)
 {
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
        struct inode *inode = mapping->host;
        ssize_t ret;
-       loff_t pos = *ppos;
 
-       ret = __generic_file_aio_write_nolock(iocb, iov, nr_segs, ppos);
+       BUG_ON(iocb->ki_pos != pos);
+
+       ret = __generic_file_aio_write_nolock(iocb, iov, nr_segs,
+                       &iocb->ki_pos);
 
        if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
-               int err;
+               ssize_t err;
 
                err = sync_page_range_nolock(inode, mapping, pos, ret);
                if (err < 0)
@@ -2338,6 +2337,7 @@ generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
        }
        return ret;
 }
+EXPORT_SYMBOL(generic_file_aio_write_nolock);
 
 static ssize_t
 __generic_file_write_nolock(struct file *file, const struct iovec *iov,
@@ -2347,8 +2347,9 @@ __generic_file_write_nolock(struct file *file, const struct iovec *iov,
        ssize_t ret;
 
        init_sync_kiocb(&kiocb, file);
+       kiocb.ki_pos = *ppos;
        ret = __generic_file_aio_write_nolock(&kiocb, iov, nr_segs, ppos);
-       if (ret == -EIOCBQUEUED)
+       if (-EIOCBQUEUED == ret)
                ret = wait_on_sync_kiocb(&kiocb);
        return ret;
 }
@@ -2361,28 +2362,28 @@ generic_file_write_nolock(struct file *file, const struct iovec *iov,
        ssize_t ret;
 
        init_sync_kiocb(&kiocb, file);
-       ret = generic_file_aio_write_nolock(&kiocb, iov, nr_segs, ppos);
+       kiocb.ki_pos = *ppos;
+       ret = generic_file_aio_write_nolock(&kiocb, iov, nr_segs, *ppos);
        if (-EIOCBQUEUED == ret)
                ret = wait_on_sync_kiocb(&kiocb);
+       *ppos = kiocb.ki_pos;
        return ret;
 }
 EXPORT_SYMBOL(generic_file_write_nolock);
 
-ssize_t generic_file_aio_write(struct kiocb *iocb, const char __user *buf,
-                              size_t count, loff_t pos)
+ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
+               unsigned long nr_segs, loff_t pos)
 {
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
        struct inode *inode = mapping->host;
        ssize_t ret;
-       struct iovec local_iov = { .iov_base = (void __user *)buf,
-                                       .iov_len = count };
 
        BUG_ON(iocb->ki_pos != pos);
 
        mutex_lock(&inode->i_mutex);
-       ret = __generic_file_aio_write_nolock(iocb, &local_iov, 1,
-                                               &iocb->ki_pos);
+       ret = __generic_file_aio_write_nolock(iocb, iov, nr_segs,
+                       &iocb->ki_pos);
        mutex_unlock(&inode->i_mutex);
 
        if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
index 1bc4167..df92e42 100644 (file)
 #include <linux/netfilter.h>
 
 static int sock_no_open(struct inode *irrelevant, struct file *dontcare);
-static ssize_t sock_aio_read(struct kiocb *iocb, char __user *buf,
-                            size_t size, loff_t pos);
-static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *buf,
-                             size_t size, loff_t pos);
+static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
+                        unsigned long nr_segs, loff_t pos);
+static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov,
+                         unsigned long nr_segs, loff_t pos);
 static int sock_mmap(struct file *file, struct vm_area_struct *vma);
 
 static int sock_close(struct inode *inode, struct file *file);
@@ -664,7 +664,6 @@ static ssize_t sock_sendpage(struct file *file, struct page *page,
 }
 
 static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb,
-                                        char __user *ubuf, size_t size,
                                         struct sock_iocb *siocb)
 {
        if (!is_sync_kiocb(iocb)) {
@@ -675,16 +674,13 @@ static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb,
        }
 
        siocb->kiocb = iocb;
-       siocb->async_iov.iov_base = ubuf;
-       siocb->async_iov.iov_len = size;
-
        iocb->private = siocb;
        return siocb;
 }
 
 static ssize_t do_sock_read(struct msghdr *msg, struct kiocb *iocb,
-                           struct file *file, struct iovec *iov,
-                           unsigned long nr_segs)
+               struct file *file, const struct iovec *iov,
+               unsigned long nr_segs)
 {
        struct socket *sock = file->private_data;
        size_t size = 0;
@@ -715,32 +711,33 @@ static ssize_t sock_readv(struct file *file, const struct iovec *iov,
        init_sync_kiocb(&iocb, NULL);
        iocb.private = &siocb;
 
-       ret = do_sock_read(&msg, &iocb, file, (struct iovec *)iov, nr_segs);
+       ret = do_sock_read(&msg, &iocb, file, iov, nr_segs);
        if (-EIOCBQUEUED == ret)
                ret = wait_on_sync_kiocb(&iocb);
        return ret;
 }
 
-static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf,
-                            size_t count, loff_t pos)
+static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
+                               unsigned long nr_segs, loff_t pos)
 {
        struct sock_iocb siocb, *x;
 
        if (pos != 0)
                return -ESPIPE;
-       if (count == 0)         /* Match SYS5 behaviour */
+
+       if (iocb->ki_left == 0) /* Match SYS5 behaviour */
                return 0;
 
-       x = alloc_sock_iocb(iocb, ubuf, count, &siocb);
+
+       x = alloc_sock_iocb(iocb, &siocb);
        if (!x)
                return -ENOMEM;
-       return do_sock_read(&x->async_msg, iocb, iocb->ki_filp,
-                           &x->async_iov, 1);
+       return do_sock_read(&x->async_msg, iocb, iocb->ki_filp, iov, nr_segs);
 }
 
 static ssize_t do_sock_write(struct msghdr *msg, struct kiocb *iocb,
-                            struct file *file, struct iovec *iov,
-                            unsigned long nr_segs)
+                       struct file *file, const struct iovec *iov,
+                       unsigned long nr_segs)
 {
        struct socket *sock = file->private_data;
        size_t size = 0;
@@ -773,28 +770,28 @@ static ssize_t sock_writev(struct file *file, const struct iovec *iov,
        init_sync_kiocb(&iocb, NULL);
        iocb.private = &siocb;
 
-       ret = do_sock_write(&msg, &iocb, file, (struct iovec *)iov, nr_segs);
+       ret = do_sock_write(&msg, &iocb, file, iov, nr_segs);
        if (-EIOCBQUEUED == ret)
                ret = wait_on_sync_kiocb(&iocb);
        return ret;
 }
 
-static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf,
-                             size_t count, loff_t pos)
+static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov,
+                         unsigned long nr_segs, loff_t pos)
 {
        struct sock_iocb siocb, *x;
 
        if (pos != 0)
                return -ESPIPE;
-       if (count == 0)         /* Match SYS5 behaviour */
+
+       if (iocb->ki_left == 0) /* Match SYS5 behaviour */
                return 0;
 
-       x = alloc_sock_iocb(iocb, (void __user *)ubuf, count, &siocb);
+       x = alloc_sock_iocb(iocb, &siocb);
        if (!x)
                return -ENOMEM;
 
-       return do_sock_write(&x->async_msg, iocb, iocb->ki_filp,
-                            &x->async_iov, 1);
+       return do_sock_write(&x->async_msg, iocb, iocb->ki_filp, iov, nr_segs);
 }
 
 /*