[PATCH] Vectorize aio_read/aio_write fileop methods

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 <[email protected]>
Signed-off-by: Christoph Hellwig <[email protected]>
Cc: Michael Holzheu <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
This commit is contained in:
Badari Pulavarty 2006-09-30 23:28:46 -07:00 • committed by Linus Torvalds
commit 027445c372
22 changed files with 242 additions and 191 deletions

View file

@ -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;

View 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,

View 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;

View 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.

View 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;

View 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;

View 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);

View 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");

View 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);

View 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

View 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