diff mbox series

Prevent CPU deadlock with fbdev based consoles while printing scheduler warnings

Message ID 20220802033142.31655-1-mpenttil@redhat.com (mailing list archive)
State New, archived
Headers show
Series Prevent CPU deadlock with fbdev based consoles while printing scheduler warnings | expand

Commit Message

Mika Penttilä Aug. 2, 2022, 3:31 a.m. UTC
From: Mika Penttilä <mpenttil@redhat.com>

With some fbdev based consoles, using the deferred_io mechanism and drm_fb_helper,
there can be a call chain like:

Backtrack:

try_to_wake_up  <-- rq_lock taken
__queue_work
queue_work_on
soft_cursor
hide_cursor
vt_console_print
console_unlock
vprintk_emit
printk
__warn_printk
(cfs_rq_is_decayed -> SCHED_WARN_ON)
__update_blocked_fair
update_blocked_averages   <-- rq_lock taken

Example producer is with qemu bochs virtio device (qemu stdvga),
and drm bochs support in the guest.

This can fixed be used using schedule_delayed_work() to get out of scheduler context,
if needed, while queueing the damage_work.

Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
Cc: David Airlie <airlied@linux.ie>
---
 drivers/gpu/drm/drm_fb_helper.c | 8 ++++----
 include/drm/drm_fb_helper.h     | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

Comments

Mika Penttilä Aug. 22, 2022, 5:41 a.m. UTC | #1
Gentle ping, any concerns or suggestions on this topic or solution in general?

Thanks,
Mika


