On 23/05/23 09:32, Maíra Canal wrote:
> Currently, it is possible for the composer to be set as enabled and then
> as disabled without a proper call for the vkms_vblank_simulate(). This
> is problematic, because the driver would skip one CRC output, causing CRC
> tests to fail. Therefore, we need to make sure that, for each time the
> composer is set as enabled, a composer job is added to the queue.
> 
> In order to provide this guarantee, add a mutex that will lock before
> the composer is set as enabled and will unlock only after the composer
> job is added to the queue. This way, we can have a guarantee that the
> driver won't skip a CRC entry.
> 
> This race-condition is affecting the IGT test "writeback-check-output",
> making the test fail and also, leaking writeback framebuffers, as the
> writeback job is queued, but it is not signaled. This patch avoids both
> problems.
> 
> [v2]:
>     * Create a new mutex and keep the spinlock across the atomic commit in
>       order to avoid interrupts that could result in deadlocks.
> 
> Signed-off-by: Maíra Canal <mca...@igalia.com>

Great catch!

Reviewed-by: Arthur Grillo <arthurgri...@riseup.net>

> ---
>  drivers/gpu/drm/vkms/vkms_composer.c | 9 +++++++--
>  drivers/gpu/drm/vkms/vkms_crtc.c     | 9 +++++----
>  drivers/gpu/drm/vkms/vkms_drv.h      | 4 +++-
>  3 files changed, 15 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/gpu/drm/vkms/vkms_composer.c 
> b/drivers/gpu/drm/vkms/vkms_composer.c
> index 906d3df40cdb..b12188fd6b38 100644
> --- a/drivers/gpu/drm/vkms/vkms_composer.c
> +++ b/drivers/gpu/drm/vkms/vkms_composer.c
> @@ -320,10 +320,15 @@ void vkms_set_composer(struct vkms_output *out, bool 
> enabled)
>       if (enabled)
>               drm_crtc_vblank_get(&out->crtc);
>  
> -     spin_lock_irq(&out->lock);
> +     mutex_lock(&out->enabled_lock);
>       old_enabled = out->composer_enabled;
>       out->composer_enabled = enabled;
> -     spin_unlock_irq(&out->lock);
> +
> +     /* the composition wasn't enabled, so unlock the lock to make sure the 
> lock
> +      * will be balanced even if we have a failed commit
> +      */
> +     if (!out->composer_enabled)
> +             mutex_unlock(&out->enabled_lock);
>  
>       if (old_enabled)
>               drm_crtc_vblank_put(&out->crtc);
> diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c 
> b/drivers/gpu/drm/vkms/vkms_crtc.c
> index 515f6772b866..3079013c8b32 100644
> --- a/drivers/gpu/drm/vkms/vkms_crtc.c
> +++ b/drivers/gpu/drm/vkms/vkms_crtc.c
> @@ -16,7 +16,7 @@ static enum hrtimer_restart vkms_vblank_simulate(struct 
> hrtimer *timer)
>       struct drm_crtc *crtc = &output->crtc;
>       struct vkms_crtc_state *state;
>       u64 ret_overrun;
> -     bool ret, fence_cookie;
> +     bool ret, fence_cookie, composer_enabled;
>  
>       fence_cookie = dma_fence_begin_signalling();
>  
> @@ -25,15 +25,15 @@ static enum hrtimer_restart vkms_vblank_simulate(struct 
> hrtimer *timer)
>       if (ret_overrun != 1)
>               pr_warn("%s: vblank timer overrun\n", __func__);
>  
> -     spin_lock(&output->lock);
>       ret = drm_crtc_handle_vblank(crtc);
>       if (!ret)
>               DRM_ERROR("vkms failure on handling vblank");
>  
>       state = output->composer_state;
> -     spin_unlock(&output->lock);
> +     composer_enabled = output->composer_enabled;
> +     mutex_unlock(&output->enabled_lock);
>  
> -     if (state && output->composer_enabled) {
> +     if (state && composer_enabled) {
>               u64 frame = drm_crtc_accurate_vblank_count(crtc);
>  
>               /* update frame_start only if a queued vkms_composer_worker()
> @@ -292,6 +292,7 @@ int vkms_crtc_init(struct drm_device *dev, struct 
> drm_crtc *crtc,
>  
>       spin_lock_init(&vkms_out->lock);
>       spin_lock_init(&vkms_out->composer_lock);
> +     mutex_init(&vkms_out->enabled_lock);
>  
>       vkms_out->composer_workq = alloc_ordered_workqueue("vkms_composer", 0);
>       if (!vkms_out->composer_workq)
> diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
> index 5f1a0a44a78c..dcf4e302fb4d 100644
> --- a/drivers/gpu/drm/vkms/vkms_drv.h
> +++ b/drivers/gpu/drm/vkms/vkms_drv.h
> @@ -100,8 +100,10 @@ struct vkms_output {
>       struct workqueue_struct *composer_workq;
>       /* protects concurrent access to composer */
>       spinlock_t lock;
> +     /* guarantees that if the composer is enabled, a job will be queued */
> +     struct mutex enabled_lock;
>  
> -     /* protected by @lock */
> +     /* protected by @enabled_lock */
>       bool composer_enabled;
>       struct vkms_crtc_state *composer_state;
>  

Reply via email to