| From 998a7f0c2d492a02f223a1271e94228334431916 Mon Sep 17 00:00:00 2001 |
| From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> |
| Date: Thu, 21 Feb 2019 02:51:37 +0200 |
| Subject: drm: writeback: Fix leak of writeback job |
| |
| [ Upstream commit e482ae9b5fdc01a343f22f52930e85a6cfdf85eb ] |
| |
| Writeback jobs are allocated when the WRITEBACK_FB_ID is set, and |
| deleted when the jobs complete. This results in both a memory leak of |
| the job and a leak of the framebuffer if the atomic commit returns |
| before the job is queued for processing, for instance if the atomic |
| check fails or if the commit runs in test-only mode. |
| |
| Fix this by implementing the drm_writeback_cleanup_job() function and |
| calling it from __drm_atomic_helper_connector_destroy_state(). As |
| writeback jobs are removed from the state when they're queued for |
| processing, any job left in the state when the state gets destroyed |
| needs to be cleaned up. |
| |
| The existing declaration of the drm_writeback_cleanup_job() function |
| without an implementation hints that this problem was considered, but |
| never addressed. |
| |
| Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> |
| Reviewed-by: Brian Starkey <brian.starkey@arm.com> |
| Acked-by: Liviu Dudau <liviu.dudau@arm.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/gpu/drm/drm_atomic_state_helper.c | 4 ++++ |
| drivers/gpu/drm/drm_writeback.c | 14 +++++++++++--- |
| 2 files changed, 15 insertions(+), 3 deletions(-) |
| |
| diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c |
| index 4985384e51f6e..59ffb6b9c7453 100644 |
| --- a/drivers/gpu/drm/drm_atomic_state_helper.c |
| +++ b/drivers/gpu/drm/drm_atomic_state_helper.c |
| @@ -30,6 +30,7 @@ |
| #include <drm/drm_connector.h> |
| #include <drm/drm_atomic.h> |
| #include <drm/drm_device.h> |
| +#include <drm/drm_writeback.h> |
| |
| #include <linux/slab.h> |
| #include <linux/dma-fence.h> |
| @@ -412,6 +413,9 @@ __drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state) |
| |
| if (state->commit) |
| drm_crtc_commit_put(state->commit); |
| + |
| + if (state->writeback_job) |
| + drm_writeback_cleanup_job(state->writeback_job); |
| } |
| EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state); |
| |
| diff --git a/drivers/gpu/drm/drm_writeback.c b/drivers/gpu/drm/drm_writeback.c |
| index c20e6fe00cb38..2d75032f81591 100644 |
| --- a/drivers/gpu/drm/drm_writeback.c |
| +++ b/drivers/gpu/drm/drm_writeback.c |
| @@ -268,6 +268,15 @@ void drm_writeback_queue_job(struct drm_writeback_connector *wb_connector, |
| } |
| EXPORT_SYMBOL(drm_writeback_queue_job); |
| |
| +void drm_writeback_cleanup_job(struct drm_writeback_job *job) |
| +{ |
| + if (job->fb) |
| + drm_framebuffer_put(job->fb); |
| + |
| + kfree(job); |
| +} |
| +EXPORT_SYMBOL(drm_writeback_cleanup_job); |
| + |
| /* |
| * @cleanup_work: deferred cleanup of a writeback job |
| * |
| @@ -280,10 +289,9 @@ static void cleanup_work(struct work_struct *work) |
| struct drm_writeback_job *job = container_of(work, |
| struct drm_writeback_job, |
| cleanup_work); |
| - drm_framebuffer_put(job->fb); |
| - kfree(job); |
| -} |
| |
| + drm_writeback_cleanup_job(job); |
| +} |
| |
| /** |
| * drm_writeback_signal_completion - Signal the completion of a writeback job |
| -- |
| 2.20.1 |
| |