History

drm/dp/mst: Remove port after removing connector.

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."

Maarten Lankhorst committed 11 years ago

Commit 4772ff01 parent 5677d672 files · +13 −8Browse files

Unified · Split

2 files
  1. drivers/gpu/drm/drm_dp_mst_topology.c +13 −6
  2. include/drm/drm_crtc.h +0 −2
drivers/gpu/drm/drm_dp_mst_topology.c+13−6
@@ -873,9 +873,10 @@ static void drm_dp_destroy_port(struct kref *kref) · 872 unmodified lines
873873 from an EDID retrieval */
874874 if (port->connector) {
875875 mutex_lock(&mgr->destroy_connector_lock);
876− list_add(&port->connector->destroy_list, &mgr->destroy_connector_list);
876+ list_add(&port->next, &mgr->destroy_connector_list);
877877 mutex_unlock(&mgr->destroy_connector_lock);
878878 schedule_work(&mgr->destroy_connector_work);
879+ return;
879880 }
880881 drm_dp_port_teardown_pdt(port, port->pdt);
881882
@@ -2660,7 +2661,7 @@ static void drm_dp_tx_work(struct work_struct *work) · 1778 unmodified lines
26602661 static void drm_dp_destroy_connector_work(struct work_struct *work)
26612662 {
26622663 struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work);
2663− struct drm_connector *connector;
2664+ struct drm_dp_mst_port *port;
26642665
26652666 /*
26662667 * Not a regular list traverse as we have to drop the destroy
@@ -2669,15 +2670,21 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) · 2 unmodified lines
26692670 */
26702671 for (;;) {
26712672 mutex_lock(&mgr->destroy_connector_lock);
2672− connector = list_first_entry_or_null(&mgr->destroy_connector_list, struct drm_connector, destroy_list);
2673− if (!connector) {
2673+ port = list_first_entry_or_null(&mgr->destroy_connector_list, struct drm_dp_mst_port, next);
2674+ if (!port) {
26742675 mutex_unlock(&mgr->destroy_connector_lock);
26752676 break;
26762677 }
2677− list_del(&connector->destroy_list);
2678+ list_del(&port->next);
26782679 mutex_unlock(&mgr->destroy_connector_lock);
26792680
2680− mgr->cbs->destroy_connector(mgr, connector);
2681+ mgr->cbs->destroy_connector(mgr, port->connector);
2682+
2683+ drm_dp_port_teardown_pdt(port, port->pdt);
2684+
2685+ if (!port->input && port->vcpi.vcpi > 0)
2686+ drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi);
2687+ kfree(port);
26812688 }
26822689 }
26832690
include/drm/drm_crtc.h+0−2
@@ -743,8 +743,6 @@ struct drm_connector { · 742 unmodified lines
743743 uint8_t num_h_tile, num_v_tile;
744744 uint8_t tile_h_loc, tile_v_loc;
745745 uint16_t tile_h_size, tile_v_size;
746−
747− struct list_head destroy_list;
748746 };
749747
750748 /**