From faff6846474e99295a139997f93ef6db222b5cee Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Fri, 16 Jan 2026 08:10:18 +0000 Subject: [PATCH 1/4] gpio: cdev: Correct return code on memory allocation failure -ENOMEM is a more appropriate return code for memory allocation failures. Correct it. Cc: stable@vger.kernel.org Fixes: 20bddcb40b2b ("gpiolib: cdev: replace locking wrappers for gpio_device with guards") Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20260116081036.352286-6-tzungbi@kernel.org Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-cdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index 3735c9fe1502..67cbb05d34ca 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -2696,7 +2696,7 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file) cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); if (!cdev) - return -ENODEV; + return -ENOMEM; cdev->watched_lines = bitmap_zalloc(gdev->ngpio, GFP_KERNEL); if (!cdev->watched_lines) From 70b3c280533167749a8f740acaa8ef720f78f984 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Tue, 20 Jan 2026 03:08:56 +0000 Subject: [PATCH 2/4] gpio: cdev: Fix resource leaks on errors in lineinfo_changed_notify() On error handling paths, lineinfo_changed_notify() doesn't free the allocated resources which results leaks. Fix it. Cc: stable@vger.kernel.org Fixes: d4cd0902c156 ("gpio: cdev: make sure the cdev fd is still active before emitting events") Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20260120030857.2144847-1-tzungbi@kernel.org Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-cdev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index 67cbb05d34ca..ed249a45d658 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -2549,6 +2549,7 @@ static int lineinfo_changed_notify(struct notifier_block *nb, ctx = kzalloc(sizeof(*ctx), GFP_ATOMIC); if (!ctx) { pr_err("Failed to allocate memory for line info notification\n"); + fput(fp); return NOTIFY_DONE; } From 8a8c942cad4cd12f739a8bb60cac77fd173c4e07 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Tue, 20 Jan 2026 09:26:50 +0000 Subject: [PATCH 3/4] gpio: cdev: Fix resource leaks on errors in gpiolib_cdev_register() On error handling paths, gpiolib_cdev_register() doesn't free the allocated resources which results leaks. Fix it. Cc: stable@vger.kernel.org Fixes: 7b9b77a8bba9 ("gpiolib: add a per-gpio_device line state notification workqueue") Fixes: d83cee3d2bb1 ("gpio: protect the pointer to gpio_chip in gpio_device with SRCU") Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20260120092650.2305319-1-tzungbi@kernel.org Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-cdev.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index ed249a45d658..2adc3c070908 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -2797,13 +2797,18 @@ int gpiolib_cdev_register(struct gpio_device *gdev, dev_t devt) return -ENOMEM; ret = cdev_device_add(&gdev->chrdev, &gdev->dev); - if (ret) + if (ret) { + destroy_workqueue(gdev->line_state_wq); return ret; + } guard(srcu)(&gdev->srcu); gc = srcu_dereference(gdev->chip, &gdev->srcu); - if (!gc) + if (!gc) { + cdev_device_del(&gdev->chrdev, &gdev->dev); + destroy_workqueue(gdev->line_state_wq); return -ENODEV; + } gpiochip_dbg(gc, "added GPIO chardev (%d:%d)\n", MAJOR(devt), gdev->id); From 4918cc05137cb347686462923ab3fd249ef7899d Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 20 Jan 2026 16:49:13 +0100 Subject: [PATCH 4/4] gpio: shared: propagate configuration to pinctrl Just toggling the descriptor's "requested" flag is not enough. We need to properly request it in order to potentially propagate any configuration to pinctrl via the .request() callback. We must not take the reference to the device at this point (the device is not ready but we're also requesting the device's own descriptor) so make the _commit() variants of request and free functions available to GPIO core in order to use them instead of their regular counterparts. This fixes an audio issue reported on one of the Qualcomm platforms. Fixes: a060b8c511ab ("gpiolib: implement low-level, shared GPIO support") Reviewed-by: Linus Walleij Tested-by: Ravi Hothi Link: https://lore.kernel.org/r/20260120154913.61991-1-bartosz.golaszewski@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-shared.c | 16 +++++++++++----- drivers/gpio/gpiolib.c | 4 ++-- drivers/gpio/gpiolib.h | 2 ++ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c index 17343fdc9758..9e6544203439 100644 --- a/drivers/gpio/gpiolib-shared.c +++ b/drivers/gpio/gpiolib-shared.c @@ -515,7 +515,7 @@ int gpio_device_setup_shared(struct gpio_device *gdev) { struct gpio_shared_entry *entry; struct gpio_shared_ref *ref; - unsigned long *flags; + struct gpio_desc *desc; int ret; list_for_each_entry(entry, &gpio_shared_list, list) { @@ -543,15 +543,17 @@ int gpio_device_setup_shared(struct gpio_device *gdev) if (list_count_nodes(&entry->refs) <= 1) continue; - flags = &gdev->descs[entry->offset].flags; + desc = &gdev->descs[entry->offset]; - __set_bit(GPIOD_FLAG_SHARED, flags); + __set_bit(GPIOD_FLAG_SHARED, &desc->flags); /* * Shared GPIOs are not requested via the normal path. Make * them inaccessible to anyone even before we register the * chip. */ - __set_bit(GPIOD_FLAG_REQUESTED, flags); + ret = gpiod_request_commit(desc, "shared"); + if (ret) + return ret; pr_debug("GPIO %u owned by %s is shared by multiple consumers\n", entry->offset, gpio_device_get_label(gdev)); @@ -562,8 +564,10 @@ int gpio_device_setup_shared(struct gpio_device *gdev) ref->con_id ?: "(none)"); ret = gpio_shared_make_adev(gdev, entry, ref); - if (ret) + if (ret) { + gpiod_free_commit(desc); return ret; + } } } @@ -579,6 +583,8 @@ void gpio_device_teardown_shared(struct gpio_device *gdev) if (!device_match_fwnode(&gdev->dev, entry->fwnode)) continue; + gpiod_free_commit(&gdev->descs[entry->offset]); + list_for_each_entry(ref, &entry->refs, list) { guard(mutex)(&ref->lock); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index fe2d107b0a84..1578cf3a8c74 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2453,7 +2453,7 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges); * on each other, and help provide better diagnostics in debugfs. * They're called even less than the "set direction" calls. */ -static int gpiod_request_commit(struct gpio_desc *desc, const char *label) +int gpiod_request_commit(struct gpio_desc *desc, const char *label) { unsigned int offset; int ret; @@ -2515,7 +2515,7 @@ int gpiod_request(struct gpio_desc *desc, const char *label) return ret; } -static void gpiod_free_commit(struct gpio_desc *desc) +void gpiod_free_commit(struct gpio_desc *desc) { unsigned long flags; diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 77f6f2936dc2..3abb90385829 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -244,7 +244,9 @@ DEFINE_CLASS(gpio_chip_guard, struct gpio_desc *desc) int gpiod_request(struct gpio_desc *desc, const char *label); +int gpiod_request_commit(struct gpio_desc *desc, const char *label); void gpiod_free(struct gpio_desc *desc); +void gpiod_free_commit(struct gpio_desc *desc); static inline int gpiod_request_user(struct gpio_desc *desc, const char *label) {