The basic problem was
mmap_sem (do_mmap()) -> struct_mutex (drm_gem_mmap())
struct_mutex (i915_gem_execbuffer()) -> mmap_sem (copy_from/to_user())

We have plenty of places where we want to hold device state the same
(struct_mutex) while we move a non-trivial amount of data
(copy_from/to_user()), such as i915_gem_pwrite().  Solve this by moving the
one thing that needed struct_mutex with mmap_sem held to using a lock to cover
just those data structures (offset hash and offset manager).

Signed-off-by: Eric Anholt <e...@anholt.net>
---
 drivers/gpu/drm/drm_gem.c       |    8 ++++----
 drivers/gpu/drm/i915/i915_gem.c |    5 +++++
 include/drm/drmP.h              |    1 +
 3 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 6915fb8..7fe91b6 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -97,6 +97,7 @@ drm_gem_init(struct drm_device *dev)
 
        dev->mm_private = mm;
 
+       mutex_init(&mm->offset_mutex);
        if (drm_ht_create(&mm->offset_hash, 19)) {
                drm_free(mm, sizeof(struct drm_gem_mm), DRM_MEM_MM);
                return -ENOMEM;
@@ -485,10 +486,9 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct 
*vma)
        unsigned long prot;
        int ret = 0;
 
-       mutex_lock(&dev->struct_mutex);
-
+       mutex_lock(&mm->offset_mutex);
        if (drm_ht_find_item(&mm->offset_hash, vma->vm_pgoff, &hash)) {
-               mutex_unlock(&dev->struct_mutex);
+               mutex_unlock(&mm->offset_mutex);
                return drm_mmap(filp, vma);
        }
 
@@ -525,7 +525,7 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct 
*vma)
        drm_vm_open_locked(vma);
 
 out_unlock:
-       mutex_unlock(&dev->struct_mutex);
+       mutex_unlock(&mm->offset_mutex);
 
        return ret;
 }
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 6a9e3a8..8754054 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -646,6 +646,7 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj)
        map->size = obj->size;
        map->handle = obj;
 
+       mutex_lock(&mm->offset_mutex);
        /* Get a DRM GEM mmap offset allocated... */
        list->file_offset_node = drm_mm_search_free(&mm->offset_manager,
                                                    obj->size / PAGE_SIZE, 0, 
0);
@@ -671,12 +672,14 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj)
        /* By now we should be all set, any drm_mmap request on the offset
         * below will get to our mmap & fault handler */
        obj_priv->mmap_offset = ((uint64_t) list->hash.key) << PAGE_SHIFT;
+       mutex_unlock(&mm->offset_mutex);
 
        return 0;
 
 out_free_mm:
        drm_mm_put_block(list->file_offset_node);
 out_free_list:
+       mutex_unlock(&mm->offset_mutex);
        drm_free(list->map, sizeof(struct drm_map_list), DRM_MEM_DRIVER);
 
        return ret;
@@ -2896,6 +2899,7 @@ void i915_gem_free_object(struct drm_gem_object *obj)
 
        i915_gem_object_unbind(obj);
 
+       mutex_lock(&mm->offset_mutex);
        list = &obj->map_list;
        drm_ht_remove_item(&mm->offset_hash, &list->hash);
 
@@ -2903,6 +2907,7 @@ void i915_gem_free_object(struct drm_gem_object *obj)
                drm_mm_put_block(list->file_offset_node);
                list->file_offset_node = NULL;
        }
+       mutex_unlock(&mm->offset_mutex);
 
        map = list->map;
        if (map) {
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 8190b9b..daadf06 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -570,6 +570,7 @@ struct drm_ati_pcigart_info {
 struct drm_gem_mm {
        struct drm_mm offset_manager;   /**< Offset mgmt for buffer objects */
        struct drm_open_hash offset_hash; /**< User token hash table for maps */
+       struct mutex offset_mutex; /**< covers offset_manager and offset_hash */
 };
 
 /**
-- 
1.5.6.5


------------------------------------------------------------------------------
Create and Deploy Rich Internet Apps outside the browser with Adobe(R)AIR(TM)
software. With Adobe AIR, Ajax developers can use existing skills and code to
build responsive, highly engaging applications that combine the power of local
resources and data with the reach of the web. Download the Adobe AIR SDK and
Ajax docs to start building applications today-http://p.sf.net/sfu/adobe-com
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to