]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/i915/frontbuffer: Move bo refcounting intel_frontbuffer_{get,release}()
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Fri, 3 Oct 2025 14:57:30 +0000 (17:57 +0300)
committerVille Syrjälä <ville.syrjala@linux.intel.com>
Thu, 9 Oct 2025 18:01:48 +0000 (21:01 +0300)
Currently xe's intel_frontbuffer implementation forgets to
hold a reference on the bo. This makes the entire thing
extremely fragile as the cleanup order now depends on bo
references held by other things
(namely intel_fb_bo_framebuffer_fini()).

Move the bo refcounting to intel_frontbuffer_{get,release}()
so that both i915 and xe do this the same way.

I first tried to fix this by having xe do the refcounting
from its intel_bo_set_frontbuffer() implementation
(which is what i915 does currently), but turns out xe's
drm_gem_object_free() can sleep and thus drm_gem_object_put()
isn't safe to call while we hold fb_tracking.lock.

Fixes: 10690b8a49bc ("drm/i915/display: Add intel_fb_bo_framebuffer_fini")
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20251003145734.7634-2-ville.syrjala@linux.intel.com
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
drivers/gpu/drm/i915/display/intel_frontbuffer.c
drivers/gpu/drm/i915/gem/i915_gem_object_frontbuffer.h

index 43be5377ddc1a00bfa592d280caca8efe003884c..73ed28ac957341d3506fad67386f480091860acb 100644 (file)
@@ -270,6 +270,8 @@ static void frontbuffer_release(struct kref *ref)
        spin_unlock(&display->fb_tracking.lock);
 
        i915_active_fini(&front->write);
+
+       drm_gem_object_put(obj);
        kfree_rcu(front, rcu);
 }
 
@@ -287,6 +289,8 @@ intel_frontbuffer_get(struct drm_gem_object *obj)
        if (!front)
                return NULL;
 
+       drm_gem_object_get(obj);
+
        front->obj = obj;
        kref_init(&front->ref);
        atomic_set(&front->bits, 0);
@@ -299,8 +303,12 @@ intel_frontbuffer_get(struct drm_gem_object *obj)
        spin_lock(&display->fb_tracking.lock);
        cur = intel_bo_set_frontbuffer(obj, front);
        spin_unlock(&display->fb_tracking.lock);
-       if (cur != front)
+
+       if (cur != front) {
+               drm_gem_object_put(obj);
                kfree(front);
+       }
+
        return cur;
 }
 
index b6dc3d1b9bb1316c5c2186253800dc67bfda09ee..b682969e3a293c2b40b14b4a229cdd9e45fc3d21 100644 (file)
@@ -89,12 +89,10 @@ i915_gem_object_set_frontbuffer(struct drm_i915_gem_object *obj,
 
        if (!front) {
                RCU_INIT_POINTER(obj->frontbuffer, NULL);
-               drm_gem_object_put(intel_bo_to_drm_bo(obj));
        } else if (rcu_access_pointer(obj->frontbuffer)) {
                cur = rcu_dereference_protected(obj->frontbuffer, true);
                kref_get(&cur->ref);
        } else {
-               drm_gem_object_get(intel_bo_to_drm_bo(obj));
                rcu_assign_pointer(obj->frontbuffer, front);
        }