drm/i915: Only discard backing storage on releasing the last ref
authorChris Wilson <chris@chris-wilson.co.uk>
Thu, 22 May 2014 08:16:52 +0000 (09:16 +0100)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Thu, 22 May 2014 13:06:34 +0000 (15:06 +0200)
Before purging our pages (as opposed to copying back the contents from
the GPU), make sure that there is not an exposed CPU mmapping through
which the user can inspect the results.

Regression from

commit 5537252b6b6d71fb1a8ed7395a8e5babf91953fd
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Tue Mar 25 13:23:06 2014 +0000

    drm/i915: Invalidate our pages under memory pressure

Testcase: igt/gem_mmap/new-object
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=79005
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Tested-by: Guo Jinxian <jinxianx.guo@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/i915_gem.c

index 440979f44a1aa849bcaec899468e6d971670113f..6d64cff37fe2de67fb17fab78218d002d5323fc9 100644 (file)
@@ -4246,6 +4246,30 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
        return obj;
 }
 
+static bool discard_backing_storage(struct drm_i915_gem_object *obj)
+{
+       /* If we are the last user of the backing storage (be it shmemfs
+        * pages or stolen etc), we know that the pages are going to be
+        * immediately released. In this case, we can then skip copying
+        * back the contents from the GPU.
+        */
+
+       if (obj->madv != I915_MADV_WILLNEED)
+               return false;
+
+       if (obj->base.filp == NULL)
+               return true;
+
+       /* At first glance, this looks racy, but then again so would be
+        * userspace racing mmap against close. However, the first external
+        * reference to the filp can only be obtained through the
+        * i915_gem_mmap_ioctl() which safeguards us against the user
+        * acquiring such a reference whilst we are in the middle of
+        * freeing the object.
+        */
+       return atomic_long_read(&obj->base.filp->f_count) == 1;
+}
+
 void i915_gem_free_object(struct drm_gem_object *gem_obj)
 {
        struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
@@ -4284,7 +4308,7 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
 
        if (WARN_ON(obj->pages_pin_count))
                obj->pages_pin_count = 0;
-       if (obj->madv != __I915_MADV_PURGED)
+       if (discard_backing_storage(obj))
                obj->madv = I915_MADV_DONTNEED;
        i915_gem_object_put_pages(obj);
        i915_gem_object_free_mmap_offset(obj);