staging:iio:events: Don't copy data to user-space with a locked spinlock.
authorArve Hjønnevåg <arve@android.com>
Tue, 16 Oct 2012 03:58:20 +0000 (20:58 -0700)
committerArve Hjønnevåg <arve@android.com>
Mon, 1 Jul 2013 21:16:11 +0000 (14:16 -0700)
iio_event_chrdev_read would return -EFAULT if the user-space page was
not resident.

Change-Id: I4ac5d3bc791bb503d014d9db576b9d6d522505b2
Signed-off-by: Arve Hjønnevåg <arve@android.com>
drivers/iio/industrialio-event.c

index 10aa9ef86cece1b80fa09c57d2a52e344e4dfc12..145c98617936ac979cf3ff7e417e4f1412a1e289 100644 (file)
@@ -35,6 +35,7 @@
  */
 struct iio_event_interface {
        wait_queue_head_t       wait;
+       struct mutex            read_lock;
        DECLARE_KFIFO(det_events, struct iio_event_data, 16);
 
        struct list_head        dev_attr_list;
@@ -97,14 +98,16 @@ static ssize_t iio_event_chrdev_read(struct file *filep,
        if (count < sizeof(struct iio_event_data))
                return -EINVAL;
 
-       spin_lock_irq(&ev_int->wait.lock);
+       if (mutex_lock_interruptible(&ev_int->read_lock))
+               return -ERESTARTSYS;
+
        if (kfifo_is_empty(&ev_int->det_events)) {
                if (filep->f_flags & O_NONBLOCK) {
                        ret = -EAGAIN;
                        goto error_unlock;
                }
                /* Blocking on device; waiting for something to be there */
-               ret = wait_event_interruptible_locked_irq(ev_int->wait,
+               ret = wait_event_interruptible(ev_int->wait,
                                        !kfifo_is_empty(&ev_int->det_events));
                if (ret)
                        goto error_unlock;
@@ -114,7 +117,7 @@ static ssize_t iio_event_chrdev_read(struct file *filep,
        ret = kfifo_to_user(&ev_int->det_events, buf, count, &copied);
 
 error_unlock:
-       spin_unlock_irq(&ev_int->wait.lock);
+       mutex_unlock(&ev_int->read_lock);
 
        return ret ? ret : copied;
 }
@@ -371,6 +374,7 @@ static void iio_setup_ev_int(struct iio_event_interface *ev_int)
 {
        INIT_KFIFO(ev_int->det_events);
        init_waitqueue_head(&ev_int->wait);
+       mutex_init(&ev_int->read_lock);
 }
 
 static const char *iio_event_group_name = "events";
@@ -434,6 +438,7 @@ int iio_device_register_eventset(struct iio_dev *indio_dev)
 
 error_free_setup_event_lines:
        __iio_remove_event_config_attrs(indio_dev);
+       mutex_destroy(&indio_dev->event_interface->read_lock);
        kfree(indio_dev->event_interface);
 error_ret:
 
@@ -446,5 +451,6 @@ void iio_device_unregister_eventset(struct iio_dev *indio_dev)
                return;
        __iio_remove_event_config_attrs(indio_dev);
        kfree(indio_dev->event_interface->group.attrs);
+       mutex_destroy(&indio_dev->event_interface->read_lock);
        kfree(indio_dev->event_interface);
 }