summaryrefslogtreecommitdiffstats
path: root/drivers/char/drm
diff options
context:
space:
mode:
authorThomas Hellstrom <thomas-at-tungstengraphics-dot-com>2007-03-24 17:52:49 +1100
committerDave Airlie <airlied@linux.ie>2007-03-24 18:00:22 +1100
commitd7d8aac79dc38cbdef83b774e49bafdae9918137 (patch)
tree45eb61fb816117ac0913fbe63d2e430bbfaa65a2 /drivers/char/drm
parent040ac32048d5efabd557c1e0a6ab8aec2c710c56 (diff)
drm: fix up mmap locking in preparation for ttm changes
This change is needed to protect againt disappearing maps which aren't common. The map lists are protected using sturct_mutex but drm_mmap never locked it. Signed-off-by: Dave Airlie <airlied@linux.ie>
Diffstat (limited to 'drivers/char/drm')
-rw-r--r--drivers/char/drm/drm_vm.c35
1 files changed, 26 insertions, 9 deletions
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index 239ac33a6e1..f7d4e29d507 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -413,7 +413,7 @@ static struct vm_operations_struct drm_vm_sg_ops = {
* Create a new drm_vma_entry structure as the \p vma private data entry and
* add it to drm_device::vmalist.
*/
-static void drm_vm_open(struct vm_area_struct *vma)
+static void drm_vm_open_locked(struct vm_area_struct *vma)
{
drm_file_t *priv = vma->vm_file->private_data;
drm_device_t *dev = priv->head->dev;
@@ -425,15 +425,23 @@ static void drm_vm_open(struct vm_area_struct *vma)
vma_entry = drm_alloc(sizeof(*vma_entry), DRM_MEM_VMAS);
if (vma_entry) {
- mutex_lock(&dev->struct_mutex);
vma_entry->vma = vma;
vma_entry->next = dev->vmalist;
vma_entry->pid = current->pid;
dev->vmalist = vma_entry;
- mutex_unlock(&dev->struct_mutex);
}
}
+static void drm_vm_open(struct vm_area_struct *vma)
+{
+ drm_file_t *priv = vma->vm_file->private_data;
+ drm_device_t *dev = priv->head->dev;
+
+ mutex_lock(&dev->struct_mutex);
+ drm_vm_open_locked(vma);
+ mutex_unlock(&dev->struct_mutex);
+}
+
/**
* \c close method for all virtual memory types.
*
@@ -484,7 +492,6 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
drm_device_dma_t *dma;
unsigned long length = vma->vm_end - vma->vm_start;
- lock_kernel();
dev = priv->head->dev;
dma = dev->dma;
DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
@@ -492,10 +499,8 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
/* Length must match exact page count */
if (!dma || (length >> PAGE_SHIFT) != dma->page_count) {
- unlock_kernel();
return -EINVAL;
}
- unlock_kernel();
if (!capable(CAP_SYS_ADMIN) &&
(dma->flags & _DRM_DMA_USE_PCI_RO)) {
@@ -518,7 +523,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
vma->vm_flags |= VM_RESERVED; /* Don't swap */
vma->vm_file = filp; /* Needed for drm_vm_open() */
- drm_vm_open(vma);
+ drm_vm_open_locked(vma);
return 0;
}
@@ -553,7 +558,7 @@ EXPORT_SYMBOL(drm_core_get_reg_ofs);
* according to the mapping type and remaps the pages. Finally sets the file
* pointer and calls vm_open().
*/
-int drm_mmap(struct file *filp, struct vm_area_struct *vma)
+static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
{
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->head->dev;
@@ -667,8 +672,20 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
vma->vm_flags |= VM_RESERVED; /* Don't swap */
vma->vm_file = filp; /* Needed for drm_vm_open() */
- drm_vm_open(vma);
+ drm_vm_open_locked(vma);
return 0;
}
+int drm_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->head->dev;
+ int ret;
+
+ mutex_lock(&dev->struct_mutex);
+ ret = drm_mmap_locked(filp, vma);
+ mutex_unlock(&dev->struct_mutex);
+
+ return ret;
+}
EXPORT_SYMBOL(drm_mmap);