Skip to content

Commit

Permalink
drm/i915: Keep refs on the object over the lifetime of vmas for GTT m…
Browse files Browse the repository at this point in the history
…map.

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>
  • Loading branch information
Jesse Barnes authored and Dave Airlie committed Feb 20, 2009
1 parent 496818f commit ab00b3e
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 18 deletions.
28 changes: 28 additions & 0 deletions drivers/gpu/drm/drm_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,26 @@ drm_gem_object_handle_free(struct kref *kref)
}
EXPORT_SYMBOL(drm_gem_object_handle_free);

void drm_gem_vm_open(struct vm_area_struct *vma)
{
struct drm_gem_object *obj = vma->vm_private_data;

drm_gem_object_reference(obj);
}
EXPORT_SYMBOL(drm_gem_vm_open);

void drm_gem_vm_close(struct vm_area_struct *vma)
{
struct drm_gem_object *obj = vma->vm_private_data;
struct drm_device *dev = obj->dev;

mutex_lock(&dev->struct_mutex);
drm_gem_object_unreference(obj);
mutex_unlock(&dev->struct_mutex);
}
EXPORT_SYMBOL(drm_gem_vm_close);


/**
* drm_gem_mmap - memory map routine for GEM objects
* @filp: DRM file pointer
Expand Down Expand Up @@ -524,6 +544,14 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
#endif
vma->vm_page_prot = __pgprot(prot);

/* Take a ref for this mapping of the object, so that the fault
* handler can dereference the mmap offset's pointer to the object.
* This reference is cleaned up by the corresponding vm_close
* (which should happen whether the vma was created by this call, or
* by a vm_open due to mremap or partial unmap or whatever).
*/
drm_gem_object_reference(obj);

vma->vm_file = filp; /* Needed for drm_vm_open() */
drm_vm_open_locked(vma);

Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/i915/i915_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ static int i915_resume(struct drm_device *dev)

static struct vm_operations_struct i915_gem_vm_ops = {
.fault = i915_gem_fault,
.open = drm_gem_vm_open,
.close = drm_gem_vm_close,
};

static struct drm_driver driver = {
Expand Down
43 changes: 25 additions & 18 deletions drivers/gpu/drm/i915/i915_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -607,8 +607,6 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
case -EAGAIN:
return VM_FAULT_OOM;
case -EFAULT:
case -EBUSY:
DRM_ERROR("can't insert pfn?? fault or busy...\n");
return VM_FAULT_SIGBUS;
default:
return VM_FAULT_NOPAGE;
Expand Down Expand Up @@ -684,6 +682,30 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj)
return ret;
}

static void
i915_gem_free_mmap_offset(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
struct drm_i915_gem_object *obj_priv = obj->driver_private;
struct drm_gem_mm *mm = dev->mm_private;
struct drm_map_list *list;

list = &obj->map_list;
drm_ht_remove_item(&mm->offset_hash, &list->hash);

if (list->file_offset_node) {
drm_mm_put_block(list->file_offset_node);
list->file_offset_node = NULL;
}

if (list->map) {
drm_free(list->map, sizeof(struct drm_map), DRM_MEM_DRIVER);
list->map = NULL;
}

obj_priv->mmap_offset = 0;
}

/**
* i915_gem_get_gtt_alignment - return required GTT alignment for an object
* @obj: object to check
Expand Down Expand Up @@ -2896,9 +2918,6 @@ int i915_gem_init_object(struct drm_gem_object *obj)
void i915_gem_free_object(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
struct drm_gem_mm *mm = dev->mm_private;
struct drm_map_list *list;
struct drm_map *map;
struct drm_i915_gem_object *obj_priv = obj->driver_private;

while (obj_priv->pin_count > 0)
Expand All @@ -2909,19 +2928,7 @@ void i915_gem_free_object(struct drm_gem_object *obj)

i915_gem_object_unbind(obj);

list = &obj->map_list;
drm_ht_remove_item(&mm->offset_hash, &list->hash);

if (list->file_offset_node) {
drm_mm_put_block(list->file_offset_node);
list->file_offset_node = NULL;
}

map = list->map;
if (map) {
drm_free(map, sizeof(*map), DRM_MEM_DRIVER);
list->map = NULL;
}
i915_gem_free_mmap_offset(obj);

drm_free(obj_priv->page_cpu_valid, 1, DRM_MEM_DRIVER);
drm_free(obj->driver_private, 1, DRM_MEM_DRIVER);
Expand Down
2 changes: 2 additions & 0 deletions include/drm/drmP.h
Original file line number Diff line number Diff line change
Expand Up @@ -1321,6 +1321,8 @@ void drm_gem_object_free(struct kref *kref);
struct drm_gem_object *drm_gem_object_alloc(struct drm_device *dev,
size_t size);
void drm_gem_object_handle_free(struct kref *kref);
void drm_gem_vm_open(struct vm_area_struct *vma);
void drm_gem_vm_close(struct vm_area_struct *vma);
int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);

static inline void
Expand Down

0 comments on commit ab00b3e

Please sign in to comment.