diff options
Diffstat (limited to 'drivers/usb/gadget/function/f_fs.c')
| -rw-r--r-- | drivers/usb/gadget/function/f_fs.c | 204 |
1 files changed, 79 insertions, 125 deletions
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index af98b096af2f..175c9956cbe3 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 | } |
| @@ -898,37 +864,6 @@ error: | |||
| 898 | return ret; | 864 | return ret; |
| 899 | } | 865 | } |
| 900 | 866 | ||
| 901 | static ssize_t | ||
| 902 | ffs_epfile_write(struct file *file, const char __user *buf, size_t len, | ||
| 903 | loff_t *ptr) | ||
| 904 | { | ||
| 905 | struct ffs_io_data io_data; | ||
| 906 | |||
| 907 | ENTER(); | ||
| 908 | |||
| 909 | io_data.aio = false; | ||
| 910 | io_data.read = false; | ||
| 911 | io_data.buf = (char * __user)buf; | ||
| 912 | io_data.len = len; | ||
| 913 | |||
| 914 | return ffs_epfile_io(file, &io_data); | ||
| 915 | } | ||
| 916 | |||
| 917 | static ssize_t | ||
| 918 | ffs_epfile_read(struct file *file, char __user *buf, size_t len, loff_t *ptr) | ||
| 919 | { | ||
| 920 | struct ffs_io_data io_data; | ||
| 921 | |||
| 922 | ENTER(); | ||
| 923 | |||
| 924 | io_data.aio = false; | ||
| 925 | io_data.read = true; | ||
| 926 | io_data.buf = buf; | ||
| 927 | io_data.len = len; | ||
| 928 | |||
| 929 | return ffs_epfile_io(file, &io_data); | ||
| 930 | } | ||
| 931 | |||
| 932 | static int | 867 | static int |
| 933 | ffs_epfile_open(struct inode *inode, struct file *file) | 868 | ffs_epfile_open(struct inode *inode, struct file *file) |
| 934 | { | 869 | { |
| @@ -965,67 +900,86 @@ static int ffs_aio_cancel(struct kiocb *kiocb) | |||
| 965 | return value; | 900 | return value; |
| 966 | } | 901 | } |
| 967 | 902 | ||
| 968 | static ssize_t ffs_epfile_aio_write(struct kiocb *kiocb, | 903 | static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from) |
| 969 | const struct iovec *iovec, | ||
| 970 | unsigned long nr_segs, loff_t loff) | ||
| 971 | { | 904 | { |
| 972 | struct ffs_io_data *io_data; | 905 | struct ffs_io_data io_data, *p = &io_data; |
| 906 | ssize_t res; | ||
| 973 | 907 | ||
| 974 | ENTER(); | 908 | ENTER(); |
| 975 | 909 | ||
| 976 | io_data = kmalloc(sizeof(*io_data), GFP_KERNEL); | 910 | if (!is_sync_kiocb(kiocb)) { |
| 977 | if (unlikely(!io_data)) | 911 | p = kmalloc(sizeof(io_data), GFP_KERNEL); |
| 978 | return -ENOMEM; | 912 | if (unlikely(!p)) |
| 913 | return -ENOMEM; | ||
| 914 | p->aio = true; | ||
| 915 | } else { | ||
| 916 | p->aio = false; | ||
| 917 | } | ||
| 979 | 918 | ||
| 980 | io_data->aio = true; | 919 | p->read = false; |
| 981 | io_data->read = false; | 920 | p->kiocb = kiocb; |
| 982 | io_data->kiocb = kiocb; | 921 | p->data = *from; |
| 983 | io_data->iovec = iovec; | 922 | p->mm = current->mm; |
| 984 | io_data->nr_segs = nr_segs; | ||
| 985 | io_data->len = kiocb->ki_nbytes; | ||
| 986 | io_data->mm = current->mm; | ||
| 987 | 923 | ||
| 988 | kiocb->private = io_data; | 924 | kiocb->private = p; |
| 989 | 925 | ||
| 990 | kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); | 926 | kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); |
| 991 | 927 | ||
| 992 | return ffs_epfile_io(kiocb->ki_filp, io_data); | 928 | res = ffs_epfile_io(kiocb->ki_filp, p); |
| 929 | if (res == -EIOCBQUEUED) | ||
| 930 | return res; | ||
| 931 | if (p->aio) | ||
| 932 | kfree(p); | ||
| 933 | else | ||
| 934 | *from = p->data; | ||
| 935 | return res; | ||
| 993 | } | 936 | } |
| 994 | 937 | ||
| 995 | static ssize_t ffs_epfile_aio_read(struct kiocb *kiocb, | 938 | static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to) |
| 996 | const struct iovec *iovec, | ||
| 997 | unsigned long nr_segs, loff_t loff) | ||
| 998 | { | 939 | { |
| 999 | struct ffs_io_data *io_data; | 940 | struct ffs_io_data io_data, *p = &io_data; |
| 1000 | struct iovec *iovec_copy; | 941 | ssize_t res; |
| 1001 | 942 | ||
| 1002 | ENTER(); | 943 | ENTER(); |
| 1003 | 944 | ||
| 1004 | iovec_copy = kmalloc_array(nr_segs, sizeof(*iovec_copy), GFP_KERNEL); | 945 | if (!is_sync_kiocb(kiocb)) { |
| 1005 | if (unlikely(!iovec_copy)) | 946 | p = kmalloc(sizeof(io_data), GFP_KERNEL); |
| 1006 | return -ENOMEM; | 947 | if (unlikely(!p)) |
| 1007 | 948 | return -ENOMEM; | |
| 1008 | memcpy(iovec_copy, iovec, sizeof(struct iovec)*nr_segs); | 949 | p->aio = true; |
| 1009 | 950 | } else { | |
| 1010 | io_data = kmalloc(sizeof(*io_data), GFP_KERNEL); | 951 | p->aio = false; |
| 1011 | if (unlikely(!io_data)) { | ||
| 1012 | kfree(iovec_copy); | ||
| 1013 | return -ENOMEM; | ||
| 1014 | } | 952 | } |
| 1015 | 953 | ||
| 1016 | io_data->aio = true; | 954 | p->read = true; |
| 1017 | io_data->read = true; | 955 | p->kiocb = kiocb; |
| 1018 | io_data->kiocb = kiocb; | 956 | if (p->aio) { |
| 1019 | io_data->iovec = iovec_copy; | 957 | p->to_free = dup_iter(&p->data, to, GFP_KERNEL); |
| 1020 | io_data->nr_segs = nr_segs; | 958 | if (!p->to_free) { |
| 1021 | io_data->len = kiocb->ki_nbytes; | 959 | kfree(p); |
| 1022 | io_data->mm = current->mm; | 960 | return -ENOMEM; |
| 961 | } | ||
| 962 | } else { | ||
| 963 | p->data = *to; | ||
| 964 | p->to_free = NULL; | ||
| 965 | } | ||
| 966 | p->mm = current->mm; | ||
| 1023 | 967 | ||
| 1024 | kiocb->private = io_data; | 968 | kiocb->private = p; |
| 1025 | 969 | ||
| 1026 | kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); | 970 | kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); |
| 1027 | 971 | ||
| 1028 | return ffs_epfile_io(kiocb->ki_filp, io_data); | 972 | res = ffs_epfile_io(kiocb->ki_filp, p); |
| 973 | if (res == -EIOCBQUEUED) | ||
| 974 | return res; | ||
| 975 | |||
| 976 | if (p->aio) { | ||
| 977 | kfree(p->to_free); | ||
| 978 | kfree(p); | ||
| 979 | } else { | ||
| 980 | *to = p->data; | ||
| 981 | } | ||
| 982 | return res; | ||
| 1029 | } | 983 | } |
| 1030 | 984 | ||
| 1031 | static int | 985 | static int |
| @@ -1105,10 +1059,10 @@ static const struct file_operations ffs_epfile_operations = { | |||
| 1105 | .llseek = no_llseek, | 1059 | .llseek = no_llseek, |
| 1106 | 1060 | ||
| 1107 | .open = ffs_epfile_open, | 1061 | .open = ffs_epfile_open, |
| 1108 | .write = ffs_epfile_write, | 1062 | .write = new_sync_write, |
| 1109 | .read = ffs_epfile_read, | 1063 | .read = new_sync_read, |
| 1110 | .aio_write = ffs_epfile_aio_write, | 1064 | .write_iter = ffs_epfile_write_iter, |
| 1111 | .aio_read = ffs_epfile_aio_read, | 1065 | .read_iter = ffs_epfile_read_iter, |
| 1112 | .release = ffs_epfile_release, | 1066 | .release = ffs_epfile_release, |
| 1113 | .unlocked_ioctl = ffs_epfile_ioctl, | 1067 | .unlocked_ioctl = ffs_epfile_ioctl, |
| 1114 | }; | 1068 | }; |
