aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2009-02-11 17:01:46 -0500
committerDave Airlie <airlied@redhat.com>2009-02-19 21:21:13 -0500
commitab00b3e5210954cbaff9207db874a9f03197e3ba (patch)
tree68359cf341eb58cefa9d8c91200e6d137ff2007c
parent496818f08a78476abdb307e241911536221239fc (diff)
drm/i915: Keep refs on the object over the lifetime of vmas for GTT mmap.
This fixes potential fault at fault time if the object was unreferenced while the mapping still existed. Now, while the mmap_offset only lives for the lifetime of the object, the object also stays alive while a vma exists that needs it. Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Eric Anholt <eric@anholt.net> Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/drm_gem.c28
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c2
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c43
-rw-r--r--include/drm/drmP.h2
4 files changed, 57 insertions, 18 deletions
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 5dad6b9d0dec..88d3368ffddd 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -463,6 +463,26 @@ drm_gem_object_handle_free(struct kref *kref)
463} 463}
464EXPORT_SYMBOL(drm_gem_object_handle_free); 464EXPORT_SYMBOL(drm_gem_object_handle_free);
465 465
466void drm_gem_vm_open(struct vm_area_struct *vma)
467{
468 struct drm_gem_object *obj = vma->vm_private_data;
469
470 drm_gem_object_reference(obj);
471}
472EXPORT_SYMBOL(drm_gem_vm_open);
473
474void drm_gem_vm_close(struct vm_area_struct *vma)
475{
476 struct drm_gem_object *obj = vma->vm_private_data;
477 struct drm_device *dev = obj->dev;
478
479 mutex_lock(&dev->struct_mutex);
480 drm_gem_object_unreference(obj);
481 mutex_unlock(&dev->struct_mutex);
482}
483EXPORT_SYMBOL(drm_gem_vm_close);
484
485
466/** 486/**
467 * drm_gem_mmap - memory map routine for GEM objects 487 * drm_gem_mmap - memory map routine for GEM objects
468 * @filp: DRM file pointer 488 * @filp: DRM file pointer
@@ -524,6 +544,14 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
524#endif 544#endif
525 vma->vm_page_prot = __pgprot(prot); 545 vma->vm_page_prot = __pgprot(prot);
526 546
547 /* Take a ref for this mapping of the object, so that the fault
548 * handler can dereference the mmap offset's pointer to the object.
549 * This reference is cleaned up by the corresponding vm_close
550 * (which should happen whether the vma was created by this call, or
551 * by a vm_open due to mremap or partial unmap or whatever).
552 */
553 drm_gem_object_reference(obj);
554
527 vma->vm_file = filp; /* Needed for drm_vm_open() */ 555 vma->vm_file = filp; /* Needed for drm_vm_open() */
528 drm_vm_open_locked(vma); 556 drm_vm_open_locked(vma);
529 557
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index aac12ee31a46..a31cbdbc3c54 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -94,6 +94,8 @@ static int i915_resume(struct drm_device *dev)
94 94
95static struct vm_operations_struct i915_gem_vm_ops = { 95static struct vm_operations_struct i915_gem_vm_ops = {
96 .fault = i915_gem_fault, 96 .fault = i915_gem_fault,
97 .open = drm_gem_vm_open,
98 .close = drm_gem_vm_close,
97}; 99};
98 100
99static struct drm_driver driver = { 101static struct drm_driver driver = {
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 078858178832..ac534c9a2f81 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -607,8 +607,6 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
607 case -EAGAIN: 607 case -EAGAIN:
608 return VM_FAULT_OOM; 608 return VM_FAULT_OOM;
609 case -EFAULT: 609 case -EFAULT:
610 case -EBUSY:
611 DRM_ERROR("can't insert pfn?? fault or busy...\n");
612 return VM_FAULT_SIGBUS; 610 return VM_FAULT_SIGBUS;
613 default: 611 default:
614 return VM_FAULT_NOPAGE; 612 return VM_FAULT_NOPAGE;
@@ -684,6 +682,30 @@ out_free_list:
684 return ret; 682 return ret;
685} 683}
686 684
685static void
686i915_gem_free_mmap_offset(struct drm_gem_object *obj)
687{
688 struct drm_device *dev = obj->dev;
689 struct drm_i915_gem_object *obj_priv = obj->driver_private;
690 struct drm_gem_mm *mm = dev->mm_private;
691 struct drm_map_list *list;
692
693 list = &obj->map_list;
694 drm_ht_remove_item(&mm->offset_hash, &list->hash);
695
696 if (list->file_offset_node) {
697 drm_mm_put_block(list->file_offset_node);
698 list->file_offset_node = NULL;
699 }
700
701 if (list->map) {
702 drm_free(list->map, sizeof(struct drm_map), DRM_MEM_DRIVER);
703 list->map = NULL;
704 }
705
706 obj_priv->mmap_offset = 0;
707}
708
687/** 709/**
688 * i915_gem_get_gtt_alignment - return required GTT alignment for an object 710 * i915_gem_get_gtt_alignment - return required GTT alignment for an object
689 * @obj: object to check 711 * @obj: object to check
@@ -2896,9 +2918,6 @@ int i915_gem_init_object(struct drm_gem_object *obj)
2896void i915_gem_free_object(struct drm_gem_object *obj) 2918void i915_gem_free_object(struct drm_gem_object *obj)
2897{ 2919{
2898 struct drm_device *dev = obj->dev; 2920 struct drm_device *dev = obj->dev;
2899 struct drm_gem_mm *mm = dev->mm_private;
2900 struct drm_map_list *list;
2901 struct drm_map *map;
2902 struct drm_i915_gem_object *obj_priv = obj->driver_private; 2921 struct drm_i915_gem_object *obj_priv = obj->driver_private;
2903 2922
2904 while (obj_priv->pin_count > 0) 2923 while (obj_priv->pin_count > 0)
@@ -2909,19 +2928,7 @@ void i915_gem_free_object(struct drm_gem_object *obj)
2909 2928
2910 i915_gem_object_unbind(obj); 2929 i915_gem_object_unbind(obj);
2911 2930
2912 list = &obj->map_list; 2931 i915_gem_free_mmap_offset(obj);
2913 drm_ht_remove_item(&mm->offset_hash, &list->hash);
2914
2915 if (list->file_offset_node) {
2916 drm_mm_put_block(list->file_offset_node);
2917 list->file_offset_node = NULL;
2918 }
2919
2920 map = list->map;
2921 if (map) {
2922 drm_free(map, sizeof(*map), DRM_MEM_DRIVER);
2923 list->map = NULL;
2924 }
2925 2932
2926 drm_free(obj_priv->page_cpu_valid, 1, DRM_MEM_DRIVER); 2933 drm_free(obj_priv->page_cpu_valid, 1, DRM_MEM_DRIVER);
2927 drm_free(obj->driver_private, 1, DRM_MEM_DRIVER); 2934 drm_free(obj->driver_private, 1, DRM_MEM_DRIVER);
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 8190b9bcc2d9..e5f4ae989abf 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -1321,6 +1321,8 @@ void drm_gem_object_free(struct kref *kref);
1321struct drm_gem_object *drm_gem_object_alloc(struct drm_device *dev, 1321struct drm_gem_object *drm_gem_object_alloc(struct drm_device *dev,
1322 size_t size); 1322 size_t size);
1323void drm_gem_object_handle_free(struct kref *kref); 1323void drm_gem_object_handle_free(struct kref *kref);
1324void drm_gem_vm_open(struct vm_area_struct *vma);
1325void drm_gem_vm_close(struct vm_area_struct *vma);
1324int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma); 1326int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
1325 1327
1326static inline void 1328static inline void