From 699d4ad53a62e46344b672365dda0be4001edd99 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 20 Apr 2005 18:50:49 +0000 Subject: 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. --- linux-core/drm_lock.c | 15 ++++++++++----- linux/drm_drv.h | 21 ++++++++++++--------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index b9833724..048f084f 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -99,6 +99,9 @@ int drm_lock(struct inode *inode, struct file *filp, current->state = TASK_RUNNING; 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); sigaddset(&dev->sigmask, SIGSTOP); sigaddset(&dev->sigmask, SIGTSTP); @@ -111,8 +114,12 @@ int drm_lock(struct inode *inode, struct file *filp, if (dev->driver->dma_ready && (lock.flags & _DRM_LOCK_READY)) 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); + } + } if (dev->driver->kernel_context_switch && dev->last_context != lock.context) { @@ -120,9 +127,7 @@ int drm_lock(struct inode *inode, struct file *filp, lock.context); } - DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); - - return ret; + return 0; } /** diff --git a/linux/drm_drv.h b/linux/drm_drv.h index 6e8a9ea5..7bb87726 100644 --- a/linux/drm_drv.h +++ b/linux/drm_drv.h @@ -1048,7 +1048,10 @@ int DRM(lock)( struct inode *inode, struct file *filp, } current->state = TASK_RUNNING; 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 ); sigaddset( &dev->sigmask, SIGSTOP ); sigaddset( &dev->sigmask, SIGTSTP ); @@ -1062,19 +1065,19 @@ int DRM(lock)( struct inode *inode, struct file *filp, if (dev->fn_tbl.dma_ready && (lock.flags & _DRM_LOCK_READY)) dev->fn_tbl.dma_ready(dev); - if ( dev->fn_tbl.dma_quiescent && (lock.flags & _DRM_LOCK_QUIESCENT )) - return dev->fn_tbl.dma_quiescent(dev); - - + if (dev->fn_tbl.dma_quiescent && (lock.flags & _DRM_LOCK_QUIESCENT)) { + if (dev->fn_tbl.dma_quiescent(dev)) { + DRM_DEBUG( "%d waiting for DMA quiescent\n", lock.context); + return DRM_ERR(EBUSY); + } + } + if ( dev->fn_tbl.kernel_context_switch && dev->last_context != lock.context ) { dev->fn_tbl.kernel_context_switch(dev, dev->last_context, lock.context); } - - DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" ); - - return ret; + return 0; } /** -- cgit v1.2.3