diff options
author | Maarten Lankhorst <maarten.lankhorst@linux.intel.com> | 2015-08-11 09:54:29 +0200 |
---|---|---|
committer | Sasha Levin <sasha.levin@oracle.com> | 2016-02-15 15:45:35 -0500 |
commit | 7d1dc93a85c3593f35985b78ab5325085c2fa2e6 (patch) | |
tree | 2a4692411b9f1504f016189e78dfac418db3b71c | |
parent | 95b098789dd20a09885c288fe8db200c26490c18 (diff) | |
download | lwn-7d1dc93a85c3593f35985b78ab5325085c2fa2e6.tar.gz lwn-7d1dc93a85c3593f35985b78ab5325085c2fa2e6.zip |
drm/dp/mst: Remove port after removing connector.
[ Upstream commit 4772ff03df8094fd99d28de5fcf5df3a3e9c68bb ]
The port is removed synchronously, but the connector delayed.
This causes a use after free which can cause a kernel BUG with
slug_debug=FPZU. This is fixed by freeing the port after the
connector.
This fixes a regression introduced with
6b8eeca65b18ae77e175cc2b6571731f0ee413bf
"drm/dp/mst: close deadlock in connector destruction."
Cc: stable@vger.kernel.org
Cc: Dave Airlie <airlied@redhat.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
-rw-r--r-- | drivers/gpu/drm/drm_dp_mst_topology.c | 19 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 2 |
2 files changed, 13 insertions, 8 deletions
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 6010976a62ec..d7d70e873488 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -871,9 +871,10 @@ static void drm_dp_destroy_port(struct kref *kref) from an EDID retrieval */ if (port->connector) { mutex_lock(&mgr->destroy_connector_lock); - list_add(&port->connector->destroy_list, &mgr->destroy_connector_list); + list_add(&port->next, &mgr->destroy_connector_list); mutex_unlock(&mgr->destroy_connector_lock); schedule_work(&mgr->destroy_connector_work); + return; } drm_dp_port_teardown_pdt(port, port->pdt); @@ -2738,7 +2739,7 @@ static void drm_dp_tx_work(struct work_struct *work) static void drm_dp_destroy_connector_work(struct work_struct *work) { struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work); - struct drm_connector *connector; + struct drm_dp_mst_port *port; /* * Not a regular list traverse as we have to drop the destroy @@ -2747,15 +2748,21 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) */ for (;;) { mutex_lock(&mgr->destroy_connector_lock); - connector = list_first_entry_or_null(&mgr->destroy_connector_list, struct drm_connector, destroy_list); - if (!connector) { + port = list_first_entry_or_null(&mgr->destroy_connector_list, struct drm_dp_mst_port, next); + if (!port) { mutex_unlock(&mgr->destroy_connector_lock); break; } - list_del(&connector->destroy_list); + list_del(&port->next); mutex_unlock(&mgr->destroy_connector_lock); - mgr->cbs->destroy_connector(mgr, connector); + mgr->cbs->destroy_connector(mgr, port->connector); + + drm_dp_port_teardown_pdt(port, port->pdt); + + if (!port->input && port->vcpi.vcpi > 0) + drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); + kfree(port); } } diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 54233583c6cb..ca71c03143d1 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -731,8 +731,6 @@ struct drm_connector { uint8_t num_h_tile, num_v_tile; uint8_t tile_h_loc, tile_v_loc; uint16_t tile_h_size, tile_v_size; - - struct list_head destroy_list; }; /** |