Re: [PATCH RFC v3] drm/client: Avoid warning on vblank timeout during modeset client waits

Krystian Kaniewski <[email protected]>
Newsgroups dev.linux.lists.syzbot
Message-ID <[email protected]>
Keep the timeout-warning suppression limited to the best-effort DRM 
client path, but fix the public helper's error-source ambiguity. The 
current wrapper emits the wait-timeout warning whenever the internal 
helper returns `-ETIMEDOUT`. That return value can also come from 
`drm_vblank_get()`, which propagates the driver's `enable_vblank()` 
errno. If acquisition returns `-ETIMEDOUT`, no wait occurred, yet the 
patch emits both the availability warning and a false wait-timeout warning.

Separate vblank acquisition from the quiet counter wait. Make the 
private helper perform only the counter sampling and 
`wait_event_timeout()` under a caller-held vblank reference. Keep the 
client's existing outer `drm_crtc_vblank_get()` and 
`drm_crtc_vblank_put()` pair, call the private helper between them, and 
continue to ignore its timeout result.

In the exported `drm_crtc_wait_one_vblank()` wrapper, perform 
`drm_vblank_get()` and its availability warning directly, and return an 
acquisition error immediately. Only after successful acquisition should 
it call the private helper and emit the timeout warning for 
`-ETIMEDOUT`. Preserve the original warning-before-put ordering, return 
values, one-second deadline, wait predicate, public signature, exported 
ABI, and strict behavior of all direct public callers. Keep 
`drm_atomic_helper_wait_for_vblanks()` unchanged.

Retain the cleaned commit-message style, corrected `Fixes` tag, AI 
provenance, report links, and current recipient list. Update the 
explanation to state that keeping acquisition in the public wrapper 
prevents an `enable_vblank()` error from being mislabeled as a wait timeout.

