* [PATCH v5 0/7] drm/bridge: protect encoder bridge chain with a mutex
@ 2026-03-24 8:58 Luca Ceresoli
2026-03-24 8:58 ` [PATCH v5 1/7] drm/encoder: add mutex to protect the bridge chain Luca Ceresoli
` (7 more replies)
0 siblings, 8 replies; 16+ messages in thread
From: Luca Ceresoli @ 2026-03-24 8:58 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec
Cc: Hui Pu, Thomas Petazzoni, dri-devel, linux-kernel, Ian Ray,
Luca Ceresoli
This series ensures that the bridge chain of the encoder will not be
modified while some other concurrent code flows are iterating over it.
Some patches are already Reviewed-by: Maxime Ripard, some are unreviewed.
== Series description
The per-encoder bridge chain is currently assumed to be static once it is
fully initialized. Work is in progress to support hot-pluggable bridges,
breaking that assumption.
With hotplug and especially hot-unplug, bridges will be added and removed
without notice, and thus be added/removed to/from the encoder chain in
drm_bridge_attach/detach(), concurrently to the code iterating on the
chain. This can result in disruption of the code iterating over the
chain.
Patch 2 has a detailed example to describe the problem.
This series prevents concurrency bugs by introducing a mutex to make list
insertion, removal and iterations mutually exclusive.
== Grand plan
This is part of the work to support hotplug of DRM bridges. The grand plan
was discussed in [0].
Here's the work breakdown (➜ marks the current series):
1. ➜ add refcounting to DRM bridges struct drm_bridge,
based on devm_drm_bridge_alloc()
A. ✔ add new alloc API and refcounting (v6.16)
B. ✔ convert all bridge drivers to new API (v6.17)
C. ✔ kunit tests (v6.17)
D. ✔ add get/put to drm_bridge_add/remove() + attach/detach()
and warn on old allocation pattern (v6.17)
E. ➜ add get/put on drm_bridge accessors
1. ✔ drm_bridge_chain_get_first_bridge(), add cleanup action (v6.18)
2. ✔ drm_bridge_get_prev_bridge() (v6.18)
3. ✔ drm_bridge_get_next_bridge() (v6.19)
4. ✔ drm_for_each_bridge_in_chain() (v6.19)
5. ✔ drm_bridge_connector_init (v6.19)
6. ➜ protect encoder bridge chain with a mutex
7. … of_drm_find_bridge
a. ✔ add of_drm_get_bridge() (v7.0),
convert basic direct users (v7.0-v7.1)
b. ✔ convert direct of_drm_get_bridge() users, part 2 (v7.0)
c. ✔ convert direct of_drm_get_bridge() users, part 3 (v7.0)
d. ✔… convert direct of_drm_get_bridge() users, part 4
(some v7.1, some pending)
e. convert bridge-only drm_of_find_panel_or_bridge() users
8. drm_of_find_panel_or_bridge, *_of_get_bridge
9. ✔ enforce drm_bridge_add before drm_bridge_attach (v6.19)
F. ✔ debugfs improvements
1. ✔ add top-level 'bridges' file (v6.16)
2. ✔ show refcount and list lingering bridges (v6.19)
2. … handle gracefully atomic updates during bridge removal
A. ✔ Add drm_bridge_enter/exit() to protect device resources (v7.0)
B. … protect private_obj removal from list
C. ✔ Add drm_bridge_clear_and_put() (v7.1)
3. … DSI host-device driver interaction
4. ✔ removing the need for the "always-disconnected" connector
5. … Migrate i.MX LCDIF driver to bridge-connector
6. DRM bridge hotplug
A. Bridge hotplug management in the DRM core
B. Device tree description
[0] https://lore.kernel.org/lkml/20250206-hotplug-drm-bridge-v6-0-9d6f2c9c3058@bootlin.com/#t
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
Changes in v5:
- Improved cover letter and patch 2 commit message
- Rebased and tested on current drm-misc-next (v7.1-rc3)
- Link to v4: https://lore.kernel.org/r/20251111-drm-bridge-alloc-encoder-chain-mutex-v4-0-12b13eb8c0f8@bootlin.com
Changes in v4:
- No patch changes (this series was tested a lot since v3 without issues)
- Added Reviewed-by from Maxime
- Rebased on current drm-misc-next
- Small improvement to kerneldoc for the two for_each macros
- Link to v3: https://lore.kernel.org/r/20251009-drm-bridge-alloc-encoder-chain-mutex-v3-0-c90ed744efec@bootlin.com
Changes in v3:
- Re-added the drm_bridge_put() in the for_each macros, leading to largely
rewrite them
- Removed the drm_encoder_chain_[un]lock() wrappers
- Fixed a potential ABBA deadlock in patch
- Improved some commit messages
- Link to v2: https://lore.kernel.org/r/20251003-drm-bridge-alloc-encoder-chain-mutex-v2-0-78bf61580a06@bootlin.com
Changes in v2:
- Improve commit messages and add documentation as per v1 review
- Patch 4: fixed infinite loop when encoder->bridge_chain is empty
- Link to v1: https://lore.kernel.org/r/20250926-drm-bridge-alloc-encoder-chain-mutex-v1-0-23b62c47356a@bootlin.com
---
Luca Ceresoli (7):
drm/encoder: add mutex to protect the bridge chain
drm/encoder: drm_encoder_cleanup: lock the encoder chain mutex during removal
drm/bridge: drm_bridge_attach: lock the encoder chain mutex during insertion
drm/bridge: lock the encoder chain in scoped for_each loops
drm/bridge: prevent encoder chain changes while iterating with list_for_each_entry_from()
drm/bridge: prevent encoder chain changes while iterating with list_for_each_entry_reverse()
drm/bridge: prevent encoder chain changes in pre_enable/post_disable
drivers/gpu/drm/drm_bridge.c | 83 ++++++++++++++++++++++---------------------
drivers/gpu/drm/drm_encoder.c | 18 ++++++++--
include/drm/drm_bridge.h | 73 +++++++++++++++++++++++--------------
include/drm/drm_encoder.h | 4 +++
4 files changed, 109 insertions(+), 69 deletions(-)
---
base-commit: f6d00f979306cb9baf5ab3d4f61dd34857e78c13
change-id: 20250925-drm-bridge-alloc-encoder-chain-mutex-b78d62085ee5
Best regards,
--
Luca Ceresoli <luca.ceresoli@bootlin.com>
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v5 1/7] drm/encoder: add mutex to protect the bridge chain
2026-03-24 8:58 [PATCH v5 0/7] drm/bridge: protect encoder bridge chain with a mutex Luca Ceresoli
@ 2026-03-24 8:58 ` Luca Ceresoli
2026-03-24 20:59 ` Claude review: " Claude Code Review Bot
2026-03-24 8:58 ` [PATCH v5 2/7] drm/encoder: drm_encoder_cleanup: lock the encoder chain mutex during removal Luca Ceresoli
` (6 subsequent siblings)
7 siblings, 1 reply; 16+ messages in thread
From: Luca Ceresoli @ 2026-03-24 8:58 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec
Cc: Hui Pu, Thomas Petazzoni, dri-devel, linux-kernel, Ian Ray,
Luca Ceresoli
The per-encoder bridge chain is currently assumed to be static once it is
fully initialized. Work is in progress to add hot-pluggable bridges,
breaking that assumption.
With bridge removal, the encoder chain can change without notice, removing
tail bridges. This can be problematic while iterating over the chain.
Add a mutex to be taken whenever looping or changing the encoder chain.
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
Changes in v3:
- Removed the drm_encoder_chain_[un]lock() wrappers
Changes in v2:
- Added documentation to new APIs
---
drivers/gpu/drm/drm_encoder.c | 2 ++
include/drm/drm_encoder.h | 4 ++++
2 files changed, 6 insertions(+)
diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c
index 8f2bc6a28482..3261f142baea 100644
--- a/drivers/gpu/drm/drm_encoder.c
+++ b/drivers/gpu/drm/drm_encoder.c
@@ -129,6 +129,7 @@ static int __drm_encoder_init(struct drm_device *dev,
}
INIT_LIST_HEAD(&encoder->bridge_chain);
+ mutex_init(&encoder->bridge_chain_mutex);
list_add_tail(&encoder->head, &dev->mode_config.encoder_list);
encoder->index = dev->mode_config.num_encoder++;
@@ -202,6 +203,7 @@ void drm_encoder_cleanup(struct drm_encoder *encoder)
kfree(encoder->name);
list_del(&encoder->head);
dev->mode_config.num_encoder--;
+ mutex_destroy(&encoder->bridge_chain_mutex);
memset(encoder, 0, sizeof(*encoder));
}
diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h
index 977a9381c8ba..eded7c34481a 100644
--- a/include/drm/drm_encoder.h
+++ b/include/drm/drm_encoder.h
@@ -25,6 +25,7 @@
#include <linux/list.h>
#include <linux/ctype.h>
+#include <linux/mutex.h>
#include <drm/drm_crtc.h>
#include <drm/drm_mode.h>
#include <drm/drm_mode_object.h>
@@ -189,6 +190,9 @@ struct drm_encoder {
*/
struct list_head bridge_chain;
+ /** @bridge_chain_mutex: protect bridge_chain from changes while iterating */
+ struct mutex bridge_chain_mutex;
+
const struct drm_encoder_funcs *funcs;
const struct drm_encoder_helper_funcs *helper_private;
--
2.53.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v5 2/7] drm/encoder: drm_encoder_cleanup: lock the encoder chain mutex during removal
2026-03-24 8:58 [PATCH v5 0/7] drm/bridge: protect encoder bridge chain with a mutex Luca Ceresoli
2026-03-24 8:58 ` [PATCH v5 1/7] drm/encoder: add mutex to protect the bridge chain Luca Ceresoli
@ 2026-03-24 8:58 ` Luca Ceresoli
2026-03-24 20:59 ` Claude review: " Claude Code Review Bot
2026-03-24 8:58 ` [PATCH v5 3/7] drm/bridge: drm_bridge_attach: lock the encoder chain mutex during insertion Luca Ceresoli
` (5 subsequent siblings)
7 siblings, 1 reply; 16+ messages in thread
From: Luca Ceresoli @ 2026-03-24 8:58 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec
Cc: Hui Pu, Thomas Petazzoni, dri-devel, linux-kernel, Ian Ray,
Luca Ceresoli
drm_encoder_cleanup() modifies the encoder chain by removing bridges via
drm_bridge_detach(). Protect this whole operation by taking the mutex, so
that:
* any users iterating over the chain will not access it during the change
* other code willing to modify the list (drm_bridge_attach()) will wait
until drm_encoder_cleanup() is done
Note that the _safe macro in use here is providing a different and
orthogonal kind of protection than the mutex:
1. list_for_each_entry_safe() allows removing the current entry from the
list it is iterating on, synchronously; the non-safe version would be
unable to find the next entry after the current entry has been removed
2. the mutex being added allows to ensure that the list is not used
asynchronously by other code while it is being modified; this prevents
such other concurrent code to derail because it is iterating over an
element while it is removed
The _safe macro, which works by taking the "next" pointer in addition to
the "current" one, does not even try to provide the protection at item 2
above. This is visible e.g. when the "next" element is removed by other
concurrent code. This is what would happen without the added mutex:
1. start loop: list_for_each_entry_safe(pos, n, ...) sets:
pos = list_first_entry() = (bridge 1)
n = list_next_entry(pos) = (bridge 2)
2. enter the loop 1st time, do something with *pos (bridge 1)
3. in the meanwhile bridge 2 is hot-unplugged
-> another thread removes bridge 2
-> drm_bridge_detach()
-> list_del() sets (bridge 2)->next = LIST_POISON1
4. loop iteration 1 finishes, list_for_each_entry_safe() sets:
pos = n (previously set to bridge 2)
n = (bridge 2)->next = LIST_POISON1
5. enter the loop 2nd time, do something with *pos (bridge 2)
6. loop iteration 2 finishes, list_for_each_entry_safe() sets:
pos = n = LIST_POISON1 ==> bug!
However, simply adding mutex_[un]lock(&encoder->bridge_chain_mutex)
before/after the list_for_each_entry_safe() seems a simple and good
solution, but it is introducing a possible ABBA deadlock (found by
PROVE_LOCKING). The two code paths involved are:
* drm_encoder_cleanup():
- takes the bridge_chain_mutex (A)
- calls drm_bridge_detach -> drm_atomic_private_obj_fini ->
DRM_MODESET_LOCK_ALL_BEGIN() which takes all locks in the
acquisition context (B)
* drm_mode_getconnector() (and other code paths):
- calls drm_helper_probe_single_connector_modes() which:
- takes a drm_modeset_lock in the acquisition context (B)
- calls __drm_helper_update_and_validate ->
drm_bridge_chain_mode_valid -> drm_for_each_bridge_in_chain_from()
which takes the bridge_chain_mutex (A)
To avoid this potential ABBA deadlock, move all list items to a temporary
list while holding the bridge_chain_mutex, then detach all elements from
the temporary list without the mutex.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
Changes in v5:
- Small commit message improvement
Changes in v3:
- Prevent ABBA deadlock by using a temporary list
- Improve commit message
Changes in v2:
- Expanded commit messge with rationale, as discussed
---
drivers/gpu/drm/drm_encoder.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c
index 3261f142baea..0d5dbed06db4 100644
--- a/drivers/gpu/drm/drm_encoder.c
+++ b/drivers/gpu/drm/drm_encoder.c
@@ -189,14 +189,26 @@ void drm_encoder_cleanup(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct drm_bridge *bridge, *next;
+ LIST_HEAD(tmplist);
/* Note that the encoder_list is considered to be static; should we
* remove the drm_encoder at runtime we would have to decrement all
* the indices on the drm_encoder after us in the encoder_list.
*/
- list_for_each_entry_safe(bridge, next, &encoder->bridge_chain,
- chain_node)
+ /*
+ * We need the bridge_chain_mutex to modify the chain, but
+ * drm_bridge_detach() will call DRM_MODESET_LOCK_ALL_BEGIN() (in
+ * drm_modeset_lock_fini()), resulting in a possible ABBA circular
+ * deadlock. Avoid it by first moving all the bridges to a
+ * temporary list holding the lock, and then calling
+ * drm_bridge_detach() without the lock.
+ */
+ mutex_lock(&encoder->bridge_chain_mutex);
+ list_cut_before(&tmplist, &encoder->bridge_chain, &encoder->bridge_chain);
+ mutex_unlock(&encoder->bridge_chain_mutex);
+
+ list_for_each_entry_safe(bridge, next, &tmplist, chain_node)
drm_bridge_detach(bridge);
drm_mode_object_unregister(dev, &encoder->base);
--
2.53.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v5 3/7] drm/bridge: drm_bridge_attach: lock the encoder chain mutex during insertion
2026-03-24 8:58 [PATCH v5 0/7] drm/bridge: protect encoder bridge chain with a mutex Luca Ceresoli
2026-03-24 8:58 ` [PATCH v5 1/7] drm/encoder: add mutex to protect the bridge chain Luca Ceresoli
2026-03-24 8:58 ` [PATCH v5 2/7] drm/encoder: drm_encoder_cleanup: lock the encoder chain mutex during removal Luca Ceresoli
@ 2026-03-24 8:58 ` Luca Ceresoli
2026-03-24 20:59 ` Claude review: " Claude Code Review Bot
2026-03-24 8:58 ` [PATCH v5 4/7] drm/bridge: lock the encoder chain in scoped for_each loops Luca Ceresoli
` (4 subsequent siblings)
7 siblings, 1 reply; 16+ messages in thread
From: Luca Ceresoli @ 2026-03-24 8:58 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec
Cc: Hui Pu, Thomas Petazzoni, dri-devel, linux-kernel, Ian Ray,
Luca Ceresoli
drm_bridge_attach() modifies the encoder bridge chain, so take a mutex
around such operations to allow users of the chain to protect themselves
from chain modifications while iterating.
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
Changes in v3:
- Lock encoder->bridge_chain_mutex directly, no wrappers
Changes in v2:
- Removed comment before on drm_bridge_detach()
---
drivers/gpu/drm/drm_bridge.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 30d957675d87..42ca4b243579 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -574,10 +574,12 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
bridge->dev = encoder->dev;
bridge->encoder = encoder;
+ mutex_lock(&encoder->bridge_chain_mutex);
if (previous)
list_add(&bridge->chain_node, &previous->chain_node);
else
list_add(&bridge->chain_node, &encoder->bridge_chain);
+ mutex_unlock(&encoder->bridge_chain_mutex);
if (bridge->funcs->attach) {
ret = bridge->funcs->attach(bridge, encoder, flags);
@@ -594,7 +596,9 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
err_reset_bridge:
bridge->dev = NULL;
bridge->encoder = NULL;
+ mutex_lock(&encoder->bridge_chain_mutex);
list_del(&bridge->chain_node);
+ mutex_unlock(&encoder->bridge_chain_mutex);
if (ret != -EPROBE_DEFER)
DRM_ERROR("failed to attach bridge %pOF to encoder %s: %d\n",
--
2.53.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v5 4/7] drm/bridge: lock the encoder chain in scoped for_each loops
2026-03-24 8:58 [PATCH v5 0/7] drm/bridge: protect encoder bridge chain with a mutex Luca Ceresoli
` (2 preceding siblings ...)
2026-03-24 8:58 ` [PATCH v5 3/7] drm/bridge: drm_bridge_attach: lock the encoder chain mutex during insertion Luca Ceresoli
@ 2026-03-24 8:58 ` Luca Ceresoli
2026-03-24 20:59 ` Claude review: " Claude Code Review Bot
2026-03-24 8:58 ` [PATCH v5 5/7] drm/bridge: prevent encoder chain changes while iterating with list_for_each_entry_from() Luca Ceresoli
` (3 subsequent siblings)
7 siblings, 1 reply; 16+ messages in thread
From: Luca Ceresoli @ 2026-03-24 8:58 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec
Cc: Hui Pu, Thomas Petazzoni, dri-devel, linux-kernel, Ian Ray,
Luca Ceresoli
drm_for_each_bridge_in_chain_scoped() and
drm_for_each_bridge_in_chain_from() currently get/put the bridge at each
iteration. But they don't protect the encoder chain, so it could change
(bridges added/removed) while some code is iterating over the list
itself. Such code can then derail on incorrect pointers.
To make iterations safe, augment these for_each macros to lock the encoder
chain mutex at the beginning and unlock it at the end of the loop (be it at
the end of the list, or earlier due to a 'break' or 'return' statement).
This change requires more operations when starting and ending the loop. To
avoid making the macros even more complex, move these operations to helper
functions. Also remname some of the existing helper functions for
consistency.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
Changed in v4:
- Slightly improve kerneldoc to clarify a bridge reference is held in
addition to the mutex
Changed in v3:
- Re-add drm_bridge_get/put()
Changed in v2:
- Fixed infinite loop in drm_for_each_bridge_in_chain_scoped() when
encoder->bridge_chain is empty, reported here:
https://lore.kernel.org/lkml/202509301358.38036b85-lkp@intel.com/
- Slightly improved commit message
---
include/drm/drm_bridge.h | 73 +++++++++++++++++++++++++++++++-----------------
1 file changed, 47 insertions(+), 26 deletions(-)
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 66ab89cf48aa..9aa10219ae36 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -1456,26 +1456,37 @@ drm_bridge_chain_get_last_bridge(struct drm_encoder *encoder)
struct drm_bridge, chain_node));
}
-/**
- * drm_bridge_get_next_bridge_and_put - Get the next bridge in the chain
- * and put the previous
- * @bridge: bridge object
- *
- * Same as drm_bridge_get_next_bridge() but additionally puts the @bridge.
- *
- * RETURNS:
- * the next bridge in the chain after @bridge, or NULL if @bridge is the last.
- */
-static inline struct drm_bridge *
-drm_bridge_get_next_bridge_and_put(struct drm_bridge *bridge)
+/* Internal to drm_for_each_bridge_in_chain*() */
+static inline struct drm_bridge *__drm_for_each_bridge_in_chain_next(struct drm_bridge *bridge)
{
struct drm_bridge *next = drm_bridge_get_next_bridge(bridge);
+ if (!next)
+ mutex_unlock(&bridge->encoder->bridge_chain_mutex);
+
drm_bridge_put(bridge);
return next;
}
+/* Internal to drm_for_each_bridge_in_chain*() */
+DEFINE_FREE(__drm_for_each_bridge_in_chain_cleanup, struct drm_bridge *,
+ if (_T) { mutex_unlock(&_T->encoder->bridge_chain_mutex); drm_bridge_put(_T); })
+
+/* Internal to drm_for_each_bridge_in_chain_scoped() */
+static inline struct drm_bridge *
+__drm_for_each_bridge_in_chain_scoped_start(struct drm_encoder *encoder)
+{
+ mutex_lock(&encoder->bridge_chain_mutex);
+
+ struct drm_bridge *bridge = drm_bridge_chain_get_first_bridge(encoder);
+
+ if (!bridge)
+ mutex_unlock(&encoder->bridge_chain_mutex);
+
+ return bridge;
+}
+
/**
* drm_for_each_bridge_in_chain_scoped - iterate over all bridges attached
* to an encoder
@@ -1485,14 +1496,24 @@ drm_bridge_get_next_bridge_and_put(struct drm_bridge *bridge)
*
* Iterate over all bridges present in the bridge chain attached to @encoder.
*
- * Automatically gets/puts the bridge reference while iterating, and puts
- * the reference even if returning or breaking in the middle of the loop.
+ * Automatically gets/puts the bridge reference while iterating and locks
+ * the encoder chain mutex to prevent chain modifications while iterating.
*/
-#define drm_for_each_bridge_in_chain_scoped(encoder, bridge) \
- for (struct drm_bridge *bridge __free(drm_bridge_put) = \
- drm_bridge_chain_get_first_bridge(encoder); \
- bridge; \
- bridge = drm_bridge_get_next_bridge_and_put(bridge))
+#define drm_for_each_bridge_in_chain_scoped(encoder, bridge) \
+ for (struct drm_bridge *bridge __free(__drm_for_each_bridge_in_chain_cleanup) = \
+ __drm_for_each_bridge_in_chain_scoped_start((encoder)); \
+ bridge; \
+ bridge = __drm_for_each_bridge_in_chain_next(bridge)) \
+
+/* Internal to drm_for_each_bridge_in_chain_from() */
+static inline struct drm_bridge *
+__drm_for_each_bridge_in_chain_from_start(struct drm_bridge *bridge)
+{
+ drm_bridge_get(bridge);
+ mutex_lock(&bridge->encoder->bridge_chain_mutex);
+
+ return bridge;
+}
/**
* drm_for_each_bridge_in_chain_from - iterate over all bridges starting
@@ -1504,14 +1525,14 @@ drm_bridge_get_next_bridge_and_put(struct drm_bridge *bridge)
* Iterate over all bridges in the encoder chain starting from
* @first_bridge, included.
*
- * Automatically gets/puts the bridge reference while iterating, and puts
- * the reference even if returning or breaking in the middle of the loop.
+ * Automatically gets/puts the bridge reference while iterating and locks
+ * the encoder chain mutex to prevent chain modifications while iterating.
*/
-#define drm_for_each_bridge_in_chain_from(first_bridge, bridge) \
- for (struct drm_bridge *bridge __free(drm_bridge_put) = \
- drm_bridge_get(first_bridge); \
- bridge; \
- bridge = drm_bridge_get_next_bridge_and_put(bridge))
+#define drm_for_each_bridge_in_chain_from(first_bridge, bridge) \
+ for (struct drm_bridge *bridge __free(__drm_for_each_bridge_in_chain_cleanup) = \
+ __drm_for_each_bridge_in_chain_from_start(first_bridge); \
+ bridge; \
+ bridge = __drm_for_each_bridge_in_chain_next(bridge)) \
enum drm_mode_status
drm_bridge_chain_mode_valid(struct drm_bridge *bridge,
--
2.53.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v5 5/7] drm/bridge: prevent encoder chain changes while iterating with list_for_each_entry_from()
2026-03-24 8:58 [PATCH v5 0/7] drm/bridge: protect encoder bridge chain with a mutex Luca Ceresoli
` (3 preceding siblings ...)
2026-03-24 8:58 ` [PATCH v5 4/7] drm/bridge: lock the encoder chain in scoped for_each loops Luca Ceresoli
@ 2026-03-24 8:58 ` Luca Ceresoli
2026-03-24 20:59 ` Claude review: " Claude Code Review Bot
2026-03-24 8:58 ` [PATCH v5 6/7] drm/bridge: prevent encoder chain changes while iterating with list_for_each_entry_reverse() Luca Ceresoli
` (2 subsequent siblings)
7 siblings, 1 reply; 16+ messages in thread
From: Luca Ceresoli @ 2026-03-24 8:58 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec
Cc: Hui Pu, Thomas Petazzoni, dri-devel, linux-kernel, Ian Ray,
Luca Ceresoli
These loops in drm_bridge.c iterate over the encoder chain using
list_for_each_entry_from(), which does not prevent changes to the bridge
chain while iterating over it.
Convert most of those loops to instead use
drm_for_each_bridge_in_chain_from(), which locks the chain.
This also simplifies code.
All the "simple" loops are converted here. The only ones not touched are
those in drm_atomic_bridge_chain_pre_enable() and
drm_atomic_bridge_chain_post_disable(), because they have nested loops
which are not well handled by drm_for_each_bridge_in_chain_from(). Those
two functions are handled by a separate commit.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/drm_bridge.c | 35 ++++++++++++-----------------------
1 file changed, 12 insertions(+), 23 deletions(-)
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 42ca4b243579..37feb8143de4 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -725,7 +725,7 @@ void drm_bridge_detach(struct drm_bridge *bridge)
/**
* drm_bridge_chain_mode_valid - validate the mode against all bridges in the
* encoder chain.
- * @bridge: bridge control structure
+ * @first_bridge: bridge control structure
* @info: display info against which the mode shall be validated
* @mode: desired mode to be validated
*
@@ -739,17 +739,14 @@ void drm_bridge_detach(struct drm_bridge *bridge)
* MODE_OK on success, drm_mode_status Enum error code on failure
*/
enum drm_mode_status
-drm_bridge_chain_mode_valid(struct drm_bridge *bridge,
+drm_bridge_chain_mode_valid(struct drm_bridge *first_bridge,
const struct drm_display_info *info,
const struct drm_display_mode *mode)
{
- struct drm_encoder *encoder;
-
- if (!bridge)
+ if (!first_bridge)
return MODE_OK;
- encoder = bridge->encoder;
- list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
+ drm_for_each_bridge_in_chain_from(first_bridge, bridge) {
enum drm_mode_status ret;
if (!bridge->funcs->mode_valid)
@@ -767,7 +764,7 @@ EXPORT_SYMBOL(drm_bridge_chain_mode_valid);
/**
* drm_bridge_chain_mode_set - set proposed mode for all bridges in the
* encoder chain
- * @bridge: bridge control structure
+ * @first_bridge: bridge control structure
* @mode: desired mode to be set for the encoder chain
* @adjusted_mode: updated mode that works for this encoder chain
*
@@ -776,20 +773,16 @@ EXPORT_SYMBOL(drm_bridge_chain_mode_valid);
*
* Note: the bridge passed should be the one closest to the encoder
*/
-void drm_bridge_chain_mode_set(struct drm_bridge *bridge,
+void drm_bridge_chain_mode_set(struct drm_bridge *first_bridge,
const struct drm_display_mode *mode,
const struct drm_display_mode *adjusted_mode)
{
- struct drm_encoder *encoder;
-
- if (!bridge)
+ if (!first_bridge)
return;
- encoder = bridge->encoder;
- list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
+ drm_for_each_bridge_in_chain_from(first_bridge, bridge)
if (bridge->funcs->mode_set)
bridge->funcs->mode_set(bridge, mode, adjusted_mode);
- }
}
EXPORT_SYMBOL(drm_bridge_chain_mode_set);
@@ -1013,7 +1006,7 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable);
/**
* drm_atomic_bridge_chain_enable - enables all bridges in the encoder chain
- * @bridge: bridge control structure
+ * @first_bridge: bridge control structure
* @state: atomic state being committed
*
* Calls &drm_bridge_funcs.atomic_enable (falls back on
@@ -1023,22 +1016,18 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable);
*
* Note: the bridge passed should be the one closest to the encoder
*/
-void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge,
+void drm_atomic_bridge_chain_enable(struct drm_bridge *first_bridge,
struct drm_atomic_state *state)
{
- struct drm_encoder *encoder;
-
- if (!bridge)
+ if (!first_bridge)
return;
- encoder = bridge->encoder;
- list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
+ drm_for_each_bridge_in_chain_from(first_bridge, bridge)
if (bridge->funcs->atomic_enable) {
bridge->funcs->atomic_enable(bridge, state);
} else if (bridge->funcs->enable) {
bridge->funcs->enable(bridge);
}
- }
}
EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
--
2.53.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v5 6/7] drm/bridge: prevent encoder chain changes while iterating with list_for_each_entry_reverse()
2026-03-24 8:58 [PATCH v5 0/7] drm/bridge: protect encoder bridge chain with a mutex Luca Ceresoli
` (4 preceding siblings ...)
2026-03-24 8:58 ` [PATCH v5 5/7] drm/bridge: prevent encoder chain changes while iterating with list_for_each_entry_from() Luca Ceresoli
@ 2026-03-24 8:58 ` Luca Ceresoli
2026-03-24 20:59 ` Claude review: " Claude Code Review Bot
2026-03-24 8:58 ` [PATCH v5 7/7] drm/bridge: prevent encoder chain changes in pre_enable/post_disable Luca Ceresoli
2026-03-24 20:59 ` Claude review: drm/bridge: protect encoder bridge chain with a mutex Claude Code Review Bot
7 siblings, 1 reply; 16+ messages in thread
From: Luca Ceresoli @ 2026-03-24 8:58 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec
Cc: Hui Pu, Thomas Petazzoni, dri-devel, linux-kernel, Ian Ray,
Luca Ceresoli
These loops in drm_bridge.c iterate over the encoder chain using
list_for_each_entry_reverse(), which does not prevent changes to the bridge
chain while iterating over it.
Take the encoder chain mutex while iterating to avoid chain changes while
iterating.
All the "simple" loops are converted. drm_atomic_bridge_chain_pre_enable()
and drm_atomic_bridge_chain_post_disable() are handled by a separate
commit.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
Changes in v3:
- Lock encoder->bridge_chain_mutex directly, no wrappers
Changes in v2: none
---
drivers/gpu/drm/drm_bridge.c | 40 ++++++++++++++++++++++------------------
1 file changed, 22 insertions(+), 18 deletions(-)
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 37feb8143de4..c76f3451af39 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -808,6 +808,7 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge,
return;
encoder = bridge->encoder;
+ mutex_lock(&encoder->bridge_chain_mutex);
list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
if (iter->funcs->atomic_disable) {
iter->funcs->atomic_disable(iter, state);
@@ -818,6 +819,7 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge,
if (iter == bridge)
break;
}
+ mutex_unlock(&encoder->bridge_chain_mutex);
}
EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
@@ -1322,25 +1324,27 @@ int drm_atomic_bridge_chain_check(struct drm_bridge *bridge,
return ret;
encoder = bridge->encoder;
- list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
- int ret;
-
- /*
- * Bus flags are propagated by default. If a bridge needs to
- * tweak the input bus flags for any reason, it should happen
- * in its &drm_bridge_funcs.atomic_check() implementation such
- * that preceding bridges in the chain can propagate the new
- * bus flags.
- */
- drm_atomic_bridge_propagate_bus_flags(iter, conn,
- crtc_state->state);
-
- ret = drm_atomic_bridge_check(iter, crtc_state, conn_state);
- if (ret)
- return ret;
+ scoped_guard(mutex, &encoder->bridge_chain_mutex) {
+ list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
+ int ret;
+
+ /*
+ * Bus flags are propagated by default. If a bridge needs to
+ * tweak the input bus flags for any reason, it should happen
+ * in its &drm_bridge_funcs.atomic_check() implementation such
+ * that preceding bridges in the chain can propagate the new
+ * bus flags.
+ */
+ drm_atomic_bridge_propagate_bus_flags(iter, conn,
+ crtc_state->state);
+
+ ret = drm_atomic_bridge_check(iter, crtc_state, conn_state);
+ if (ret)
+ return ret;
- if (iter == bridge)
- break;
+ if (iter == bridge)
+ break;
+ }
}
return 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v5 7/7] drm/bridge: prevent encoder chain changes in pre_enable/post_disable
2026-03-24 8:58 [PATCH v5 0/7] drm/bridge: protect encoder bridge chain with a mutex Luca Ceresoli
` (5 preceding siblings ...)
2026-03-24 8:58 ` [PATCH v5 6/7] drm/bridge: prevent encoder chain changes while iterating with list_for_each_entry_reverse() Luca Ceresoli
@ 2026-03-24 8:58 ` Luca Ceresoli
2026-03-24 20:59 ` Claude review: " Claude Code Review Bot
2026-03-24 20:59 ` Claude review: drm/bridge: protect encoder bridge chain with a mutex Claude Code Review Bot
7 siblings, 1 reply; 16+ messages in thread
From: Luca Ceresoli @ 2026-03-24 8:58 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec
Cc: Hui Pu, Thomas Petazzoni, dri-devel, linux-kernel, Ian Ray,
Luca Ceresoli
Take the encoder chain mutex while iterating over the encoder chain in
drm_atomic_bridge_chain_pre_enable() and
drm_atomic_bridge_chain_post_disable() to ensure the lists won't change
while being inspected.
These functions have nested list_for_each_*() loops, which makes them
complicated. list_for_each_entry_from() loops could be replaced by
drm_for_each_bridge_in_chain_from(), but it would not work in a nested way
in its current implementation. Besides, there is no "_reverse" variant of
drm_for_each_bridge_in_chain_from().
Keep code simple and readable by explicitly locking around the outer
loop. Thankfully there are no break or return points inside the loops, so
the change is trivial and readable.
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
Changes in v3:
- Lock encoder->bridge_chain_mutex directly, no wrappers
- Improved commit message
Changes in v2:
- Improved commit message
---
drivers/gpu/drm/drm_bridge.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index c76f3451af39..29231730e1f8 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -867,6 +867,7 @@ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge,
encoder = bridge->encoder;
+ mutex_lock(&encoder->bridge_chain_mutex);
list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
limit = NULL;
@@ -915,6 +916,7 @@ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge,
/* Jump all bridges that we have already post_disabled */
bridge = limit;
}
+ mutex_unlock(&encoder->bridge_chain_mutex);
}
EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
@@ -961,6 +963,7 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge,
encoder = bridge->encoder;
+ mutex_lock(&encoder->bridge_chain_mutex);
list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
if (iter->pre_enable_prev_first) {
next = iter;
@@ -1003,6 +1006,7 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge,
if (iter == bridge)
break;
}
+ mutex_unlock(&encoder->bridge_chain_mutex);
}
EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable);
--
2.53.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Claude review: drm/bridge: protect encoder bridge chain with a mutex
2026-03-24 8:58 [PATCH v5 0/7] drm/bridge: protect encoder bridge chain with a mutex Luca Ceresoli
` (6 preceding siblings ...)
2026-03-24 8:58 ` [PATCH v5 7/7] drm/bridge: prevent encoder chain changes in pre_enable/post_disable Luca Ceresoli
@ 2026-03-24 20:59 ` Claude Code Review Bot
7 siblings, 0 replies; 16+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 20:59 UTC (permalink / raw)
To: dri-devel-reviews
Overall Series Review
Subject: drm/bridge: protect encoder bridge chain with a mutex
Author: Luca Ceresoli <luca.ceresoli@bootlin.com>
Patches: 8
Reviewed: 2026-03-25T06:59:29.998864
---
This is a well-structured v5 series that adds mutex protection to the DRM encoder bridge chain, preparing for hot-pluggable bridge support. The approach is sound: a per-encoder mutex serializes bridge chain modifications (attach/detach) against iterations over the chain. The series is incremental and logical, building from mutex introduction through progressive coverage of all iteration sites.
The ABBA deadlock avoidance in patch 2 (using `list_cut_before` to a temporary list) is clever and correct. The scoped for_each macros in patch 4 are well-designed, using `__free()` cleanup attributes to ensure the mutex is always released even on early return/break.
One concern worth noting: patches 6 and 7 hold the mutex while calling bridge driver callbacks (`atomic_disable`, `atomic_enable`, `pre_enable`, `post_disable`, etc.). If any bridge driver callback were to attempt a bridge attach/detach on the same encoder, this would deadlock. This seems unlikely in practice, but should be documented or at least noted.
Overall: the series looks correct and ready to merge. Minor issues noted below.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 16+ messages in thread
* Claude review: drm/encoder: add mutex to protect the bridge chain
2026-03-24 8:58 ` [PATCH v5 1/7] drm/encoder: add mutex to protect the bridge chain Luca Ceresoli
@ 2026-03-24 20:59 ` Claude Code Review Bot
0 siblings, 0 replies; 16+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 20:59 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
Clean and straightforward. Adds `bridge_chain_mutex` to `struct drm_encoder`, initializes it in `__drm_encoder_init()`, and destroys it in `drm_encoder_cleanup()`.
No issues. The placement of `mutex_destroy()` after `list_del(&encoder->head)` and before `memset()` is fine.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 16+ messages in thread
* Claude review: drm/encoder: drm_encoder_cleanup: lock the encoder chain mutex during removal
2026-03-24 8:58 ` [PATCH v5 2/7] drm/encoder: drm_encoder_cleanup: lock the encoder chain mutex during removal Luca Ceresoli
@ 2026-03-24 20:59 ` Claude Code Review Bot
0 siblings, 0 replies; 16+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 20:59 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
The ABBA deadlock analysis in the commit message is excellent. The solution using `list_cut_before()` is correct:
```c
list_cut_before(&tmplist, &encoder->bridge_chain, &encoder->bridge_chain);
```
When `entry == head` (third arg == second arg), `list_cut_before` moves all entries to `tmplist` and leaves `bridge_chain` empty, which is the desired behavior. The empty-list case (`head->next == entry` when the list is empty, i.e., `head->next == head`) correctly initializes `tmplist` as empty and returns early.
**Minor note:** The comment says `drm_modeset_lock_fini()` but the code path described mentions `drm_atomic_private_obj_fini -> DRM_MODESET_LOCK_ALL_BEGIN()`. Worth verifying that `drm_modeset_lock_fini` is really what's meant here, but this is just a comment clarity issue.
**Concern:** After `list_cut_before`, bridges are detached without the mutex. During this window, another thread could see an empty `bridge_chain` and proceed with operations on a partially-torn-down encoder. However, since `drm_encoder_cleanup` is a teardown path, this is acceptable — no new operations should be starting on an encoder being cleaned up.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 16+ messages in thread
* Claude review: drm/bridge: drm_bridge_attach: lock the encoder chain mutex during insertion
2026-03-24 8:58 ` [PATCH v5 3/7] drm/bridge: drm_bridge_attach: lock the encoder chain mutex during insertion Luca Ceresoli
@ 2026-03-24 20:59 ` Claude Code Review Bot
0 siblings, 0 replies; 16+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 20:59 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
Correct. The mutex is taken only around the `list_add` operation and the error-path `list_del`, not around the `bridge->funcs->attach()` callback. This is the right granularity — it avoids holding the mutex during potentially slow or lock-taking driver callbacks.
No issues.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 16+ messages in thread
* Claude review: drm/bridge: lock the encoder chain in scoped for_each loops
2026-03-24 8:58 ` [PATCH v5 4/7] drm/bridge: lock the encoder chain in scoped for_each loops Luca Ceresoli
@ 2026-03-24 20:59 ` Claude Code Review Bot
0 siblings, 0 replies; 16+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 20:59 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
This is the most complex patch. The mutex lifecycle in the for_each macros is well-designed:
**`__drm_for_each_bridge_in_chain_next()`**: Gets the next bridge (incrementing its refcount), then conditionally unlocks the mutex only when we've reached the end of the chain (`!next`), then puts the current bridge. The ordering is correct — the next bridge's refcount is incremented before the current bridge is released.
**`__drm_for_each_bridge_in_chain_cleanup`**: Called via `__free()` when the loop variable goes out of scope (break/return). Correctly checks `if (_T)` to handle the normal loop-completion case where `_T` is already NULL (mutex was already unlocked in `_next()`).
**`__drm_for_each_bridge_in_chain_scoped_start()`**: Locks mutex, gets first bridge, unlocks if no bridges exist. This avoids leaving the mutex locked when there's nothing to iterate.
**Potential concern:** In `__drm_for_each_bridge_in_chain_from_start()`, the bridge is `drm_bridge_get()`'d before the mutex is locked. If the bridge is being concurrently removed from the chain (before the mutex is taken), the bridge struct remains valid due to the refcount, but its `chain_node` links could be poisoned. Since `drm_bridge_detach()` calls `list_del()` which sets the pointers to `LIST_POISON`, this could be problematic. However, the refcount prevents the bridge from being freed, and the mutex prevents concurrent chain modifications during actual iteration. The brief window between `drm_bridge_get()` and `mutex_lock()` should be safe because the caller is expected to already hold a reference to `first_bridge`.
No blocking issues.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 16+ messages in thread
* Claude review: drm/bridge: prevent encoder chain changes while iterating with list_for_each_entry_from()
2026-03-24 8:58 ` [PATCH v5 5/7] drm/bridge: prevent encoder chain changes while iterating with list_for_each_entry_from() Luca Ceresoli
@ 2026-03-24 20:59 ` Claude Code Review Bot
0 siblings, 0 replies; 16+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 20:59 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
Clean conversion of three functions to use `drm_for_each_bridge_in_chain_from()`. The parameter rename from `bridge` to `first_bridge` is appropriate.
In `drm_bridge_chain_mode_valid()`, the `return ret` inside the `drm_for_each_bridge_in_chain_from()` loop will correctly trigger the `__free` cleanup, unlocking the mutex and putting the bridge. Correct.
In `drm_bridge_chain_mode_set()` and `drm_atomic_bridge_chain_enable()`, the loop bodies don't use braces around multi-statement `if/else if` blocks — but that's consistent with the existing kernel style for these functions and technically correct since `drm_for_each_bridge_in_chain_from` expands to a `for` statement.
No issues.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 16+ messages in thread
* Claude review: drm/bridge: prevent encoder chain changes while iterating with list_for_each_entry_reverse()
2026-03-24 8:58 ` [PATCH v5 6/7] drm/bridge: prevent encoder chain changes while iterating with list_for_each_entry_reverse() Luca Ceresoli
@ 2026-03-24 20:59 ` Claude Code Review Bot
0 siblings, 0 replies; 16+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 20:59 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
Two functions are protected:
**`drm_atomic_bridge_chain_disable()`**: Uses explicit `mutex_lock`/`mutex_unlock` around the loop. Bridge driver callbacks (`atomic_disable`, `disable`) are called under the mutex. No early returns inside the loop, so the unlock is always reached.
**`drm_atomic_bridge_chain_check()`**: Uses `scoped_guard(mutex, ...)`. The inner `return ret` at line 1314 will correctly trigger the scoped_guard cleanup, unlocking the mutex. Note the inner `int ret` declaration shadows the outer `ret` — this is intentional and correct, as the inner `ret` is only used for the return within the scoped block.
No issues.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 16+ messages in thread
* Claude review: drm/bridge: prevent encoder chain changes in pre_enable/post_disable
2026-03-24 8:58 ` [PATCH v5 7/7] drm/bridge: prevent encoder chain changes in pre_enable/post_disable Luca Ceresoli
@ 2026-03-24 20:59 ` Claude Code Review Bot
0 siblings, 0 replies; 16+ messages in thread
From: Claude Code Review Bot @ 2026-03-24 20:59 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
Adds explicit `mutex_lock`/`mutex_unlock` around the outer loops in `drm_atomic_bridge_chain_post_disable()` and `drm_atomic_bridge_chain_pre_enable()`. As the commit message notes, there are no break or return points inside the outer loops (the `break` statements terminate the outer `list_for_each` which then falls through to the unlock), so the placement is correct.
**Note on holding the mutex during callbacks:** Both `drm_atomic_bridge_call_post_disable()` and `drm_atomic_bridge_call_pre_enable()` call into bridge driver callbacks while the mutex is held. This is the same situation as patch 6. If a bridge driver's `pre_enable`/`post_disable` callback were to call `drm_bridge_attach`/`drm_bridge_detach` on the same encoder, it would deadlock. This is extremely unlikely but might warrant a `lockdep_assert_held` annotation or documentation note in the future.
No blocking issues.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2026-03-24 20:59 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-24 8:58 [PATCH v5 0/7] drm/bridge: protect encoder bridge chain with a mutex Luca Ceresoli
2026-03-24 8:58 ` [PATCH v5 1/7] drm/encoder: add mutex to protect the bridge chain Luca Ceresoli
2026-03-24 20:59 ` Claude review: " Claude Code Review Bot
2026-03-24 8:58 ` [PATCH v5 2/7] drm/encoder: drm_encoder_cleanup: lock the encoder chain mutex during removal Luca Ceresoli
2026-03-24 20:59 ` Claude review: " Claude Code Review Bot
2026-03-24 8:58 ` [PATCH v5 3/7] drm/bridge: drm_bridge_attach: lock the encoder chain mutex during insertion Luca Ceresoli
2026-03-24 20:59 ` Claude review: " Claude Code Review Bot
2026-03-24 8:58 ` [PATCH v5 4/7] drm/bridge: lock the encoder chain in scoped for_each loops Luca Ceresoli
2026-03-24 20:59 ` Claude review: " Claude Code Review Bot
2026-03-24 8:58 ` [PATCH v5 5/7] drm/bridge: prevent encoder chain changes while iterating with list_for_each_entry_from() Luca Ceresoli
2026-03-24 20:59 ` Claude review: " Claude Code Review Bot
2026-03-24 8:58 ` [PATCH v5 6/7] drm/bridge: prevent encoder chain changes while iterating with list_for_each_entry_reverse() Luca Ceresoli
2026-03-24 20:59 ` Claude review: " Claude Code Review Bot
2026-03-24 8:58 ` [PATCH v5 7/7] drm/bridge: prevent encoder chain changes in pre_enable/post_disable Luca Ceresoli
2026-03-24 20:59 ` Claude review: " Claude Code Review Bot
2026-03-24 20:59 ` Claude review: drm/bridge: protect encoder bridge chain with a mutex Claude Code Review Bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox