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
873 from an EDID retrieval */873 from an EDID retrieval */
874 if (port->connector) {874 if (port->connector) {
875 mutex_lock(&mgr->destroy_connector_lock);875 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);
877 mutex_unlock(&mgr->destroy_connector_lock);877 mutex_unlock(&mgr->destroy_connector_lock);
878 schedule_work(&mgr->destroy_connector_work);878 schedule_work(&mgr->destroy_connector_work);
879 return;
879 }880 }
880 drm_dp_port_teardown_pdt(port, port->pdt);881 drm_dp_port_teardown_pdt(port, port->pdt);
881 882
@@ -2660,7 +2661,7 @@ static void drm_dp_tx_work(struct work_struct *work) · 1778 unmodified lines
2660static void drm_dp_destroy_connector_work(struct work_struct *work)2661static void drm_dp_destroy_connector_work(struct work_struct *work)
2661{2662{
2662 struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work);2663 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;
2664 2665
2665 /*2666 /*
2666 * Not a regular list traverse as we have to drop the destroy2667 * 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
2669 */2670 */
2670 for (;;) {2671 for (;;) {
2671 mutex_lock(&mgr->destroy_connector_lock);2672 mutex_lock(&mgr->destroy_connector_lock);
2672 connector = list_first_entry_or_null(&mgr->destroy_connector_list, struct drm_connector, destroy_list);2673 port = list_first_entry_or_null(&mgr->destroy_connector_list, struct drm_dp_mst_port, next);
2673 if (!connector) {2674 if (!port) {
2674 mutex_unlock(&mgr->destroy_connector_lock);2675 mutex_unlock(&mgr->destroy_connector_lock);
2675 break;2676 break;
2676 }2677 }
2677 list_del(&connector->destroy_list);2678 list_del(&port->next);
2678 mutex_unlock(&mgr->destroy_connector_lock);2679 mutex_unlock(&mgr->destroy_connector_lock);
2679 2680
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);
2681 }2688 }
2682}2689}
2683 2690
include/drm/drm_crtc.h+0−2
@@ -743,8 +743,6 @@ struct drm_connector { · 742 unmodified lines
743 uint8_t num_h_tile, num_v_tile;743 uint8_t num_h_tile, num_v_tile;
744 uint8_t tile_h_loc, tile_v_loc;744 uint8_t tile_h_loc, tile_v_loc;
745 uint16_t tile_h_size, tile_v_size;745 uint16_t tile_h_size, tile_v_size;
746
747 struct list_head destroy_list;
748};746};
749 747
750/**748/**