diff options
author | Thomas Hellstrom <thellstrom-at-vmware-dot-com> | 2009-02-05 15:30:38 +0100 |
---|---|---|
committer | Thomas Hellstrom <thellstrom-at-vmware-dot-com> | 2009-02-05 15:33:51 +0100 |
commit | 72ee1c68baa24ea612af2fc2d6a53a8b38668c9a (patch) | |
tree | 186f92dfdfec23dd4b0b2108b9d4b06a8783b453 | |
parent | b909e98de73cfd4903554f26590f70a224508198 (diff) |
drm_core: Avoid dri client deadlocks when master disappears by 1) Notify lock waiters when we close the master file descriptor. Not when the master structure is removed. 2) Send a SIGTERM to all clients waiting for the lock.
-rw-r--r-- | linux-core/drm_fops.c | 15 | ||||
-rw-r--r-- | linux-core/drm_lock.c | 1 | ||||
-rw-r--r-- | linux-core/drm_stub.c | 8 |
3 files changed, 15 insertions, 9 deletions
diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index 1f3c0398..40dd7b27 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -414,7 +414,6 @@ int drm_release(struct inode *inode, struct file *filp) } - if (drm_i_have_hw_lock(dev, file_priv)) { DRM_DEBUG("File %p released, freeing lock for context %d\n", filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); @@ -463,6 +462,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) && @@ -470,6 +470,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/linux-core/drm_lock.c b/linux-core/drm_lock.c index df0a8d3b..dbfe9c6c 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/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/linux-core/drm_stub.c b/linux-core/drm_stub.c index 42bb1944..18c905fd 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -139,14 +139,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; /* SHM removed */ - master->lock.file_priv = NULL; - wake_up_interruptible_all(&master->lock.lock_queue); - } - drm_free(master, sizeof(*master), DRM_MEM_DRIVER); } |