Commit fda714c2 authored by Thomas Hellstrom's avatar Thomas Hellstrom Committed by Dave Airlie

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: default avatarThomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: default avatarDave Airlie <airlied@linux.ie>
parent 171901d1
...@@ -484,6 +484,7 @@ int drm_release(struct inode *inode, struct file *filp) ...@@ -484,6 +484,7 @@ int drm_release(struct inode *inode, struct file *filp)
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
if (file_priv->is_master) { if (file_priv->is_master) {
struct drm_master *master = file_priv->master;
struct drm_file *temp; struct drm_file *temp;
list_for_each_entry(temp, &dev->filelist, lhead) { list_for_each_entry(temp, &dev->filelist, lhead) {
if ((temp->master == file_priv->master) && if ((temp->master == file_priv->master) &&
...@@ -491,6 +492,19 @@ int drm_release(struct inode *inode, struct file *filp) ...@@ -491,6 +492,19 @@ int drm_release(struct inode *inode, struct file *filp)
temp->authenticated = 0; 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) { if (file_priv->minor->master == file_priv->master) {
/* drop the reference held my the minor */ /* drop the reference held my the minor */
drm_master_put(&file_priv->minor->master); drm_master_put(&file_priv->minor->master);
......
...@@ -80,6 +80,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) ...@@ -80,6 +80,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
__set_current_state(TASK_INTERRUPTIBLE); __set_current_state(TASK_INTERRUPTIBLE);
if (!master->lock.hw_lock) { if (!master->lock.hw_lock) {
/* Device has been unregistered */ /* Device has been unregistered */
send_sig(SIGTERM, current, 0);
ret = -EINTR; ret = -EINTR;
break; break;
} }
......
...@@ -146,14 +146,6 @@ static void drm_master_destroy(struct kref *kref) ...@@ -146,14 +146,6 @@ static void drm_master_destroy(struct kref *kref)
drm_ht_remove(&master->magiclist); 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); drm_free(master, sizeof(*master), DRM_MEM_DRIVER);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment