diff options
Diffstat (limited to 'drivers/usb/gadget/function/f_fs.c')
-rw-r--r-- | drivers/usb/gadget/function/f_fs.c | 107 |
1 files changed, 92 insertions, 15 deletions
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 54ad100af35b..e40d47d47d82 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c | |||
@@ -136,8 +136,60 @@ struct ffs_epfile { | |||
136 | /* | 136 | /* |
137 | * Buffer for holding data from partial reads which may happen since | 137 | * Buffer for holding data from partial reads which may happen since |
138 | * we’re rounding user read requests to a multiple of a max packet size. | 138 | * we’re rounding user read requests to a multiple of a max packet size. |
139 | * | ||
140 | * The pointer is initialised with NULL value and may be set by | ||
141 | * __ffs_epfile_read_data function to point to a temporary buffer. | ||
142 | * | ||
143 | * In normal operation, calls to __ffs_epfile_read_buffered will consume | ||
144 | * data from said buffer and eventually free it. Importantly, while the | ||
145 | * function is using the buffer, it sets the pointer to NULL. This is | ||
146 | * all right since __ffs_epfile_read_data and __ffs_epfile_read_buffered | ||
147 | * can never run concurrently (they are synchronised by epfile->mutex) | ||
148 | * so the latter will not assign a new value to the pointer. | ||
149 | * | ||
150 | * Meanwhile ffs_func_eps_disable frees the buffer (if the pointer is | ||
151 | * valid) and sets the pointer to READ_BUFFER_DROP value. This special | ||
152 | * value is crux of the synchronisation between ffs_func_eps_disable and | ||
153 | * __ffs_epfile_read_data. | ||
154 | * | ||
155 | * Once __ffs_epfile_read_data is about to finish it will try to set the | ||
156 | * pointer back to its old value (as described above), but seeing as the | ||
157 | * pointer is not-NULL (namely READ_BUFFER_DROP) it will instead free | ||
158 | * the buffer. | ||
159 | * | ||
160 | * == State transitions == | ||
161 | * | ||
162 | * • ptr == NULL: (initial state) | ||
163 | * ◦ __ffs_epfile_read_buffer_free: go to ptr == DROP | ||
164 | * ◦ __ffs_epfile_read_buffered: nop | ||
165 | * ◦ __ffs_epfile_read_data allocates temp buffer: go to ptr == buf | ||
166 | * ◦ reading finishes: n/a, not in ‘and reading’ state | ||
167 | * • ptr == DROP: | ||
168 | * ◦ __ffs_epfile_read_buffer_free: nop | ||
169 | * ◦ __ffs_epfile_read_buffered: go to ptr == NULL | ||
170 | * ◦ __ffs_epfile_read_data allocates temp buffer: free buf, nop | ||
171 | * ◦ reading finishes: n/a, not in ‘and reading’ state | ||
172 | * • ptr == buf: | ||
173 | * ◦ __ffs_epfile_read_buffer_free: free buf, go to ptr == DROP | ||
174 | * ◦ __ffs_epfile_read_buffered: go to ptr == NULL and reading | ||
175 | * ◦ __ffs_epfile_read_data: n/a, __ffs_epfile_read_buffered | ||
176 | * is always called first | ||
177 | * ◦ reading finishes: n/a, not in ‘and reading’ state | ||
178 | * • ptr == NULL and reading: | ||
179 | * ◦ __ffs_epfile_read_buffer_free: go to ptr == DROP and reading | ||
180 | * ◦ __ffs_epfile_read_buffered: n/a, mutex is held | ||
181 | * ◦ __ffs_epfile_read_data: n/a, mutex is held | ||
182 | * ◦ reading finishes and … | ||
183 | * … all data read: free buf, go to ptr == NULL | ||
184 | * … otherwise: go to ptr == buf and reading | ||
185 | * • ptr == DROP and reading: | ||
186 | * ◦ __ffs_epfile_read_buffer_free: nop | ||
187 | * ◦ __ffs_epfile_read_buffered: n/a, mutex is held | ||
188 | * ◦ __ffs_epfile_read_data: n/a, mutex is held | ||
189 | * ◦ reading finishes: free buf, go to ptr == DROP | ||
139 | */ | 190 | */ |
140 | struct ffs_buffer *read_buffer; /* P: epfile->mutex */ | 191 | struct ffs_buffer *read_buffer; |
192 | #define READ_BUFFER_DROP ((struct ffs_buffer *)ERR_PTR(-ESHUTDOWN)) | ||
141 | 193 | ||
142 | char name[5]; | 194 | char name[5]; |
143 | 195 | ||
@@ -736,25 +788,47 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep, | |||
736 | schedule_work(&io_data->work); | 788 | schedule_work(&io_data->work); |
737 | } | 789 | } |
738 | 790 | ||
791 | static void __ffs_epfile_read_buffer_free(struct ffs_epfile *epfile) | ||
792 | { | ||
793 | /* | ||
794 | * See comment in struct ffs_epfile for full read_buffer pointer | ||
795 | * synchronisation story. | ||
796 | */ | ||
797 | struct ffs_buffer *buf = xchg(&epfile->read_buffer, READ_BUFFER_DROP); | ||
798 | if (buf && buf != READ_BUFFER_DROP) | ||
799 | kfree(buf); | ||
800 | } | ||
801 | |||
739 | /* Assumes epfile->mutex is held. */ | 802 | /* Assumes epfile->mutex is held. */ |
740 | static ssize_t __ffs_epfile_read_buffered(struct ffs_epfile *epfile, | 803 | static ssize_t __ffs_epfile_read_buffered(struct ffs_epfile *epfile, |
741 | struct iov_iter *iter) | 804 | struct iov_iter *iter) |
742 | { | 805 | { |
743 | struct ffs_buffer *buf = epfile->read_buffer; | 806 | /* |
807 | * Null out epfile->read_buffer so ffs_func_eps_disable does not free | ||
808 | * the buffer while we are using it. See comment in struct ffs_epfile | ||
809 | * for full read_buffer pointer synchronisation story. | ||
810 | */ | ||
811 | struct ffs_buffer *buf = xchg(&epfile->read_buffer, NULL); | ||
744 | ssize_t ret; | 812 | ssize_t ret; |
745 | if (!buf) | 813 | if (!buf || buf == READ_BUFFER_DROP) |
746 | return 0; | 814 | return 0; |
747 | 815 | ||
748 | ret = copy_to_iter(buf->data, buf->length, iter); | 816 | ret = copy_to_iter(buf->data, buf->length, iter); |
749 | if (buf->length == ret) { | 817 | if (buf->length == ret) { |
750 | kfree(buf); | 818 | kfree(buf); |
751 | epfile->read_buffer = NULL; | 819 | return ret; |
752 | } else if (unlikely(iov_iter_count(iter))) { | 820 | } |
821 | |||
822 | if (unlikely(iov_iter_count(iter))) { | ||
753 | ret = -EFAULT; | 823 | ret = -EFAULT; |
754 | } else { | 824 | } else { |
755 | buf->length -= ret; | 825 | buf->length -= ret; |
756 | buf->data += ret; | 826 | buf->data += ret; |
757 | } | 827 | } |
828 | |||
829 | if (cmpxchg(&epfile->read_buffer, NULL, buf)) | ||
830 | kfree(buf); | ||
831 | |||
758 | return ret; | 832 | return ret; |
759 | } | 833 | } |
760 | 834 | ||
@@ -783,7 +857,15 @@ static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile, | |||
783 | buf->length = data_len; | 857 | buf->length = data_len; |
784 | buf->data = buf->storage; | 858 | buf->data = buf->storage; |
785 | memcpy(buf->storage, data + ret, data_len); | 859 | memcpy(buf->storage, data + ret, data_len); |
786 | epfile->read_buffer = buf; | 860 | |
861 | /* | ||
862 | * At this point read_buffer is NULL or READ_BUFFER_DROP (if | ||
863 | * ffs_func_eps_disable has been called in the meanwhile). See comment | ||
864 | * in struct ffs_epfile for full read_buffer pointer synchronisation | ||
865 | * story. | ||
866 | */ | ||
867 | if (unlikely(cmpxchg(&epfile->read_buffer, NULL, buf))) | ||
868 | kfree(buf); | ||
787 | 869 | ||
788 | return ret; | 870 | return ret; |
789 | } | 871 | } |
@@ -1097,8 +1179,7 @@ ffs_epfile_release(struct inode *inode, struct file *file) | |||
1097 | 1179 | ||
1098 | ENTER(); | 1180 | ENTER(); |
1099 | 1181 | ||
1100 | kfree(epfile->read_buffer); | 1182 | __ffs_epfile_read_buffer_free(epfile); |
1101 | epfile->read_buffer = NULL; | ||
1102 | ffs_data_closed(epfile->ffs); | 1183 | ffs_data_closed(epfile->ffs); |
1103 | 1184 | ||
1104 | return 0; | 1185 | return 0; |
@@ -1724,24 +1805,20 @@ static void ffs_func_eps_disable(struct ffs_function *func) | |||
1724 | unsigned count = func->ffs->eps_count; | 1805 | unsigned count = func->ffs->eps_count; |
1725 | unsigned long flags; | 1806 | unsigned long flags; |
1726 | 1807 | ||
1808 | spin_lock_irqsave(&func->ffs->eps_lock, flags); | ||
1727 | do { | 1809 | do { |
1728 | if (epfile) | ||
1729 | mutex_lock(&epfile->mutex); | ||
1730 | spin_lock_irqsave(&func->ffs->eps_lock, flags); | ||
1731 | /* pending requests get nuked */ | 1810 | /* pending requests get nuked */ |
1732 | if (likely(ep->ep)) | 1811 | if (likely(ep->ep)) |
1733 | usb_ep_disable(ep->ep); | 1812 | usb_ep_disable(ep->ep); |
1734 | ++ep; | 1813 | ++ep; |
1735 | spin_unlock_irqrestore(&func->ffs->eps_lock, flags); | ||
1736 | 1814 | ||
1737 | if (epfile) { | 1815 | if (epfile) { |
1738 | epfile->ep = NULL; | 1816 | epfile->ep = NULL; |
1739 | kfree(epfile->read_buffer); | 1817 | __ffs_epfile_read_buffer_free(epfile); |
1740 | epfile->read_buffer = NULL; | ||
1741 | mutex_unlock(&epfile->mutex); | ||
1742 | ++epfile; | 1818 | ++epfile; |
1743 | } | 1819 | } |
1744 | } while (--count); | 1820 | } while (--count); |
1821 | spin_unlock_irqrestore(&func->ffs->eps_lock, flags); | ||
1745 | } | 1822 | } |
1746 | 1823 | ||
1747 | static int ffs_func_eps_enable(struct ffs_function *func) | 1824 | static int ffs_func_eps_enable(struct ffs_function *func) |