Skip to content

Commit

Permalink
[PATCH] Vectorize aio_read/aio_write fileop methods
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
Badari Pulavarty authored and Linus Torvalds committed Oct 1, 2006
1 parent 9ea0f94 commit 027445c
Show file tree
Hide file tree
Showing 22 changed files with 242 additions and 191 deletions.
5 changes: 2 additions & 3 deletions Documentation/filesystems/Locking
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions Documentation/filesystems/vfs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
17 changes: 13 additions & 4 deletions arch/s390/hypfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand Down
14 changes: 1 addition & 13 deletions drivers/char/raw.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
80 changes: 55 additions & 25 deletions drivers/usb/gadget/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down Expand Up @@ -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)
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -634,7 +651,8 @@ ep_aio_rwtail(
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)) {
Expand Down Expand Up @@ -674,41 +692,53 @@ ep_aio_rwtail(
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);
}

/*----------------------------------------------------------------------*/
Expand Down
15 changes: 11 additions & 4 deletions fs/aio.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <linux/aio_abi.h>
#include <linux/module.h>
#include <linux/syscalls.h>
#include <linux/uio.h>

#define DEBUG 0

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down
10 changes: 1 addition & 9 deletions fs/block_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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,
Expand Down
6 changes: 3 additions & 3 deletions fs/cifs/cifsfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 3 additions & 2 deletions fs/ext3/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading

0 comments on commit 027445c

Please sign in to comment.