From nobody Thu Apr 2 03:24:59 2026 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 853093B38A0 for ; Tue, 10 Mar 2026 12:13:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773144826; cv=none; b=LDeli5apgqXBmfXt5M+1lnrSEQP/VN5uBjDu8+HwCSd4gZRRsvdmiMQpdlpKM7V7UHAT3LkUvvnsXEiL9gD04uSsACyqJ70HLfZ5MJSbgIIWBNSqjv/3+v1AipUPtk21jnIRGpjB8zar/R91Oy+K6Ll3HeOuCOiQzGgSfsbrDYc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773144826; c=relaxed/simple; bh=S98WM+1d2mKKGTvWJ/tJxFA82RG3aPy9qt+9Y455dCU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Lm2gbxvtvQInaSRAwqELZO/DunNe+T5XlCcDdL+4pEryTKNPEpWhTLu02hLmGPLGc9+8ho0LFVCZpqRYWllNpTdVsWRA4Hnkx7m1TPizEaNNcdcUl1E/eZrwn7Ey9yA6rnkaZz2eB0rlpAwE6Jyr7jCeA4BkIoMmUSzajDS9iRQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=p7kjSbtk; arc=none smtp.client-ip=185.246.85.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="p7kjSbtk" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id EDBAA4E42571; Tue, 10 Mar 2026 12:13:43 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id C1A3A60002; Tue, 10 Mar 2026 12:13:43 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id A3BA910369C2C; Tue, 10 Mar 2026 13:13:39 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1773144822; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=jFa3HhMOQ05RoZTHCb1XkHixgVs2EPgA338waxzgtnY=; b=p7kjSbtkLm3dFXw8FUtfw0IsSQaVc5ykunUggP8/bV34x3fOkIeCoRdJbtI0iZQnRpLDc1 tojoFS619oftGVxxqu7wuIU5/pRzMDA6PunnxVTRigWVuxjpqy4DgUHd6z315pYhx5lx4V Ct1GuCJhx7R+61y3G2UFf44gbxHb+g1aRWyFWqgcI1Y4DCbJMy6zPI7qdtaO0JL3dNzJO3 nyo8Xx1GX8LS6JzZYTtmz5/XfUd3V9roiRU4ACrLw+IEwnqaB+feVPAEBIkOjK4ZNsGN2S THOvpVwlB2lFRPOBVHhV/eIYF3Cxbx4H/P4czC6+syi5Zwc6Bth2F/9CPLtjdA== From: Luca Ceresoli Date: Tue, 10 Mar 2026 13:13:23 +0100 Subject: [PATCH v2 1/2] drm/bridge: add drm_bridge_clear_and_put() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260310-drm-bridge-atomic-vs-remove-clear_and_put-v2-1-51fe222f3cf0@bootlin.com> References: <20260310-drm-bridge-atomic-vs-remove-clear_and_put-v2-0-51fe222f3cf0@bootlin.com> In-Reply-To: <20260310-drm-bridge-atomic-vs-remove-clear_and_put-v2-0-51fe222f3cf0@bootlin.com> To: Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Inki Dae , Jagan Teki , Marek Szyprowski Cc: Osama Abdelkader , Hui Pu , Ian Ray , Thomas Petazzoni , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Luca Ceresoli X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 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 =3D 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 =3D my_priv->some_bridge; my_priv->some_bridge =3D 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. Signed-off-by: Luca Ceresoli Acked-by: Maxime Ripard --- This is a renamed version of drm_bridge_put_and_clear() which was sent as part of a larger patch [0] but with largely rewritten documentation and a detailed commit message. [0] https://lore.kernel.org/lkml/20250206-hotplug-drm-bridge-v6-14-9d6f2c9c= 3058@bootlin.com/ --- drivers/gpu/drm/drm_bridge.c | 34 ++++++++++++++++++++++++++++++++++ include/drm/drm_bridge.h | 1 + 2 files changed, 35 insertions(+) diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index f8b0333a0a3b..0260b16cb47d 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -304,6 +304,9 @@ EXPORT_SYMBOL(drm_bridge_get); * * This function decrements the bridge's reference count and frees the * object if the reference count drops to zero. + * + * See also drm_bridge_clear_and_put() if you also need to set the pointer + * to NULL */ void drm_bridge_put(struct drm_bridge *bridge) { @@ -312,6 +315,37 @@ void drm_bridge_put(struct drm_bridge *bridge) } EXPORT_SYMBOL(drm_bridge_put); =20 +/** + * drm_bridge_clear_and_put - Given a bridge pointer, clear the pointer + * then put the bridge + * @bridge_pp: pointer to pointer to a struct drm_bridge; ``bridge_pp`` + * must be non-NULL; if ``*bridge_pp`` is NULL this function + * does nothing + * + * Helper to put a DRM bridge, but only after setting its pointer to + * NULL. Useful when a struct drm_bridge reference must be dropped without + * leaving a use-after-free window where the pointed bridge might have been + * freed while still holding a pointer to it. + * + * For struct ``drm_bridge *some_bridge``, this code:: + * + * drm_bridge_clear_and_put(&some_bridge); + * + * is equivalent to the more complex:: + * + * struct drm_bridge *temp =3D some_bridge; + * some_bridge =3D NULL; + * drm_bridge_put(temp); + */ +void drm_bridge_clear_and_put(struct drm_bridge **bridge_pp) +{ + struct drm_bridge *bridge =3D *bridge_pp; + + *bridge_pp =3D NULL; + drm_bridge_put(bridge); +} +EXPORT_SYMBOL(drm_bridge_clear_and_put); + /** * drm_bridge_put_void - wrapper to drm_bridge_put() taking a void pointer * 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); =20 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); =20 /* Cleanup action for use with __free() */ DEFINE_FREE(drm_bridge_put, struct drm_bridge *, if (_T) drm_bridge_put(_T= )) --=20 2.53.0 From nobody Thu Apr 2 03:24:59 2026 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 87BD33B47C0 for ; Tue, 10 Mar 2026 12:13:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773144830; cv=none; b=fhog5Gc2zdfwWJ5oSYqHRjJc9a/fDIXF/nbwQ5zoDT74uVcSlIVg/+uI7AZZBaqzzLzvQZ4qq1S2/HkmXIQEVwIecWtD44BYF7EclnDDO63TCmpdNRCXGCfrWZ/JleVuc0Hp2S5AEcHLt6inSQqca2KVBQqTAlJcqKmdoPo7VGk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773144830; c=relaxed/simple; bh=u8LgKOqYd/2wQk/bKimVZSnVoanddwJO8gLL/2yWdbo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Ck1m+5phtlW0Rv8al4+7WJtokuqv90vkNB2rZafcdgL/f6go7Ghp7xr/PK7lI5vaglWaGeNs5Pt4QEK5FlJ+UDV4TQdd0iML+uTEiH72sZOmC2Kqih++wb64MDg+8jed2oAZ86Rzm+G6J+zWwsoV3nkr64mnqpmQLVMm/A9vCeY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=0oEUXSfQ; arc=none smtp.client-ip=185.246.85.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="0oEUXSfQ" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id 20DFB4E4256E; Tue, 10 Mar 2026 12:13:47 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id EAAAA60002; Tue, 10 Mar 2026 12:13:46 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id CC33310369BAD; Tue, 10 Mar 2026 13:13:42 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1773144825; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=Y1oplMH3OPrATXzqC7EfKDrsJmUbEpetqvKYhQAX6tY=; b=0oEUXSfQt28DhcP23+gkxbwwsh7xRXGZn8MlgyfaJmePp+hR4FTY5vwnl4LHCTX5vU0uLf NLOSPVGQIPuEz2Wjnw7mUqwBFtKMdwHFQV4b8zlcW+etv4jBYwgmDZiQqRa2lY2i2AO6DS uwzCzUPn+o1g/tnMk3VfAKbTC5GNgDAyB9+ZeJkz96AOKQNCcz5vPsdVNx2KIvya4tmUNS srLtbrWqEcqU0yLU8BMshMLJhzn7JXJpXuZmJssReC9pwFtS6qWPONaNnRyasbBWvjYbeR voUpYHHEKult8vtPE8cetEqRbBZnynh/sMdiL9ZqWpKROdBLJhzC2HRKDwdcSw== From: Luca Ceresoli Date: Tue, 10 Mar 2026 13:13:24 +0100 Subject: [PATCH v2 2/2] drm/bridge: samsung-dsim: use drm_bridge_clear_and_put() to put the next bridge Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260310-drm-bridge-atomic-vs-remove-clear_and_put-v2-2-51fe222f3cf0@bootlin.com> References: <20260310-drm-bridge-atomic-vs-remove-clear_and_put-v2-0-51fe222f3cf0@bootlin.com> In-Reply-To: <20260310-drm-bridge-atomic-vs-remove-clear_and_put-v2-0-51fe222f3cf0@bootlin.com> To: Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Inki Dae , Jagan Teki , Marek Szyprowski Cc: Osama Abdelkader , Hui Pu , Ian Ray , Thomas Petazzoni , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Luca Ceresoli X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 drm_bridge_clear_and_put() is simpler to write and it prevents any potential future use-after-free. Reviewed-by: Osama Abdelkader Signed-off-by: Luca Ceresoli Acked-by: Marek Szyprowski Acked-by: Maxime Ripard --- drivers/gpu/drm/bridge/samsung-dsim.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge= /samsung-dsim.c index ec632f268644..c3eb437ef1b0 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -1988,9 +1988,7 @@ static int samsung_dsim_host_attach(struct mipi_dsi_h= ost *host, return 0; =20 err_release_next_bridge: - drm_bridge_put(dsi->bridge.next_bridge); - dsi->bridge.next_bridge =3D NULL; - + drm_bridge_clear_and_put(&dsi->bridge.next_bridge); if (!(device->mode_flags & MIPI_DSI_MODE_VIDEO)) samsung_dsim_unregister_te_irq(dsi); err_remove_bridge: @@ -2007,8 +2005,7 @@ static int samsung_dsim_host_detach(struct mipi_dsi_h= ost *host, if (pdata->host_ops && pdata->host_ops->detach) pdata->host_ops->detach(dsi, device); =20 - drm_bridge_put(dsi->bridge.next_bridge); - dsi->bridge.next_bridge =3D NULL; + drm_bridge_clear_and_put(&dsi->bridge.next_bridge); =20 samsung_dsim_unregister_te_irq(dsi); =20 --=20 2.53.0