From 8f3c83720555ffa96799896f2a0bb985a03a89f4 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Tue, 10 Mar 2026 13:13:23 +0100 Subject: drm/bridge: add drm_bridge_clear_and_put() Drivers having a struct drm_bridge pointer pointing to a bridge in many cases hold that reference until the owning device is removed. In those cases the reference to the bridge can be put in the .remove callback (possibly using devm actions) or in the .destroy func (possibly with the help of struct drm_bridge::next_bridge). At those moments the driver should not be operating anymore and won't dereference the bridge pointer after it is put. However there are cases when drivers need to stop holding a reference to a bridge even when their device is not being removed. This is the case for bridge hot-unplug, when a bridge is removed but the previous entity (bridge or encoder) is staying. In such case the "previous entity" needs to put it but cannot do it via devm or .destroy, because it is not being removed. The easy way to dispose of such pointer is: drm_bridge_put(my_priv->some_bridge); my_priv->some_bridge = NULL; However this is risky because there is a time window between the two lines where the reference is put, and thus the bridge could be deallocated, but the pointer is still assigned. If other functions of the same driver were invoked concurrently they might dereference my_priv->some_bridge during that window, resulting in use-after-free. A correct solution is to clear the pointer before putting the reference, but that needs a temporary variable: struct drm_bridge *temp = my_priv->some_bridge; my_priv->some_bridge = NULL; drm_bridge_put(temp); This solution is however annoying to write, so the incorrect version might still sneak in. Add a simple, easy to use function to put a bridge after setting its pointer to NULL in the correct way. Acked-by: Maxime Ripard Link: https://patch.msgid.link/20260310-drm-bridge-atomic-vs-remove-clear_and_put-v2-1-51fe222f3cf0@bootlin.com Signed-off-by: Luca Ceresoli --- include/drm/drm_bridge.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 4f19f7064ee3..66ab89cf48aa 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -1290,6 +1290,7 @@ void drm_bridge_unplug(struct drm_bridge *bridge); struct drm_bridge *drm_bridge_get(struct drm_bridge *bridge); void drm_bridge_put(struct drm_bridge *bridge); +void drm_bridge_clear_and_put(struct drm_bridge **bridge_pp); /* Cleanup action for use with __free() */ DEFINE_FREE(drm_bridge_put, struct drm_bridge *, if (_T) drm_bridge_put(_T)) -- cgit v1.2.3