All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] drm/fb-helper: Don't call dirty callback for untouched clips
@ 2016-10-20 14:39 Takashi Iwai
  2016-10-20 14:56 ` Ville Syrjälä
  0 siblings, 1 reply; 12+ messages in thread
From: Takashi Iwai @ 2016-10-20 14:39 UTC (permalink / raw)
  To: dri-devel
  Cc: linux-kernel, Daniel Vetter, Ville Syrjälä,
	Noralf Trønnes, David Airlie

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
Fixes: eaa434defaca ('drm/fb-helper: Add fb_deferred_io support')
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 drivers/gpu/drm/drm_fb_helper.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 03414bde1f15..d790d205129e 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -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);
 }
 
 /**
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH] drm/fb-helper: Don't call dirty callback for untouched clips
  2016-10-20 14:39 [PATCH] drm/fb-helper: Don't call dirty callback for untouched clips Takashi Iwai
@ 2016-10-20 14:56 ` Ville Syrjälä
  2016-10-20 15:00   ` Takashi Iwai
  0 siblings, 1 reply; 12+ messages in thread
From: Ville Syrjälä @ 2016-10-20 14:56 UTC (permalink / raw)
  To: Takashi Iwai
  Cc: dri-devel, linux-kernel, Daniel Vetter, Noralf Trønnes,
	David Airlie

On Thu, Oct 20, 2016 at 04:39:52PM +0200, Takashi Iwai wrote:
> 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
> Fixes: eaa434defaca ('drm/fb-helper: Add fb_deferred_io support')
> Cc: <stable@vger.kernel.org>
> Signed-off-by: Takashi Iwai <tiwai@suse.de>
> ---
>  drivers/gpu/drm/drm_fb_helper.c | 13 +++++++++----
>  1 file changed, 9 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 03414bde1f15..d790d205129e 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -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)

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.

> +		helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, &clip_copy, 1);
>  }
>  
>  /**
> -- 
> 2.10.1

-- 
Ville Syrjälä
Intel OTC

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] drm/fb-helper: Don't call dirty callback for untouched clips
  2016-10-20 14:56 ` Ville Syrjälä
@ 2016-10-20 15:00   ` Takashi Iwai
  2016-10-21 12:30     ` Daniel Vetter
  0 siblings, 1 reply; 12+ messages in thread
From: Takashi Iwai @ 2016-10-20 15:00 UTC (permalink / raw)
  To: Ville Syrjälä
  Cc: dri-devel, linux-kernel, Daniel Vetter, Noralf Trønnes,
	David Airlie

On Thu, 20 Oct 2016 16:56:04 +0200,
Ville Syrjälä wrote:
> 
> On Thu, Oct 20, 2016 at 04:39:52PM +0200, Takashi Iwai wrote:
> > 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
> > Fixes: eaa434defaca ('drm/fb-helper: Add fb_deferred_io support')
> > Cc: <stable@vger.kernel.org>
> > Signed-off-by: Takashi Iwai <tiwai@suse.de>
> > ---
> >  drivers/gpu/drm/drm_fb_helper.c | 13 +++++++++----
> >  1 file changed, 9 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> > index 03414bde1f15..d790d205129e 100644
> > --- a/drivers/gpu/drm/drm_fb_helper.c
> > +++ b/drivers/gpu/drm/drm_fb_helper.c
> > @@ -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)
> 
> 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

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] drm/fb-helper: Don't call dirty callback for untouched clips
  2016-10-20 15:00   ` Takashi Iwai
@ 2016-10-21 12:30     ` Daniel Vetter
  2016-10-21 12:48         ` Takashi Iwai
  2016-10-21 12:57       ` Chris Wilson
  0 siblings, 2 replies; 12+ messages in thread
From: Daniel Vetter @ 2016-10-21 12:30 UTC (permalink / raw)
  To: Takashi Iwai
  Cc: Ville Syrjälä,
	dri-devel, linux-kernel, Daniel Vetter, Noralf Trønnes,
	David Airlie