On 8/6/2026 8:10 PM, syzbot wrote:
> On PREEMPT_RT kernels, a user-space task with elevated Real-Time (RT)
> priority can starve essential kernel threads. For example, the VKMS driver
> simulates vblank interrupts using hrtimers. On PREEMPT_RT, these timers run
> in the per-CPU timer threads at a low RT priority. If a user-space task
> elevates its priority above the timer thread and monopolizes the CPU, the
> timer thread is starved and the VKMS software vblank delivery is delayed
> beyond the timeout.
>
> This leads to a timeout when a worker thread waits for the vblank event.
> For instance, a console update triggers a framebuffer update, scheduling
> drm_fb_helper_damage_work() on the system workqueue. The worker thread
> eventually calls drm_client_modeset_wait_for_vblank() to synchronize the
> screen update with the vblank interval. Due to the starved timer, the wait
> times out and triggers a warning in drm_crtc_wait_one_vblank().
>
> Since this vblank wait in the client modeset path is only used for optional
> client update throttling, a timeout is acceptable and does not indicate a
> kernel bug. Therefore, a warning should not be triggered in this case.
>
> Introduce drm_crtc_wait_one_vblank_internal(), which performs the vblank
> wait without triggering a warning on timeout. This new function is used in
> drm_client_modeset_wait_for_vblank() to avoid the warning, while keeping
> the warning in drm_crtc_wait_one_vblank() for other callers where a timeout
> might still indicate an actual issue.
>
> Fixes: d8c4bddcd8bc ("drm/fb-helper: Synchronize dirty worker with vblank")
> Assisted-by: Gemini:gemini-3.5-flash Gemini:gemini-3.1-pro-preview syzbot
> Reported-by: [email protected]
> Closes: https://syzkaller.appspot.com/bug?extid=f59157955aba9d0cb43b
> Link: https://syzkaller.appspot.com/ai_job?id=527b7209-9098-44da-8634-7792d361dea5
> To: "David Airlie" <[email protected]>
> To: <[email protected]>
> To: "Maarten Lankhorst" <[email protected]>
> To: "Maxime Ripard" <[email protected]>
> To: "Simona Vetter" <[email protected]>
> To: "Thomas Zimmermann" <[email protected]>
> Cc: <[email protected]>
>
> ---
> v3:
> - Removed the raw kernel cut marker and full warning trace from the commit description.
> - Replaced first-person phrasing with impersonal wording in the commit description.
>
> v2:
> - Introduced drm_crtc_wait_one_vblank_internal() to allow waiting for vblank without warning on timeout.
> - Updated drm_client_modeset_wait_for_vblank() to use the new internal function, avoiding warnings during optional client update throttling.
> - Restored the warning in drm_crtc_wait_one_vblank() for other callers.
> https://lore.kernel.org/all/[email protected]/T/
>
> v1:
> https://lore.kernel.org/all/[email protected]/T/
> ---
> diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c
> index 0080a8e95..7ff0f24a0 100644
> --- a/drivers/gpu/drm/drm_client_modeset.c
> +++ b/drivers/gpu/drm/drm_client_modeset.c
> @@ -1328,7 +1328,7 @@ int drm_client_modeset_wait_for_vblank(struct drm_client_dev *client, unsigned i
>   	 */
>   	ret = drm_crtc_vblank_get(crtc);
>   	if (!ret) {
> -		drm_crtc_wait_one_vblank(crtc);
> +		drm_crtc_wait_one_vblank_internal(crtc);
>   		drm_crtc_vblank_put(crtc);
>   	}
>   
> diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
> index f893b1e3a..6fd33672d 100644
> --- a/drivers/gpu/drm/drm_internal.h
> +++ b/drivers/gpu/drm/drm_internal.h
> @@ -115,6 +115,7 @@ void drm_vblank_disable_and_save(struct drm_device *dev, unsigned int pipe);
>   int drm_vblank_get(struct drm_device *dev, unsigned int pipe);
>   void drm_vblank_put(struct drm_device *dev, unsigned int pipe);
>   u64 drm_vblank_count(struct drm_device *dev, unsigned int pipe);
> +int drm_crtc_wait_one_vblank_internal(struct drm_crtc *crtc);
>   
>   /* drm_vblank_work.c */
>   static inline void drm_vblank_flush_worker(struct drm_vblank_crtc *vblank)
> diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
> index f90fb2d13..7758e8265 100644
> --- a/drivers/gpu/drm/drm_vblank.c
> +++ b/drivers/gpu/drm/drm_vblank.c
> @@ -1297,17 +1297,7 @@ void drm_crtc_vblank_put(struct drm_crtc *crtc)
>   }
>   EXPORT_SYMBOL(drm_crtc_vblank_put);
>   
> -/**
> - * drm_crtc_wait_one_vblank - wait for one vblank
> - * @crtc: DRM crtc
> - *
> - * This waits for one vblank to pass on @crtc, using the irq driver interfaces.
> - * It is a failure to call this when the vblank irq for @crtc is disabled, e.g.
> - * due to lack of driver support or because the crtc is off.
> - *
> - * Returns: 0 on success, negative error on failures.
> - */
> -int drm_crtc_wait_one_vblank(struct drm_crtc *crtc)
> +int drm_crtc_wait_one_vblank_internal(struct drm_crtc *crtc)
>   {
>   	struct drm_device *dev = crtc->dev;
>   	int pipe = drm_crtc_index(crtc);
> @@ -1326,12 +1316,30 @@ int drm_crtc_wait_one_vblank(struct drm_crtc *crtc)
>   				 last != drm_vblank_count(dev, pipe),
>   				 msecs_to_jiffies(1000));
>   
> -	drm_WARN(dev, ret == 0, "vblank wait timed out on crtc %i\n", pipe);
> -
>   	drm_vblank_put(dev, pipe);
>   
>   	return ret ? 0 : -ETIMEDOUT;
>   }
> +
> +/**
> + * drm_crtc_wait_one_vblank - wait for one vblank
> + * @crtc: DRM crtc
> + *
> + * This waits for one vblank to pass on @crtc, using the irq driver interfaces.
> + * It is a failure to call this when the vblank irq for @crtc is disabled, e.g.
> + * due to lack of driver support or because the crtc is off.
> + *
> + * Returns: 0 on success, negative error on failures.
> + */
> +int drm_crtc_wait_one_vblank(struct drm_crtc *crtc)
> +{
> +	int ret = drm_crtc_wait_one_vblank_internal(crtc);
> +
> +	drm_WARN(crtc->dev, ret == -ETIMEDOUT, "vblank wait timed out on crtc %i\n",
> +		 drm_crtc_index(crtc));
> +
> +	return ret;
> +}
>   EXPORT_SYMBOL(drm_crtc_wait_one_vblank);
>   
>   /**
>
>
> base-commit: f5098b6bae761e346ebcd9da7f95622c04733cff
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.