diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-07-30 01:48:31 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-08-22 01:29:52 -0400 |
commit | 929d1af5478dec82903e05aa9662a4ec12ad655b (patch) | |
tree | a794fc36f04e592a56a8857493968ced44eedfae /drivers/input | |
parent | c0bb1f975ca06b17d595937c5e91578b36047039 (diff) |
Input: uinput - take event lock when fetching events from buffer
When fetching events form device's buffer in uinput_read() we need to
take input device's event_lock to avoid racing with new event delivery.
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/misc/uinput.c | 27 |
1 files changed, 24 insertions, 3 deletions
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 736056897e50..1b4ee4a5c49c 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c | |||
@@ -452,9 +452,28 @@ static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t | |||
452 | return retval; | 452 | return retval; |
453 | } | 453 | } |
454 | 454 | ||
455 | static bool uinput_fetch_next_event(struct uinput_device *udev, | ||
456 | struct input_event *event) | ||
457 | { | ||
458 | bool have_event; | ||
459 | |||
460 | spin_lock_irq(&udev->dev->event_lock); | ||
461 | |||
462 | have_event = udev->head != udev->tail; | ||
463 | if (have_event) { | ||
464 | *event = udev->buff[udev->tail]; | ||
465 | udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE; | ||
466 | } | ||
467 | |||
468 | spin_unlock_irq(&udev->dev->event_lock); | ||
469 | |||
470 | return have_event; | ||
471 | } | ||
472 | |||
455 | static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) | 473 | static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) |
456 | { | 474 | { |
457 | struct uinput_device *udev = file->private_data; | 475 | struct uinput_device *udev = file->private_data; |
476 | struct input_event event; | ||
458 | int retval = 0; | 477 | int retval = 0; |
459 | 478 | ||
460 | if (udev->state != UIST_CREATED) | 479 | if (udev->state != UIST_CREATED) |
@@ -477,12 +496,14 @@ static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, | |||
477 | goto out; | 496 | goto out; |
478 | } | 497 | } |
479 | 498 | ||
480 | while (udev->head != udev->tail && retval + input_event_size() <= count) { | 499 | while (retval + input_event_size() <= count && |
481 | if (input_event_to_user(buffer + retval, &udev->buff[udev->tail])) { | 500 | uinput_fetch_next_event(udev, &event)) { |
501 | |||
502 | if (input_event_to_user(buffer + retval, &event)) { | ||
482 | retval = -EFAULT; | 503 | retval = -EFAULT; |
483 | goto out; | 504 | goto out; |
484 | } | 505 | } |
485 | udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE; | 506 | |
486 | retval += input_event_size(); | 507 | retval += input_event_size(); |
487 | } | 508 | } |
488 | 509 | ||