On Thu, Oct 20, 2016 at 05:00:35PM +0200, Takashi Iwai wrote:
> On Thu, 20 Oct 2016 16:56:04 +0200,
> Ville Syrjälä wrote:
> > 
> > On Thu, Oct 20, 2016 at 04:39:52PM +0200, Takashi Iwai wrote:
> > > 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
> > > Fixes: eaa434defaca ('drm/fb-helper: Add fb_deferred_io support')
> > > Cc: <stable@vger.kernel.org>
> > > Signed-off-by: Takashi Iwai <tiwai@suse.de>
> > > ---
> > >  drivers/gpu/drm/drm_fb_helper.c | 13 +++++++++----
> > >  1 file changed, 9 insertions(+), 4 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> > > index 03414bde1f15..d790d205129e 100644
> > > --- a/drivers/gpu/drm/drm_fb_helper.c
> > > +++ b/drivers/gpu/drm/drm_fb_helper.c
> > > @@ -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)
> > 
> > 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

> 
> 
> Takashi

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] drm/fb-helper: Don't call dirty callback for untouched clips
  2016-10-21 12:30     ` Daniel Vetter
@ 2016-10-21 12:48         ` Takashi Iwai
  2016-10-21 12:57       ` Chris Wilson
  1 sibling, 0 replies; 12+ messages in thread
From: Takashi Iwai @ 2016-10-21 12:48 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: Ville Syrjälä,
	dri-devel, linux-kernel, Noralf Trønnes, David Airlie

On Fri, 21 Oct 2016 14:30:32 +0200,
Daniel Vetter wrote:
> 
> On Thu, Oct 20, 2016 at 05:00:35PM +0200, Takashi Iwai wrote:
> > On Thu, 20 Oct 2016 16:56:04 +0200,
> > Ville Syrjälä wrote:
> > > 
> > > On Thu, Oct 20, 2016 at 04:39:52PM +0200, Takashi Iwai wrote:
> > > > 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
> > > > Fixes: eaa434defaca ('drm/fb-helper: Add fb_deferred_io support')
> > > > Cc: <stable@vger.kernel.org>
> > > > Signed-off-by: Takashi Iwai <tiwai@suse.de>
> > > > ---
> > > >  drivers/gpu/drm/drm_fb_helper.c | 13 +++++++++----
> > > >  1 file changed, 9 insertions(+), 4 deletions(-)
> > > > 
> > > > diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> > > > index 03414bde1f15..d790d205129e 100644
> > > > --- a/drivers/gpu/drm/drm_fb_helper.c
> > > > +++ b/drivers/gpu/drm/drm_fb_helper.c
> > > > @@ -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)
> > > 
> > > 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
> ;-)

OK, then how about adding a helper to call the dirty callback with a
sanity check like below?


Takashi

---
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 03414bde1f15..7bef4d642511 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -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);
 }
 
 /**
diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
index 398efd67cb93..0817a0b607c5 100644
--- a/drivers/gpu/drm/drm_framebuffer.c
+++ b/drivers/gpu/drm/drm_framebuffer.c
@@ -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);
diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h
index f5ae1f436a4b..feabd9139fdb 100644
--- a/include/drm/drm_framebuffer.h
+++ b/include/drm/drm_framebuffer.h
@@ -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

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH] drm/fb-helper: Don't call dirty callback for untouched clips
@ 2016-10-21 12:48         ` Takashi Iwai
  0 siblings, 0 replies; 12+ messages in thread
From: Takashi Iwai @ 2016-10-21 12:48 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel, linux-kernel

