aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Baldyga <r.baldyga@samsung.com>2014-02-10 04:42:44 -0500
committerFelipe Balbi <balbi@ti.com>2014-02-18 11:53:02 -0500
commit2e4c7553cd6f9c68bb741582dcb614edcbeca70f (patch)
treeb4c5b2066d145eb224809b32b585fde8424f5f87
parent23de91e970a410a30b5927b9a749ed1dfd914140 (diff)
usb: gadget: f_fs: add aio support
This patch adds asynchronous I/O support for FunctionFS endpoint files. It adds ffs_epfile_aio_write() and ffs_epfile_aio_read() functions responsible for preparing AIO operations. It also modifies ffs_epfile_io() function, adding aio handling code. Instead of extending list of parameters of this function, there is new struct ffs_io_data which contains all information needed to perform I/O operation. Pointer to this struct replaces "buf" and "len" parameters of ffs_epfile_io() function. Allocated buffer is freed immediately only after sync operation, because in async IO it's freed in complete funcion. For each async operation an USB request is allocated, because it allows to have more than one request queued on single endpoint. According to changes in ffs_epfile_io() function, functions ffs_epfile_write() and ffs_epfile_read() are updated to use new API. For asynchronous I/O operations there is new request complete function named ffs_epfile_async_io_complete(), which completes AIO operation, and frees used memory. Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> Acked-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r--drivers/usb/gadget/f_fs.c265
1 files changed, 239 insertions, 26 deletions
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index 20321631f0f4..1ae741fdace0 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -28,6 +28,8 @@
28#include <linux/usb/composite.h> 28#include <linux/usb/composite.h>
29#include <linux/usb/functionfs.h> 29#include <linux/usb/functionfs.h>
30 30
31#include <linux/aio.h>
32#include <linux/mmu_context.h>
31#include <linux/poll.h> 33#include <linux/poll.h>
32 34
33#include "u_fs.h" 35#include "u_fs.h"
@@ -158,6 +160,25 @@ struct ffs_epfile {
158 unsigned char _pad; 160 unsigned char _pad;
159}; 161};
160 162
163/* ffs_io_data structure ***************************************************/
164
165struct ffs_io_data {
166 bool aio;
167 bool read;
168
169 struct kiocb *kiocb;
170 const struct iovec *iovec;
171 unsigned long nr_segs;
172 char __user *buf;
173 size_t len;
174
175 struct mm_struct *mm;
176 struct work_struct work;
177
178 struct usb_ep *ep;
179 struct usb_request *req;
180};
181
161static int __must_check ffs_epfiles_create(struct ffs_data *ffs); 182static int __must_check ffs_epfiles_create(struct ffs_data *ffs);
162static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count); 183static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
163 184
@@ -635,8 +656,52 @@ static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
635 } 656 }
636} 657}
637 658
638static ssize_t ffs_epfile_io(struct file *file, 659static void ffs_user_copy_worker(struct work_struct *work)
639 char __user *buf, size_t len, int read) 660{
661 struct ffs_io_data *io_data = container_of(work, struct ffs_io_data,
662 work);
663 int ret = io_data->req->status ? io_data->req->status :
664 io_data->req->actual;
665
666 if (io_data->read && ret > 0) {
667 int i;
668 size_t pos = 0;
669 use_mm(io_data->mm);
670 for (i = 0; i < io_data->nr_segs; i++) {
671 if (unlikely(copy_to_user(io_data->iovec[i].iov_base,
672 &io_data->buf[pos],
673 io_data->iovec[i].iov_len))) {
674 ret = -EFAULT;
675 break;
676 }
677 pos += io_data->iovec[i].iov_len;
678 }
679 unuse_mm(io_data->mm);
680 }
681
682 aio_complete(io_data->kiocb, ret, ret);
683
684 usb_ep_free_request(io_data->ep, io_data->req);
685
686 io_data->kiocb->private = NULL;
687 if (io_data->read)
688 kfree(io_data->iovec);
689 kfree(io_data->buf);
690 kfree(io_data);
691}
692
693static void ffs_epfile_async_io_complete(struct usb_ep *_ep,
694 struct usb_request *req)
695{
696 struct ffs_io_data *io_data = req->context;
697
698 ENTER();
699
700 INIT_WORK(&io_data->work, ffs_user_copy_worker);
701 schedule_work(&io_data->work);
702}
703
704static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
640{ 705{
641 struct ffs_epfile *epfile = file->private_data; 706 struct ffs_epfile *epfile = file->private_data;
642 struct usb_gadget *gadget = epfile->ffs->gadget; 707 struct usb_gadget *gadget = epfile->ffs->gadget;
@@ -667,7 +732,7 @@ static ssize_t ffs_epfile_io(struct file *file,
667 } 732 }
668 733
669 /* Do we halt? */ 734 /* Do we halt? */
670 halt = !read == !epfile->in; 735 halt = (!io_data->read == !epfile->in);
671 if (halt && epfile->isoc) { 736 if (halt && epfile->isoc) {
672 ret = -EINVAL; 737 ret = -EINVAL;
673 goto error; 738 goto error;
@@ -679,15 +744,32 @@ static ssize_t ffs_epfile_io(struct file *file,
679 * Controller may require buffer size to be aligned to 744 * Controller may require buffer size to be aligned to
680 * maxpacketsize of an out endpoint. 745 * maxpacketsize of an out endpoint.
681 */ 746 */
682 data_len = read ? usb_ep_align_maybe(gadget, ep->ep, len) : len; 747 data_len = io_data->read ?
748 usb_ep_align_maybe(gadget, ep->ep, io_data->len) :
749 io_data->len;
683 750
684 data = kmalloc(data_len, GFP_KERNEL); 751 data = kmalloc(data_len, GFP_KERNEL);
685 if (unlikely(!data)) 752 if (unlikely(!data))
686 return -ENOMEM; 753 return -ENOMEM;
687 754 if (io_data->aio && !io_data->read) {
688 if (!read && unlikely(copy_from_user(data, buf, len))) { 755 int i;
689 ret = -EFAULT; 756 size_t pos = 0;
690 goto error; 757 for (i = 0; i < io_data->nr_segs; i++) {
758 if (unlikely(copy_from_user(&data[pos],
759 io_data->iovec[i].iov_base,
760 io_data->iovec[i].iov_len))) {
761 ret = -EFAULT;
762 goto error;
763 }
764 pos += io_data->iovec[i].iov_len;
765 }
766 } else {
767 if (!io_data->read &&
768 unlikely(__copy_from_user(data, io_data->buf,
769 io_data->len))) {
770 ret = -EFAULT;
771 goto error;
772 }
691 } 773 }
692 } 774 }
693 775
@@ -710,24 +792,52 @@ static ssize_t ffs_epfile_io(struct file *file,
710 ret = -EBADMSG; 792 ret = -EBADMSG;
711 } else { 793 } else {
712 /* Fire the request */ 794 /* Fire the request */
713 DECLARE_COMPLETION_ONSTACK(done); 795 struct usb_request *req;
714 796
715 struct usb_request *req = ep->req; 797 if (io_data->aio) {
716 req->context = &done; 798 req = usb_ep_alloc_request(ep->ep, GFP_KERNEL);
717 req->complete = ffs_epfile_io_complete; 799 if (unlikely(!req))
718 req->buf = data; 800 goto error;
719 req->length = data_len;
720 801
721 ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); 802 req->buf = data;
803 req->length = io_data->len;
722 804
723 spin_unlock_irq(&epfile->ffs->eps_lock); 805 io_data->buf = data;
806 io_data->ep = ep->ep;
807 io_data->req = req;
724 808
725 if (unlikely(ret < 0)) { 809 req->context = io_data;
726 /* nop */ 810 req->complete = ffs_epfile_async_io_complete;
727 } else if (unlikely(wait_for_completion_interruptible(&done))) { 811
728 ret = -EINTR; 812 ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
729 usb_ep_dequeue(ep->ep, req); 813 if (unlikely(ret)) {
814 usb_ep_free_request(ep->ep, req);
815 goto error;
816 }
817 ret = -EIOCBQUEUED;
818
819 spin_unlock_irq(&epfile->ffs->eps_lock);
730 } else { 820 } else {
821 DECLARE_COMPLETION_ONSTACK(done);
822
823 req = ep->req;
824 req->buf = data;
825 req->length = io_data->len;
826
827 req->context = &done;
828 req->complete = ffs_epfile_io_complete;
829
830 ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
831
832 spin_unlock_irq(&epfile->ffs->eps_lock);
833
834 if (unlikely(ret < 0)) {
835 /* nop */
836 } else if (unlikely(
837 wait_for_completion_interruptible(&done))) {
838 ret = -EINTR;
839 usb_ep_dequeue(ep->ep, req);
840 } else {
731 /* 841 /*
732 * XXX We may end up silently droping data here. 842 * XXX We may end up silently droping data here.
733 * Since data_len (i.e. req->length) may be bigger 843 * Since data_len (i.e. req->length) may be bigger
@@ -736,14 +846,18 @@ static ssize_t ffs_epfile_io(struct file *file,
736 * space for. 846 * space for.
737 */ 847 */
738 ret = ep->status; 848 ret = ep->status;
739 if (read && ret > 0 && 849 if (io_data->read && ret > 0 &&
740 unlikely(copy_to_user(buf, data, 850 unlikely(copy_to_user(io_data->buf, data,
741 min_t(size_t, ret, len)))) 851 min_t(size_t, ret,
852 io_data->len))))
742 ret = -EFAULT; 853 ret = -EFAULT;
854 }
855 kfree(data);
743 } 856 }
744 } 857 }
745 858
746 mutex_unlock(&epfile->mutex); 859 mutex_unlock(&epfile->mutex);
860 return ret;
747error: 861error:
748 kfree(data); 862 kfree(data);
749 return ret; 863 return ret;
@@ -753,17 +867,31 @@ static ssize_t
753ffs_epfile_write(struct file *file, const char __user *buf, size_t len, 867ffs_epfile_write(struct file *file, const char __user *buf, size_t len,
754 loff_t *ptr) 868 loff_t *ptr)
755{ 869{
870 struct ffs_io_data io_data;
871
756 ENTER(); 872 ENTER();
757 873
758 return ffs_epfile_io(file, (char __user *)buf, len, 0); 874 io_data.aio = false;
875 io_data.read = false;
876 io_data.buf = (char * __user)buf;
877 io_data.len = len;
878
879 return ffs_epfile_io(file, &io_data);
759} 880}
760 881
761static ssize_t 882static ssize_t
762ffs_epfile_read(struct file *file, char __user *buf, size_t len, loff_t *ptr) 883ffs_epfile_read(struct file *file, char __user *buf, size_t len, loff_t *ptr)
763{ 884{
885 struct ffs_io_data io_data;
886
764 ENTER(); 887 ENTER();
765 888
766 return ffs_epfile_io(file, buf, len, 1); 889 io_data.aio = false;
890 io_data.read = true;
891 io_data.buf = buf;
892 io_data.len = len;
893
894 return ffs_epfile_io(file, &io_data);
767} 895}
768 896
769static int 897static int
@@ -782,6 +910,89 @@ ffs_epfile_open(struct inode *inode, struct file *file)
782 return 0; 910 return 0;
783} 911}
784 912
913static int ffs_aio_cancel(struct kiocb *kiocb)
914{
915 struct ffs_io_data *io_data = kiocb->private;
916 struct ffs_epfile *epfile = kiocb->ki_filp->private_data;
917 int value;
918
919 ENTER();
920
921 spin_lock_irq(&epfile->ffs->eps_lock);
922
923 if (likely(io_data && io_data->ep && io_data->req))
924 value = usb_ep_dequeue(io_data->ep, io_data->req);
925 else
926 value = -EINVAL;
927
928 spin_unlock_irq(&epfile->ffs->eps_lock);
929
930 return value;
931}
932
933static ssize_t ffs_epfile_aio_write(struct kiocb *kiocb,
934 const struct iovec *iovec,
935 unsigned long nr_segs, loff_t loff)
936{
937 struct ffs_io_data *io_data;
938
939 ENTER();
940
941 io_data = kmalloc(sizeof(*io_data), GFP_KERNEL);
942 if (unlikely(!io_data))
943 return -ENOMEM;
944
945 io_data->aio = true;
946 io_data->read = false;
947 io_data->kiocb = kiocb;
948 io_data->iovec = iovec;
949 io_data->nr_segs = nr_segs;
950 io_data->len = kiocb->ki_nbytes;
951 io_data->mm = current->mm;
952
953 kiocb->private = io_data;
954
955 kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
956
957 return ffs_epfile_io(kiocb->ki_filp, io_data);
958}
959
960static ssize_t ffs_epfile_aio_read(struct kiocb *kiocb,
961 const struct iovec *iovec,
962 unsigned long nr_segs, loff_t loff)
963{
964 struct ffs_io_data *io_data;
965 struct iovec *iovec_copy;
966
967 ENTER();
968
969 iovec_copy = kmalloc_array(nr_segs, sizeof(*iovec_copy), GFP_KERNEL);
970 if (unlikely(!iovec_copy))
971 return -ENOMEM;
972
973 memcpy(iovec_copy, iovec, sizeof(struct iovec)*nr_segs);
974
975 io_data = kmalloc(sizeof(*io_data), GFP_KERNEL);
976 if (unlikely(!io_data)) {
977 kfree(iovec_copy);
978 return -ENOMEM;
979 }
980
981 io_data->aio = true;
982 io_data->read = true;
983 io_data->kiocb = kiocb;
984 io_data->iovec = iovec_copy;
985 io_data->nr_segs = nr_segs;
986 io_data->len = kiocb->ki_nbytes;
987 io_data->mm = current->mm;
988
989 kiocb->private = io_data;
990
991 kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
992
993 return ffs_epfile_io(kiocb->ki_filp, io_data);
994}
995
785static int 996static int
786ffs_epfile_release(struct inode *inode, struct file *file) 997ffs_epfile_release(struct inode *inode, struct file *file)
787{ 998{
@@ -838,6 +1049,8 @@ static const struct file_operations ffs_epfile_operations = {
838 .open = ffs_epfile_open, 1049 .open = ffs_epfile_open,
839 .write = ffs_epfile_write, 1050 .write = ffs_epfile_write,
840 .read = ffs_epfile_read, 1051 .read = ffs_epfile_read,
1052 .aio_write = ffs_epfile_aio_write,
1053 .aio_read = ffs_epfile_aio_read,
841 .release = ffs_epfile_release, 1054 .release = ffs_epfile_release,
842 .unlocked_ioctl = ffs_epfile_ioctl, 1055 .unlocked_ioctl = ffs_epfile_ioctl,
843}; 1056};