Browse Source

drm: fix quiescent locking

A fix for a locking bug which is triggered when a client tries to lock with
flag DMA_QUIESCENT (typically the X server), but gets interrupted by a signal.
The locking IOCTL should then return an error, but if DMA_QUIESCENT succeeds
it returns 0, and the client falsely thinks it has the lock. In addition
The client waits for DMA_QUISCENT and possibly DMA_READY without having the lock.

From: Thomas Hellstrom
Signed-off-by: Dave Airlie <airlied@linux.ie>
Dave Airlie 19 years ago
parent
commit
cf65f1623d
1 changed files with 11 additions and 5 deletions
  1. 11 5
      drivers/char/drm/drm_lock.c

+ 11 - 5
drivers/char/drm/drm_lock.c

@@ -104,6 +104,10 @@ int drm_lock(struct inode *inode, struct file *filp,
 	__set_current_state(TASK_RUNNING);
 	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(&dev->lock.lock_queue, &entry);
 	remove_wait_queue(&dev->lock.lock_queue, &entry);
 
 
+	DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
+	if (ret)
+		return ret;
+
 	sigemptyset(&dev->sigmask);
 	sigemptyset(&dev->sigmask);
 	sigaddset(&dev->sigmask, SIGSTOP);
 	sigaddset(&dev->sigmask, SIGSTOP);
 	sigaddset(&dev->sigmask, SIGTSTP);
 	sigaddset(&dev->sigmask, SIGTSTP);
@@ -116,8 +120,12 @@ int drm_lock(struct inode *inode, struct file *filp,
 	if (dev->driver->dma_ready && (lock.flags & _DRM_LOCK_READY))
 	if (dev->driver->dma_ready && (lock.flags & _DRM_LOCK_READY))
 		dev->driver->dma_ready(dev);
 		dev->driver->dma_ready(dev);
 
 
-	if (dev->driver->dma_quiescent && (lock.flags & _DRM_LOCK_QUIESCENT))
-		return dev->driver->dma_quiescent(dev);
+	if (dev->driver->dma_quiescent && (lock.flags & _DRM_LOCK_QUIESCENT)) {
+		if (dev->driver->dma_quiescent(dev)) {
+			DRM_DEBUG("%d waiting for DMA quiescent\n", lock.context);
+			return DRM_ERR(EBUSY);
+		}
+	}
 
 
 	/* dev->driver->kernel_context_switch isn't used by any of the x86
 	/* dev->driver->kernel_context_switch isn't used by any of the x86
 	 *  drivers but is used by the Sparc driver.
 	 *  drivers but is used by the Sparc driver.
@@ -128,9 +136,7 @@ int drm_lock(struct inode *inode, struct file *filp,
 		dev->driver->kernel_context_switch(dev, dev->last_context,
 		dev->driver->kernel_context_switch(dev, dev->last_context,
 						   lock.context);
 						   lock.context);
 	}
 	}
-	DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
-
-	return ret;
+	return 0;
 }
 }
 
 
 /**
 /**