diff options
-rw-r--r-- | drivers/spi/spidev.c | 19 |
1 files changed, 13 insertions, 6 deletions
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 2833fd772a24..e5e0cfed5e3b 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c | |||
@@ -228,7 +228,6 @@ static int spidev_message(struct spidev_data *spidev, | |||
228 | * We walk the array of user-provided transfers, using each one | 228 | * We walk the array of user-provided transfers, using each one |
229 | * to initialize a kernel version of the same transfer. | 229 | * to initialize a kernel version of the same transfer. |
230 | */ | 230 | */ |
231 | mutex_lock(&spidev->buf_lock); | ||
232 | buf = spidev->buffer; | 231 | buf = spidev->buffer; |
233 | total = 0; | 232 | total = 0; |
234 | for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers; | 233 | for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers; |
@@ -296,14 +295,12 @@ static int spidev_message(struct spidev_data *spidev, | |||
296 | status = total; | 295 | status = total; |
297 | 296 | ||
298 | done: | 297 | done: |
299 | mutex_unlock(&spidev->buf_lock); | ||
300 | kfree(k_xfers); | 298 | kfree(k_xfers); |
301 | return status; | 299 | return status; |
302 | } | 300 | } |
303 | 301 | ||
304 | static int | 302 | static long |
305 | spidev_ioctl(struct inode *inode, struct file *filp, | 303 | spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
306 | unsigned int cmd, unsigned long arg) | ||
307 | { | 304 | { |
308 | int err = 0; | 305 | int err = 0; |
309 | int retval = 0; | 306 | int retval = 0; |
@@ -341,6 +338,14 @@ spidev_ioctl(struct inode *inode, struct file *filp, | |||
341 | if (spi == NULL) | 338 | if (spi == NULL) |
342 | return -ESHUTDOWN; | 339 | return -ESHUTDOWN; |
343 | 340 | ||
341 | /* use the buffer lock here for triple duty: | ||
342 | * - prevent I/O (from us) so calling spi_setup() is safe; | ||
343 | * - prevent concurrent SPI_IOC_WR_* from morphing | ||
344 | * data fields while SPI_IOC_RD_* reads them; | ||
345 | * - SPI_IOC_MESSAGE needs the buffer locked "normally". | ||
346 | */ | ||
347 | mutex_lock(&spidev->buf_lock); | ||
348 | |||
344 | switch (cmd) { | 349 | switch (cmd) { |
345 | /* read requests */ | 350 | /* read requests */ |
346 | case SPI_IOC_RD_MODE: | 351 | case SPI_IOC_RD_MODE: |
@@ -456,6 +461,8 @@ spidev_ioctl(struct inode *inode, struct file *filp, | |||
456 | kfree(ioc); | 461 | kfree(ioc); |
457 | break; | 462 | break; |
458 | } | 463 | } |
464 | |||
465 | mutex_unlock(&spidev->buf_lock); | ||
459 | spi_dev_put(spi); | 466 | spi_dev_put(spi); |
460 | return retval; | 467 | return retval; |
461 | } | 468 | } |
@@ -533,7 +540,7 @@ static struct file_operations spidev_fops = { | |||
533 | */ | 540 | */ |
534 | .write = spidev_write, | 541 | .write = spidev_write, |
535 | .read = spidev_read, | 542 | .read = spidev_read, |
536 | .ioctl = spidev_ioctl, | 543 | .unlocked_ioctl = spidev_ioctl, |
537 | .open = spidev_open, | 544 | .open = spidev_open, |
538 | .release = spidev_release, | 545 | .release = spidev_release, |
539 | }; | 546 | }; |