Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [Low] drm/tests: lockless access to connector->modes violates locking rules - [Low] drm/tests: memory leak of cloned modes on KUnit assertion failure --
commit 806dc20896099436a3d060ce16a4a8cb84cf8467 Author: Hugo Sales <[email protected]> Subject: drm/tests: Add KUnit tests for the client mode size limits This commit adds KUnit tests for various client mode pickers to ensure they skip modes larger than the client's size. It also tests that the modeset probe properly retains the preferred mode. > diff --git a/drivers/gpu/drm/tests/drm_client_modeset_test.c > b/drivers/gpu/drm/tests/drm_client_modeset_test.c > index 00f43fca97954..93aa919d4f317 100644 > --- a/drivers/gpu/drm/tests/drm_client_modeset_test.c > +++ b/drivers/gpu/drm/tests/drm_client_modeset_test.c [ ... ] > @@ -197,6 +213,206 @@ static struct kunit_suite > drm_test_pick_cmdline_test_suite = { > > kunit_test_suite(drm_test_pick_cmdline_test_suite); > > +static void drm_test_pick_first_mode_within_limits(struct kunit *test) > +{ [ ... ] > + mutex_lock(&drm->mode_config.mutex); > + ret = drm_helper_probe_single_connector_modes(connector, 1920, 1080); > + mutex_unlock(&drm->mode_config.mutex); > + KUNIT_ASSERT_GT(test, ret, 0); > + > + mode = drm_connector_first_mode(connector, 1920, 1080); [Severity: Low] The connector->modes list is explicitly documented as being protected by dev->mode_config.mutex. Here, the mutex is unlocked just before calling drm_connector_first_mode(), which iterates over connector->modes. While this is isolated test code and no concurrent modification occurs, could this lockless iteration trigger static analysis tools or lockdep warnings? > + KUNIT_ASSERT_NOT_NULL(test, mode); > + KUNIT_EXPECT_EQ(test, mode->hdisplay, 1920); > + KUNIT_EXPECT_EQ(test, mode->vdisplay, 1080); [ ... ] > +static void drm_test_pick_cmdline_mode_within_limits(struct kunit *test) > +{ [ ... ] > + mutex_lock(&drm->mode_config.mutex); > + ret = drm_helper_probe_single_connector_modes(connector, 1920, 1080); > + mutex_unlock(&drm->mode_config.mutex); > + KUNIT_ASSERT_GT(test, ret, 0); > + > + mode = drm_connector_pick_cmdline_mode(connector, 1920, 1080); [Severity: Low] Similarly here, drm_connector_pick_cmdline_mode() iterates over connector->modes outside of drm->mode_config.mutex. Does this violate the locking rules for the connector modes list? > + KUNIT_ASSERT_NOT_NULL(test, mode); [ ... ] > +static void drm_test_pick_tiled_mode_within_limits(struct kunit *test) > +{ [ ... ] > + mutex_lock(&drm->mode_config.mutex); > + ret = drm_helper_probe_single_connector_modes(connector, 1920, 1080); > + mutex_unlock(&drm->mode_config.mutex); > + KUNIT_ASSERT_GT(test, ret, 0); > + > + mode = drm_connector_get_tiled_mode(connector, 1920, 1080); [Severity: Low] As with the previous pickers, drm_connector_get_tiled_mode() accesses connector->modes without the required drm->mode_config.mutex held. > + KUNIT_ASSERT_NOT_NULL(test, mode); [ ... ] > +static void drm_test_pick_clone_mode_within_limits(struct kunit *test) > +{ [ ... ] > + mutex_lock(&drm->mode_config.mutex); > + for (i = 0; i < ARRAY_SIZE(connectors); i++) { > + ret = drm_helper_probe_single_connector_modes(connectors[i], > 1920, 1080); > + KUNIT_EXPECT_GT(test, ret, 0); > + } > + mutex_unlock(&drm->mode_config.mutex); > + > + KUNIT_EXPECT_TRUE(test, drm_client_target_cloned(drm, connectors, > ARRAY_SIZE(connectors), > + modes, offsets, > enabled, 1024, 768)); [Severity: Low] This call to drm_client_target_cloned() also iterates over connector->modes after the config mutex has been released. > + for (i = 0; i < ARRAY_SIZE(connectors); i++) { > + KUNIT_ASSERT_NOT_NULL(test, modes[i]); [Severity: Low] If this KUNIT_ASSERT_NOT_NULL() assertion fails, it immediately forces an early return from the test. Because drm_client_target_cloned() allocates new modes via mode_replace(), would an early return here bypass the mandatory modes_destroy() cleanup below and leak the dynamically allocated mode objects? Could KUnit's managed allocations (like kunit_add_action) be used to ensure modes_destroy() always runs on cleanup? > + KUNIT_EXPECT_EQ(test, modes[i]->hdisplay, 1024); > + KUNIT_EXPECT_EQ(test, modes[i]->vdisplay, 768); > + } > + modes_destroy(drm, modes, ARRAY_SIZE(connectors)); [ ... ] > +static void drm_test_probe_keeps_modes_above_limits(struct kunit *test) > +{ [ ... ] > + ret = drm_client_modeset_probe(client, 1024, 768); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + mode = client->modesets[0].mode; > + KUNIT_ASSERT_NOT_NULL(test, mode); > + KUNIT_EXPECT_EQ(test, mode->hdisplay, 1024); > + KUNIT_EXPECT_EQ(test, mode->vdisplay, 768); > + > + mode = drm_connector_preferred_mode(connector, 1920, 1080); [Severity: Low] Once again, drm_connector_preferred_mode() is called to iterate the connector->modes list without the config mutex held. > + KUNIT_ASSERT_NOT_NULL(test, mode); -- Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
