summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2014-09-03 22:23:37 +0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2014-09-04 11:56:07 +0400
commit4ad72b7fadd285f849439cdbc408f8b847cef704 (patch)
treeeabc1578fbc3ade244c77c19f90294991717b324 /drivers/gpu/drm/i915
parent8fe8a3feeb5aedd17f7b09e51b60b38a6ba7005f (diff)
downloadlinux-4ad72b7fadd285f849439cdbc408f8b847cef704.tar.xz
drm/i915: Fix unsafe vma iteration in i915_drop_caches
When unbinding, there is a possibility that we drop the active reference on the object, thereby freeing it. If that happens, we may destroy the vm link as well as the object and vma. So iterate carefully. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915')
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c17
1 files changed, 11 insertions, 6 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index d8389b2dcd77..c19fbdc1430b 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -3812,8 +3812,6 @@ i915_drop_caches_set(void *data, u64 val)
struct drm_device *dev = data;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj, *next;
- struct i915_address_space *vm;
- struct i915_vma *vma, *x;
int ret;
DRM_DEBUG("Dropping caches: 0x%08llx\n", val);
@@ -3834,16 +3832,23 @@ i915_drop_caches_set(void *data, u64 val)
i915_gem_retire_requests(dev);
if (val & DROP_BOUND) {
- list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
- list_for_each_entry_safe(vma, x, &vm->inactive_list,
- mm_list) {
+ list_for_each_entry_safe(obj, next, &dev_priv->mm.bound_list,
+ global_list) {
+ struct i915_vma *vma, *v;
+
+ ret = 0;
+ drm_gem_object_reference(&obj->base);
+ list_for_each_entry_safe(vma, v, &obj->vma_list, vma_link) {
if (vma->pin_count)
continue;
ret = i915_vma_unbind(vma);
if (ret)
- goto unlock;
+ break;
}
+ drm_gem_object_unreference(&obj->base);
+ if (ret)
+ goto unlock;
}
}