drm/fb-helper: Don't call dirty callback for untouched clips
Subsystems (2)
PATCH 1/1 drm/fb-helper: Don't call dirty callback for untouched clips
Since 4.7 kernel, we've seen the error messages like
kernel: [TTM] Buffer eviction failed
kernel: qxl 0000:00:02.0: object_init failed for (4026540032, 0x00000001)
kernel: [drm:qxl_alloc_bo_reserved [qxl]] *ERROR* failed to allocate VRAM BO
on QXL when switching and accessing on VT. The culprit was the generic deferred_io code (qxl driver switched to it since 4.7). There is a race between the dirty clip update and the call of callback.
In drm_fb_helper_dirty(), the dirty clip is updated in the spinlock, while it kicks off the update worker outside the spinlock. Meanwhile the update worker clears the dirty clip in the spinlock, too. Thus, when drm_fb_helper_dirty() is called concurrently, schedule_work() is called after the clip is cleared in the first worker call.
This patch addresses it by validating the clip before calling the dirty fb callback.
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98322
Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=1003298
--- drivers/gpu/drm/drm_fb_helper.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
drivers/gpu/drm/drm_fb_helper.c +9 -4
@@ -636,15 +636,20 @@ static void drm_fb_helper_dirty_work(struct work_struct *work) dirty_work);struct drm_clip_rect *clip = &helper->dirty_clip;struct drm_clip_rect clip_copy; +bool dirty;unsigned long flags;spin_lock_irqsave (&helper->dirty_lock, flags); - clip_copy = *clip; - clip->x1 = clip->y1 = ~0 ; - clip->x2 = clip->y2 =0 ; + dirty = (clip->x1 < clip->x2 && clip->y1 < clip->y2); +if (dirty) { + clip_copy = *clip; + clip->x1 = clip->y1 = ~0 ; + clip->x2 = clip->y2 =0 ; + }spin_unlock_irqrestore (&helper->dirty_lock, flags); - helper->fb->funcs->dirty (helper->fb,NULL ,0 ,0 , &clip_copy,1 ); +if (dirty) + helper->fb->funcs->dirty (helper->fb,NULL ,0 ,0 , &clip_copy,1 ); }/**
Signature · 1 line
2.10.1
Quoted 44 lines · Takashi Iwai
Since 4.7 kernel, we've seen the error messages like
kernel: [TTM] Buffer eviction failed
kernel: qxl 0000:00:02.0:object_initfailed for (4026540032,0x00000001)
kernel: [drm:qxl_alloc_bo_reserved [qxl]] *ERROR* failed to allocate VRAM BOon QXL when switching and accessing on VT. The culprit was the generic
deferred_iocode (qxl driver switched to it since 4.7). There is a race between the dirty clip update and the call of callback.In
drm_fb_helper_dirty(), the dirty clip is updated in the spinlock, while it kicks off the update worker outside the spinlock. Meanwhile the update worker clears the dirty clip in the spinlock, too. Thus, whendrm_fb_helper_dirty()is called concurrently,schedule_work()is called after the clip is cleared in the first worker call.This patch addresses it by validating the clip before calling the dirty fb callback.
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98322
Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=1003298Fixes eaa434defaca ('drm/fb-helper: Add fb_deferred_io support')Cc <[email protected]>Signed-off-by Takashi Iwai <[email protected]>--- drivers/gpu/drm/drm_fb_helper.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)drivers/gpu/drm/drm_fb_helper.c +1
-3@@ -636,15 +636,20 @@ static void drm_fb_helper_dirty_work(struct work_struct *work) dirty_work);struct drm_clip_rect *clip = &helper->dirty_clip;struct drm_clip_rect clip_copy; +bool dirty;unsigned long flags;spin_lock_irqsave (&helper->dirty_lock, flags); - clip_copy = *clip; - clip->x1 = clip->y1 = ~0 ; - clip->x2 = clip->y2 =0 ;
drivers/gpu/drm/drm_fb_helper.c static void drm_fb_helper_dirty_work(struct work_struct *work) · line 651
Quoted 10 lines
drivers/gpu/drm/drm_fb_helper.c +7
-1+ dirty = (clip->x1 < clip->x2 && clip->y1 < clip->y2); +if (dirty) { + clip_copy = *clip; + clip->x1 = clip->y1 = ~0 ; + clip->x2 = clip->y2 =0 ; + }spin_unlock_irqrestore (&helper->dirty_lock, flags); - helper->fb->funcs->dirty (helper->fb,NULL ,0 ,0 , &clip_copy,1 ); +if (dirty)
Could do it the other way too, ie. just make the copy, and then check the copy (can be done after dropping the lock even). Would avoid having to add the 'dirty' variable.
Quoted 6 lines
drivers/gpu/drm/drm_fb_helper.c +1
-0+ helper->fb->funcs->dirty (helper->fb,NULL ,0 ,0 , &clip_copy,1 ); }/** Signature · 1 line
2.10.1
Signature · 2 lines
Ville Syrjälä Intel OTC
Quoted 54 lines · Ville Syrjälä
Quoted 52 lines · Takashi Iwai
Since 4.7 kernel, we've seen the error messages like
kernel: [TTM] Buffer eviction failed
kernel: qxl 0000:00:02.0:object_initfailed for (4026540032,0x00000001)
kernel: [drm:qxl_alloc_bo_reserved [qxl]] *ERROR* failed to allocate VRAM BOon QXL when switching and accessing on VT. The culprit was the generic
deferred_iocode (qxl driver switched to it since 4.7). There is a race between the dirty clip update and the call of callback.In
drm_fb_helper_dirty(), the dirty clip is updated in the spinlock, while it kicks off the update worker outside the spinlock. Meanwhile the update worker clears the dirty clip in the spinlock, too. Thus, whendrm_fb_helper_dirty()is called concurrently,schedule_work()is called after the clip is cleared in the first worker call.This patch addresses it by validating the clip before calling the dirty fb callback.
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98322
Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=1003298Fixes eaa434defaca ('drm/fb-helper: Add fb_deferred_io support')Cc <[email protected]>Signed-off-by Takashi Iwai <[email protected]>--- drivers/gpu/drm/drm_fb_helper.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)drivers/gpu/drm/drm_fb_helper.c +7
-3@@ -636,15 +636,20 @@ static void drm_fb_helper_dirty_work(struct work_struct *work) dirty_work);struct drm_clip_rect *clip = &helper->dirty_clip;struct drm_clip_rect clip_copy; +bool dirty;unsigned long flags;spin_lock_irqsave (&helper->dirty_lock, flags); - clip_copy = *clip; - clip->x1 = clip->y1 = ~0 ; - clip->x2 = clip->y2 =0 ; + dirty = (clip->x1 < clip->x2 && clip->y1 < clip->y2); +if (dirty) { + clip_copy = *clip; + clip->x1 = clip->y1 = ~0 ; + clip->x2 = clip->y2 =0 ; + }spin_unlock_irqrestore (&helper->dirty_lock, flags);
Quoted 6 lines
drivers/gpu/drm/drm_fb_helper.c static void drm_fb_helper_dirty_work(struct work_struct *work) · line 651
Quoted 2 lines
drivers/gpu/drm/drm_fb_helper.c +1
-1- helper->fb->funcs->dirty (helper->fb,NULL ,0 ,0 , &clip_copy,1 ); +if (dirty)Could do it the other way too, ie. just make the copy, and then check the copy (can be done after dropping the lock even). Would avoid having to add the 'dirty' variable.
Sounds good. Let me try...
Takashi
Quoted 56 lines · Takashi Iwai
Quoted 54 lines · Ville Syrjälä
Quoted 52 lines · Takashi Iwai
Since 4.7 kernel, we've seen the error messages like
kernel: [TTM] Buffer eviction failed
kernel: qxl 0000:00:02.0:object_initfailed for (4026540032,0x00000001)
kernel: [drm:qxl_alloc_bo_reserved [qxl]] *ERROR* failed to allocate VRAM BOon QXL when switching and accessing on VT. The culprit was the generic
deferred_iocode (qxl driver switched to it since 4.7). There is a race between the dirty clip update and the call of callback.In
drm_fb_helper_dirty(), the dirty clip is updated in the spinlock, while it kicks off the update worker outside the spinlock. Meanwhile the update worker clears the dirty clip in the spinlock, too. Thus, whendrm_fb_helper_dirty()is called concurrently,schedule_work()is called after the clip is cleared in the first worker call.This patch addresses it by validating the clip before calling the dirty fb callback.
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98322
Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=1003298Fixes eaa434defaca ('drm/fb-helper: Add fb_deferred_io support')Cc <[email protected]>Signed-off-by Takashi Iwai <[email protected]>--- drivers/gpu/drm/drm_fb_helper.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)drivers/gpu/drm/drm_fb_helper.c +7
-3@@ -636,15 +636,20 @@ static void drm_fb_helper_dirty_work(struct work_struct *work) dirty_work);struct drm_clip_rect *clip = &helper->dirty_clip;struct drm_clip_rect clip_copy; +bool dirty;unsigned long flags;spin_lock_irqsave (&helper->dirty_lock, flags); - clip_copy = *clip; - clip->x1 = clip->y1 = ~0 ; - clip->x2 = clip->y2 =0 ; + dirty = (clip->x1 < clip->x2 && clip->y1 < clip->y2); +if (dirty) { + clip_copy = *clip; + clip->x1 = clip->y1 = ~0 ; + clip->x2 = clip->y2 =0 ; + }spin_unlock_irqrestore (&helper->dirty_lock, flags);
Quoted 8 lines
Quoted 6 lines
drivers/gpu/drm/drm_fb_helper.c static void drm_fb_helper_dirty_work(struct work_struct *work) · line 651
Quoted 2 lines
drivers/gpu/drm/drm_fb_helper.c +1
-1- helper->fb->funcs->dirty (helper->fb,NULL ,0 ,0 , &clip_copy,1 ); +if (dirty)Could do it the other way too, ie. just make the copy, and then check the copy (can be done after dropping the lock even). Would avoid having to add the 'dirty' variable.
Sounds good. Let me try...
Another thing: How do we prevent userspace from doing the same, i.e. submitting an empty rectangle? Do we need to patch up drm_mode_dirtyfb_ioctl too? Not much point if we fix this bug in the fb helpers and leave the barn door wide open for userspace to oops drivers ;-)
-Daniel
Quoted 3 lines
Takashi
Signature · 3 lines
Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch
Quoted 65 lines · Daniel Vetter
Quoted 63 lines · Takashi Iwai
Quoted 60 lines · Ville Syrjälä
Quoted 44 lines · Takashi Iwai
Since 4.7 kernel, we've seen the error messages like
kernel: [TTM] Buffer eviction failed
kernel: qxl 0000:00:02.0:object_initfailed for (4026540032,0x00000001)
kernel: [drm:qxl_alloc_bo_reserved [qxl]] *ERROR* failed to allocate VRAM BOon QXL when switching and accessing on VT. The culprit was the generic
deferred_iocode (qxl driver switched to it since 4.7). There is a race between the dirty clip update and the call of callback.In
drm_fb_helper_dirty(), the dirty clip is updated in the spinlock, while it kicks off the update worker outside the spinlock. Meanwhile the update worker clears the dirty clip in the spinlock, too. Thus, whendrm_fb_helper_dirty()is called concurrently,schedule_work()is called after the clip is cleared in the first worker call.This patch addresses it by validating the clip before calling the dirty fb callback.
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98322
Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=1003298Fixes eaa434defaca ('drm/fb-helper: Add fb_deferred_io support')Cc <[email protected]>Signed-off-by Takashi Iwai <[email protected]>--- drivers/gpu/drm/drm_fb_helper.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)drivers/gpu/drm/drm_fb_helper.c +1
-3@@ -636,15 +636,20 @@ static void drm_fb_helper_dirty_work(struct work_struct *work) dirty_work);struct drm_clip_rect *clip = &helper->dirty_clip;struct drm_clip_rect clip_copy; +bool dirty;unsigned long flags;spin_lock_irqsave (&helper->dirty_lock, flags); - clip_copy = *clip; - clip->x1 = clip->y1 = ~0 ; - clip->x2 = clip->y2 =0 ;drivers/gpu/drm/drm_fb_helper.c static void drm_fb_helper_dirty_work(struct work_struct *work) · line 651
Quoted 10 lines
drivers/gpu/drm/drm_fb_helper.c +7
-1+ dirty = (clip->x1 < clip->x2 && clip->y1 < clip->y2); +if (dirty) { + clip_copy = *clip; + clip->x1 = clip->y1 = ~0 ; + clip->x2 = clip->y2 =0 ; + }spin_unlock_irqrestore (&helper->dirty_lock, flags); - helper->fb->funcs->dirty (helper->fb,NULL ,0 ,0 , &clip_copy,1 ); +if (dirty)Could do it the other way too, ie. just make the copy, and then check the copy (can be done after dropping the lock even). Would avoid having to add the 'dirty' variable.
Quoted 7 lines
Quoted 1 line
Sounds good. Let me try...
Another thing: How do we prevent userspace from doing the same, i.e. submitting an empty rectangle? Do we need to patch up
drm_mode_dirtyfb_ioctltoo? Not much point if we fix this bug in the fb helpers and leave the barn door wide open for userspace to oops drivers ;-)
OK, then how about adding a helper to call the dirty callback with a sanity check like below?
Takashi
---
drivers/gpu/drm/drm_fb_helper.c +1 -1
@@ -644,7 +644,7 @@ static void drm_fb_helper_dirty_work(struct work_struct *work) clip->x2 = clip->y2 =0 ;spin_unlock_irqrestore (&helper->dirty_lock, flags); - helper->fb->funcs->dirty (helper->fb,NULL ,0 ,0 , &clip_copy,1 ); +drm_framebuffer_update_dirty (helper->fb,NULL ,0 ,0 , &clip_copy,1 ); }/**
drivers/gpu/drm/drm_framebuffer.c +21 -6
@@ -529,6 +529,25 @@ int drm_mode_getfb(struct drm_device *dev, }/** +* blah blah +*/ +int drm_framebuffer_update_dirty (struct drm_framebuffer *fb, +struct drm_file *file_priv, +unsigned flags,unsigned color, +struct drm_clip_rect *clips, +unsigned num_clips) +{ +if (!fb->funcs->dirty) +return -ENOSYS ; +if (!num_clips) +return 0 ; +if (clips->x1 >= clips->x2 || clips->y1 >= clips->y2) +return 0 ; +return fb->funcs->dirty (fb, file_priv, flags, color, clips, num_clips); +} +EXPORT_SYMBOL (drm_framebuffer_update_dirty); + +/** * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB * @dev: drm device for the ioctl * @data: data pointer for the ioctl
@@ -600,12 +619,8 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, } } -if (fb->funcs->dirty) { - ret = fb->funcs->dirty (fb, file_priv, flags, r->color, - clips, num_clips); - }else { - ret = -ENOSYS ; - } + ret =drm_framebuffer_update_dirty (fb, file_priv, flags, r->color, + clips, num_clips); out_err2:kfree (clips);
include/drm/drm_framebuffer.h +6 -0
@@ -217,6 +217,12 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb);void drm_framebuffer_cleanup (struct drm_framebuffer *fb);void drm_framebuffer_unregister_private (struct drm_framebuffer *fb); +int drm_framebuffer_update_dirty (struct drm_framebuffer *fb, +struct drm_file *file_priv, +unsigned flags,unsigned color, +struct drm_clip_rect *clips, +unsigned num_clips); +/** * drm_framebuffer_reference - incr the fb refcnt * @fb: framebuffer
Quoted 107 lines · Takashi Iwai
Quoted 65 lines · Daniel Vetter
Quoted 63 lines · Takashi Iwai
Quoted 60 lines · Ville Syrjälä
Quoted 44 lines · Takashi Iwai
Since 4.7 kernel, we've seen the error messages like
kernel: [TTM] Buffer eviction failed
kernel: qxl 0000:00:02.0:object_initfailed for (4026540032,0x00000001)
kernel: [drm:qxl_alloc_bo_reserved [qxl]] *ERROR* failed to allocate VRAM BOon QXL when switching and accessing on VT. The culprit was the generic
deferred_iocode (qxl driver switched to it since 4.7). There is a race between the dirty clip update and the call of callback.In
drm_fb_helper_dirty(), the dirty clip is updated in the spinlock, while it kicks off the update worker outside the spinlock. Meanwhile the update worker clears the dirty clip in the spinlock, too. Thus, whendrm_fb_helper_dirty()is called concurrently,schedule_work()is called after the clip is cleared in the first worker call.This patch addresses it by validating the clip before calling the dirty fb callback.
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98322
Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=1003298Fixes eaa434defaca ('drm/fb-helper: Add fb_deferred_io support')Cc <[email protected]>Signed-off-by Takashi Iwai <[email protected]>--- drivers/gpu/drm/drm_fb_helper.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)drivers/gpu/drm/drm_fb_helper.c +1
-3@@ -636,15 +636,20 @@ static void drm_fb_helper_dirty_work(struct work_struct *work) dirty_work);struct drm_clip_rect *clip = &helper->dirty_clip;struct drm_clip_rect clip_copy; +bool dirty;unsigned long flags;spin_lock_irqsave (&helper->dirty_lock, flags); - clip_copy = *clip; - clip->x1 = clip->y1 = ~0 ; - clip->x2 = clip->y2 =0 ;drivers/gpu/drm/drm_fb_helper.c static void drm_fb_helper_dirty_work(struct work_struct *work) · line 651
Quoted 10 lines
drivers/gpu/drm/drm_fb_helper.c +7
-1+ dirty = (clip->x1 < clip->x2 && clip->y1 < clip->y2); +if (dirty) { + clip_copy = *clip; + clip->x1 = clip->y1 = ~0 ; + clip->x2 = clip->y2 =0 ; + }spin_unlock_irqrestore (&helper->dirty_lock, flags); - helper->fb->funcs->dirty (helper->fb,NULL ,0 ,0 , &clip_copy,1 ); +if (dirty)Could do it the other way too, ie. just make the copy, and then check the copy (can be done after dropping the lock even). Would avoid having to add the 'dirty' variable.
Quoted 7 lines
Quoted 1 line
Sounds good. Let me try...
Another thing: How do we prevent userspace from doing the same, i.e. submitting an empty rectangle? Do we need to patch up
drm_mode_dirtyfb_ioctltoo? Not much point if we fix this bug in the fb helpers and leave the barn door wide open for userspace to oops drivers ;-)OK, then how about adding a helper to call the dirty callback with a sanity check like below?
Takashi
---
drivers/gpu/drm/drm_fb_helper.c +1
-1@@ -644,7 +644,7 @@ static void drm_fb_helper_dirty_work(struct work_struct *work) clip->x2 = clip->y2 =0 ;spin_unlock_irqrestore (&helper->dirty_lock, flags); - helper->fb->funcs->dirty (helper->fb,NULL ,0 ,0 , &clip_copy,1 ); +drm_framebuffer_update_dirty (helper->fb,NULL ,0 ,0 , &clip_copy,1 ); }/** drivers/gpu/drm/drm_framebuffer.c +4
-0@@ -529,6 +529,25 @@ int drm_mode_getfb(struct drm_device *dev, }/** +* blah blah +*/ +int drm_framebuffer_update_dirty(struct drm_framebuffer *fb, + struct drm_file *file_priv,
drivers/gpu/drm/drm_framebuffer.c int drm_mode_getfb(struct drm_device *dev, · line 545
Quoted 10 lines
drivers/gpu/drm/drm_framebuffer.c +10
-0+ unsigned flags, unsigned color, + struct drm_clip_rect *clips, + unsigned num_clips) +{ + if (!fb->funcs->dirty) + return -ENOSYS; +if (!num_clips) +return 0 ; +if (clips->x1 >= clips->x2 || clips->y1 >= clips->y2) +return 0 ;
Would need to check every rect here.
Also for the ANNOTATE_COPY thing, should we check that each pair of rects has the same size?
Quoted 40 lines
drivers/gpu/drm/drm_framebuffer.c +7
-6+return fb->funcs->dirty (fb, file_priv, flags, color, clips, num_clips); +} +EXPORT_SYMBOL (drm_framebuffer_update_dirty); + +/** * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB * @dev: drm device for the ioctl * @data: data pointer for the ioctl @@ -600,12 +619,8 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, } } -if (fb->funcs->dirty) { - ret = fb->funcs->dirty (fb, file_priv, flags, r->color, - clips, num_clips); - }else { - ret = -ENOSYS ; - } + ret =drm_framebuffer_update_dirty (fb, file_priv, flags, r->color, + clips, num_clips); out_err2:kfree (clips);include/drm/drm_framebuffer.h +6
-0@@ -217,6 +217,12 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb);void drm_framebuffer_cleanup (struct drm_framebuffer *fb);void drm_framebuffer_unregister_private (struct drm_framebuffer *fb); +int drm_framebuffer_update_dirty (struct drm_framebuffer *fb, +struct drm_file *file_priv, +unsigned flags,unsigned color, +struct drm_clip_rect *clips, +unsigned num_clips); +/** * drm_framebuffer_reference - incr the fb refcnt * @fb: framebuffer
Signature · 2 lines
Ville Syrjälä Intel OTC
Quoted 64 lines · Daniel Vetter
Quoted 63 lines · Takashi Iwai
Quoted 60 lines · Ville Syrjälä
Quoted 44 lines · Takashi Iwai
Since 4.7 kernel, we've seen the error messages like
kernel: [TTM] Buffer eviction failed
kernel: qxl 0000:00:02.0:object_initfailed for (4026540032,0x00000001)
kernel: [drm:qxl_alloc_bo_reserved [qxl]] *ERROR* failed to allocate VRAM BOon QXL when switching and accessing on VT. The culprit was the generic
deferred_iocode (qxl driver switched to it since 4.7). There is a race between the dirty clip update and the call of callback.In
drm_fb_helper_dirty(), the dirty clip is updated in the spinlock, while it kicks off the update worker outside the spinlock. Meanwhile the update worker clears the dirty clip in the spinlock, too. Thus, whendrm_fb_helper_dirty()is called concurrently,schedule_work()is called after the clip is cleared in the first worker call.This patch addresses it by validating the clip before calling the dirty fb callback.
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98322
Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=1003298Fixes eaa434defaca ('drm/fb-helper: Add fb_deferred_io support')Cc <[email protected]>Signed-off-by Takashi Iwai <[email protected]>--- drivers/gpu/drm/drm_fb_helper.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)drivers/gpu/drm/drm_fb_helper.c +1
-3@@ -636,15 +636,20 @@ static void drm_fb_helper_dirty_work(struct work_struct *work) dirty_work);struct drm_clip_rect *clip = &helper->dirty_clip;struct drm_clip_rect clip_copy; +bool dirty;unsigned long flags;spin_lock_irqsave (&helper->dirty_lock, flags); - clip_copy = *clip; - clip->x1 = clip->y1 = ~0 ; - clip->x2 = clip->y2 =0 ;drivers/gpu/drm/drm_fb_helper.c static void drm_fb_helper_dirty_work(struct work_struct *work) · line 651
Quoted 10 lines
drivers/gpu/drm/drm_fb_helper.c +7
-1+ dirty = (clip->x1 < clip->x2 && clip->y1 < clip->y2); +if (dirty) { + clip_copy = *clip; + clip->x1 = clip->y1 = ~0 ; + clip->x2 = clip->y2 =0 ; + }spin_unlock_irqrestore (&helper->dirty_lock, flags); - helper->fb->funcs->dirty (helper->fb,NULL ,0 ,0 , &clip_copy,1 ); +if (dirty)Could do it the other way too, ie. just make the copy, and then check the copy (can be done after dropping the lock even). Would avoid having to add the 'dirty' variable.
Quoted 7 lines
Quoted 1 line
Sounds good. Let me try...
Another thing: How do we prevent userspace from doing the same, i.e. submitting an empty rectangle? Do we need to patch up
drm_mode_dirtyfb_ioctltoo? Not much point if we fix this bug in the fb helpers and leave the barn door wide open for userspace to oops drivers ;-)
I think of a use for sending an empty clip: where you don't want to push any new pixel data, but you do want to be sure that the pipeline has been flushed.
The change I would suggest here would be
dirty = clip->x1 <= clip->x2 && clip->y1 <= clip->y2
as the bug is not the empty rectangle but the invalid one. However, that may be overkill, and none of the backends care about the empty rect!
But, indeed, we do not validate the incoming dirtyfb either.
drivers/gpu/drm/drm_framebuffer.c +11 -0
@@ -504,10 +504,13 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, }if (num_clips && clips_ptr) { +int i; +if (num_clips <0 || num_clips >DRM_MODE_FB_DIRTY_MAX_CLIPS ) { ret = -EINVAL ; goto out_err1; } + clips =kcalloc (num_clips,sizeof (*clips),GFP_KERNEL );if (!clips) { ret = -ENOMEM ;
@@ -520,6 +523,14 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, ret = -EFAULT ; goto out_err2; } + +for (i =0 ; i < num_clips; i++) { +if (clips[i].x2 < clips[i].x1 || + clips[i].y2 < clips[i].y1) { + ret = -EINVAL ; + goto out_err2; + } + } }if (fb->funcs->dirty)
Signature · 1 line
Chris Wilson, Intel Open Source Technology Centre
Quoted 73 lines · Chris Wilson
Quoted 64 lines · Daniel Vetter
Quoted 63 lines · Takashi Iwai
Quoted 60 lines · Ville Syrjälä
Quoted 44 lines · Takashi Iwai
Since 4.7 kernel, we've seen the error messages like
kernel: [TTM] Buffer eviction failed
kernel: qxl 0000:00:02.0:object_initfailed for (4026540032,0x00000001)
kernel: [drm:qxl_alloc_bo_reserved [qxl]] *ERROR* failed to allocate VRAM BOon QXL when switching and accessing on VT. The culprit was the generic
deferred_iocode (qxl driver switched to it since 4.7). There is a race between the dirty clip update and the call of callback.In
drm_fb_helper_dirty(), the dirty clip is updated in the spinlock, while it kicks off the update worker outside the spinlock. Meanwhile the update worker clears the dirty clip in the spinlock, too. Thus, whendrm_fb_helper_dirty()is called concurrently,schedule_work()is called after the clip is cleared in the first worker call.This patch addresses it by validating the clip before calling the dirty fb callback.
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98322
Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=1003298Fixes eaa434defaca ('drm/fb-helper: Add fb_deferred_io support')Cc <[email protected]>Signed-off-by Takashi Iwai <[email protected]>--- drivers/gpu/drm/drm_fb_helper.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)drivers/gpu/drm/drm_fb_helper.c +1
-3@@ -636,15 +636,20 @@ static void drm_fb_helper_dirty_work(struct work_struct *work) dirty_work);struct drm_clip_rect *clip = &helper->dirty_clip;struct drm_clip_rect clip_copy; +bool dirty;unsigned long flags;spin_lock_irqsave (&helper->dirty_lock, flags); - clip_copy = *clip; - clip->x1 = clip->y1 = ~0 ; - clip->x2 = clip->y2 =0 ;drivers/gpu/drm/drm_fb_helper.c static void drm_fb_helper_dirty_work(struct work_struct *work) · line 651
Quoted 10 lines
drivers/gpu/drm/drm_fb_helper.c +7
-1+ dirty = (clip->x1 < clip->x2 && clip->y1 < clip->y2); +if (dirty) { + clip_copy = *clip; + clip->x1 = clip->y1 = ~0 ; + clip->x2 = clip->y2 =0 ; + }spin_unlock_irqrestore (&helper->dirty_lock, flags); - helper->fb->funcs->dirty (helper->fb,NULL ,0 ,0 , &clip_copy,1 ); +if (dirty)Could do it the other way too, ie. just make the copy, and then check the copy (can be done after dropping the lock even). Would avoid having to add the 'dirty' variable.
Quoted 7 lines
Quoted 1 line
Sounds good. Let me try...
Another thing: How do we prevent userspace from doing the same, i.e. submitting an empty rectangle? Do we need to patch up
drm_mode_dirtyfb_ioctltoo? Not much point if we fix this bug in the fb helpers and leave the barn door wide open for userspace to oops drivers ;-)
Quoted 3 lines
I think of a use for sending an empty clip: where you don't want to push any new pixel data, but you do want to be sure that the pipeline has been flushed.
What exactly should an empty rectangle flush out? It's a bit unclear, but for speed I guess drivers should be allowed to make dirty async ... -Daniel
Quoted 51 lines
The change I would suggest here would be
dirty = clip->x1 <= clip->x2 && clip->y1 <= clip->y2as the bug is not the empty rectangle but the invalid one. However, that may be overkill, and none of the backends care about the empty rect!
But, indeed, we do not validate the incoming dirtyfb either.
drivers/gpu/drm/drm_framebuffer.c +11
-0@@ -504,10 +504,13 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, }if (num_clips && clips_ptr) { +int i; +if (num_clips <0 || num_clips >DRM_MODE_FB_DIRTY_MAX_CLIPS ) { ret = -EINVAL ; goto out_err1; } + clips =kcalloc (num_clips,sizeof (*clips),GFP_KERNEL );if (!clips) { ret = -ENOMEM ;@@ -520,6 +523,14 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, ret = -EFAULT ; goto out_err2; } + +for (i =0 ; i < num_clips; i++) { +if (clips[i].x2 < clips[i].x1 || + clips[i].y2 < clips[i].y1) { + ret = -EINVAL ; + goto out_err2; + } + } }if (fb->funcs->dirty)Signature · 6 lines
-- Chris Wilson, Intel Open Source Technology Centre _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
Signature · 3 lines
Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch
Quoted 7 lines · Daniel Vetter
Quoted 3 lines · Chris Wilson
I think of a use for sending an empty clip: where you don't want to push any new pixel data, but you do want to be sure that the pipeline has been flushed.
What exactly should an empty rectangle flush out? It's a bit unclear, but for speed I guess drivers should be allowed to make dirty async ...
No idea! I'm just speculating that I can see a use for a dirtyfb barrier even with an empty cliprect. Empty clips are a useful distinction elsewhere that I would suggest not forbidding them outright but defining their behaviour.
-Chris
Signature · 1 line
Chris Wilson, Intel Open Source Technology Centre
Quoted 6 lines · Chris Wilson
Quoted 5 lines · Daniel Vetter
Quoted 3 lines · Chris Wilson
I think of a use for sending an empty clip: where you don't want to push any new pixel data, but you do want to be sure that the pipeline has been flushed.
Quoted 7 lines
Quoted 2 lines
What exactly should an empty rectangle flush out? It's a bit unclear, but for speed I guess drivers should be allowed to make dirty async ...
No idea! I'm just speculating that I can see a use for a dirtyfb barrier even with an empty cliprect. Empty clips are a useful distinction elsewhere that I would suggest not forbidding them outright but defining their behaviour.
In general I prefer clarifying unused and undefined cases to "reject them". We can always add a cap later on when we want to give them some real meaning.
-Daniel
Signature · 7 lines
Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel