aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Hellstrom <thellstrom@vmware.com>2018-11-12 09:46:39 -0500
committerThomas Hellstrom <thellstrom@vmware.com>2018-12-05 04:08:53 -0500
commit9da6e26c0aae3fda6017c1ecf5c8881f8dbc37df (patch)
treef5508c1cf472149239011c514789cde6788390fc
parent9d9486e43728cd513e10ed3dd54e156c8ab7bd2a (diff)
drm/vmwgfx: Fix a layout race condition
This fixes a layout update race condition. We make sure the crtc mutex is locked before we dereference crtc->state. Otherwise the state might change under us. Since now we're already holding the crtc mutexes when reading the gui coordinates, protect them with the crtc mutexes rather than with the requested_layout mutex. Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Reviewed-by: Deepak Rawat <drawat@vmware.com> Reviewed-by: Sinclair Yeh <syeh@vmware.com>
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c1
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h9
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c66
3 files changed, 39 insertions, 37 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index b9c078860a7c..9fd8b4e75a8c 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -665,7 +665,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
665 mutex_init(&dev_priv->cmdbuf_mutex); 665 mutex_init(&dev_priv->cmdbuf_mutex);
666 mutex_init(&dev_priv->release_mutex); 666 mutex_init(&dev_priv->release_mutex);
667 mutex_init(&dev_priv->binding_mutex); 667 mutex_init(&dev_priv->binding_mutex);
668 mutex_init(&dev_priv->requested_layout_mutex);
669 mutex_init(&dev_priv->global_kms_state_mutex); 668 mutex_init(&dev_priv->global_kms_state_mutex);
670 ttm_lock_init(&dev_priv->reservation_sem); 669 ttm_lock_init(&dev_priv->reservation_sem);
671 spin_lock_init(&dev_priv->resource_lock); 670 spin_lock_init(&dev_priv->resource_lock);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index 5fbe47a52609..d7f6cb9331de 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -466,15 +466,6 @@ struct vmw_private {
466 uint32_t num_displays; 466 uint32_t num_displays;
467 467
468 /* 468 /*
469 * Currently requested_layout_mutex is used to protect the gui
470 * positionig state in display unit. With that use case currently this
471 * mutex is only taken during layout ioctl and atomic check_modeset.
472 * Other display unit state can be protected with this mutex but that
473 * needs careful consideration.
474 */
475 struct mutex requested_layout_mutex;
476
477 /*
478 * Framebuffer info. 469 * Framebuffer info.
479 */ 470 */
480 471
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 43ee7ccca418..b351fb5214d3 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -1599,7 +1599,6 @@ static int vmw_kms_check_implicit(struct drm_device *dev,
1599static int vmw_kms_check_topology(struct drm_device *dev, 1599static int vmw_kms_check_topology(struct drm_device *dev,
1600 struct drm_atomic_state *state) 1600 struct drm_atomic_state *state)
1601{ 1601{
1602 struct vmw_private *dev_priv = vmw_priv(dev);
1603 struct drm_crtc_state *old_crtc_state, *new_crtc_state; 1602 struct drm_crtc_state *old_crtc_state, *new_crtc_state;
1604 struct drm_rect *rects; 1603 struct drm_rect *rects;
1605 struct drm_crtc *crtc; 1604 struct drm_crtc *crtc;
@@ -1611,19 +1610,31 @@ static int vmw_kms_check_topology(struct drm_device *dev,
1611 if (!rects) 1610 if (!rects)
1612 return -ENOMEM; 1611 return -ENOMEM;
1613 1612
1614 mutex_lock(&dev_priv->requested_layout_mutex);
1615
1616 drm_for_each_crtc(crtc, dev) { 1613 drm_for_each_crtc(crtc, dev) {
1617 struct vmw_display_unit *du = vmw_crtc_to_du(crtc); 1614 struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
1618 struct drm_crtc_state *crtc_state = crtc->state; 1615 struct drm_crtc_state *crtc_state;
1619 1616
1620 i = drm_crtc_index(crtc); 1617 i = drm_crtc_index(crtc);
1621 1618
1622 if (crtc_state && crtc_state->enable) { 1619 crtc_state = vmw_crtc_state_and_lock(state, crtc);
1620 if (IS_ERR(crtc_state)) {
1621 ret = PTR_ERR(crtc_state);
1622 goto clean;
1623 }
1624
1625 if (!crtc_state)
1626 continue;
1627
1628 if (crtc_state->enable) {
1623 rects[i].x1 = du->gui_x; 1629 rects[i].x1 = du->gui_x;
1624 rects[i].y1 = du->gui_y; 1630 rects[i].y1 = du->gui_y;
1625 rects[i].x2 = du->gui_x + crtc_state->mode.hdisplay; 1631 rects[i].x2 = du->gui_x + crtc_state->mode.hdisplay;
1626 rects[i].y2 = du->gui_y + crtc_state->mode.vdisplay; 1632 rects[i].y2 = du->gui_y + crtc_state->mode.vdisplay;
1633 } else {
1634 rects[i].x1 = 0;
1635 rects[i].y1 = 0;
1636 rects[i].x2 = 0;
1637 rects[i].y2 = 0;
1627 } 1638 }
1628 } 1639 }
1629 1640
@@ -1635,14 +1646,6 @@ static int vmw_kms_check_topology(struct drm_device *dev,
1635 struct drm_connector_state *conn_state; 1646 struct drm_connector_state *conn_state;
1636 struct vmw_connector_state *vmw_conn_state; 1647 struct vmw_connector_state *vmw_conn_state;
1637 1648
1638 if (!new_crtc_state->enable) {
1639 rects[i].x1 = 0;
1640 rects[i].y1 = 0;
1641 rects[i].x2 = 0;
1642 rects[i].y2 = 0;
1643 continue;
1644 }
1645
1646 if (!du->pref_active) { 1649 if (!du->pref_active) {
1647 ret = -EINVAL; 1650 ret = -EINVAL;
1648 goto clean; 1651 goto clean;
@@ -1663,18 +1666,12 @@ static int vmw_kms_check_topology(struct drm_device *dev,
1663 vmw_conn_state = vmw_connector_state_to_vcs(conn_state); 1666 vmw_conn_state = vmw_connector_state_to_vcs(conn_state);
1664 vmw_conn_state->gui_x = du->gui_x; 1667 vmw_conn_state->gui_x = du->gui_x;
1665 vmw_conn_state->gui_y = du->gui_y; 1668 vmw_conn_state->gui_y = du->gui_y;
1666
1667 rects[i].x1 = du->gui_x;
1668 rects[i].y1 = du->gui_y;
1669 rects[i].x2 = du->gui_x + new_crtc_state->mode.hdisplay;
1670 rects[i].y2 = du->gui_y + new_crtc_state->mode.vdisplay;
1671 } 1669 }
1672 1670
1673 ret = vmw_kms_check_display_memory(dev, dev->mode_config.num_crtc, 1671 ret = vmw_kms_check_display_memory(dev, dev->mode_config.num_crtc,
1674 rects); 1672 rects);
1675 1673
1676clean: 1674clean:
1677 mutex_unlock(&dev_priv->requested_layout_mutex);
1678 kfree(rects); 1675 kfree(rects);
1679 return ret; 1676 return ret;
1680} 1677}
@@ -2031,11 +2028,25 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv,
2031 struct vmw_display_unit *du; 2028 struct vmw_display_unit *du;
2032 struct drm_connector *con; 2029 struct drm_connector *con;
2033 struct drm_connector_list_iter conn_iter; 2030 struct drm_connector_list_iter conn_iter;
2031 struct drm_modeset_acquire_ctx ctx;
2032 struct drm_crtc *crtc;
2033 int ret;
2034
2035 /* Currently gui_x/y is protected with the crtc mutex */
2036 mutex_lock(&dev->mode_config.mutex);
2037 drm_modeset_acquire_init(&ctx, 0);
2038retry:
2039 drm_for_each_crtc(crtc, dev) {
2040 ret = drm_modeset_lock(&crtc->mutex, &ctx);
2041 if (ret < 0) {
2042 if (ret == -EDEADLK) {
2043 drm_modeset_backoff(&ctx);
2044 goto retry;
2045 }
2046 goto out_fini;
2047 }
2048 }
2034 2049
2035 /*
2036 * Currently only gui_x/y is protected with requested_layout_mutex.
2037 */
2038 mutex_lock(&dev_priv->requested_layout_mutex);
2039 drm_connector_list_iter_begin(dev, &conn_iter); 2050 drm_connector_list_iter_begin(dev, &conn_iter);
2040 drm_for_each_connector_iter(con, &conn_iter) { 2051 drm_for_each_connector_iter(con, &conn_iter) {
2041 du = vmw_connector_to_du(con); 2052 du = vmw_connector_to_du(con);
@@ -2054,9 +2065,7 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv,
2054 } 2065 }
2055 } 2066 }
2056 drm_connector_list_iter_end(&conn_iter); 2067 drm_connector_list_iter_end(&conn_iter);
2057 mutex_unlock(&dev_priv->requested_layout_mutex);
2058 2068
2059 mutex_lock(&dev->mode_config.mutex);
2060 list_for_each_entry(con, &dev->mode_config.connector_list, head) { 2069 list_for_each_entry(con, &dev->mode_config.connector_list, head) {
2061 du = vmw_connector_to_du(con); 2070 du = vmw_connector_to_du(con);
2062 if (num_rects > du->unit) { 2071 if (num_rects > du->unit) {
@@ -2076,10 +2085,13 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv,
2076 } 2085 }
2077 con->status = vmw_du_connector_detect(con, true); 2086 con->status = vmw_du_connector_detect(con, true);
2078 } 2087 }
2079 mutex_unlock(&dev->mode_config.mutex);
2080 2088
2081 drm_sysfs_hotplug_event(dev); 2089 drm_sysfs_hotplug_event(dev);
2082 2090out_fini:
2091 drm_modeset_drop_locks(&ctx);
2092 drm_modeset_acquire_fini(&ctx);
2093 mutex_unlock(&dev->mode_config.mutex);
2094
2083 return 0; 2095 return 0;
2084} 2096}
2085 2097