aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2015-11-25 09:39:03 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2015-11-26 09:21:27 -0500
commit9b2c0b7fb4ce79566d830d03ce7aa11cccc39f97 (patch)
tree9d5e5e095ceb0b817f7666412a9772caacb46d57
parent83eb64c85b80959549c114365016276f318afeb2 (diff)
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>
-rw-r--r--drivers/gpu/drm/drm_fops.c18
-rw-r--r--include/drm/drmP.h2
2 files changed, 15 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)
172 init_waitqueue_head(&priv->event_wait); 172 init_waitqueue_head(&priv->event_wait);
173 priv->event_space = 4096; /* set aside 4k for event buffer */ 173 priv->event_space = 4096; /* set aside 4k for event buffer */
174 174
175 mutex_init(&priv->event_read_lock);
176
175 if (drm_core_check_feature(dev, DRIVER_GEM)) 177 if (drm_core_check_feature(dev, DRIVER_GEM))
176 drm_gem_open(dev, priv); 178 drm_gem_open(dev, priv);
177 179
@@ -483,11 +485,15 @@ ssize_t drm_read(struct file *filp, char __user *buffer,
483{ 485{
484 struct drm_file *file_priv = filp->private_data; 486 struct drm_file *file_priv = filp->private_data;
485 struct drm_device *dev = file_priv->minor->dev; 487 struct drm_device *dev = file_priv->minor->dev;
486 ssize_t ret = 0; 488 ssize_t ret;
487 489
488 if (!access_ok(VERIFY_WRITE, buffer, count)) 490 if (!access_ok(VERIFY_WRITE, buffer, count))
489 return -EFAULT; 491 return -EFAULT;
490 492
493 ret = mutex_lock_interruptible(&file_priv->event_read_lock);
494 if (ret)
495 return ret;
496
491 for (;;) { 497 for (;;) {
492 struct drm_pending_event *e = NULL; 498 struct drm_pending_event *e = NULL;
493 499
@@ -509,12 +515,13 @@ ssize_t drm_read(struct file *filp, char __user *buffer,
509 break; 515 break;
510 } 516 }
511 517
518 mutex_unlock(&file_priv->event_read_lock);
512 ret = wait_event_interruptible(file_priv->event_wait, 519 ret = wait_event_interruptible(file_priv->event_wait,
513 !list_empty(&file_priv->event_list)); 520 !list_empty(&file_priv->event_list));
514 if (ret < 0) 521 if (ret >= 0)
515 break; 522 ret = mutex_lock_interruptible(&file_priv->event_read_lock);
516 523 if (ret)
517 ret = 0; 524 return ret;
518 } else { 525 } else {
519 unsigned length = e->event->length; 526 unsigned length = e->event->length;
520 527
@@ -537,6 +544,7 @@ put_back_event:
537 e->destroy(e); 544 e->destroy(e);
538 } 545 }
539 } 546 }
547 mutex_unlock(&file_priv->event_read_lock);
540 548
541 return ret; 549 return ret;
542} 550}
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 30d4a5a495e2..8e1df1f7057c 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -344,6 +344,8 @@ struct drm_file {
344 struct list_head event_list; 344 struct list_head event_list;
345 int event_space; 345 int event_space;
346 346
347 struct mutex event_read_lock;
348
347 struct drm_prime_file_private prime; 349 struct drm_prime_file_private prime;
348}; 350};
349 351