On Fri, 21 Oct 2016 14:30:32 +0200,
Daniel Vetter wrote:
> 
> On Thu, Oct 20, 2016 at 05:00:35PM +0200, Takashi Iwai wrote:
> > On Thu, 20 Oct 2016 16:56:04 +0200,
> > Ville Syrjälä wrote:
> > > 
> > > On Thu, Oct 20, 2016 at 04:39:52PM +0200, Takashi Iwai wrote:
> > > > 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
> > > > Fixes: eaa434defaca ('drm/fb-helper: Add fb_deferred_io support')
> > > > Cc: <stable@vger.kernel.org>
> > > > Signed-off-by: Takashi Iwai <tiwai@suse.de>
> > > > ---
> > > >  drivers/gpu/drm/drm_fb_helper.c | 13 +++++++++----
> > > >  1 file changed, 9 insertions(+), 4 deletions(-)
> > > > 
> > > > diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> > > > index 03414bde1f15..d790d205129e 100644
> > > > --- a/drivers/gpu/drm/drm_fb_helper.c
> > > > +++ b/drivers/gpu/drm/drm_fb_helper.c
> > > > @@ -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)
> > > 
> > > 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
> ;-)

OK, then how about adding a helper to call the dirty callback with a
sanity check like below?


Takashi

