Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm: writeback: Fix leak of writeback job

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>

+15 -3
+4
drivers/gpu/drm/drm_atomic_state_helper.c
··· 30 30 #include <drm/drm_connector.h> 31 31 #include <drm/drm_atomic.h> 32 32 #include <drm/drm_device.h> 33 + #include <drm/drm_writeback.h> 33 34 34 35 #include <linux/slab.h> 35 36 #include <linux/dma-fence.h> ··· 413 412 414 413 if (state->commit) 415 414 drm_crtc_commit_put(state->commit); 415 + 416 + if (state->writeback_job) 417 + drm_writeback_cleanup_job(state->writeback_job); 416 418 } 417 419 EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state); 418 420
+11 -3
drivers/gpu/drm/drm_writeback.c
··· 273 273 } 274 274 EXPORT_SYMBOL(drm_writeback_queue_job); 275 275 276 + void drm_writeback_cleanup_job(struct drm_writeback_job *job) 277 + { 278 + if (job->fb) 279 + drm_framebuffer_put(job->fb); 280 + 281 + kfree(job); 282 + } 283 + EXPORT_SYMBOL(drm_writeback_cleanup_job); 284 + 276 285 /* 277 286 * @cleanup_work: deferred cleanup of a writeback job 278 287 * ··· 294 285 struct drm_writeback_job *job = container_of(work, 295 286 struct drm_writeback_job, 296 287 cleanup_work); 297 - drm_framebuffer_put(job->fb); 298 - kfree(job); 299 - } 300 288 289 + drm_writeback_cleanup_job(job); 290 + } 301 291 302 292 /** 303 293 * drm_writeback_signal_completion - Signal the completion of a writeback job