nouveau_connector_irq() schedules irq_work on the system workqueue. nouveau_connector_destroy() calls nvif_event_dtor() which unregisters the interrupt event source so no new callbacks will fire, but it does not drain the system workqueue. If a work item was already queued, nouveau_dp_irq() can run after kfree(connector) and dereference freed memory.
Add cancel_work_sync() after nvif_event_dtor() so any in-flight or pending irq_work completes before the connector is freed. Cc: [email protected] Signed-off-by: Aldo Ariel Panzardo <[email protected]> --- drivers/gpu/drm/nouveau/nouveau_connector.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index XXXXXXX..YYYYYYY 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -395,6 +395,7 @@ nouveau_connector_destroy(struct drm_connector *connector) struct nouveau_connector *nv_connector = nouveau_connector(connector); nvif_event_dtor(&nv_connector->irq); nvif_event_dtor(&nv_connector->hpd); + cancel_work_sync(&nv_connector->irq_work); kfree(nv_connector->edid); drm_connector_unregister(connector); drm_connector_cleanup(connector);
