[PATCH 1/2] gpio: shared: fix deadlock on shared proxy's parent removal
From: Bartosz Golaszewski
Date: Fri May 22 2026 - 05:19:35 EST
Commit 710abda58055 ("gpio: shared: call gpio_chip::of_xlate() if set")
used the mutex embedded in struct gpio_shared_entry to protect the
offset field which now can be modified after assignment. The critical
section however is too wide and introduced a potential deadlock on the
removal of the shared GPIO proxy's parent.
Make the critical section shorter - only protect the offset when it's
being read.
While at it: mention the fact that the entry lock is now also used to
protect against concurrent access to the offset field in the structure's
documentation.
Cc: stable@xxxxxxxxxxxxxxx
Fixes: 710abda58055 ("gpio: shared: call gpio_chip::of_xlate() if set")
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@xxxxxxxxxxxxxxxx>
---
drivers/gpio/gpiolib-shared.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c
index e02d6b93a4ab42b197f0fd64e4854a303f54f140..087b64c06c9f42b698abe5741e63102538beb488 100644
--- a/drivers/gpio/gpiolib-shared.c
+++ b/drivers/gpio/gpiolib-shared.c
@@ -53,7 +53,7 @@ struct gpio_shared_entry {
unsigned int offset;
/* Index in the property value array. */
size_t index;
- /* Synchronizes the modification of shared_desc. */
+ /* Synchronizes the modification of shared_desc and offset. */
struct mutex lock;
struct gpio_shared_desc *shared_desc;
struct kref ref;
@@ -598,12 +598,11 @@ void gpio_device_teardown_shared(struct gpio_device *gdev)
struct gpio_shared_ref *ref;
list_for_each_entry(entry, &gpio_shared_list, list) {
- guard(mutex)(&entry->lock);
-
if (!device_match_fwnode(&gdev->dev, entry->fwnode))
continue;
- gpiod_free_commit(&gdev->descs[entry->offset]);
+ scoped_guard(mutex, &entry->lock)
+ gpiod_free_commit(&gdev->descs[entry->offset]);
list_for_each_entry(ref, &entry->refs, list) {
guard(mutex)(&ref->lock);
--
2.47.3