drm/i915: Hold an object reference whilst we shrink it
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / i915 / i915_gem.c
index f21a0c36a40b31d70dbeebe1dcfec0a1a2d73e75..d9e337feef14f7c2a30b61f4d9e671cb24bb6cd1 100644 (file)
@@ -1695,6 +1695,7 @@ static long
 __i915_gem_shrink(struct drm_i915_private *dev_priv, long target,
                  bool purgeable_only)
 {
+       struct list_head still_bound_list;
        struct drm_i915_gem_object *obj, *next;
        long count = 0;
 
@@ -1709,23 +1710,55 @@ __i915_gem_shrink(struct drm_i915_private *dev_priv, long target,
                }
        }
 
-       list_for_each_entry_safe(obj, next, &dev_priv->mm.bound_list,
-                                global_list) {
+       /*
+        * As we may completely rewrite the bound list whilst unbinding
+        * (due to retiring requests) we have to strictly process only
+        * one element of the list at the time, and recheck the list
+        * on every iteration.
+        */
+       INIT_LIST_HEAD(&still_bound_list);
+       while (count < target && !list_empty(&dev_priv->mm.bound_list)) {
                struct i915_vma *vma, *v;
 
+               obj = list_first_entry(&dev_priv->mm.bound_list,
+                                      typeof(*obj), global_list);
+               list_move_tail(&obj->global_list, &still_bound_list);
+
                if (!i915_gem_object_is_purgeable(obj) && purgeable_only)
                        continue;
 
+               /*
+                * Hold a reference whilst we unbind this object, as we may
+                * end up waiting for and retiring requests. This might
+                * release the final reference (held by the active list)
+                * and result in the object being freed from under us.
+                * in this object being freed.
+                *
+                * Note 1: Shrinking the bound list is special since only active
+                * (and hence bound objects) can contain such limbo objects, so
+                * we don't need special tricks for shrinking the unbound list.
+                * The only other place where we have to be careful with active
+                * objects suddenly disappearing due to retiring requests is the
+                * eviction code.
+                *
+                * Note 2: Even though the bound list doesn't hold a reference
+                * to the object we can safely grab one here: The final object
+                * unreferencing and the bound_list are both protected by the
+                * dev->struct_mutex and so we won't ever be able to observe an
+                * object on the bound_list with a reference count equals 0.
+                */
+               drm_gem_object_reference(&obj->base);
+
                list_for_each_entry_safe(vma, v, &obj->vma_list, vma_link)
                        if (i915_vma_unbind(vma))
                                break;
 
-               if (!i915_gem_object_put_pages(obj)) {
+               if (i915_gem_object_put_pages(obj) == 0)
                        count += obj->base.size >> PAGE_SHIFT;
-                       if (count >= target)
-                               return count;
-               }
+
+               drm_gem_object_unreference(&obj->base);
        }
+       list_splice(&still_bound_list, &dev_priv->mm.bound_list);
 
        return count;
 }