All of lore.kernel.org
 help / color / mirror / Atom feed
From: Luca Ceresoli <luca.ceresoli@bootlin.com>
To: Maxime Ripard <mripard@kernel.org>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
	Thomas Zimmermann <tzimmermann@suse.de>,
	David Airlie <airlied@gmail.com>, Simona Vetter <simona@ffwll.ch>,
	Andrzej Hajda <andrzej.hajda@intel.com>,
	Neil Armstrong <neil.armstrong@linaro.org>,
	Robert Foss <rfoss@kernel.org>,
	Laurent Pinchart <Laurent.pinchart@ideasonboard.com>,
	Jonas Karlman <jonas@kwiboo.se>,
	Jernej Skrabec <jernej.skrabec@gmail.com>,
	Hui Pu <Hui.Pu@gehealthcare.com>,
	Thomas Petazzoni <thomas.petazzoni@bootlin.com>,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH 2/7] drm/encoder: drm_encoder_cleanup: take chain mutex while tearing down
Date: Mon, 29 Sep 2025 16:31:27 +0200	[thread overview]
Message-ID: <20250929163127.5ad20e05@booty> (raw)
In-Reply-To: <20250929-flat-koel-from-nibiru-665d49@houat>

Hi Maxime,

On Mon, 29 Sep 2025 14:45:10 +0200
Maxime Ripard <mripard@kernel.org> wrote:

> On Fri, Sep 26, 2025 at 05:59:43PM +0200, Luca Ceresoli wrote:
> > drm_encoder_cleanup() modifies the encoder chain by removing bridges via
> > drm_bridge_detach(). Protect this whole operation by taking the mutex, so
> > any users iterating over the chain will not access it during the change.
> > 
> > Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
> > ---
> >  drivers/gpu/drm/drm_encoder.c | 2 ++
> >  1 file changed, 2 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c
> > index 3261f142baea30c516499d23dbf8d0acf5952cd6..3a04bedf9b759acd6826864b7f2cc9b861a8f170 100644
> > --- a/drivers/gpu/drm/drm_encoder.c
> > +++ b/drivers/gpu/drm/drm_encoder.c
> > @@ -195,9 +195,11 @@ void drm_encoder_cleanup(struct drm_encoder *encoder)
> >  	 * the indices on the drm_encoder after us in the encoder_list.
> >  	 */
> >  
> > +	mutex_lock(&encoder->bridge_chain_mutex);
> >  	list_for_each_entry_safe(bridge, next, &encoder->bridge_chain,
> >  				 chain_node)
> >  		drm_bridge_detach(bridge);
> > +	mutex_unlock(&encoder->bridge_chain_mutex);  
> 
> You were claiming that the mutex was to prevent issues with concurrent
> iteration and removal of the list members. list_for_each_entry_safe() is
> explicitly made to protect against that. Why do we need both?

You're right saying we don't need both. With a mutex preventing the list
from any change, we can actually simpify code a bit to use the non-safe
list macro:

-	struct drm_bridge *bridge, *next;
+	struct drm_bridge *bridge;
...
+	mutex_lock(&encoder->bridge_chain_mutex);
- 	list_for_each_entry_safe(bridge, next, &encoder->bridge_chain,
+ 	list_for_each_entry(bridge, &encoder->bridge_chain,
 				 chain_node)
 		drm_bridge_detach(bridge);
+	mutex_unlock(&encoder->bridge_chain_mutex);
 
But it's not fully correct that list_for_each_entry_safe() protects
against concurrent removal. As I see it, all the _safe variants of
list_for_each*() macros protect against one specific and frequent use
case:

	list_for_each_entry_safe(curs, n, some_list, membername) {
		...
		list_del(&curs->membername);
		...
	}

So the _safe variant protect from removing the element at the current
iteration (*curs). It does so by taking the following element pointer in
advance, in the auxiliary variable @n. But _concurrent_ removal (the
topic of this series) means the element being removed could just be the
following one.

Consider this sequence:

 1. start loop: list_for_each_entry_safe() 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 item 2 -> drm_bridge_detach()
    -> list_del() sets bridge->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 (previously set to LIST_POISON1) -> bug

Do you think this explains the need for this series?

If it does, I should probably add this to the cover letter and maybe
patch 1.

Luca

-- 
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

  reply	other threads:[~2025-09-29 14:31 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-26 15:59 [PATCH 0/7] drm/bridge: protect encoder bridge chain with a mutex Luca Ceresoli
2025-09-26 15:59 ` [PATCH 1/7] drm/encoder: add mutex to protect the bridge chain Luca Ceresoli
2025-09-29 12:43   ` Maxime Ripard
2025-09-29 14:45     ` Luca Ceresoli
2025-09-26 15:59 ` [PATCH 2/7] drm/encoder: drm_encoder_cleanup: take chain mutex while tearing down Luca Ceresoli
2025-09-29 12:45   ` Maxime Ripard
2025-09-29 14:31     ` Luca Ceresoli [this message]
2025-10-03 10:37       ` Luca Ceresoli
2025-09-26 15:59 ` [PATCH 3/7] drm/bridge: lock the encoder bridge chain mutex during insertion Luca Ceresoli
2025-09-29 12:46   ` Maxime Ripard
2025-09-29 14:53     ` Luca Ceresoli
2025-09-26 15:59 ` [PATCH 4/7] drm/bridge: lock the encoder chain in scoped for_each loops Luca Ceresoli
2025-09-30  6:16   ` kernel test robot
2025-10-02 15:33     ` Luca Ceresoli
2025-09-26 15:59 ` [PATCH 5/7] drm/bridge: prevent encoder chain changes while iterating with list_for_each_entry_from() Luca Ceresoli
2025-09-26 15:59 ` [PATCH 6/7] drm/bridge: prevent encoder chain changes while iterating with list_for_each_entry_reverse() Luca Ceresoli
2025-09-26 15:59 ` [PATCH 7/7] drm/bridge: prevent encoder chain changes while iterating in drm_atomic_bridge_chain_post_disable/pre_enable() Luca Ceresoli

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250929163127.5ad20e05@booty \
    --to=luca.ceresoli@bootlin.com \
    --cc=Hui.Pu@gehealthcare.com \
    --cc=Laurent.pinchart@ideasonboard.com \
    --cc=airlied@gmail.com \
    --cc=andrzej.hajda@intel.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=jernej.skrabec@gmail.com \
    --cc=jonas@kwiboo.se \
    --cc=linux-kernel@vger.kernel.org \
    --cc=maarten.lankhorst@linux.intel.com \
    --cc=mripard@kernel.org \
    --cc=neil.armstrong@linaro.org \
    --cc=rfoss@kernel.org \
    --cc=simona@ffwll.ch \
    --cc=thomas.petazzoni@bootlin.com \
    --cc=tzimmermann@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.