Hi, I am trying to collapse all the vectored and AIO operations to a single set of file-operations. My initial posting, is available here:
http://marc.theaimsgroup.com/?l=linux-kernel&m=113889673116697&w=2 As part of this work, I changed aio_read()/aio_write() methods to take a vector, so I can drop readv/writev methods. I was trying to fix usb/gadget/inode.c ep_aio_read()/ep_aio_write() to support vector. I am hoping some one can help me, since I don't understand the code well enough :( For my first (dumb) pass, I just loop through all the vectors. Does this look right ? Does vectorizing these makes sense at all ? Please let me know, how this can be optimized. (BTW, I just included only usb/gadget related patch here - if some one wants to see the whole thing, I can post it here). Thanks, Badari
=================================================================== --- linux-2.6.16-rc1.quilt.orig/Documentation/filesystems/vfs.txt 2006-02-01 16:36:55.000000000 -0800 +++ linux-2.6.16-rc1.quilt/Documentation/filesystems/vfs.txt 2006-02-01 16:38:14.000000000 -0800 @@ -526,9 +526,9 @@ 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: linux-2.6.16-rc1.quilt/drivers/usb/gadget/inode.c =================================================================== --- linux-2.6.16-rc1.quilt.orig/drivers/usb/gadget/inode.c 2006-02-01 16:16:50.000000000 -0800 +++ linux-2.6.16-rc1.quilt/drivers/usb/gadget/inode.c 2006-02-02 16:37:46.000000000 -0800 @@ -675,36 +675,60 @@ } 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 *iv, + unsigned long count, loff_t o) { struct ep_data *epdata = iocb->ki_filp->private_data; char *buf; + size_t len; + int i = 0; + ssize_t ret; if (unlikely(epdata->desc.bEndpointAddress & USB_DIR_IN)) return -EINVAL; - buf = kmalloc(len, GFP_KERNEL); - if (unlikely(!buf)) - return -ENOMEM; - iocb->ki_retry = ep_aio_read_retry; - return ep_aio_rwtail(iocb, buf, len, epdata, ubuf); + + while (i++ < count) { + len = iv->iov_len; + buf = kmalloc(len, GFP_KERNEL); + if (unlikely(!buf)) + return -ENOMEM; + iocb->ki_retry = ep_aio_read_retry; + ret = ep_aio_rwtail(iocb, buf, len, epdata, iv->iov_base); + if ((ret < 0) && (ret != -EIOCBQUEUED)) + break; + iv++; + } + return ret; } 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 *iv, + unsigned long count, loff_t o) { struct ep_data *epdata = iocb->ki_filp->private_data; char *buf; + size_t len; + int i = 0; + ssize_t ret; if (unlikely(!(epdata->desc.bEndpointAddress & USB_DIR_IN))) return -EINVAL; - buf = kmalloc(len, GFP_KERNEL); - if (unlikely(!buf)) - return -ENOMEM; - if (unlikely(copy_from_user(buf, ubuf, len) != 0)) { - kfree(buf); - return -EFAULT; + + while (i++ < count) { + len = iv->iov_len; + buf = kmalloc(len, GFP_KERNEL); + if (unlikely(!buf)) + return -ENOMEM; + if (unlikely(copy_from_user(buf, iv->iov_base, len) != 0)) { + kfree(buf); + return -EFAULT; + } + ret = ep_aio_rwtail(iocb, buf, len, epdata, NULL); + if ((ret < 0) && (ret != -EIOCBQUEUED)) + break; + iv++; } - return ep_aio_rwtail(iocb, buf, len, epdata, NULL); + return ret; } /*----------------------------------------------------------------------*/