summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_fops.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2015-11-25 14:39:03 +0000
committerDaniel Vetter <daniel.vetter@ffwll.ch>2015-11-26 15:21:27 +0100
commit9b2c0b7fb4ce79566d830d03ce7aa11cccc39f97 (patch)
tree9d5e5e095ceb0b817f7666412a9772caacb46d57 /drivers/gpu/drm/drm_fops.c
parent83eb64c85b80959549c114365016276f318afeb2 (diff)
downloadlinux-9b2c0b7fb4ce79566d830d03ce7aa11cccc39f97.tar.bz2
drm: Serialise multiple event readers
The previous patch reintroduced a race condition whereby a failure in one reader may allow a second reader to see out-of-order events. Introduce a mutex to serialise readers so that an event is completed in its entirety before another reader may process an event. The two readers may race against each other, but the events each retrieves are in the correct order. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Thomas Hellstrom <thellstrom@vmware.com> Cc: Takashi Iwai <tiwai@suse.de> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Link: http://patchwork.freedesktop.org/patch/msgid/1448462343-2072-2-git-send-email-chris@chris-wilson.co.uk Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/drm_fops.c')
-rw-r--r--drivers/gpu/drm/drm_fops.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index eb8702d39e7d..81df9ae95e2e 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -172,6 +172,8 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor)
init_waitqueue_head(&priv->event_wait);
priv->event_space = 4096; /* set aside 4k for event buffer */
+ mutex_init(&priv->event_read_lock);
+
if (drm_core_check_feature(dev, DRIVER_GEM))
drm_gem_open(dev, priv);
@@ -483,11 +485,15 @@ ssize_t drm_read(struct file *filp, char __user *buffer,
{
struct drm_file *file_priv = filp->private_data;
struct drm_device *dev = file_priv->minor->dev;
- ssize_t ret = 0;
+ ssize_t ret;
if (!access_ok(VERIFY_WRITE, buffer, count))
return -EFAULT;
+ ret = mutex_lock_interruptible(&file_priv->event_read_lock);
+ if (ret)
+ return ret;
+
for (;;) {
struct drm_pending_event *e = NULL;
@@ -509,12 +515,13 @@ ssize_t drm_read(struct file *filp, char __user *buffer,
break;
}
+ mutex_unlock(&file_priv->event_read_lock);
ret = wait_event_interruptible(file_priv->event_wait,
!list_empty(&file_priv->event_list));
- if (ret < 0)
- break;
-
- ret = 0;
+ if (ret >= 0)
+ ret = mutex_lock_interruptible(&file_priv->event_read_lock);
+ if (ret)
+ return ret;
} else {
unsigned length = e->event->length;
@@ -537,6 +544,7 @@ put_back_event:
e->destroy(e);
}
}
+ mutex_unlock(&file_priv->event_read_lock);
return ret;
}