---
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 03414bde1f15..7bef4d642511 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -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);
 }
 
 /**
diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
index 398efd67cb93..0817a0b607c5 100644
--- a/drivers/gpu/drm/drm_framebuffer.c
+++ b/drivers/gpu/drm/drm_framebuffer.c
@@ -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);
diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h
index f5ae1f436a4b..feabd9139fdb 100644
--- a/include/drm/drm_framebuffer.h
+++ b/include/drm/drm_framebuffer.h
@@ -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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH] drm/fb-helper: Don't call dirty callback for untouched clips
  2016-10-21 12:30     ` Daniel Vetter
  2016-10-21 12:48         ` Takashi Iwai
@ 2016-10-21 12:57       ` Chris Wilson
  2016-10-21 18:19         ` Daniel Vetter
  1 sibling, 1 reply; 12+ messages in thread
From: Chris Wilson @ 2016-10-21 12:57 UTC (permalink / raw)
  To: Takashi Iwai, Ville Syrjälä,
	dri-devel, linux-kernel, Noralf Trønnes, David Airlie

On Fri, Oct 21, 2016 at 02:30:32PM +0200, Daniel Vetter wrote:
> On Thu, Oct 20, 2016 at 05:00:35PM +0200, Takashi Iwai wrote:
> > On Thu, 20 Oct 2016 16:56:04 +0200,
> > Ville Syrjälä wrote:
> > > 
> > > On Thu, Oct 20, 2016 at 04:39:52PM +0200, Takashi Iwai wrote:
> > > > 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
> > > > Fixes: eaa434defaca ('drm/fb-helper: Add fb_deferred_io support')
> > > > Cc: <stable@vger.kernel.org>
> > > > Signed-off-by: Takashi Iwai <tiwai@suse.de>
> > > > ---
> > > >  drivers/gpu/drm/drm_fb_helper.c | 13 +++++++++----
> > > >  1 file changed, 9 insertions(+), 4 deletions(-)
> > > > 
> > > > diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> > > > index 03414bde1f15..d790d205129e 100644
> > > > --- a/drivers/gpu/drm/drm_fb_helper.c
> > > > +++ b/drivers/gpu/drm/drm_fb_helper.c
> > > > @@ -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)
> > > 
> > > 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
> ;-)

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.

diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
index 49fd7db758e0..ada6a5517945 100644
--- a/drivers/gpu/drm/drm_framebuffer.c
+++ b/drivers/gpu/drm/drm_framebuffer.c
@@ -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) 


-- 
Chris Wilson, Intel Open Source Technology Centre

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH] drm/fb-helper: Don't call dirty callback for untouched clips
  2016-10-21 12:48         ` Takashi Iwai
  (?)
@ 2016-10-21 12:57         ` Ville Syrjälä
  -1 siblings, 0 replies; 12+ messages in thread
From: Ville Syrjälä @ 2016-10-21 12:57 UTC (permalink / raw)
  To: Takashi Iwai
  Cc: Daniel Vetter, dri-devel, linux-kernel, Noralf Trønnes,
	David Airlie

On Fri, Oct 21, 2016 at 02:48:49PM +0200, Takashi Iwai wrote:
> On Fri, 21 Oct 2016 14:30:32 +0200,
> Daniel Vetter wrote:
> > 
> > On Thu, Oct 20, 2016 at 05:00:35PM +0200, Takashi Iwai wrote:
> > > On Thu, 20 Oct 2016 16:56:04 +0200,
> > > Ville Syrjälä wrote:
> > > > 
> > > > On Thu, Oct 20, 2016 at 04:39:52PM +0200, Takashi Iwai wrote:
> > > > > 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
> > > > > Fixes: eaa434defaca ('drm/fb-helper: Add fb_deferred_io support')
> > > > > Cc: <stable@vger.kernel.org>
> > > > > Signed-off-by: Takashi Iwai <tiwai@suse.de>
> > > > > ---
> > > > >  drivers/gpu/drm/drm_fb_helper.c | 13 +++++++++----
> > > > >  1 file changed, 9 insertions(+), 4 deletions(-)
> > > > > 
> > > > > diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> > > > > index 03414bde1f15..d790d205129e 100644
> > > > > --- a/drivers/gpu/drm/drm_fb_helper.c
> > > > > +++ b/drivers/gpu/drm/drm_fb_helper.c
> > > > > @@ -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)
> > > > 
> > > > 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
> > ;-)
> 
> OK, then how about adding a helper to call the dirty callback with a
> sanity check like below?
> 
> 
> Takashi
> 
> ---
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 03414bde1f15..7bef4d642511 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -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);
>  }
>  
>  /**
> diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
> index 398efd67cb93..0817a0b607c5 100644
> --- a/drivers/gpu/drm/drm_framebuffer.c
> +++ b/drivers/gpu/drm/drm_framebuffer.c
> @@ -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;

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?

> +	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);
> diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h
> index f5ae1f436a4b..feabd9139fdb 100644
> --- a/include/drm/drm_framebuffer.h
> +++ b/include/drm/drm_framebuffer.h
> @@ -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

-- 
Ville Syrjälä
Intel OTC

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] drm/fb-helper: Don't call dirty callback for untouched clips
  2016-10-21 12:57       ` Chris Wilson
@ 2016-10-21 18:19         ` Daniel Vetter
  2016-10-21 20:02           ` Chris Wilson
  0 siblings, 1 reply; 12+ messages in thread
From: Daniel Vetter @ 2016-10-21 18:19 UTC (permalink / raw)
  To: Chris Wilson, Takashi Iwai, Ville Syrjälä,
	dri-devel, linux-kernel, Noralf Trønnes, David Airlie

On Fri, Oct 21, 2016 at 01:57:28PM +0100, Chris Wilson wrote:
> On Fri, Oct 21, 2016 at 02:30:32PM +0200, Daniel Vetter wrote:
> > On Thu, Oct 20, 2016 at 05:00:35PM +0200, Takashi Iwai wrote:
> > > On Thu, 20 Oct 2016 16:56:04 +0200,
> > > Ville Syrjälä wrote:
> > > > 
> > > > On Thu, Oct 20, 2016 at 04:39:52PM +0200, Takashi Iwai wrote:
> > > > > 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
> > > > > Fixes: eaa434defaca ('drm/fb-helper: Add fb_deferred_io support')
> > > > > Cc: <stable@vger.kernel.org>
> > > > > Signed-off-by: Takashi Iwai <tiwai@suse.de>
> > > > > ---
> > > > >  drivers/gpu/drm/drm_fb_helper.c | 13 +++++++++----
> > > > >  1 file changed, 9 insertions(+), 4 deletions(-)
> > > > > 
> > > > > diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> > > > > index 03414bde1f15..d790d205129e 100644
> > > > > --- a/drivers/gpu/drm/drm_fb_helper.c
> > > > > +++ b/drivers/gpu/drm/drm_fb_helper.c
> > > > > @@ -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)
> > > > 
> > > > 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
> > ;-)
> 
> 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

> 
> 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.
> 
> diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
> index 49fd7db758e0..ada6a5517945 100644
> --- a/drivers/gpu/drm/drm_framebuffer.c
> +++ b/drivers/gpu/drm/drm_framebuffer.c
> @@ -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) 
> 
> 
> -- 
> Chris Wilson, Intel Open Source Technology Centre
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] drm/fb-helper: Don't call dirty callback for untouched clips
  2016-10-21 18:19         ` Daniel Vetter
@ 2016-10-21 20:02           ` Chris Wilson
  2016-10-22  8:41               ` Daniel Vetter
  0 siblings, 1 reply; 12+ messages in thread
From: Chris Wilson @ 2016-10-21 20:02 UTC (permalink / raw)
  To: Takashi Iwai, Ville Syrjälä,
	dri-devel, linux-kernel, Noralf Trønnes, David Airlie

On Fri, Oct 21, 2016 at 08:19:03PM +0200, Daniel Vetter wrote:
> On Fri, Oct 21, 2016 at 01:57:28PM +0100, Chris Wilson wrote:
> > 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

-- 
Chris Wilson, Intel Open Source Technology Centre

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] drm/fb-helper: Don't call dirty callback for untouched clips
  2016-10-21 20:02           ` Chris Wilson
@ 2016-10-22  8:41               ` Daniel Vetter
  0 siblings, 0 replies; 12+ messages in thread
From: Daniel Vetter @ 2016-10-22  8:41 UTC (permalink / raw)
  To: Chris Wilson, Takashi Iwai, Ville Syrjälä,
	dri-devel, linux-kernel, Noralf Trønnes, David Airlie

On Fri, Oct 21, 2016 at 09:02:27PM +0100, Chris Wilson wrote:
> On Fri, Oct 21, 2016 at 08:19:03PM +0200, Daniel Vetter wrote:
> > On Fri, Oct 21, 2016 at 01:57:28PM +0100, Chris Wilson wrote:
> > > 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.

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
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] drm/fb-helper: Don't call dirty callback for untouched clips
@ 2016-10-22  8:41               ` Daniel Vetter
  0 siblings, 0 replies; 12+ messages in thread
From: Daniel Vetter @ 2016-10-22  8:41 UTC (permalink / raw)
  To: Chris Wilson, Takashi Iwai, Ville Syrjälä,
	dri-devel, linux-kernel, Noralf Trønnes, David Airlie

On Fri, Oct 21, 2016 at 09:02:27PM +0100, Chris Wilson wrote:
> On Fri, Oct 21, 2016 at 08:19:03PM +0200, Daniel Vetter wrote:
> > On Fri, Oct 21, 2016 at 01:57:28PM +0100, Chris Wilson wrote:
> > > 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.

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
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2016-10-22  8:41 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-20 14:39 [PATCH] drm/fb-helper: Don't call dirty callback for untouched clips Takashi Iwai
2016-10-20 14:56 ` Ville Syrjälä
2016-10-20 15:00   ` Takashi Iwai
2016-10-21 12:30     ` Daniel Vetter
2016-10-21 12:48       ` Takashi Iwai
2016-10-21 12:48         ` Takashi Iwai
2016-10-21 12:57         ` Ville Syrjälä
2016-10-21 12:57       ` Chris Wilson
2016-10-21 18:19         ` Daniel Vetter
2016-10-21 20:02           ` Chris Wilson
2016-10-22  8:41             ` Daniel Vetter
2016-10-22  8:41               ` Daniel Vetter

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.