Commit a1b83660 authored by Bartosz Golaszewski's avatar Bartosz Golaszewski
Browse files

gpio: shared: fix deadlock on shared proxy's parent removal



Commit 710abda5 ("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@vger.kernel.org
Fixes: 710abda5 ("gpio: shared: call gpio_chip::of_xlate() if set")
Reviewed-by: default avatarLinus Walleij <linusw@kernel.org>
Link: https://patch.msgid.link/20260522-gpio-shared-deadlock-v1-1-76bca088f8c0@oss.qualcomm.com


Signed-off-by: default avatarBartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
parent a5c627d9
Loading
Loading
Loading
Loading
+3 −4
Original line number Diff line number Diff line
@@ -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,11 +598,10 @@ 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;

		scoped_guard(mutex, &entry->lock)
			gpiod_free_commit(&gdev->descs[entry->offset]);

		list_for_each_entry(ref, &entry->refs, list) {