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 |
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; > > /**
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 --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; /**