From nobody Wed Dec 17 17:39:17 2025 Received: from smtpout-04.galae.net (smtpout-04.galae.net [185.171.202.116]) (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 3722681720 for ; Fri, 3 Oct 2025 10:39:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.171.202.116 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759487985; cv=none; b=M+F8aKMcWQVp219ko2XeENtizNv3rH8MlbatO6g1ZoAhq2SHVj72y+rIJ6drPLGzy8bnb/NuJdbZZz5bIc+W6sz4IDxmLCGvwoqojPI0Ct1I+VHeJh0Ii60PNB6ewZGxxHdspat9nmM3Y2WZlK+QrAejORcmyc1xyCtq4dmlh/U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759487985; c=relaxed/simple; bh=KX49EIdCKMoNVJPsWgELjfff+Y5Kp5R86U4uS+ZpzDk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=hYNutGfsQJlGyQQcuspmLNlgd5ELcrSjrm5oKDtV2IIp0mE5NJEYjA9of/ocYENKNqbJ897suVGF11U8vs8r2XqaVy7rxWaieyFfbMIYG+KAo7zf6zOzEbNk4otyTetzkwqI6JzqIltu9vJICsQ5Fzk+x9sjewGEAWxHZtp6OaA= 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=upwAZc38; arc=none smtp.client-ip=185.171.202.116 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="upwAZc38" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id 85783C00D99; Fri, 3 Oct 2025 10:39:23 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 84F6760683; Fri, 3 Oct 2025 10:39:41 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 12F32102F1C67; Fri, 3 Oct 2025 12:39:38 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1759487980; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=Qfu3JgcIsjrYY7+XbEdTvSNI3rVgt39kSDML/1Ac/9c=; b=upwAZc38H/sjoI9c8mcboj6oeXPAJsQPew3TzYvjqR+/+DCQJwSLAKqGKNyNWl756zzr49 szwqN8H2FHqMLIev5WxWCl6dT+Wwz6ciHofzvk1iB8weZj+lBuM0NmH+ws2oFdnYk/j7BN HzNerP9hTrCEbPd7JD5cpY7FUpMnRL358Z9SYCmjyZg+wK7ZYh2vvFzrRbpLplUIbSpFur TAAQfT9x6VmEUUTX4ZESiiqEW1o3inCegiUwVczkpuU1YdHUfhC6fkp64ocqe4fpPb87iX PAp5jgCBjTqcovr1HSJPLjoOFNCjjSdXH33jTGxuDYlJRKsGCSGugzpZotDUxg== From: Luca Ceresoli Date: Fri, 03 Oct 2025 12:39:23 +0200 Subject: [PATCH v2 1/7] drm/encoder: add mutex to protect the bridge chain 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: <20251003-drm-bridge-alloc-encoder-chain-mutex-v2-1-78bf61580a06@bootlin.com> References: <20251003-drm-bridge-alloc-encoder-chain-mutex-v2-0-78bf61580a06@bootlin.com> In-Reply-To: <20251003-drm-bridge-alloc-encoder-chain-mutex-v2-0-78bf61580a06@bootlin.com> 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@lists.freedesktop.org, linux-kernel@vger.kernel.org, Luca Ceresoli X-Mailer: b4 0.14.2 X-Last-TLS-Session-Version: TLSv1.3 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. Also add two APIs to lock/unlock the mutex without the need to manipulate internal struct drm_encoder fields. Signed-off-by: Luca Ceresoli --- Changes in v2: - Added documentation to new APIs --- drivers/gpu/drm/drm_encoder.c | 2 ++ include/drm/drm_encoder.h | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c index 8f2bc6a28482229fd0b030a1958f87753ad7885f..3261f142baea30c516499d23dbf= 8d0acf5952cd6 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, } =20 INIT_LIST_HEAD(&encoder->bridge_chain); + mutex_init(&encoder->bridge_chain_mutex); list_add_tail(&encoder->head, &dev->mode_config.encoder_list); encoder->index =3D dev->mode_config.num_encoder++; =20 @@ -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); =20 memset(encoder, 0, sizeof(*encoder)); } diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h index 977a9381c8ba943b4d3e021635ea14856df8a17d..449281c37e39f67a0037603762f= 347f5086df983 100644 --- a/include/drm/drm_encoder.h +++ b/include/drm/drm_encoder.h @@ -25,6 +25,7 @@ =20 #include #include +#include #include #include #include @@ -189,6 +190,9 @@ struct drm_encoder { */ struct list_head bridge_chain; =20 + /** @bridge_chain_mutex: protect bridge_chain from changes while iteratin= g */ + struct mutex bridge_chain_mutex; + const struct drm_encoder_funcs *funcs; const struct drm_encoder_helper_funcs *helper_private; =20 @@ -319,6 +323,41 @@ static inline struct drm_encoder *drm_encoder_find(str= uct drm_device *dev, return mo ? obj_to_encoder(mo) : NULL; } =20 +/** + * drm_encoder_chain_lock - lock the encoder bridge chain + * @encoder: encoder whose bridge chain must be locked + * + * Locks the mutex protecting the bridge chain from concurrent access. + * To be called by code modifying ot iterating over the bridge chain to + * prevent the list from changing while iterating over it. + * Call drm_encoder_chain_unlock() when done to unlock the mutex. + * + * Returns: + * Pointer to @encoder. Useful to lock the chain and then operate on the + * in the same statement, e.g.: + * list_first_entry_or_null(&drm_encoder_chain_lock(encoder)->bridge_chain) + */ +static inline struct drm_encoder *drm_encoder_chain_lock(struct drm_encode= r *encoder) +{ + if (!WARN_ON_ONCE(!encoder)) + mutex_lock(&encoder->bridge_chain_mutex); + + return encoder; +} + +/** + * drm_encoder_chain_unlock - unlock the encoder bridge chain + * @encoder: encoder whose bridge chain must be unlocked + * + * Unlocks the mutex protecting the bridge chain from concurrent access, + * matching drm_encoder_chain_lock(). + */ +static inline void drm_encoder_chain_unlock(struct drm_encoder *encoder) +{ + if (!WARN_ON_ONCE(!encoder)) + mutex_unlock(&encoder->bridge_chain_mutex); +} + void drm_encoder_cleanup(struct drm_encoder *encoder); =20 /** --=20 2.51.0 From nobody Wed Dec 17 17:39:17 2025 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 BDD3C2EACF0 for ; Fri, 3 Oct 2025 10:39: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=1759487987; cv=none; b=pG4RjFdSLEYgELWVeuERYck69H5HvxO9sObVamUa7YMCA+DEoSIxSzERGp/70ywIzbvoFpt3VqzTtIuD5mHDGAikqphE6wgtXuDDM+LnKvV3xUBiYIYF+mbxtAV27dNvGaRpmYaSnhpcTc7ORe2E322+rXjI4cMZNkBbvonaUss= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759487987; c=relaxed/simple; bh=HMvi2j0QlEMQyT/jCSYHu0a121jZL0pa33H1GYrotIo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=mVmkCfbZY3AJsuaOjCMe35TpPlhBtJyatjSglIntksdw/3cFvhX743QPJE3Pyxn+Kqs5lk5viZHndGVgLqYHkp8Obl2eLYOhf3kygekSSIxpxhGwCkfZxO/YKvbSfgnN+tFsbFFIKIZSm+G2UYWwP7UVSiT0VLb3GeSlaKQC4mQ= 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=eRdfyp0n; 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="eRdfyp0n" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id D04744E40E8F; Fri, 3 Oct 2025 10:39:43 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id A612A60683; Fri, 3 Oct 2025 10:39:43 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 21F0A102F1C38; Fri, 3 Oct 2025 12:39:41 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1759487982; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=kfCgGhXzegBkEi7/jTiC8TroMsKwhRsoP8qpHUK1OHg=; b=eRdfyp0n1w8OILY1RNCEU5BvMLz+Xfe4lWwMagXQg++17EnQ69cKqNm8NQTJMUfpsqsmfs FCmk/y/qBF9RFRTWCDLz+3HaCw3WsALzfIxGdnXVUvbGWyByBjpukT+MzsEmgoxj4BoLIH T2A8tbcgGLtHWQvaTkjCJa7ml3/CLXeu1JttTXQIl0OGs+1vlCg8l1xwp4XkIIa/Qd2qnS wrG9jOclv9ErWAilDgyjrgo0k6j9WjkTfk+nb1U4I7ptO8x6eN55oEcSoro4Sgoh0isqwO fw10qS7OdKfgeF7UYRsjvJQGy9jQSSm/RLqK0KjbaISwB2MczlruMXnGRvQFNQ== From: Luca Ceresoli Date: Fri, 03 Oct 2025 12:39:24 +0200 Subject: [PATCH v2 2/7] drm/encoder: drm_encoder_cleanup: take chain mutex while tearing down 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: <20251003-drm-bridge-alloc-encoder-chain-mutex-v2-2-78bf61580a06@bootlin.com> References: <20251003-drm-bridge-alloc-encoder-chain-mutex-v2-0-78bf61580a06@bootlin.com> In-Reply-To: <20251003-drm-bridge-alloc-encoder-chain-mutex-v2-0-78bf61580a06@bootlin.com> 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@lists.freedesktop.org, linux-kernel@vger.kernel.org, Luca Ceresoli X-Mailer: b4 0.14.2 X-Last-TLS-Session-Version: TLSv1.3 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 * any other code willing to modify the list (e.g. drm_bridge_attach()) will wait until drm_encoder_cleanup() is done Note that the _safe macro in use here is providing a different 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 when the current entry has been removed 2. the mutex being added allows to ensure that the list is not used concurrently 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, is insufficient to provide the protection at item 2. 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 =3D list_first_entry() =3D (bridge 1) n =3D list_next_entry(pos) =3D (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 =3D LIST_POISON1 4. loop iteration 1 finishes, list_for_each_entry_safe() sets: pos =3D n (previously set to bridge 2) n =3D (bridge 2)->next =3D 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 =3D n =3D LIST_POISON1 =3D=3D> bug! Signed-off-by: Luca Ceresoli --- Changes in v2: - Expanded commit messge with rationale, as discussed --- 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..3a04bedf9b759acd6826864b7f2= cc9b861a8f170 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. */ =20 + 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); =20 drm_mode_object_unregister(dev, &encoder->base); kfree(encoder->name); --=20 2.51.0 From nobody Wed Dec 17 17:39:17 2025 Received: from smtpout-02.galae.net (smtpout-02.galae.net [185.246.84.56]) (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 525962EB5C4 for ; Fri, 3 Oct 2025 10:39:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.84.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759487989; cv=none; b=VIxfwZjkjL/bgMzPzV9kpC4vnJM8ZsX5nIRPUpTRWc2RwOiCoMTM1wV0Xd1d+kNjBWx+mRXFfB8Lq6XzYjXoNOFP9GTOjettlMkgLHiTs4/gSJqd1ljT4DY5hswbQfeUXXJ5AlcZR9Gijsx+Jfq0LbtJYOzLtEEMmWLn4Nv2uCU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759487989; c=relaxed/simple; bh=sgR/vk9NFVTq9/RGQC8Ws+41fPZiEQ+J5+Vd7L06AeU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=TofrC5QHCh1Isa71SAzCJXpaNt/wfsO2ZSUoul+21p3x+kt5Yil6601Fijrt0PyOT5zUZVvX5QQRQ73/m1IclKI2khTg8tpS8tDRfGF7D/JIw/ZTc2S/hvmXrm5Tq3v7ili5OYyGvx71lQSoxxIkq/XAP9/uS3zKqqnRGGXm0Hs= 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=TavQ+tKW; arc=none smtp.client-ip=185.246.84.56 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="TavQ+tKW" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-02.galae.net (Postfix) with ESMTPS id B81071A10C7; Fri, 3 Oct 2025 10:39:45 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 87D9160683; Fri, 3 Oct 2025 10:39:45 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 44522102F1C34; Fri, 3 Oct 2025 12:39:43 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1759487984; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=i5fUEUgIVWMunz1YPOYTWYL3LVH7gS/tsB8DL80Sfco=; b=TavQ+tKW/HRQ5PLxtRACT02jNmQLru465Io0wcsbv+cPYz6k/sFZUzp6HlYCS+RETRuqTl p+mC5LXxgAB6pPEEKBB1pg9kLsaEmrnNpDQ3jRsxenZ+7CMyJn3lBjWYle/qdjd+dl2gGF bFHUQZuajWIi1KTBuvk0J/j9HMAuPOBHV+4WjLp24x1pAeTWqLAFMk04RKQ8nSfS8NNf2o H1XX8UKGEpT6+XPnMoWS3eOoRzoLhcjdWc3RJK8DudQnJ4i3duha3dkRn8TgVFpvbrqQRX 4dP0OMpgDaPTOVVizDgSvuJGYGg75oOHibkKay+1nayWwWSStQPcj6G2wDrzhA== From: Luca Ceresoli Date: Fri, 03 Oct 2025 12:39:25 +0200 Subject: [PATCH v2 3/7] drm/bridge: lock the encoder bridge chain mutex during insertion 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: <20251003-drm-bridge-alloc-encoder-chain-mutex-v2-3-78bf61580a06@bootlin.com> References: <20251003-drm-bridge-alloc-encoder-chain-mutex-v2-0-78bf61580a06@bootlin.com> In-Reply-To: <20251003-drm-bridge-alloc-encoder-chain-mutex-v2-0-78bf61580a06@bootlin.com> 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@lists.freedesktop.org, linux-kernel@vger.kernel.org, Luca Ceresoli X-Mailer: b4 0.14.2 X-Last-TLS-Session-Version: TLSv1.3 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. Signed-off-by: Luca Ceresoli --- 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 53e7ece36dd940aabd1c0880f296fce7224a12ac..d2ab7cef0b768b0ff674a779778= 33da27133912f 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -453,10 +453,12 @@ int drm_bridge_attach(struct drm_encoder *encoder, st= ruct drm_bridge *bridge, bridge->dev =3D encoder->dev; bridge->encoder =3D encoder; =20 + drm_encoder_chain_lock(encoder); if (previous) list_add(&bridge->chain_node, &previous->chain_node); else list_add(&bridge->chain_node, &encoder->bridge_chain); + drm_encoder_chain_unlock(encoder); =20 if (bridge->funcs->attach) { ret =3D bridge->funcs->attach(bridge, encoder, flags); @@ -487,7 +489,9 @@ int drm_bridge_attach(struct drm_encoder *encoder, stru= ct drm_bridge *bridge, err_reset_bridge: bridge->dev =3D NULL; bridge->encoder =3D NULL; + drm_encoder_chain_lock(encoder); list_del(&bridge->chain_node); + drm_encoder_chain_unlock(encoder); =20 if (ret !=3D -EPROBE_DEFER) DRM_ERROR("failed to attach bridge %pOF to encoder %s: %d\n", --=20 2.51.0 From nobody Wed Dec 17 17:39:17 2025 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 B18A12EB863 for ; Fri, 3 Oct 2025 10:39:49 +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=1759487991; cv=none; b=cSPeObJNgH4/4635r0tF5DkyRmWA3oX21j6PYYhoeo42mTyZj6O56rkJN9HlPGlFl9NIOPZRj6QrRwUGXuerfu8zdsxWeUV2M8hVb92aE4gmVgluK2baK1AHGsyz2mCzZGJPPBW6QddsCODsjVwDkc16r7EFGmADM+mR903Zf9w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759487991; c=relaxed/simple; bh=oI+h/dewJH8/oOjgfCtg16wIt9ZpcbhQF4ffLHDJXS0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=BTJm8FNLPL9Ffm7Ek/z9SgQ/bMR4aY1KcvHkSW5emQewnTJgpdoVS9zFD4fIiGZ6NeSWG89oLXuhWXVITlCwpQBnSbXJkRXMrL/CvdvUvTEloR9XamMQ9R3wKJquQkDYtzisCxFqXYB8Q1SKKszsp+RlrP2jlAsXTKqH7SlJtME= 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=p9TdMw1G; 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="p9TdMw1G" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id F0C7D4E40E8F; Fri, 3 Oct 2025 10:39:47 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id BAA3660683; Fri, 3 Oct 2025 10:39:47 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 2FEB4102F1C67; Fri, 3 Oct 2025 12:39:45 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1759487987; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=nYh+hMqLvgQPGb4l+T5RHzaDkje85oxW7gyHSJVOEyk=; b=p9TdMw1Gf8V95fW1JXIcKNKN7CwpKX7/i5q/eVjG4WlejLRCsdSFWXzXpIWbN1sfpLvo6I DndD/pIvCGMHlkQH0qXxLOZvsftvxA8d27USabCFYud25LKhrTYeYi0rL+VqXsDMOCsAeh DepIdILCD+6S5CuALcPvgEPF2TTsvA86rP8WabDAmh7oKVG58oNvdikoIEFgikLoYoQ8M9 1UyC1Vhftgc2p2gYY1tFZsEGWXDqb7xuag1UUv21+89A6qdHX0nKFUP/xU9OQ2idVMIWKZ WoBRqvETRvS04TcXqDfHjnhpjgTYgT2BleVHC5y7WGkwoeGFMTQF/NVgNFMH6Q== From: Luca Ceresoli Date: Fri, 03 Oct 2025 12:39:26 +0200 Subject: [PATCH v2 4/7] drm/bridge: lock the encoder chain in scoped for_each loops 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: <20251003-drm-bridge-alloc-encoder-chain-mutex-v2-4-78bf61580a06@bootlin.com> References: <20251003-drm-bridge-alloc-encoder-chain-mutex-v2-0-78bf61580a06@bootlin.com> In-Reply-To: <20251003-drm-bridge-alloc-encoder-chain-mutex-v2-0-78bf61580a06@bootlin.com> 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@lists.freedesktop.org, linux-kernel@vger.kernel.org, Luca Ceresoli X-Mailer: b4 0.14.2 X-Last-TLS-Session-Version: TLSv1.3 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. To make iterations safe, change the logic of 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). Also remove the get/put on the current bridge because it is not needed anymore. In fact all bridges in the encoder chain are refcounted already thanks to the drm_bridge_get() in drm_bridge_attach() and the drm_bridge_put() in drm_bridge_detach(). So while iterating with the mutex held the list cannot change _and_ the refcount of all bridges in the list cannot drop to zero. Signed-off-by: Luca Ceresoli --- 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 | 62 ++++++++++++++++++++++++++------------------= ---- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 0ff7ab4aa8689a022458f935a7ffb23a2b715802..5a72817f04a78f5379f69e72fe5= 19c5eb3ea043e 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -1440,26 +1440,29 @@ drm_bridge_chain_get_last_bridge(struct drm_encoder= *encoder) struct drm_bridge, chain_node)); } =20 -/** - * 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 l= ast. - */ -static inline struct drm_bridge * -drm_bridge_get_next_bridge_and_put(struct drm_bridge *bridge) +static inline struct drm_bridge *drm_bridge_encoder_chain_lock(struct drm_= bridge *bridge) { - struct drm_bridge *next =3D drm_bridge_get_next_bridge(bridge); + drm_encoder_chain_lock(bridge->encoder); + + return bridge; +} =20 - drm_bridge_put(bridge); +/* Internal to drm_for_each_bridge_in_chain*() */ +static inline struct drm_bridge *__drm_encoder_bridge_chain_next(struct dr= m_bridge *bridge) +{ + if (list_is_last(&bridge->chain_node, &bridge->encoder->bridge_chain)) { + drm_encoder_chain_unlock(bridge->encoder); =20 - return next; + return NULL; + } + + return list_next_entry(bridge, chain_node); } =20 +/* Internal to drm_for_each_bridge_in_chain*() */ +DEFINE_FREE(drm_bridge_encoder_chain_unlock, struct drm_bridge *, + if (_T) drm_encoder_chain_unlock(_T->encoder);) + /** * drm_for_each_bridge_in_chain_scoped - iterate over all bridges attached * to an encoder @@ -1469,14 +1472,15 @@ drm_bridge_get_next_bridge_and_put(struct drm_bridg= e *bridge) * * Iterate over all bridges present in the bridge chain attached to @encod= er. * - * Automatically gets/puts the bridge reference while iterating, and puts - * the reference even if returning or breaking in the middle of the loop. + * Automatically 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) =3D \ - drm_bridge_chain_get_first_bridge(encoder); \ - bridge; \ - bridge =3D 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_bridge_encoder_chain_unlock) = =3D \ + list_first_entry_or_null(&drm_encoder_chain_lock(encoder)->bridge_c= hain, \ + struct drm_bridge, chain_node); \ + bridge; \ + bridge =3D __drm_encoder_bridge_chain_next(bridge)) \ =20 /** * drm_for_each_bridge_in_chain_from - iterate over all bridges starting @@ -1488,14 +1492,14 @@ drm_bridge_get_next_bridge_and_put(struct drm_bridg= e *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 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) =3D \ - drm_bridge_get(first_bridge); \ - bridge; \ - bridge =3D 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_bridge_encoder_chain_unlock) = =3D \ + drm_bridge_encoder_chain_lock(first_bridge); \ + bridge; \ + bridge =3D __drm_encoder_bridge_chain_next(bridge)) \ =20 enum drm_mode_status drm_bridge_chain_mode_valid(struct drm_bridge *bridge, --=20 2.51.0 From nobody Wed Dec 17 17:39:17 2025 Received: from smtpout-04.galae.net (smtpout-04.galae.net [185.171.202.116]) (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 575432EBDC0 for ; Fri, 3 Oct 2025 10:39:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.171.202.116 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759487994; cv=none; b=BcPH+ch4xq1n5DdLF8vV+gMe6EsDc/PX7cwHMaati2/b7V3z5li2iNkMDj9WFVY7yKo0gvBLi91yxxCNM0y16V0PB9hyO/OMT1XFIXhbNUeq/fHszAP0quSVFdbZXGPxkeCfUeliSJVK3UQb0oywVlkobTvIW/1LU7wy8Ji++f4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759487994; c=relaxed/simple; bh=OYF0OqEC6tlkKQsgLv1tgbt2mXWmxxI73QEr10A0p9o=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Hlh2LgwOPucBQzWKCMxaeI/457Yn0ZvCtZ+uAglCZZ0h/kYX9VBJQ9IzPxf5Mn5ZMMZUahnnp/LQ/QSuPSHOGMw9TQzAWiZVu3TSMtAOgYLVBSiWyKgxBbBpaYDjm9KsGAdzQ2enflxDODK/3Aojuv2lWZCJ4ag5qDTY2GICArY= 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=qrfYhE/2; arc=none smtp.client-ip=185.171.202.116 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="qrfYhE/2" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id C4FF6C00D98; Fri, 3 Oct 2025 10:39:32 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id C566960683; Fri, 3 Oct 2025 10:39:50 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 5D3DE102F1C6B; Fri, 3 Oct 2025 12:39:47 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1759487990; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=Zmn0YvDl/BoxozrvJssctltfT6XEmoHzgDyceLIjDFM=; b=qrfYhE/2ATcIGh6d/xFu0jQfqV3erjx060Rp0WfllFSTeCYQwjgB3VIigkT/muGVfI0gZF WDImGR2LHN/STRTNm40jEMQHN2EBdyP8W3YKyvvY9gkMpjYdtuxFK104Fn3YvzsETrTa18 +U9spZV7bZ/+hoJwR5lqINg9QKqR1k9+Nbvup6p7BwX/sMBJ/o9CXv7AJx0Rv87AHsXsJH muWizwpYO1RXxyv6obtlPnExnK65ibt8srcgzdmYVGAaDbFcArduLljfui23ak18A7huCF nN0clzArTsU9l3OXvTNL8FFjdACp0UtQyLGZZEkx1ibgpLM8WkhNxI705dIzqA== From: Luca Ceresoli Date: Fri, 03 Oct 2025 12:39:27 +0200 Subject: [PATCH v2 5/7] drm/bridge: prevent encoder chain changes while iterating with list_for_each_entry_from() 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: <20251003-drm-bridge-alloc-encoder-chain-mutex-v2-5-78bf61580a06@bootlin.com> References: <20251003-drm-bridge-alloc-encoder-chain-mutex-v2-0-78bf61580a06@bootlin.com> In-Reply-To: <20251003-drm-bridge-alloc-encoder-chain-mutex-v2-0-78bf61580a06@bootlin.com> 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@lists.freedesktop.org, linux-kernel@vger.kernel.org, Luca Ceresoli X-Mailer: b4 0.14.2 X-Last-TLS-Session-Version: TLSv1.3 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(). These two functions are handled by a separate commit. Signed-off-by: Luca Ceresoli --- 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 d2ab7cef0b768b0ff674a77977833da27133912f..be38dd7eefed0539795f721738e= 1f1df324d9a6f 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -618,7 +618,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 * @@ -632,17 +632,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; =20 - encoder =3D 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; =20 if (!bridge->funcs->mode_valid) @@ -660,7 +657,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 * @@ -669,20 +666,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; =20 - encoder =3D 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); =20 @@ -906,7 +899,7 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable); =20 /** * drm_atomic_bridge_chain_enable - enables all bridges in the encoder cha= in - * @bridge: bridge control structure + * @first_bridge: bridge control structure * @state: atomic state being committed * * Calls &drm_bridge_funcs.atomic_enable (falls back on @@ -916,22 +909,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; =20 - encoder =3D 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); =20 --=20 2.51.0 From nobody Wed Dec 17 17:39:17 2025 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 23B482EC099 for ; Fri, 3 Oct 2025 10:39:55 +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=1759487996; cv=none; b=YDv2lVpow0aoJCXY3fTRIO1TJ7xZJysDY/aYrfaMk28c45QafIlu+NaacqRbUzg/4GVy2WlfwIT1kwsBftMkwWMQsJqNgjycw3L+NTjmK6lGFTQdrec+fVwkgKEAxc8oT95/ZlZE/P12UNso8SgVOaqdj7VV9Py59lAx9qSBbZc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759487996; c=relaxed/simple; bh=+6rLZEJVLUoBOu0HBcjpZGnC3LT1sYS2H2pxgugg1Z4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=kGBltqYcOX9285rin9xgTwcNdAEAqN4Ha7lmZ/8N3Wwh6BrQcVIgRcXjy52AM2PPYcBXtA33Ggh8chbpGhumFseRU2A7IdGvKGQq9ZXPngo2qveZkAIUSa5906knI0KAa9JR7CgfCvtGkHnpzDveGpsQ17smNQtNFy6PComuyU0= 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=2vTnHhmj; 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="2vTnHhmj" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id 947464E40E91; Fri, 3 Oct 2025 10:39:53 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 64C6560683; Fri, 3 Oct 2025 10:39:53 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 8E31A102F1C74; Fri, 3 Oct 2025 12:39:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1759487992; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=tT/vWu3Z8SdD0NgF7BlgEpJEzKECdpNxQ6B86Lk3qJo=; b=2vTnHhmjgRWgLDLzVfDUrVTs5+0gLfY4ZlR864hzh+1CNwTuiDz+Yy1qn3nbP5fX1BjwrB lOYQq//h4MwSkj/AfeKRA8JAbA0e73ruUHxUtU2dzqPbjOyP3e5GkOkFJerF3roLQVIRKQ pCNLdPjwWyDLCMW+/td+WRpndSRqu8eYHkcpfCXv3SYfPxaBmW2MbUwbuka5E2hRBx7a0S BhJZEjYY76tGyAWPOhf58XohVIK7GkJ7IAQKNKp+ew9WetP3EwmrWdamJS0geepZiRieOq fhdSubgvdKud+R0n1xRbOy6hPX+VqPH0PWzs7GTjBh2bU6a0ZocONGPry5rn/w== From: Luca Ceresoli Date: Fri, 03 Oct 2025 12:39:28 +0200 Subject: [PATCH v2 6/7] drm/bridge: prevent encoder chain changes while iterating with list_for_each_entry_reverse() 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: <20251003-drm-bridge-alloc-encoder-chain-mutex-v2-6-78bf61580a06@bootlin.com> References: <20251003-drm-bridge-alloc-encoder-chain-mutex-v2-0-78bf61580a06@bootlin.com> In-Reply-To: <20251003-drm-bridge-alloc-encoder-chain-mutex-v2-0-78bf61580a06@bootlin.com> 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@lists.freedesktop.org, linux-kernel@vger.kernel.org, Luca Ceresoli X-Mailer: b4 0.14.2 X-Last-TLS-Session-Version: TLSv1.3 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 --- drivers/gpu/drm/drm_bridge.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index be38dd7eefed0539795f721738e1f1df324d9a6f..2a55ac5697e0b4faa21f01728bb= e287a95cd99a6 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -701,6 +701,7 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge = *bridge, return; =20 encoder =3D bridge->encoder; + drm_encoder_chain_lock(encoder); list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { if (iter->funcs->atomic_disable) { iter->funcs->atomic_disable(iter, state); @@ -711,6 +712,7 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge = *bridge, if (iter =3D=3D bridge) break; } + drm_encoder_chain_unlock(encoder); } EXPORT_SYMBOL(drm_atomic_bridge_chain_disable); =20 @@ -1215,6 +1217,7 @@ int drm_atomic_bridge_chain_check(struct drm_bridge *= bridge, return ret; =20 encoder =3D bridge->encoder; + drm_encoder_chain_lock(encoder); list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { int ret; =20 @@ -1229,12 +1232,15 @@ int drm_atomic_bridge_chain_check(struct drm_bridge= *bridge, crtc_state->state); =20 ret =3D drm_atomic_bridge_check(iter, crtc_state, conn_state); - if (ret) + if (ret) { + drm_encoder_chain_unlock(encoder); return ret; + } =20 if (iter =3D=3D bridge) break; } + drm_encoder_chain_unlock(encoder); =20 return 0; } --=20 2.51.0 From nobody Wed Dec 17 17:39:17 2025 Received: from smtpout-04.galae.net (smtpout-04.galae.net [185.171.202.116]) (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 0EDFA2EC0BF for ; Fri, 3 Oct 2025 10:39:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.171.202.116 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759487998; cv=none; b=Dg0yatAlyBVotGXP25Nh6JdpiLtcLR9FWkdjAwStE8tadURT7Le68rtM5oAxd3UNeItR9FQWum4Mu60LBN0xU0S8CqjXGfXxKPk6IwJ2JZWS+5ryhtX3Dj2Z3QYzRv5AqvnsHkeVYPzSY7uteVYfMIruveFoRP6chEaTesfslq0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759487998; c=relaxed/simple; bh=VOr5eBoNc9FnNHnP9I1a7YeygagW6If0Sow2UvyqWHU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=CiK78NoWz3bVCRVlUq1ltt2p3rbgt5LJBqjGOJdqKp9c9hy4QJzaZhASDU3h4onn+m2WTcniVlPC1qHbm0pKT1mRVDDV4blYn/UTMKr8oIJCbS+AJMPm8hP0gB6qPFtNNycoTHPNCiLq/A4IOSJ5t5EEnMQq/CgfSb8YPpibsSU= 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=wtYD1khi; arc=none smtp.client-ip=185.171.202.116 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="wtYD1khi" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id 808D9C00D98; Fri, 3 Oct 2025 10:39:37 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 8103560683; Fri, 3 Oct 2025 10:39:55 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id E1134102F1C6C; Fri, 3 Oct 2025 12:39:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1759487994; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=tbt/7EiW1spKYTs5CQJj03xNV0I741bKU71RrfYpRZA=; b=wtYD1khie8pKkgE+AJBUeKyUOUNq8cQJOHgD94ksjKwHFbBS2F6nPLkC1LSz2dvNsFWhd3 QFHGsvUL5GYWCJnDlmRok6dqb53ovlMujxwrl/D0C5dAtDNqNRDWxdEVGtFQ2UgM6dBNct NnUet2rzjjqbF+TcJCtTafPA0wWkWM3qJMm7WBRtfNXrYXkp9EVU0mNSFS1egijheh1pfa 9ivubEtXhh3DxPhU/mea4OxAYFKE/+xhmStjUPP7XBEBTYAfrUkeVG69eaNw4rHs9rCmfH //qxhniDxsWvLoA1kwBfW9bicTeClWf+0SlpsqbVuf+VOC7/rBwWrK/nTMORVg== From: Luca Ceresoli Date: Fri, 03 Oct 2025 12:39:29 +0200 Subject: [PATCH v2 7/7] drm/bridge: prevent encoder chain changes in pre_enable/post_disable 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: <20251003-drm-bridge-alloc-encoder-chain-mutex-v2-7-78bf61580a06@bootlin.com> References: <20251003-drm-bridge-alloc-encoder-chain-mutex-v2-0-78bf61580a06@bootlin.com> In-Reply-To: <20251003-drm-bridge-alloc-encoder-chain-mutex-v2-0-78bf61580a06@bootlin.com> 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@lists.freedesktop.org, linux-kernel@vger.kernel.org, Luca Ceresoli X-Mailer: b4 0.14.2 X-Last-TLS-Session-Version: TLSv1.3 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 return points inside the loops, so the change is trivial and readable. Signed-off-by: Luca Ceresoli --- 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 2a55ac5697e0b4faa21f01728bbe287a95cd99a6..840ea4ef4bb27ea035cda784f8e= c39cd768ed704 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -760,6 +760,7 @@ void drm_atomic_bridge_chain_post_disable(struct drm_br= idge *bridge, =20 encoder =3D bridge->encoder; =20 + drm_encoder_chain_lock(encoder); list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { limit =3D NULL; =20 @@ -808,6 +809,7 @@ void drm_atomic_bridge_chain_post_disable(struct drm_br= idge *bridge, /* Jump all bridges that we have already post_disabled */ bridge =3D limit; } + drm_encoder_chain_unlock(encoder); } EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable); =20 @@ -854,6 +856,7 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_brid= ge *bridge, =20 encoder =3D bridge->encoder; =20 + drm_encoder_chain_lock(encoder); list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { if (iter->pre_enable_prev_first) { next =3D iter; @@ -896,6 +899,7 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_brid= ge *bridge, if (iter =3D=3D bridge) break; } + drm_encoder_chain_unlock(encoder); } EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable); =20 --=20 2.51.0