diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-15 14:47:27 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-15 14:47:27 -0400 |
commit | 93ff81859733d9697a5a0cc4707e52fb17056abb (patch) | |
tree | 9bca6d06cf5dbd0feee592abecdc6e14f9a5dc92 | |
parent | 89cbec71fead552fdd1fa38c57186669dfbba734 (diff) | |
parent | 3941dae15ed90437396389e8bb7d2d5b3e63ba4a (diff) |
Merge branch 'work.__copy_to_user' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull more __copy_.._user elimination from Al Viro.
* 'work.__copy_to_user' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
drm_dp_aux_dev: switch to read_iter/write_iter
-rw-r--r-- | drivers/gpu/drm/drm_dp_aux_dev.c | 109 |
1 files changed, 46 insertions, 63 deletions
diff --git a/drivers/gpu/drm/drm_dp_aux_dev.c b/drivers/gpu/drm/drm_dp_aux_dev.c index ec1ed94b2390..d34e5096887a 100644 --- a/drivers/gpu/drm/drm_dp_aux_dev.c +++ b/drivers/gpu/drm/drm_dp_aux_dev.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
34 | #include <linux/uaccess.h> | 34 | #include <linux/uaccess.h> |
35 | #include <linux/uio.h> | ||
35 | #include <drm/drm_dp_helper.h> | 36 | #include <drm/drm_dp_helper.h> |
36 | #include <drm/drm_crtc.h> | 37 | #include <drm/drm_crtc.h> |
37 | #include <drm/drmP.h> | 38 | #include <drm/drmP.h> |
@@ -140,101 +141,83 @@ static loff_t auxdev_llseek(struct file *file, loff_t offset, int whence) | |||
140 | return fixed_size_llseek(file, offset, whence, AUX_MAX_OFFSET); | 141 | return fixed_size_llseek(file, offset, whence, AUX_MAX_OFFSET); |
141 | } | 142 | } |
142 | 143 | ||
143 | static ssize_t auxdev_read(struct file *file, char __user *buf, size_t count, | 144 | static ssize_t auxdev_read_iter(struct kiocb *iocb, struct iov_iter *to) |
144 | loff_t *offset) | ||
145 | { | 145 | { |
146 | size_t bytes_pending, num_bytes_processed = 0; | 146 | struct drm_dp_aux_dev *aux_dev = iocb->ki_filp->private_data; |
147 | struct drm_dp_aux_dev *aux_dev = file->private_data; | 147 | loff_t pos = iocb->ki_pos; |
148 | ssize_t res = 0; | 148 | ssize_t res = 0; |
149 | 149 | ||
150 | if (!atomic_inc_not_zero(&aux_dev->usecount)) | 150 | if (!atomic_inc_not_zero(&aux_dev->usecount)) |
151 | return -ENODEV; | 151 | return -ENODEV; |
152 | 152 | ||
153 | bytes_pending = min((loff_t)count, AUX_MAX_OFFSET - (*offset)); | 153 | iov_iter_truncate(to, AUX_MAX_OFFSET - pos); |
154 | |||
155 | if (!access_ok(VERIFY_WRITE, buf, bytes_pending)) { | ||
156 | res = -EFAULT; | ||
157 | goto out; | ||
158 | } | ||
159 | 154 | ||
160 | while (bytes_pending > 0) { | 155 | while (iov_iter_count(to)) { |
161 | uint8_t localbuf[DP_AUX_MAX_PAYLOAD_BYTES]; | 156 | uint8_t buf[DP_AUX_MAX_PAYLOAD_BYTES]; |
162 | ssize_t todo = min_t(size_t, bytes_pending, sizeof(localbuf)); | 157 | ssize_t todo = min(iov_iter_count(to), sizeof(buf)); |
163 | 158 | ||
164 | if (signal_pending(current)) { | 159 | if (signal_pending(current)) { |
165 | res = num_bytes_processed ? | 160 | res = -ERESTARTSYS; |
166 | num_bytes_processed : -ERESTARTSYS; | 161 | break; |
167 | goto out; | ||
168 | } | 162 | } |
169 | 163 | ||
170 | res = drm_dp_dpcd_read(aux_dev->aux, *offset, localbuf, todo); | 164 | res = drm_dp_dpcd_read(aux_dev->aux, pos, buf, todo); |
171 | if (res <= 0) { | 165 | if (res <= 0) |
172 | res = num_bytes_processed ? num_bytes_processed : res; | 166 | break; |
173 | goto out; | 167 | |
174 | } | 168 | if (copy_to_iter(buf, res, to) != res) { |
175 | if (__copy_to_user(buf + num_bytes_processed, localbuf, res)) { | 169 | res = -EFAULT; |
176 | res = num_bytes_processed ? | 170 | break; |
177 | num_bytes_processed : -EFAULT; | ||
178 | goto out; | ||
179 | } | 171 | } |
180 | bytes_pending -= res; | 172 | |
181 | *offset += res; | 173 | pos += res; |
182 | num_bytes_processed += res; | ||
183 | res = num_bytes_processed; | ||
184 | } | 174 | } |
185 | 175 | ||
186 | out: | 176 | if (pos != iocb->ki_pos) |
177 | res = pos - iocb->ki_pos; | ||
178 | iocb->ki_pos = pos; | ||
179 | |||
187 | atomic_dec(&aux_dev->usecount); | 180 | atomic_dec(&aux_dev->usecount); |
188 | wake_up_atomic_t(&aux_dev->usecount); | 181 | wake_up_atomic_t(&aux_dev->usecount); |
189 | return res; | 182 | return res; |
190 | } | 183 | } |
191 | 184 | ||
192 | static ssize_t auxdev_write(struct file *file, const char __user *buf, | 185 | static ssize_t auxdev_write_iter(struct kiocb *iocb, struct iov_iter *from) |
193 | size_t count, loff_t *offset) | ||
194 | { | 186 | { |
195 | size_t bytes_pending, num_bytes_processed = 0; | 187 | struct drm_dp_aux_dev *aux_dev = iocb->ki_filp->private_data; |
196 | struct drm_dp_aux_dev *aux_dev = file->private_data; | 188 | loff_t pos = iocb->ki_pos; |
197 | ssize_t res = 0; | 189 | ssize_t res = 0; |
198 | 190 | ||
199 | if (!atomic_inc_not_zero(&aux_dev->usecount)) | 191 | if (!atomic_inc_not_zero(&aux_dev->usecount)) |
200 | return -ENODEV; | 192 | return -ENODEV; |
201 | 193 | ||
202 | bytes_pending = min((loff_t)count, AUX_MAX_OFFSET - *offset); | 194 | iov_iter_truncate(from, AUX_MAX_OFFSET - pos); |
203 | |||
204 | if (!access_ok(VERIFY_READ, buf, bytes_pending)) { | ||
205 | res = -EFAULT; | ||
206 | goto out; | ||
207 | } | ||
208 | 195 | ||
209 | while (bytes_pending > 0) { | 196 | while (iov_iter_count(from)) { |
210 | uint8_t localbuf[DP_AUX_MAX_PAYLOAD_BYTES]; | 197 | uint8_t buf[DP_AUX_MAX_PAYLOAD_BYTES]; |
211 | ssize_t todo = min_t(size_t, bytes_pending, sizeof(localbuf)); | 198 | ssize_t todo = min(iov_iter_count(from), sizeof(buf)); |
212 | 199 | ||
213 | if (signal_pending(current)) { | 200 | if (signal_pending(current)) { |
214 | res = num_bytes_processed ? | 201 | res = -ERESTARTSYS; |
215 | num_bytes_processed : -ERESTARTSYS; | 202 | break; |
216 | goto out; | ||
217 | } | 203 | } |
218 | 204 | ||
219 | if (__copy_from_user(localbuf, | 205 | if (!copy_from_iter_full(buf, todo, from)) { |
220 | buf + num_bytes_processed, todo)) { | 206 | res = -EFAULT; |
221 | res = num_bytes_processed ? | 207 | break; |
222 | num_bytes_processed : -EFAULT; | ||
223 | goto out; | ||
224 | } | 208 | } |
225 | 209 | ||
226 | res = drm_dp_dpcd_write(aux_dev->aux, *offset, localbuf, todo); | 210 | res = drm_dp_dpcd_write(aux_dev->aux, pos, buf, todo); |
227 | if (res <= 0) { | 211 | if (res <= 0) |
228 | res = num_bytes_processed ? num_bytes_processed : res; | 212 | break; |
229 | goto out; | 213 | |
230 | } | 214 | pos += res; |
231 | bytes_pending -= res; | ||
232 | *offset += res; | ||
233 | num_bytes_processed += res; | ||
234 | res = num_bytes_processed; | ||
235 | } | 215 | } |
236 | 216 | ||
237 | out: | 217 | if (pos != iocb->ki_pos) |
218 | res = pos - iocb->ki_pos; | ||
219 | iocb->ki_pos = pos; | ||
220 | |||
238 | atomic_dec(&aux_dev->usecount); | 221 | atomic_dec(&aux_dev->usecount); |
239 | wake_up_atomic_t(&aux_dev->usecount); | 222 | wake_up_atomic_t(&aux_dev->usecount); |
240 | return res; | 223 | return res; |
@@ -251,8 +234,8 @@ static int auxdev_release(struct inode *inode, struct file *file) | |||
251 | static const struct file_operations auxdev_fops = { | 234 | static const struct file_operations auxdev_fops = { |
252 | .owner = THIS_MODULE, | 235 | .owner = THIS_MODULE, |
253 | .llseek = auxdev_llseek, | 236 | .llseek = auxdev_llseek, |
254 | .read = auxdev_read, | 237 | .read_iter = auxdev_read_iter, |
255 | .write = auxdev_write, | 238 | .write_iter = auxdev_write_iter, |
256 | .open = auxdev_open, | 239 | .open = auxdev_open, |
257 | .release = auxdev_release, | 240 | .release = auxdev_release, |
258 | }; | 241 | }; |