Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 027445c3 authored by Badari Pulavarty's avatar Badari Pulavarty Committed by Linus Torvalds
Browse files

[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: default avatarBadari Pulavarty <pbadari@us.ibm.com>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Cc: Michael Holzheu <HOLZHEU@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 9ea0f949
Loading
Loading
Loading
Loading
+2 −3
Original line number Original line Diff line number Diff line
@@ -356,10 +356,9 @@ The last two are called only from check_disk_change().
prototypes:
prototypes:
	loff_t (*llseek) (struct file *, loff_t, int);
	loff_t (*llseek) (struct file *, loff_t, int);
	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
	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 (*write) (struct file *, const char __user *, size_t, loff_t *);
	ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t,
	ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
			loff_t);
	ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
	int (*readdir) (struct file *, void *, filldir_t);
	int (*readdir) (struct file *, void *, filldir_t);
	unsigned int (*poll) (struct file *, struct poll_table_struct *);
	unsigned int (*poll) (struct file *, struct poll_table_struct *);
	int (*ioctl) (struct inode *, struct file *, unsigned int,
	int (*ioctl) (struct inode *, struct file *, unsigned int,
+2 −2
Original line number Original line Diff line number Diff line
@@ -699,9 +699,9 @@ This describes how the VFS can manipulate an open file. As of kernel
struct file_operations {
struct file_operations {
	loff_t (*llseek) (struct file *, loff_t, int);
	loff_t (*llseek) (struct file *, loff_t, int);
	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
	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 (*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);
	int (*readdir) (struct file *, void *, filldir_t);
	unsigned int (*poll) (struct file *, struct poll_table_struct *);
	unsigned int (*poll) (struct file *, struct poll_table_struct *);
	int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
	int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
+13 −4
Original line number Original line Diff line number Diff line
@@ -134,12 +134,20 @@ static int hypfs_open(struct inode *inode, struct file *filp)
	return 0;
	return 0;
}
}


static ssize_t hypfs_aio_read(struct kiocb *iocb, __user char *buf,
static ssize_t hypfs_aio_read(struct kiocb *iocb, const struct iovec *iov,
			      size_t count, loff_t offset)
			      unsigned long nr_segs, loff_t offset)
{
{
	char *data;
	char *data;
	size_t len;
	size_t len;
	struct file *filp = iocb->ki_filp;
	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;
	data = filp->private_data;
	len = strlen(data);
	len = strlen(data);
@@ -158,12 +166,13 @@ static ssize_t hypfs_aio_read(struct kiocb *iocb, __user char *buf,
out:
out:
	return count;
	return count;
}
}
static ssize_t hypfs_aio_write(struct kiocb *iocb, const char __user *buf,
static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov,
			       size_t count, loff_t pos)
			      unsigned long nr_segs, loff_t offset)
{
{
	int rc;
	int rc;
	struct super_block *sb;
	struct super_block *sb;
	struct hypfs_sb_info *fs_info;
	struct hypfs_sb_info *fs_info;
	size_t count = iov_length(iov, nr_segs);


	sb = iocb->ki_filp->f_dentry->d_inode->i_sb;
	sb = iocb->ki_filp->f_dentry->d_inode->i_sb;
	fs_info = sb->s_fs_info;
	fs_info = sb->s_fs_info;
+1 −13
Original line number Original line Diff line number Diff line
@@ -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);
	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 = {
static const struct file_operations raw_fops = {
	.read	=	generic_file_read,
	.read	=	generic_file_read,
	.aio_read = 	generic_file_aio_read,
	.aio_read = 	generic_file_aio_read,
	.write	=	raw_file_write,
	.write	=	raw_file_write,
	.aio_write = 	raw_file_aio_write,
	.aio_write = 	generic_file_aio_write_nolock,
	.open	=	raw_open,
	.open	=	raw_open,
	.release=	raw_release,
	.release=	raw_release,
	.ioctl	=	raw_ioctl,
	.ioctl	=	raw_ioctl,
+55 −25
Original line number Original line Diff line number Diff line
@@ -533,7 +533,8 @@ struct kiocb_priv {
	struct usb_request	*req;
	struct usb_request	*req;
	struct ep_data		*epdata;
	struct ep_data		*epdata;
	void			*buf;
	void			*buf;
	char __user		*ubuf;		/* NULL for writes */
	const struct iovec	*iv;
	unsigned long		nr_segs;
	unsigned		actual;
	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)
static ssize_t ep_aio_read_retry(struct kiocb *iocb)
{
{
	struct kiocb_priv	*priv = iocb->private;
	struct kiocb_priv	*priv = iocb->private;
	ssize_t			status = priv->actual;
	ssize_t			len, total;
	int			i;


  	/* we "retry" to get the right mm context for this: */
  	/* we "retry" to get the right mm context for this: */
	status = copy_to_user(priv->ubuf, priv->buf, priv->actual);

	if (unlikely(0 != status))
 	/* copy stuff into user buffers */
		status = -EFAULT;
 	total = priv->actual;
	else
 	len = 0;
		status = priv->actual;
 	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->buf);
  	kfree(priv);
  	kfree(priv);
	return status;
  	aio_put_req(iocb);
 	return len;
}
}


static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
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);
	spin_lock(&epdata->dev->lock);
	priv->req = NULL;
	priv->req = NULL;
	priv->epdata = NULL;
	priv->epdata = NULL;
	if (priv->ubuf == NULL
	if (priv->iv == NULL
			|| unlikely(req->actual == 0)
			|| unlikely(req->actual == 0)
			|| unlikely(kiocbIsCancelled(iocb))) {
			|| unlikely(kiocbIsCancelled(iocb))) {
		kfree(req->buf);
		kfree(req->buf);
@@ -619,7 +635,8 @@ ep_aio_rwtail(
	char		*buf,
	char		*buf,
	size_t		len,
	size_t		len,
	struct ep_data	*epdata,
	struct ep_data	*epdata,
	char __user	*ubuf
	const struct iovec *iv,
	unsigned long 	nr_segs
)
)
{
{
	struct kiocb_priv	*priv;
	struct kiocb_priv	*priv;
@@ -634,7 +651,8 @@ ep_aio_rwtail(
		return value;
		return value;
	}
	}
	iocb->private = priv;
	iocb->private = priv;
	priv->ubuf = ubuf;
	priv->iv = iv;
	priv->nr_segs = nr_segs;


	value = get_ready_ep(iocb->ki_filp->f_flags, epdata);
	value = get_ready_ep(iocb->ki_filp->f_flags, epdata);
	if (unlikely(value < 0)) {
	if (unlikely(value < 0)) {
@@ -674,41 +692,53 @@ ep_aio_rwtail(
		kfree(priv);
		kfree(priv);
		put_ep(epdata);
		put_ep(epdata);
	} else
	} else
		value = (ubuf ? -EIOCBRETRY : -EIOCBQUEUED);
		value = (iv ? -EIOCBRETRY : -EIOCBQUEUED);
	return value;
	return value;
}
}


static ssize_t
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;
	struct ep_data		*epdata = iocb->ki_filp->private_data;
	char			*buf;
	char			*buf;


	if (unlikely(epdata->desc.bEndpointAddress & USB_DIR_IN))
	if (unlikely(epdata->desc.bEndpointAddress & USB_DIR_IN))
		return -EINVAL;
		return -EINVAL;
	buf = kmalloc(len, GFP_KERNEL);

	buf = kmalloc(iocb->ki_left, GFP_KERNEL);
	if (unlikely(!buf))
	if (unlikely(!buf))
		return -ENOMEM;
		return -ENOMEM;

	iocb->ki_retry = ep_aio_read_retry;
	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
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;
	struct ep_data		*epdata = iocb->ki_filp->private_data;
	char			*buf;
	char			*buf;
	size_t			len = 0;
	int			i = 0;


	if (unlikely(!(epdata->desc.bEndpointAddress & USB_DIR_IN)))
	if (unlikely(!(epdata->desc.bEndpointAddress & USB_DIR_IN)))
		return -EINVAL;
		return -EINVAL;
	buf = kmalloc(len, GFP_KERNEL);

	buf = kmalloc(iocb->ki_left, GFP_KERNEL);
	if (unlikely(!buf))
	if (unlikely(!buf))
		return -ENOMEM;
		return -ENOMEM;
	if (unlikely(copy_from_user(buf, ubuf, len) != 0)) {

	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);
			kfree(buf);
			return -EFAULT;
			return -EFAULT;
		}
		}
	return ep_aio_rwtail(iocb, buf, len, epdata, NULL);
		len += iov[i].iov_len;
	}
	return ep_aio_rwtail(iocb, buf, len, epdata, NULL, 0);
}
}


/*----------------------------------------------------------------------*/
/*----------------------------------------------------------------------*/
Loading