diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2015-01-31 23:23:35 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-02-17 22:23:29 -0500 |
commit | c993c39b86398c627afda36b45dc92de655e213e (patch) | |
tree | 7135add7da7e2c35dc138f2ef69799554c347292 /drivers/usb | |
parent | de2080d41b5d584205e408d72021f0f335a046fc (diff) |
gadget/function/f_fs.c: use put iov_iter into io_data
both on aio and non-aio sides
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/gadget/function/f_fs.c | 86 |
1 files changed, 25 insertions, 61 deletions
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 3ab34a2075df..98610e4595de 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c | |||
@@ -144,10 +144,9 @@ struct ffs_io_data { | |||
144 | bool read; | 144 | bool read; |
145 | 145 | ||
146 | struct kiocb *kiocb; | 146 | struct kiocb *kiocb; |
147 | const struct iovec *iovec; | 147 | struct iov_iter data; |
148 | unsigned long nr_segs; | 148 | const void *to_free; |
149 | char __user *buf; | 149 | char *buf; |
150 | size_t len; | ||
151 | 150 | ||
152 | struct mm_struct *mm; | 151 | struct mm_struct *mm; |
153 | struct work_struct work; | 152 | struct work_struct work; |
@@ -649,29 +648,10 @@ static void ffs_user_copy_worker(struct work_struct *work) | |||
649 | io_data->req->actual; | 648 | io_data->req->actual; |
650 | 649 | ||
651 | if (io_data->read && ret > 0) { | 650 | if (io_data->read && ret > 0) { |
652 | int i; | ||
653 | size_t pos = 0; | ||
654 | |||
655 | /* | ||
656 | * Since req->length may be bigger than io_data->len (after | ||
657 | * being rounded up to maxpacketsize), we may end up with more | ||
658 | * data then user space has space for. | ||
659 | */ | ||
660 | ret = min_t(int, ret, io_data->len); | ||
661 | |||
662 | use_mm(io_data->mm); | 651 | use_mm(io_data->mm); |
663 | for (i = 0; i < io_data->nr_segs; i++) { | 652 | ret = copy_to_iter(io_data->buf, ret, &io_data->data); |
664 | size_t len = min_t(size_t, ret - pos, | 653 | if (iov_iter_count(&io_data->data)) |
665 | io_data->iovec[i].iov_len); | 654 | ret = -EFAULT; |
666 | if (!len) | ||
667 | break; | ||
668 | if (unlikely(copy_to_user(io_data->iovec[i].iov_base, | ||
669 | &io_data->buf[pos], len))) { | ||
670 | ret = -EFAULT; | ||
671 | break; | ||
672 | } | ||
673 | pos += len; | ||
674 | } | ||
675 | unuse_mm(io_data->mm); | 655 | unuse_mm(io_data->mm); |
676 | } | 656 | } |
677 | 657 | ||
@@ -684,7 +664,7 @@ static void ffs_user_copy_worker(struct work_struct *work) | |||
684 | 664 | ||
685 | io_data->kiocb->private = NULL; | 665 | io_data->kiocb->private = NULL; |
686 | if (io_data->read) | 666 | if (io_data->read) |
687 | kfree(io_data->iovec); | 667 | kfree(io_data->to_free); |
688 | kfree(io_data->buf); | 668 | kfree(io_data->buf); |
689 | kfree(io_data); | 669 | kfree(io_data); |
690 | } | 670 | } |
@@ -743,6 +723,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) | |||
743 | * before the waiting completes, so do not assign to 'gadget' earlier | 723 | * before the waiting completes, so do not assign to 'gadget' earlier |
744 | */ | 724 | */ |
745 | struct usb_gadget *gadget = epfile->ffs->gadget; | 725 | struct usb_gadget *gadget = epfile->ffs->gadget; |
726 | size_t copied; | ||
746 | 727 | ||
747 | spin_lock_irq(&epfile->ffs->eps_lock); | 728 | spin_lock_irq(&epfile->ffs->eps_lock); |
748 | /* In the meantime, endpoint got disabled or changed. */ | 729 | /* In the meantime, endpoint got disabled or changed. */ |
@@ -750,34 +731,21 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) | |||
750 | spin_unlock_irq(&epfile->ffs->eps_lock); | 731 | spin_unlock_irq(&epfile->ffs->eps_lock); |
751 | return -ESHUTDOWN; | 732 | return -ESHUTDOWN; |
752 | } | 733 | } |
734 | data_len = iov_iter_count(&io_data->data); | ||
753 | /* | 735 | /* |
754 | * Controller may require buffer size to be aligned to | 736 | * Controller may require buffer size to be aligned to |
755 | * maxpacketsize of an out endpoint. | 737 | * maxpacketsize of an out endpoint. |
756 | */ | 738 | */ |
757 | data_len = io_data->read ? | 739 | if (io_data->read) |
758 | usb_ep_align_maybe(gadget, ep->ep, io_data->len) : | 740 | data_len = usb_ep_align_maybe(gadget, ep->ep, data_len); |
759 | io_data->len; | ||
760 | spin_unlock_irq(&epfile->ffs->eps_lock); | 741 | spin_unlock_irq(&epfile->ffs->eps_lock); |
761 | 742 | ||
762 | data = kmalloc(data_len, GFP_KERNEL); | 743 | data = kmalloc(data_len, GFP_KERNEL); |
763 | if (unlikely(!data)) | 744 | if (unlikely(!data)) |
764 | return -ENOMEM; | 745 | return -ENOMEM; |
765 | if (io_data->aio && !io_data->read) { | 746 | if (!io_data->read) { |
766 | int i; | 747 | copied = copy_from_iter(data, data_len, &io_data->data); |
767 | size_t pos = 0; | 748 | if (copied != data_len) { |
768 | for (i = 0; i < io_data->nr_segs; i++) { | ||
769 | if (unlikely(copy_from_user(&data[pos], | ||
770 | io_data->iovec[i].iov_base, | ||
771 | io_data->iovec[i].iov_len))) { | ||
772 | ret = -EFAULT; | ||
773 | goto error; | ||
774 | } | ||
775 | pos += io_data->iovec[i].iov_len; | ||
776 | } | ||
777 | } else { | ||
778 | if (!io_data->read && | ||
779 | unlikely(__copy_from_user(data, io_data->buf, | ||
780 | io_data->len))) { | ||
781 | ret = -EFAULT; | 749 | ret = -EFAULT; |
782 | goto error; | 750 | goto error; |
783 | } | 751 | } |
@@ -876,10 +844,8 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) | |||
876 | */ | 844 | */ |
877 | ret = ep->status; | 845 | ret = ep->status; |
878 | if (io_data->read && ret > 0) { | 846 | if (io_data->read && ret > 0) { |
879 | ret = min_t(size_t, ret, io_data->len); | 847 | ret = copy_to_iter(data, ret, &io_data->data); |
880 | 848 | if (unlikely(iov_iter_count(&io_data->data))) | |
881 | if (unlikely(copy_to_user(io_data->buf, | ||
882 | data, ret))) | ||
883 | ret = -EFAULT; | 849 | ret = -EFAULT; |
884 | } | 850 | } |
885 | } | 851 | } |
@@ -903,13 +869,13 @@ ffs_epfile_write(struct file *file, const char __user *buf, size_t len, | |||
903 | loff_t *ptr) | 869 | loff_t *ptr) |
904 | { | 870 | { |
905 | struct ffs_io_data io_data; | 871 | struct ffs_io_data io_data; |
872 | struct iovec iov = {.iov_base = buf, .iov_len = len}; | ||
906 | 873 | ||
907 | ENTER(); | 874 | ENTER(); |
908 | 875 | ||
909 | io_data.aio = false; | 876 | io_data.aio = false; |
910 | io_data.read = false; | 877 | io_data.read = false; |
911 | io_data.buf = (char * __user)buf; | 878 | iov_iter_init(&io_data.data, WRITE, &iov, 1, len); |
912 | io_data.len = len; | ||
913 | 879 | ||
914 | return ffs_epfile_io(file, &io_data); | 880 | return ffs_epfile_io(file, &io_data); |
915 | } | 881 | } |
@@ -918,13 +884,14 @@ static ssize_t | |||
918 | ffs_epfile_read(struct file *file, char __user *buf, size_t len, loff_t *ptr) | 884 | ffs_epfile_read(struct file *file, char __user *buf, size_t len, loff_t *ptr) |
919 | { | 885 | { |
920 | struct ffs_io_data io_data; | 886 | struct ffs_io_data io_data; |
887 | struct iovec iov = {.iov_base = buf, .iov_len = len}; | ||
921 | 888 | ||
922 | ENTER(); | 889 | ENTER(); |
923 | 890 | ||
924 | io_data.aio = false; | 891 | io_data.aio = false; |
925 | io_data.read = true; | 892 | io_data.read = true; |
926 | io_data.buf = buf; | 893 | io_data.to_free = NULL; |
927 | io_data.len = len; | 894 | iov_iter_init(&io_data.data, READ, &iov, 1, len); |
928 | 895 | ||
929 | return ffs_epfile_io(file, &io_data); | 896 | return ffs_epfile_io(file, &io_data); |
930 | } | 897 | } |
@@ -981,9 +948,7 @@ static ssize_t ffs_epfile_aio_write(struct kiocb *kiocb, | |||
981 | io_data->aio = true; | 948 | io_data->aio = true; |
982 | io_data->read = false; | 949 | io_data->read = false; |
983 | io_data->kiocb = kiocb; | 950 | io_data->kiocb = kiocb; |
984 | io_data->iovec = iovec; | 951 | iov_iter_init(&io_data->data, WRITE, iovec, nr_segs, kiocb->ki_nbytes); |
985 | io_data->nr_segs = nr_segs; | ||
986 | io_data->len = kiocb->ki_nbytes; | ||
987 | io_data->mm = current->mm; | 952 | io_data->mm = current->mm; |
988 | 953 | ||
989 | kiocb->private = io_data; | 954 | kiocb->private = io_data; |
@@ -1021,9 +986,8 @@ static ssize_t ffs_epfile_aio_read(struct kiocb *kiocb, | |||
1021 | io_data->aio = true; | 986 | io_data->aio = true; |
1022 | io_data->read = true; | 987 | io_data->read = true; |
1023 | io_data->kiocb = kiocb; | 988 | io_data->kiocb = kiocb; |
1024 | io_data->iovec = iovec_copy; | 989 | io_data->to_free = iovec_copy; |
1025 | io_data->nr_segs = nr_segs; | 990 | iov_iter_init(&io_data->data, READ, iovec_copy, nr_segs, kiocb->ki_nbytes); |
1026 | io_data->len = kiocb->ki_nbytes; | ||
1027 | io_data->mm = current->mm; | 991 | io_data->mm = current->mm; |
1028 | 992 | ||
1029 | kiocb->private = io_data; | 993 | kiocb->private = io_data; |
@@ -1032,8 +996,8 @@ static ssize_t ffs_epfile_aio_read(struct kiocb *kiocb, | |||
1032 | 996 | ||
1033 | res = ffs_epfile_io(kiocb->ki_filp, io_data); | 997 | res = ffs_epfile_io(kiocb->ki_filp, io_data); |
1034 | if (res != -EIOCBQUEUED) { | 998 | if (res != -EIOCBQUEUED) { |
999 | kfree(io_data->to_free); | ||
1035 | kfree(io_data); | 1000 | kfree(io_data); |
1036 | kfree(iovec_copy); | ||
1037 | } | 1001 | } |
1038 | return res; | 1002 | return res; |
1039 | } | 1003 | } |