[PATCH v3 2/5] drm/qxl: wait for pending commits before applying DirtyFB
From: Dillon Amburgey
Date: Sat Sep 26 2026 - 12:32:07 EST
The modeset locks protect software state, but a nonblocking commit can
swap that state before its hardware updates finish. DirtyFB can then
race primary-surface replacement and draw into the preceding surface.
Wait for the current CRTC commits while holding the modeset locks before
checking the primary and issuing dirty updates. Return wait and lock
errors to the caller instead of reporting success.
Fixes: 9973c879cff7 ("drm: qxl: Atomic phase 3: Wire up atomic page_flip helper")
Assisted-by: LLM sparse
Signed-off-by: Dillon Amburgey <dillona@xxxxxxxxx>
---
drivers/gpu/drm/qxl/qxl_display.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index 1f869734e14d..51087cacff74 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -437,10 +437,17 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb,
struct qxl_bo *qobj;
struct drm_modeset_acquire_ctx ctx;
bool is_primary;
+ struct drm_crtc *crtc;
int inc = 1, ret;
DRM_MODESET_LOCK_ALL_BEGIN(fb->dev, ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret);
+ drm_for_each_crtc(crtc, &qdev->ddev) {
+ ret = drm_crtc_commit_wait(crtc->state->commit);
+ if (ret)
+ goto out_lock_end;
+ }
+
qobj = gem_to_qxl_bo(fb->obj[0]);
/* if we aren't primary surface ignore this */
is_primary = qobj->shadow ? qobj->shadow->is_primary : qobj->is_primary;
@@ -464,7 +471,7 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb,
out_lock_end:
DRM_MODESET_LOCK_ALL_END(fb->dev, ctx, ret);
- return 0;
+ return ret;
}
static const struct drm_framebuffer_funcs qxl_fb_funcs = {