diff options
| author | Chris Wilson <chris@chris-wilson.co.uk> | 2010-09-27 16:28:30 -0400 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2010-09-27 19:14:34 -0400 |
| commit | 31dfbc93923c0aaa0440b809f80ff2830c6a531a (patch) | |
| tree | 9527de1c84f266ea23d6009c454d7cf1d1769889 | |
| parent | 73758a5d51280ca0613b8380fc07351f4d64f9c8 (diff) | |
drm: Prune GEM vma entries
Hook the GEM vm open/close ops into the generic drm vm open/close so
that the private vma entries are created and destroy appropriately.
Fixes the leak of the drm_vma_entries during the lifetime of the filp.
Reported-by: Matt Mackall <mpm@selenic.com>
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: stable@kernel.org
Signed-off-by: Dave Airlie <airlied@redhat.com>
| -rw-r--r-- | drivers/gpu/drm/drm_gem.c | 9 | ||||
| -rw-r--r-- | drivers/gpu/drm/drm_vm.c | 28 | ||||
| -rw-r--r-- | include/drm/drmP.h | 1 |
3 files changed, 27 insertions, 11 deletions
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index bf92d07510df..6fe2cd298c12 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c | |||
| @@ -528,6 +528,10 @@ void drm_gem_vm_open(struct vm_area_struct *vma) | |||
| 528 | struct drm_gem_object *obj = vma->vm_private_data; | 528 | struct drm_gem_object *obj = vma->vm_private_data; |
| 529 | 529 | ||
| 530 | drm_gem_object_reference(obj); | 530 | drm_gem_object_reference(obj); |
| 531 | |||
| 532 | mutex_lock(&obj->dev->struct_mutex); | ||
| 533 | drm_vm_open_locked(vma); | ||
| 534 | mutex_unlock(&obj->dev->struct_mutex); | ||
| 531 | } | 535 | } |
| 532 | EXPORT_SYMBOL(drm_gem_vm_open); | 536 | EXPORT_SYMBOL(drm_gem_vm_open); |
| 533 | 537 | ||
| @@ -535,7 +539,10 @@ void drm_gem_vm_close(struct vm_area_struct *vma) | |||
| 535 | { | 539 | { |
| 536 | struct drm_gem_object *obj = vma->vm_private_data; | 540 | struct drm_gem_object *obj = vma->vm_private_data; |
| 537 | 541 | ||
| 538 | drm_gem_object_unreference_unlocked(obj); | 542 | mutex_lock(&obj->dev->struct_mutex); |
| 543 | drm_vm_close_locked(vma); | ||
| 544 | drm_gem_object_unreference(obj); | ||
| 545 | mutex_unlock(&obj->dev->struct_mutex); | ||
| 539 | } | 546 | } |
| 540 | EXPORT_SYMBOL(drm_gem_vm_close); | 547 | EXPORT_SYMBOL(drm_gem_vm_close); |
| 541 | 548 | ||
diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c index fda67468e603..5df450683aab 100644 --- a/drivers/gpu/drm/drm_vm.c +++ b/drivers/gpu/drm/drm_vm.c | |||
| @@ -433,15 +433,7 @@ static void drm_vm_open(struct vm_area_struct *vma) | |||
| 433 | mutex_unlock(&dev->struct_mutex); | 433 | mutex_unlock(&dev->struct_mutex); |
| 434 | } | 434 | } |
| 435 | 435 | ||
| 436 | /** | 436 | void drm_vm_close_locked(struct vm_area_struct *vma) |
| 437 | * \c close method for all virtual memory types. | ||
| 438 | * | ||
| 439 | * \param vma virtual memory area. | ||
| 440 | * | ||
| 441 | * Search the \p vma private data entry in drm_device::vmalist, unlink it, and | ||
| 442 | * free it. | ||
| 443 | */ | ||
| 444 | static void drm_vm_close(struct vm_area_struct *vma) | ||
| 445 | { | 437 | { |
| 446 | struct drm_file *priv = vma->vm_file->private_data; | 438 | struct drm_file *priv = vma->vm_file->private_data; |
| 447 | struct drm_device *dev = priv->minor->dev; | 439 | struct drm_device *dev = priv->minor->dev; |
| @@ -451,7 +443,6 @@ static void drm_vm_close(struct vm_area_struct *vma) | |||
| 451 | vma->vm_start, vma->vm_end - vma->vm_start); | 443 | vma->vm_start, vma->vm_end - vma->vm_start); |
| 452 | atomic_dec(&dev->vma_count); | 444 | atomic_dec(&dev->vma_count); |
| 453 | 445 | ||
| 454 | mutex_lock(&dev->struct_mutex); | ||
| 455 | list_for_each_entry_safe(pt, temp, &dev->vmalist, head) { | 446 | list_for_each_entry_safe(pt, temp, &dev->vmalist, head) { |
| 456 | if (pt->vma == vma) { | 447 | if (pt->vma == vma) { |
| 457 | list_del(&pt->head); | 448 | list_del(&pt->head); |
| @@ -459,6 +450,23 @@ static void drm_vm_close(struct vm_area_struct *vma) | |||
| 459 | break; | 450 | break; |
| 460 | } | 451 | } |
| 461 | } | 452 | } |
| 453 | } | ||
| 454 | |||
| 455 | /** | ||
| 456 | * \c close method for all virtual memory types. | ||
| 457 | * | ||
| 458 | * \param vma virtual memory area. | ||
| 459 | * | ||
| 460 | * Search the \p vma private data entry in drm_device::vmalist, unlink it, and | ||
| 461 | * free it. | ||
| 462 | */ | ||
| 463 | static void drm_vm_close(struct vm_area_struct *vma) | ||
| 464 | { | ||
| 465 | struct drm_file *priv = vma->vm_file->private_data; | ||
| 466 | struct drm_device *dev = priv->minor->dev; | ||
| 467 | |||
| 468 | mutex_lock(&dev->struct_mutex); | ||
| 469 | drm_vm_close_locked(vma); | ||
| 462 | mutex_unlock(&dev->struct_mutex); | 470 | mutex_unlock(&dev->struct_mutex); |
| 463 | } | 471 | } |
| 464 | 472 | ||
diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 7809d230adee..774e1d49509b 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h | |||
| @@ -1175,6 +1175,7 @@ extern int drm_release(struct inode *inode, struct file *filp); | |||
| 1175 | extern int drm_mmap(struct file *filp, struct vm_area_struct *vma); | 1175 | extern int drm_mmap(struct file *filp, struct vm_area_struct *vma); |
| 1176 | extern int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma); | 1176 | extern int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma); |
| 1177 | extern void drm_vm_open_locked(struct vm_area_struct *vma); | 1177 | extern void drm_vm_open_locked(struct vm_area_struct *vma); |
| 1178 | extern void drm_vm_close_locked(struct vm_area_struct *vma); | ||
| 1178 | extern resource_size_t drm_core_get_map_ofs(struct drm_local_map * map); | 1179 | extern resource_size_t drm_core_get_map_ofs(struct drm_local_map * map); |
| 1179 | extern resource_size_t drm_core_get_reg_ofs(struct drm_device *dev); | 1180 | extern resource_size_t drm_core_get_reg_ofs(struct drm_device *dev); |
| 1180 | extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait); | 1181 | extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait); |
