Currently, drm_helper_probe_single_connector_modes() holds
connection_mutex while it probes and prunes connector->modes, then drops
it before sorting the list and filling in the crtc_* fields of each
mode. The caller still holds mode_config.mutex at that point, but
drm_atomic_check_only() never takes it. The only lock it holds on the
connector is connection_mutex, which drm_atomic_get_connector_state()
takes for it

amdgpu walks connector->modes from its atomic_check, in
create_stream_for_sink() and amdgpu_dm_get_highest_refresh_rate_mode(),
holding only the locks of the atomic acquire context. list_sort()
NULL-terminates the list while it runs, so that walk can follow a NULL
next pointer or read a mode whose crtc_* fields are being rewritten

Sort the list and set crtcinfo before dropping the locks, as the
function already does when it probes and prunes the modes. As far as I
can tell, the unlock ended up in front of the sort when
commit 6c5ed5ae353c ("drm/atomic: Acquire connection_mutex lock in 
drm_helper_probe_single_connector_modes, v4.")
first took connection_mutex here, and that commit gives no reason for
the order

Signed-off-by: Hugo Sales <[email protected]>
---
 drivers/gpu/drm/drm_probe_helper.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/drm_probe_helper.c 
b/drivers/gpu/drm/drm_probe_helper.c
index 856b40fdaac4a..2085d93651b21 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -703,11 +703,10 @@ int drm_helper_probe_single_connector_modes(struct 
drm_connector *connector,
        }
 
 exit:
-       drm_modeset_drop_locks(&ctx);
-       drm_modeset_acquire_fini(&ctx);
-
-       if (list_empty(&connector->modes))
-               return 0;
+       if (list_empty(&connector->modes)) {
+               count = 0;
+               goto unlock;
+       }
 
        drm_mode_sort(&connector->modes);
 
@@ -720,6 +719,10 @@ int drm_helper_probe_single_connector_modes(struct 
drm_connector *connector,
                            DRM_MODE_ARG(mode));
        }
 
+unlock:
+       drm_modeset_drop_locks(&ctx);
+       drm_modeset_acquire_fini(&ctx);
+
        return count;
 }
 EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);
-- 
2.56.0

Reply via email to