(cc Icenowy)
Hi,
there are a number of similar reports. Does the attached patch fix the
problem. It picks up what you do, but in a more correct way.
Best regards
Thomas
Am 18.06.26 um 19:56 schrieb H. Nikolaus Schaller:
Am 18.06.2026 um 19:43 schrieb [email protected]:
Thank you for your contribution! Sashiko AI review found 3 potential issue(s)
to consider:
- [High] Lockless access to `crtc->state` and `crtc->primary->state` can lead
to a Use-After-Free due to concurrent atomic commits.
- [High] The patch breaks vblank synchronization for legacy (non-atomic) DRM
drivers.
- [Medium] The logic selects the first matching CRTC instead of the last active
one, contradicting the commit message.
--
commit 0337b26b606b4d905d72ea2be31bcb984fe62c6e
Author: H. Nikolaus Schaller <[email protected]>
drm/fb_helper: Determine proper crtc_index within drm_fb_helper_fb_dirty
This commit updates the dirty framebuffer worker to search for a matching
active CRTC instead of hardcoding the wait for vblank to CRTC index 0. It
aims to avoid vblank timeouts when CRTC 0 is inactive.
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
[ ... ]
@@ -232,9 +232,23 @@ static void drm_fb_helper_fb_dirty(struct drm_fb_helper
*helper)
struct drm_clip_rect clip_copy;
unsigned long flags;
int ret;
+ unsigned int crtc_index = 0;
+ struct drm_crtc *crtc;
mutex_lock(&helper->lock);
- drm_client_modeset_wait_for_vblank(&helper->client, 0);
+
+ drm_for_each_crtc(crtc, dev) {
+ if (crtc->primary && crtc->primary->state &&
+ crtc->primary->state->fb == helper->fb &&
+ crtc->state && crtc->state->active) {
[Severity: High]
Can this lockless access to crtc->state and crtc->primary->state result in a
use-after-free?
No idea...
The drm_fb_helper_fb_dirty() function holds helper->lock, but does not hold
the DRM modeset locks required to protect these state pointers. During a
Which locks are exactly recommended to add? What is their name/pointer?
concurrent atomic modeset commit, the DRM core allocates new state objects,
swaps them into place, and frees the old objects via kfree().
If this code reads an old state pointer and gets preempted, could it then
dereference the pointer after it has been freed by the concurrent commit?
[Severity: High]
Does this break vblank synchronization for legacy non-atomic DRM drivers?
Legacy drivers do not use the atomic modesetting infrastructure, so their
crtc->state and crtc->primary->state pointers remain NULL. Since the condition
above requires these pointers to be non-NULL, the loop will skip the vblank
wait entirely for legacy drivers. This skips the intended rate-limiting
behavior and could lead to unbounded damage worker execution.
What is the solution? And is this important.
Before d8c4bddcd8bcb ("drm/fb-helper: Synchronize dirty worker with vblank")
there was also no rate-limiting behavior.
+ crtc_index = drm_crtc_index(crtc) + 1;
+ break;
[Severity: Medium]
The commit message states "If multiple CRTCs match, the last active one is
selected." Does the break statement here cause the first active CRTC to be
selected instead, bypassing the remaining matches in the list?
Yes, that is correct. The description is indeed wrong.
+ }
+ }
+
+ if (crtc_index > 0)
+ drm_client_modeset_wait_for_vblank(&helper->client, crtc_index - 1);
+
mutex_unlock(&helper->lock);
--
Sashiko AI review ·
https://sashiko.dev/#/patchset/5118b37e579cec220f2d2b6ab0bb1ecfb67f0d5c.1781803617.git....@goldelico.com?part=1
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com
GF: Jochen Jaser, Andrew McDonald, Werner Knoblich, (HRB 36809, AG Nürnberg)
From 9f94e19d887ed4e456ded81d075e93005bd60d1b Mon Sep 17 00:00:00 2001
From: Thomas Zimmermann <[email protected]>
Date: Fri, 19 Jun 2026 10:31:38 +0200
Subject: [PATCH] drm/fb-helper: Only consider active CRTCs for vblank sync
Only synchronize fbdev output to the vblank of active CRTCs. Go over
the list of CRTCs and pick the first that matches. Fixes warnings as
the one shown below
[ 77.201354] WARNING: drivers/gpu/drm/drm_vblank.c:1320 at drm_crtc_wait_one_vblank+0x194/0x1cc [drm], CPU#1: kworker/1:7/1867
[ 77.201354] omapdrm omapdrm.0: [drm] vblank wait timed out on crtc 0
This currently happens if the fbdev output is not on CRTC 0.
The patch disables vblank sync on the few drivers that still do not
implement atomic modesetting. It's not at all a critical feature though.
Signed-off-by: Thomas Zimmermann <[email protected]>
Fixes: d8c4bddcd8bcb ("drm/fb-helper: Synchronize dirty worker with vblank")
---
drivers/gpu/drm/drm_fb_helper.c | 32 +++++++++++++++++++++++++++++---
1 file changed, 29 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 7b11a582f8ec..37e4d33a6d49 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -230,12 +230,38 @@ static void drm_fb_helper_fb_dirty(struct drm_fb_helper *helper)
struct drm_device *dev = helper->dev;
struct drm_clip_rect *clip = &helper->damage_clip;
struct drm_clip_rect clip_copy;
+ struct drm_plane *plane;
+ int crtc_index = -1;
unsigned long flags;
int ret;
- mutex_lock(&helper->lock);
- drm_client_modeset_wait_for_vblank(&helper->client, 0);
- mutex_unlock(&helper->lock);
+ if (drm_drv_uses_atomic_modeset(dev)) {
+ mutex_lock(&helper->lock);
+ mutex_lock(&dev->mode_config.mutex);
+
+ drm_for_each_plane(plane, dev) {
+ const struct drm_plane_state *plane_state;
+ const struct drm_crtc *crtc;
+
+ if (plane->type != DRM_PLANE_TYPE_PRIMARY)
+ continue; /* not a primary plane */
+
+ plane_state = plane->state;
+ if (plane_state->fb != helper->fb || !plane_state->crtc)
+ continue; /* plane doesn't display fbdev emulation */
+
+ crtc = plane_state->crtc;
+ if (crtc->state->active) {
+ crtc_index = crtc->index;
+ break;
+ }
+ }
+ mutex_unlock(&dev->mode_config.mutex);
+
+ if (crtc_index >= 0)
+ drm_client_modeset_wait_for_vblank(&helper->client, crtc_index);
+ mutex_unlock(&helper->lock);
+ }
if (drm_WARN_ON_ONCE(dev, !helper->funcs->fb_dirty))
return;
--
2.54.0