[PATCH] drm: fix drm_read() returning 0
Dave Airlie
airlied at gmail.com
Thu Jul 19 19:17:16 PDT 2012
On Fri, Jun 15, 2012 at 6:21 AM, David Herrmann
<dh.herrmann at googlemail.com> wrote:
> Imagine two threads read()'ing on the drm file and both are asleep waiting
> for events in drm_read(). If a single event occurs, both threads are woken
> up and start fetching the event. One thread will get it and return, the
> other thread will notice that there is no further event and return 0 to
> user-space.
>
> We can avoid this by waiting for events until we got at least one event or
> an error occurred.
Anyone understand this code enough to review/ack this? krh gets
explicit prodding.
logic look right to me,
Dave.
>
> Signed-off-by: David Herrmann <dh.herrmann at googlemail.com>
> ---
> The patch might look a bit scary but it adds only a single do { } while(!total);
> around the whole block.
>
> drivers/gpu/drm/drm_fops.c | 33 +++++++++++++++++----------------
> 1 file changed, 17 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
> index 123de28..6e7d349 100644
> --- a/drivers/gpu/drm/drm_fops.c
> +++ b/drivers/gpu/drm/drm_fops.c
> @@ -635,25 +635,26 @@ ssize_t drm_read(struct file *filp, char __user *buffer,
> {
> struct drm_file *file_priv = filp->private_data;
> struct drm_pending_event *e;
> - size_t total;
> + size_t total = 0;
> ssize_t ret;
>
> - ret = wait_event_interruptible(file_priv->event_wait,
> - !list_empty(&file_priv->event_list));
> - if (ret < 0)
> - return ret;
> -
> - total = 0;
> - while (drm_dequeue_event(file_priv, total, count, &e)) {
> - if (copy_to_user(buffer + total,
> - e->event, e->event->length)) {
> - total = -EFAULT;
> - break;
> - }
> + do {
> + ret = wait_event_interruptible(file_priv->event_wait,
> + !list_empty(&file_priv->event_list));
> + if (ret < 0)
> + return ret;
>
> - total += e->event->length;
> - e->destroy(e);
> - }
> + while (drm_dequeue_event(file_priv, total, count, &e)) {
> + if (copy_to_user(buffer + total,
> + e->event, e->event->length)) {
> + total = -EFAULT;
> + break;
> + }
> +
> + total += e->event->length;
> + e->destroy(e);
> + }
> + } while (!total);
>
> return total;
> }
> --
> 1.7.10.4
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
More information about the dri-devel
mailing list