From 4d77c88e912e5eb9480432af09e950ca8995c253 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 2 Mar 2009 11:10:54 +0100 Subject: drm: Don't return ERESTARTSYS to user-space. That return code is for in-kernel use only. Use EINTR instead. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_lock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_lock.c b/drivers/gpu/drm/drm_lock.c index 46e7b28f070..b03586fdabb 100644 --- a/drivers/gpu/drm/drm_lock.c +++ b/drivers/gpu/drm/drm_lock.c @@ -93,7 +93,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) /* Contention */ schedule(); if (signal_pending(current)) { - ret = -ERESTARTSYS; + ret = -EINTR; break; } } -- cgit v1.2.3 From 171901d15deeef61aa8e1b0d0772404f39691b73 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 2 Mar 2009 11:10:55 +0100 Subject: drm: Wake up all lock waiters when the master disappears. Currently only one waiter is woken up, leaving other waiters hanging waiting for the DRM lock. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_bufs.c | 2 +- drivers/gpu/drm/drm_stub.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index 72c667f9bee..12715d3c078 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c @@ -420,7 +420,7 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map) dev->sigdata.lock = NULL; master->lock.hw_lock = NULL; /* SHM removed */ master->lock.file_priv = NULL; - wake_up_interruptible(&master->lock.lock_queue); + wake_up_interruptible_all(&master->lock.lock_queue); } break; case _DRM_AGP: diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 46bb923b097..7b251dd7081 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -151,7 +151,7 @@ static void drm_master_destroy(struct kref *kref) dev->sigdata.lock = NULL; master->lock.hw_lock = NULL; master->lock.file_priv = NULL; - wake_up_interruptible(&master->lock.lock_queue); + wake_up_interruptible_all(&master->lock.lock_queue); } drm_free(master, sizeof(*master), DRM_MEM_DRIVER); -- cgit v1.2.3 From fda714c29cdf360464059044b221450decb4b913 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 2 Mar 2009 11:10:56 +0100 Subject: drm: Avoid client deadlocks when the master disappears. This is done by 1) Wake up lock waiters when we close the master file descriptor. Not when the master structure is removed, since the latter requires the waiters themselves to release the refcount on the master structure -> Deadlock. 2) Send a SIGTERM to all clients waiting for the lock. Normally these clients will get a SIGPIPE when the X server dies, but clients may also spin trying to grab the DRM lock, without getting any sort of notification. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_fops.c | 14 ++++++++++++++ drivers/gpu/drm/drm_lock.c | 1 + drivers/gpu/drm/drm_stub.c | 8 -------- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 6c020fe5431..f52663ebe01 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -484,6 +484,7 @@ int drm_release(struct inode *inode, struct file *filp) mutex_lock(&dev->struct_mutex); if (file_priv->is_master) { + struct drm_master *master = file_priv->master; struct drm_file *temp; list_for_each_entry(temp, &dev->filelist, lhead) { if ((temp->master == file_priv->master) && @@ -491,6 +492,19 @@ int drm_release(struct inode *inode, struct file *filp) temp->authenticated = 0; } + /** + * Since the master is disappearing, so is the + * possibility to lock. + */ + + if (master->lock.hw_lock) { + if (dev->sigdata.lock == master->lock.hw_lock) + dev->sigdata.lock = NULL; + master->lock.hw_lock = NULL; + master->lock.file_priv = NULL; + wake_up_interruptible_all(&master->lock.lock_queue); + } + if (file_priv->minor->master == file_priv->master) { /* drop the reference held my the minor */ drm_master_put(&file_priv->minor->master); diff --git a/drivers/gpu/drm/drm_lock.c b/drivers/gpu/drm/drm_lock.c index b03586fdabb..e2f70a516c3 100644 --- a/drivers/gpu/drm/drm_lock.c +++ b/drivers/gpu/drm/drm_lock.c @@ -80,6 +80,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) __set_current_state(TASK_INTERRUPTIBLE); if (!master->lock.hw_lock) { /* Device has been unregistered */ + send_sig(SIGTERM, current, 0); ret = -EINTR; break; } diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 7b251dd7081..096e2a37446 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -146,14 +146,6 @@ static void drm_master_destroy(struct kref *kref) drm_ht_remove(&master->magiclist); - if (master->lock.hw_lock) { - if (dev->sigdata.lock == master->lock.hw_lock) - dev->sigdata.lock = NULL; - master->lock.hw_lock = NULL; - master->lock.file_priv = NULL; - wake_up_interruptible_all(&master->lock.lock_queue); - } - drm_free(master, sizeof(*master), DRM_MEM_DRIVER); } -- cgit v1.2.3 From 299eb93c5f651b2bc368ada67d8471e4c575fa21 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 24 Feb 2009 22:14:12 -0800 Subject: drm/i915: Fix use-before-null-check in i915_irq_emit(). This could be triggered by a client asking to emit an irq when the device wasn't initialized. Signed-off-by: Eric Anholt Signed-off-by: Dave Airlie --- drivers/gpu/drm/i915/i915_irq.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 548ff2c6643..87b6b603469 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -383,12 +383,13 @@ int i915_irq_emit(struct drm_device *dev, void *data, drm_i915_irq_emit_t *emit = data; int result; - RING_LOCK_TEST_WITH_RETURN(dev, file_priv); - if (!dev_priv) { DRM_ERROR("called with no initialization\n"); return -EINVAL; } + + RING_LOCK_TEST_WITH_RETURN(dev, file_priv); + mutex_lock(&dev->struct_mutex); result = i915_emit_irq(dev); mutex_unlock(&dev->struct_mutex); -- cgit v1.2.3