On 2.8.2022 6.31, mpenttil@redhat.com wrote:
> From: Mika Penttilä<mpenttil@redhat.com>
>
> With some fbdev based consoles, using the deferred_io mechanism and drm_fb_helper,
> there can be a call chain like:
>
> Backtrack:
>
> try_to_wake_up  <-- rq_lock taken
> __queue_work
> queue_work_on
> soft_cursor
> hide_cursor
> vt_console_print
> console_unlock
> vprintk_emit
> printk
> __warn_printk
> (cfs_rq_is_decayed -> SCHED_WARN_ON)
> __update_blocked_fair
> update_blocked_averages   <-- rq_lock taken
>
> Example producer is with qemu bochs virtio device (qemu stdvga),
> and drm bochs support in the guest.
>
> This can fixed be used using schedule_delayed_work() to get out of scheduler context,
> if needed, while queueing the damage_work.
>
> Signed-off-by: Mika Penttilä<mpenttil@redhat.com>
> Cc: David Airlie<airlied@linux.ie>
> ---
>   drivers/gpu/drm/drm_fb_helper.c | 8 ++++----
>   include/drm/drm_fb_helper.h     | 2 +-
>   2 files changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 5ad2b6a2778c..6449e8dc97f6 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -429,7 +429,7 @@ static int drm_fb_helper_damage_blit(struct drm_fb_helper *fb_helper,
>   static void drm_fb_helper_damage_work(struct work_struct *work)
>   {
>   	struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
> -						    damage_work);
> +						    damage_work.work);
>   	struct drm_device *dev = helper->dev;
>   	struct drm_clip_rect *clip = &helper->damage_clip;
>   	struct drm_clip_rect clip_copy;
> @@ -488,7 +488,7 @@ void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
>   	INIT_LIST_HEAD(&helper->kernel_fb_list);
>   	spin_lock_init(&helper->damage_lock);
>   	INIT_WORK(&helper->resume_work, drm_fb_helper_resume_worker);
> -	INIT_WORK(&helper->damage_work, drm_fb_helper_damage_work);
> +	INIT_DELAYED_WORK(&helper->damage_work, drm_fb_helper_damage_work);
>   	helper->damage_clip.x1 = helper->damage_clip.y1 = ~0;
>   	mutex_init(&helper->lock);
>   	helper->funcs = funcs;
> @@ -625,7 +625,7 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
>   		return;
>   
>   	cancel_work_sync(&fb_helper->resume_work);
> -	cancel_work_sync(&fb_helper->damage_work);
> +	cancel_delayed_work_sync(&fb_helper->damage_work);
>   
>   	info = fb_helper->fbdev;
>   	if (info) {
> @@ -677,7 +677,7 @@ static void drm_fb_helper_damage(struct fb_info *info, u32 x, u32 y,
>   	clip->y2 = max_t(u32, clip->y2, y + height);
>   	spin_unlock_irqrestore(&helper->damage_lock, flags);
>   
> -	schedule_work(&helper->damage_work);
> +	schedule_delayed_work(&helper->damage_work, in_atomic() ? 1 : 0);
>   }
>   
>   /* Convert memory region into area of scanlines and pixels per scanline */
> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
> index 329607ca65c0..65a26d57d517 100644
> --- a/include/drm/drm_fb_helper.h
> +++ b/include/drm/drm_fb_helper.h
> @@ -132,7 +132,7 @@ struct drm_fb_helper {
>   	u32 pseudo_palette[17];
>   	struct drm_clip_rect damage_clip;
>   	spinlock_t damage_lock;
> -	struct work_struct damage_work;
> +	struct delayed_work damage_work;
>   	struct work_struct resume_work;
>   
>   	/**
Dave Airlie Aug. 22, 2022, 6:26 a.m. UTC | #2
Just adding Thomas in case he missed it.

Dave.

On Mon, 22 Aug 2022 at 15:41, Mika Penttilä <mpenttil@redhat.com> wrote:
>
> Gentle ping, any concerns or suggestions on this topic or solution in general?
>
> Thanks,
> Mika
>
>
> On 2.8.2022 6.31, mpenttil@redhat.com wrote:
>
> From: Mika Penttilä <mpenttil@redhat.com>
>
> With some fbdev based consoles, using the deferred_io mechanism and drm_fb_helper,
> there can be a call chain like:
>
> Backtrack:
>
> try_to_wake_up  <-- rq_lock taken
> __queue_work
> queue_work_on
> soft_cursor
> hide_cursor
> vt_console_print
> console_unlock
> vprintk_emit
> printk
> __warn_printk
> (cfs_rq_is_decayed -> SCHED_WARN_ON)
> __update_blocked_fair
> update_blocked_averages   <-- rq_lock taken
>
> Example producer is with qemu bochs virtio device (qemu stdvga),
> and drm bochs support in the guest.
>
> This can fixed be used using schedule_delayed_work() to get out of scheduler context,
> if needed, while queueing the damage_work.
>
> Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
> Cc: David Airlie <airlied@linux.ie>
> ---
>  drivers/gpu/drm/drm_fb_helper.c | 8 ++++----
>  include/drm/drm_fb_helper.h     | 2 +-
>  2 files changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 5ad2b6a2778c..6449e8dc97f6 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -429,7 +429,7 @@ static int drm_fb_helper_damage_blit(struct drm_fb_helper *fb_helper,
>  static void drm_fb_helper_damage_work(struct work_struct *work)
>  {
>   struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
> -    damage_work);
> +    damage_work.work);
>   struct drm_device *dev = helper->dev;
>   struct drm_clip_rect *clip = &helper->damage_clip;
>   struct drm_clip_rect clip_copy;
> @@ -488,7 +488,7 @@ void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
>   INIT_LIST_HEAD(&helper->kernel_fb_list);
>   spin_lock_init(&helper->damage_lock);
>   INIT_WORK(&helper->resume_work, drm_fb_helper_resume_worker);
> - INIT_WORK(&helper->damage_work, drm_fb_helper_damage_work);
> + INIT_DELAYED_WORK(&helper->damage_work, drm_fb_helper_damage_work);
>   helper->damage_clip.x1 = helper->damage_clip.y1 = ~0;
>   mutex_init(&helper->lock);
>   helper->funcs = funcs;
> @@ -625,7 +625,7 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
>   return;
>
>   cancel_work_sync(&fb_helper->resume_work);
> - cancel_work_sync(&fb_helper->damage_work);
> + cancel_delayed_work_sync(&fb_helper->damage_work);
>
>   info = fb_helper->fbdev;
>   if (info) {
> @@ -677,7 +677,7 @@ static void drm_fb_helper_damage(struct fb_info *info, u32 x, u32 y,
>   clip->y2 = max_t(u32, clip->y2, y + height);
>   spin_unlock_irqrestore(&helper->damage_lock, flags);
>
> - schedule_work(&helper->damage_work);
> + schedule_delayed_work(&helper->damage_work, in_atomic() ? 1 : 0);
>  }
>
>  /* Convert memory region into area of scanlines and pixels per scanline */
> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
> index 329607ca65c0..65a26d57d517 100644
> --- a/include/drm/drm_fb_helper.h
> +++ b/include/drm/drm_fb_helper.h
> @@ -132,7 +132,7 @@ struct drm_fb_helper {
>   u32 pseudo_palette[17];
>   struct drm_clip_rect damage_clip;
>   spinlock_t damage_lock;
> - struct work_struct damage_work;
> + struct delayed_work damage_work;
>   struct work_struct resume_work;
>
>   /**
>
>
diff mbox series

Patch

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 5ad2b6a2778c..6449e8dc97f6 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -429,7 +429,7 @@  static int drm_fb_helper_damage_blit(struct drm_fb_helper *fb_helper,
 static void drm_fb_helper_damage_work(struct work_struct *work)
 {
 	struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
-						    damage_work);
+						    damage_work.work);
 	struct drm_device *dev = helper->dev;
 	struct drm_clip_rect *clip = &helper->damage_clip;
 	struct drm_clip_rect clip_copy;
@@ -488,7 +488,7 @@  void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
 	INIT_LIST_HEAD(&helper->kernel_fb_list);
 	spin_lock_init(&helper->damage_lock);
 	INIT_WORK(&helper->resume_work, drm_fb_helper_resume_worker);
-	INIT_WORK(&helper->damage_work, drm_fb_helper_damage_work);
+	INIT_DELAYED_WORK(&helper->damage_work, drm_fb_helper_damage_work);
 	helper->damage_clip.x1 = helper->damage_clip.y1 = ~0;
 	mutex_init(&helper->lock);
 	helper->funcs = funcs;
@@ -625,7 +625,7 @@  void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
 		return;
 
 	cancel_work_sync(&fb_helper->resume_work);
-	cancel_work_sync(&fb_helper->damage_work);
+	cancel_delayed_work_sync(&fb_helper->damage_work);
 
 	info = fb_helper->fbdev;
 	if (info) {
@@ -677,7 +677,7 @@  static void drm_fb_helper_damage(struct fb_info *info, u32 x, u32 y,
 	clip->y2 = max_t(u32, clip->y2, y + height);
 	spin_unlock_irqrestore(&helper->damage_lock, flags);
 
-	schedule_work(&helper->damage_work);
+	schedule_delayed_work(&helper->damage_work, in_atomic() ? 1 : 0);
 }
 
 /* Convert memory region into area of scanlines and pixels per scanline */
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 329607ca65c0..65a26d57d517 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -132,7 +132,7 @@  struct drm_fb_helper {
 	u32 pseudo_palette[17];
 	struct drm_clip_rect damage_clip;
 	spinlock_t damage_lock;
-	struct work_struct damage_work;
+	struct delayed_work damage_work;
 	struct work_struct resume_work;
 
 	/**