diff options
Diffstat (limited to 'drivers/gpu/drm/drm_fops.c')
-rw-r--r-- | drivers/gpu/drm/drm_fops.c | 18 |
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; } |