From 1dcfddf9154bcce3d6e004acee7dd503c27d0f0b Mon Sep 17 00:00:00 2001 From: Jeff Hartmann Date: Wed, 5 Apr 2000 18:48:23 +0000 Subject: [PATCH] Fixed reclaim Oops --- linux-core/i810_dma.c | 12 +++--- linux-core/i810_drv.c | 4 +- linux-core/mga_drv.c | 89 +++++++++++++++++++++++++++++++++++-------- linux/i810_dma.c | 12 +++--- linux/i810_drv.c | 4 +- linux/mga_dma.c | 9 +++-- linux/mga_drv.c | 89 +++++++++++++++++++++++++++++++++++-------- linux/mga_drv.h | 1 + 8 files changed, 170 insertions(+), 50 deletions(-) diff --git a/linux-core/i810_dma.c b/linux-core/i810_dma.c index 30fda5b8..6ac4d2ee 100644 --- a/linux-core/i810_dma.c +++ b/linux-core/i810_dma.c @@ -714,17 +714,17 @@ void i810_reclaim_buffers(drm_device_t *dev, pid_t pid) if (!dma) return; if(dev->dev_private == NULL) return; - + if(dma->buflist == NULL) return; i810_flush_queue(dev); for (i = 0; i < dma->buf_count; i++) { drm_buf_t *buf = dma->buflist[ i ]; drm_i810_buf_priv_t *buf_priv = buf->dev_private; - - if (buf->pid == pid) { - /* Only buffers that need to get reclaimed ever - * get set to free */ - if(buf_priv == NULL) return; + + /* Only buffers that need to get reclaimed ever + * get set to free + */ + if (buf->pid == pid && buf_priv) { cmpxchg(buf_priv->in_use, I810_BUF_USED, I810_BUF_FREE); } diff --git a/linux-core/i810_drv.c b/linux-core/i810_drv.c index d3b35c49..f1c83250 100644 --- a/linux-core/i810_drv.c +++ b/linux-core/i810_drv.c @@ -499,7 +499,7 @@ int i810_release(struct inode *inode, struct file *filp) DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", current->pid, dev->device, dev->open_count); - if (_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) + if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && dev->lock.pid == current->pid) { i810_reclaim_buffers(dev, priv->pid); DRM_ERROR("Process %d dead, freeing lock for context %d\n", @@ -513,7 +513,7 @@ int i810_release(struct inode *inode, struct file *filp) hardware at this point, possibly processed via a callback to the X server. */ - } else { + } else if (dev->lock.hw_lock) { /* The lock is required to reclaim buffers */ DECLARE_WAITQUEUE(entry, current); add_wait_queue(&dev->lock.lock_queue, &entry); diff --git a/linux-core/mga_drv.c b/linux-core/mga_drv.c index 48041354..82dda64d 100644 --- a/linux-core/mga_drv.c +++ b/linux-core/mga_drv.c @@ -510,27 +510,86 @@ int mga_release(struct inode *inode, struct file *filp) drm_device_t *dev = priv->dev; int retcode = 0; - DRM_DEBUG("open_count = %d\n", dev->open_count); - if (!(retcode = drm_release(inode, filp))) { - MOD_DEC_USE_COUNT; - atomic_inc(&dev->total_close); - spin_lock(&dev->count_lock); - if (!--dev->open_count) { - if (atomic_read(&dev->ioctl_count) || dev->blocked) { - DRM_ERROR("Device busy: %d %d\n", - atomic_read(&dev->ioctl_count), - dev->blocked); - spin_unlock(&dev->count_lock); - return -EBUSY; + DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", + current->pid, dev->device, dev->open_count); + + if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) + && dev->lock.pid == current->pid) { + mga_reclaim_buffers(dev, priv->pid); + DRM_ERROR("Process %d dead, freeing lock for context %d\n", + current->pid, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + drm_lock_free(dev, + &dev->lock.hw_lock->lock, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + + /* FIXME: may require heavy-handed reset of + hardware at this point, possibly + processed via a callback to the X + server. */ + } else if (dev->lock.hw_lock) { + /* The lock is required to reclaim buffers */ + DECLARE_WAITQUEUE(entry, current); + add_wait_queue(&dev->lock.lock_queue, &entry); + for (;;) { + if (!dev->lock.hw_lock) { + /* Device has been unregistered */ + retcode = -EINTR; + break; + } + if (drm_lock_take(&dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + dev->lock.pid = priv->pid; + dev->lock.lock_time = jiffies; + atomic_inc(&dev->total_locks); + break; /* Got lock */ + } + /* Contention */ + atomic_inc(&dev->total_sleeps); + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (signal_pending(current)) { + retcode = -ERESTARTSYS; + break; } - spin_unlock(&dev->count_lock); - return mga_takedown(dev); } - spin_unlock(&dev->count_lock); + current->state = TASK_RUNNING; + remove_wait_queue(&dev->lock.lock_queue, &entry); + if(!retcode) { + mga_reclaim_buffers(dev, priv->pid); + drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT); + } } + drm_fasync(-1, filp, 0); + + down(&dev->struct_sem); + if (priv->prev) priv->prev->next = priv->next; + else dev->file_first = priv->next; + if (priv->next) priv->next->prev = priv->prev; + else dev->file_last = priv->prev; + up(&dev->struct_sem); + + drm_free(priv, sizeof(*priv), DRM_MEM_FILES); + MOD_DEC_USE_COUNT; + atomic_inc(&dev->total_close); + spin_lock(&dev->count_lock); + if (!--dev->open_count) { + if (atomic_read(&dev->ioctl_count) || dev->blocked) { + DRM_ERROR("Device busy: %d %d\n", + atomic_read(&dev->ioctl_count), + dev->blocked); + spin_unlock(&dev->count_lock); + return -EBUSY; + } + spin_unlock(&dev->count_lock); + return mga_takedown(dev); + } + spin_unlock(&dev->count_lock); return retcode; } + /* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. */ int mga_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, diff --git a/linux/i810_dma.c b/linux/i810_dma.c index 30fda5b8..6ac4d2ee 100644 --- a/linux/i810_dma.c +++ b/linux/i810_dma.c @@ -714,17 +714,17 @@ void i810_reclaim_buffers(drm_device_t *dev, pid_t pid) if (!dma) return; if(dev->dev_private == NULL) return; - + if(dma->buflist == NULL) return; i810_flush_queue(dev); for (i = 0; i < dma->buf_count; i++) { drm_buf_t *buf = dma->buflist[ i ]; drm_i810_buf_priv_t *buf_priv = buf->dev_private; - - if (buf->pid == pid) { - /* Only buffers that need to get reclaimed ever - * get set to free */ - if(buf_priv == NULL) return; + + /* Only buffers that need to get reclaimed ever + * get set to free + */ + if (buf->pid == pid && buf_priv) { cmpxchg(buf_priv->in_use, I810_BUF_USED, I810_BUF_FREE); } diff --git a/linux/i810_drv.c b/linux/i810_drv.c index d3b35c49..f1c83250 100644 --- a/linux/i810_drv.c +++ b/linux/i810_drv.c @@ -499,7 +499,7 @@ int i810_release(struct inode *inode, struct file *filp) DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", current->pid, dev->device, dev->open_count); - if (_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) + if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && dev->lock.pid == current->pid) { i810_reclaim_buffers(dev, priv->pid); DRM_ERROR("Process %d dead, freeing lock for context %d\n", @@ -513,7 +513,7 @@ int i810_release(struct inode *inode, struct file *filp) hardware at this point, possibly processed via a callback to the X server. */ - } else { + } else if (dev->lock.hw_lock) { /* The lock is required to reclaim buffers */ DECLARE_WAITQUEUE(entry, current); add_wait_queue(&dev->lock.lock_queue, &entry); diff --git a/linux/mga_dma.c b/linux/mga_dma.c index 59cbad6b..371706f4 100644 --- a/linux/mga_dma.c +++ b/linux/mga_dma.c @@ -1016,6 +1016,7 @@ void mga_reclaim_buffers(drm_device_t *dev, pid_t pid) if (!dma) return; if(dev->dev_private == NULL) return; + if(dma->buflist == NULL) return; mga_flush_queue(dev); @@ -1023,10 +1024,10 @@ void mga_reclaim_buffers(drm_device_t *dev, pid_t pid) drm_buf_t *buf = dma->buflist[ i ]; drm_mga_buf_priv_t *buf_priv = buf->dev_private; - if (buf->pid == pid) { - if(buf_priv == NULL) return; - /* Only buffers that need to get reclaimed ever - * get set to free */ + /* Only buffers that need to get reclaimed ever + * get set to free + */ + if (buf->pid == pid && buf_priv) { if(buf_priv->my_freelist->age == MGA_BUF_USED) buf_priv->my_freelist->age = MGA_BUF_FREE; } diff --git a/linux/mga_drv.c b/linux/mga_drv.c index 48041354..82dda64d 100644 --- a/linux/mga_drv.c +++ b/linux/mga_drv.c @@ -510,27 +510,86 @@ int mga_release(struct inode *inode, struct file *filp) drm_device_t *dev = priv->dev; int retcode = 0; - DRM_DEBUG("open_count = %d\n", dev->open_count); - if (!(retcode = drm_release(inode, filp))) { - MOD_DEC_USE_COUNT; - atomic_inc(&dev->total_close); - spin_lock(&dev->count_lock); - if (!--dev->open_count) { - if (atomic_read(&dev->ioctl_count) || dev->blocked) { - DRM_ERROR("Device busy: %d %d\n", - atomic_read(&dev->ioctl_count), - dev->blocked); - spin_unlock(&dev->count_lock); - return -EBUSY; + DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", + current->pid, dev->device, dev->open_count); + + if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) + && dev->lock.pid == current->pid) { + mga_reclaim_buffers(dev, priv->pid); + DRM_ERROR("Process %d dead, freeing lock for context %d\n", + current->pid, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + drm_lock_free(dev, + &dev->lock.hw_lock->lock, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + + /* FIXME: may require heavy-handed reset of + hardware at this point, possibly + processed via a callback to the X + server. */ + } else if (dev->lock.hw_lock) { + /* The lock is required to reclaim buffers */ + DECLARE_WAITQUEUE(entry, current); + add_wait_queue(&dev->lock.lock_queue, &entry); + for (;;) { + if (!dev->lock.hw_lock) { + /* Device has been unregistered */ + retcode = -EINTR; + break; + } + if (drm_lock_take(&dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + dev->lock.pid = priv->pid; + dev->lock.lock_time = jiffies; + atomic_inc(&dev->total_locks); + break; /* Got lock */ + } + /* Contention */ + atomic_inc(&dev->total_sleeps); + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (signal_pending(current)) { + retcode = -ERESTARTSYS; + break; } - spin_unlock(&dev->count_lock); - return mga_takedown(dev); } - spin_unlock(&dev->count_lock); + current->state = TASK_RUNNING; + remove_wait_queue(&dev->lock.lock_queue, &entry); + if(!retcode) { + mga_reclaim_buffers(dev, priv->pid); + drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT); + } } + drm_fasync(-1, filp, 0); + + down(&dev->struct_sem); + if (priv->prev) priv->prev->next = priv->next; + else dev->file_first = priv->next; + if (priv->next) priv->next->prev = priv->prev; + else dev->file_last = priv->prev; + up(&dev->struct_sem); + + drm_free(priv, sizeof(*priv), DRM_MEM_FILES); + MOD_DEC_USE_COUNT; + atomic_inc(&dev->total_close); + spin_lock(&dev->count_lock); + if (!--dev->open_count) { + if (atomic_read(&dev->ioctl_count) || dev->blocked) { + DRM_ERROR("Device busy: %d %d\n", + atomic_read(&dev->ioctl_count), + dev->blocked); + spin_unlock(&dev->count_lock); + return -EBUSY; + } + spin_unlock(&dev->count_lock); + return mga_takedown(dev); + } + spin_unlock(&dev->count_lock); return retcode; } + /* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. */ int mga_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, diff --git a/linux/mga_drv.h b/linux/mga_drv.h index 43deb613..801e707d 100644 --- a/linux/mga_drv.h +++ b/linux/mga_drv.h @@ -131,6 +131,7 @@ extern unsigned int mga_create_sync_tag(drm_device_t *dev); extern drm_buf_t *mga_freelist_get(drm_device_t *dev); extern int mga_freelist_put(drm_device_t *dev, drm_buf_t *buf); extern int mga_advance_primary(drm_device_t *dev); +extern void mga_reclaim_buffers(drm_device_t *dev, pid_t pid); /* mga_bufs.c */