Skip to content

Commit 9da6e26

Browse files
committed
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>
1 parent 9d9486e commit 9da6e26

File tree

3 files changed

+39
-37
lines changed

3 files changed

+39
-37
lines changed

drivers/gpu/drm/vmwgfx/vmwgfx_drv.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
665665
mutex_init(&dev_priv->cmdbuf_mutex);
666666
mutex_init(&dev_priv->release_mutex);
667667
mutex_init(&dev_priv->binding_mutex);
668-
mutex_init(&dev_priv->requested_layout_mutex);
669668
mutex_init(&dev_priv->global_kms_state_mutex);
670669
ttm_lock_init(&dev_priv->reservation_sem);
671670
spin_lock_init(&dev_priv->resource_lock);

drivers/gpu/drm/vmwgfx/vmwgfx_drv.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -465,15 +465,6 @@ struct vmw_private {
465465

466466
uint32_t num_displays;
467467

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-
477468
/*
478469
* Framebuffer info.
479470
*/

drivers/gpu/drm/vmwgfx/vmwgfx_kms.c

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1599,7 +1599,6 @@ static int vmw_kms_check_implicit(struct drm_device *dev,
15991599
static int vmw_kms_check_topology(struct drm_device *dev,
16001600
struct drm_atomic_state *state)
16011601
{
1602-
struct vmw_private *dev_priv = vmw_priv(dev);
16031602
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
16041603
struct drm_rect *rects;
16051604
struct drm_crtc *crtc;
@@ -1611,19 +1610,31 @@ static int vmw_kms_check_topology(struct drm_device *dev,
16111610
if (!rects)
16121611
return -ENOMEM;
16131612

1614-
mutex_lock(&dev_priv->requested_layout_mutex);
1615-
16161613
drm_for_each_crtc(crtc, dev) {
16171614
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;
16191616

16201617
i = drm_crtc_index(crtc);
16211618

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) {
16231629
rects[i].x1 = du->gui_x;
16241630
rects[i].y1 = du->gui_y;
16251631
rects[i].x2 = du->gui_x + crtc_state->mode.hdisplay;
16261632
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;
16271638
}
16281639
}
16291640

@@ -1635,14 +1646,6 @@ static int vmw_kms_check_topology(struct drm_device *dev,
16351646
struct drm_connector_state *conn_state;
16361647
struct vmw_connector_state *vmw_conn_state;
16371648

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-
16461649
if (!du->pref_active) {
16471650
ret = -EINVAL;
16481651
goto clean;
@@ -1663,18 +1666,12 @@ static int vmw_kms_check_topology(struct drm_device *dev,
16631666
vmw_conn_state = vmw_connector_state_to_vcs(conn_state);
16641667
vmw_conn_state->gui_x = du->gui_x;
16651668
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;
16711669
}
16721670

16731671
ret = vmw_kms_check_display_memory(dev, dev->mode_config.num_crtc,
16741672
rects);
16751673

16761674
clean:
1677-
mutex_unlock(&dev_priv->requested_layout_mutex);
16781675
kfree(rects);
16791676
return ret;
16801677
}
@@ -2031,11 +2028,25 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv,
20312028
struct vmw_display_unit *du;
20322029
struct drm_connector *con;
20332030
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);
2038+
retry:
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+
}
20342049

2035-
/*
2036-
* Currently only gui_x/y is protected with requested_layout_mutex.
2037-
*/
2038-
mutex_lock(&dev_priv->requested_layout_mutex);
20392050
drm_connector_list_iter_begin(dev, &conn_iter);
20402051
drm_for_each_connector_iter(con, &conn_iter) {
20412052
du = vmw_connector_to_du(con);
@@ -2054,9 +2065,7 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv,
20542065
}
20552066
}
20562067
drm_connector_list_iter_end(&conn_iter);
2057-
mutex_unlock(&dev_priv->requested_layout_mutex);
20582068

2059-
mutex_lock(&dev->mode_config.mutex);
20602069
list_for_each_entry(con, &dev->mode_config.connector_list, head) {
20612070
du = vmw_connector_to_du(con);
20622071
if (num_rects > du->unit) {
@@ -2076,10 +2085,13 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv,
20762085
}
20772086
con->status = vmw_du_connector_detect(con, true);
20782087
}
2079-
mutex_unlock(&dev->mode_config.mutex);
20802088

20812089
drm_sysfs_hotplug_event(dev);
2082-
2090+
out_fini:
2091+
drm_modeset_drop_locks(&ctx);
2092+
drm_modeset_acquire_fini(&ctx);
2093+
mutex_unlock(&dev->mode_config.mutex);
2094+
20832095
return 0;
20842096
}
20852097

0 commit comments

Comments
 (0)