On Tue, Aug 19, 2025 at 11:42:11AM +0200, Luca Ceresoli wrote: > Between drm_bridge_add() and drm_bridge_remove() bridges are "published" to > the DRM core via the global bridge_list and visible in > /sys/kernel/debug/dri/bridges. However between drm_bridge_remove() and the > last drm_bridge_put() memory is still allocated even though the bridge is > not "published", i.e. not in bridges_list, and also not visible in > debugfs. This prevents debugging refcounted bridges lifetime, especially > leaks due to any missing drm_bridge_put(). > > In order to allow debugfs to also show the removed bridges, move such > bridges into a new ad-hoc list until they are eventually freed. > > Note this requires adding INIT_LIST_HEAD(&bridge->list) in the bridge > initialization code. The lack of such init was not exposing any bug so far, > but it would with the new code, for example when a bridge is allocated and > then freed without calling drm_bridge_add(), which is common on probe > errors. > > Document the new behaviour of drm_bridge_remove() and update the > drm_bridge_add() documentation to stay consistent. > > drm_bridge_add() needs special care for bridges being added after having > been previously added and then removed. This happens for example for many > non-DCS DSI host bridge drivers like samsung-dsim which > drm_bridge_add/remove() themselves every time the DSI device does a DSI > attaches/detach. When the DSI device is hot-pluggable this happens multiple > times in the lifetime of the DSI host bridge. When this happens, the > bridge->list is found in the removed list, not at the initialized state as > drm_bridge_add() currently expects. > > Signed-off-by: Luca Ceresoli <[email protected]> > > --- > > Changes in v7: > - rebase on current drm-misc-next > - remove if (drm_bridge_is_refcounted(bridge)), refcounting is now > mandatory > - add check to detect when re-adding a bridge that is in the removed list > - improve commit message > - fix typo > > This patch was added in v6. > --- > drivers/gpu/drm/drm_bridge.c | 30 +++++++++++++++++++++++++++--- > 1 file changed, 27 insertions(+), 3 deletions(-) > > diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c > index > 36e0829d25c29457cff5da5fec99646c74b6ad5a..2e688ee14b9efbc810bcdb0ab7ecd4b688be8299 > 100644 > --- a/drivers/gpu/drm/drm_bridge.c > +++ b/drivers/gpu/drm/drm_bridge.c > @@ -197,15 +197,22 @@ > * driver. > */ > > +/* Protect bridge_list and bridge_removed_list */ > static DEFINE_MUTEX(bridge_lock); > static LIST_HEAD(bridge_list); > +static LIST_HEAD(bridge_removed_list);
I'm not super fond of "removed" here, it's ambiguous, especially since
the bridge wouldn't be considered as removed after the last put.
lingering maybe?
>
> static void __drm_bridge_free(struct kref *kref)
> {
> struct drm_bridge *bridge = container_of(kref, struct drm_bridge,
> refcount);
>
> + mutex_lock(&bridge_lock);
> + list_del(&bridge->list);
> + mutex_unlock(&bridge_lock);
> +
> if (bridge->funcs->destroy)
> bridge->funcs->destroy(bridge);
> +
> kfree(bridge->container);
> }
>
> @@ -275,6 +282,7 @@ void *__devm_drm_bridge_alloc(struct device *dev, size_t
> size, size_t offset,
> return ERR_PTR(-ENOMEM);
>
> bridge = container + offset;
> + INIT_LIST_HEAD(&bridge->list);
> bridge->container = container;
> bridge->funcs = funcs;
> kref_init(&bridge->refcount);
> @@ -288,10 +296,13 @@ void *__devm_drm_bridge_alloc(struct device *dev,
> size_t size, size_t offset,
> EXPORT_SYMBOL(__devm_drm_bridge_alloc);
>
> /**
> - * drm_bridge_add - add the given bridge to the global bridge list
> + * drm_bridge_add - publish a bridge
> *
> * @bridge: bridge control structure
> *
> + * Add the given bridge to the global list of "published" bridges, where
> + * they can be found by users via of_drm_find_bridge().
It's quite a change in semantics, at least in the doc. I believe it
should be a separate patch, since it's really more about updating the
drm_bridge_add / drm_bridge_remove doc than collecting the
removed-but-not-freed bridges.
Also, I'm not sure if it's more obvious here. The quotes around publish
kind of it to that too. Maybe using register / registration would make
it more obvious?
Maxime
signature.asc
Description: PGP signature
