Merge tag 'gpio-fixes-for-v6.19-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux

Pull gpio fixes from Bartosz Golaszewski:
 "Some fixes to resource leaks in the character device handling and
  another small fix for shared GPIO management:

   - fix resource leaks in error paths in GPIO character device code

   - return -ENOMEM and not -ENODEV on memory allocation failure

   - fix an audio issue on Qualcomm platforms due to configuration not
     being propagated to pinctrl from shared GPIO proxy"

* tag 'gpio-fixes-for-v6.19-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux:
  gpio: shared: propagate configuration to pinctrl
  gpio: cdev: Fix resource leaks on errors in gpiolib_cdev_register()
  gpio: cdev: Fix resource leaks on errors in lineinfo_changed_notify()
  gpio: cdev: Correct return code on memory allocation failure
This commit is contained in:
Linus Torvalds
2026-01-23 10:14:52 -08:00
4 changed files with 24 additions and 10 deletions

View File

@@ -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;
}
@@ -2696,7 +2697,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)
@@ -2796,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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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)
{