drm/i915: Fix unsafe vma iteration in i915_drop_caches
authorChris Wilson <chris@chris-wilson.co.uk>
Wed, 3 Sep 2014 18:23:37 +0000 (19:23 +0100)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Thu, 4 Sep 2014 07:56:07 +0000 (09:56 +0200)
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>
drivers/gpu/drm/i915/i915_debugfs.c

index d8389b2dcd774072edae037c79b129ab052d76b6..c19fbdc1430b09c484b5f34c6c8d095ed1414ee5 100644 (file)
@@ -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;
                }
        }