[PATCH v3 0/6] gpio: acpi: modernize resource management using cleanup.h

Marco Scardovi posted 6 patches 1 month ago
There is a newer version of this series
drivers/gpio/gpiolib-acpi-core.c | 57 ++++++++++++++------------------
include/linux/acpi.h             |  2 ++
include/linux/gpio/driver.h      |  2 ++
3 files changed, 28 insertions(+), 33 deletions(-)
[PATCH v3 0/6] gpio: acpi: modernize resource management using cleanup.h
Posted by Marco Scardovi 1 month ago
Hi Andy, Mika,
thanks for the patience: I was way too excited about my first patch on
the linux kernel and let it takes over the reasoning and I'm sorry for that.
I've moved the defines on the right places as requested and refactored the
patches to be smaller and tested the build with KASAN and kmemleak as requested
by @Mika without any visible regression as for now.

Marco Scardovi (6):
  ACPI: Move DEFINE_FREE(acpi_free) to global header
  gpiolib: Move DEFINE_FREE(free_gpio_desc) to driver header
  gpio: acpi: ignore out-of-range pins in acpi_gpiochip_alloc_event()
  gpio: acpi: use guard(mutex) for conn_lock
  gpio: acpi: use cleanup.h for automated resource deallocation
  gpio: acpi: sort header inclusion alphabetically

 drivers/gpio/gpiolib-acpi-core.c | 57 ++++++++++++++------------------
 include/linux/acpi.h             |  2 ++
 include/linux/gpio/driver.h      |  2 ++
 3 files changed, 28 insertions(+), 33 deletions(-)

-- 
2.54.0
Re: [PATCH v3 0/6] gpio: acpi: modernize resource management using cleanup.h
Posted by Andy Shevchenko 1 month ago
On Thu, May 07, 2026 at 05:56:41PM +0200, Marco Scardovi wrote:
> Hi Andy, Mika,
> thanks for the patience: I was way too excited about my first patch on
> the linux kernel and let it takes over the reasoning and I'm sorry for that.
> I've moved the defines on the right places as requested and refactored the
> patches to be smaller and tested the build with KASAN and kmemleak as requested
> by @Mika without any visible regression as for now.

You MUST provide:
- DCO (Developer certificate of origin)
- commit messages

Without that, it's no go *at all*.

-- 
With Best Regards,
Andy Shevchenko
[PATCH v4 0/6] gpio: acpi: modernize resource management using cleanup.h
Posted by Marco Scardovi 1 month ago
Hi Andy,
as requested I've added the missing Signed-off-by and related commits' messages.
Let me know if it's everything alright now.

Marco Scardovi (6):
  ACPI: Move DEFINE_FREE(acpi_free) to global header
  gpiolib: Move DEFINE_FREE(free_gpio_desc) to driver header
  gpio: acpi: ignore out-of-range pins in acpi_gpiochip_alloc_event()
  gpio: acpi: use guard(mutex) for conn_lock
  gpio: acpi: use cleanup.h for automated resource deallocation
  gpio: acpi: sort header inclusion alphabetically

 drivers/gpio/gpiolib-acpi-core.c | 57 ++++++++++++++------------------
 include/linux/acpi.h             |  2 ++
 include/linux/gpio/driver.h      |  2 ++
 3 files changed, 28 insertions(+), 33 deletions(-)

-- 
2.54.0
Re: [PATCH v4 0/6] gpio: acpi: modernize resource management using cleanup.h
Posted by Andy Shevchenko 1 month ago
On Fri, May 08, 2026 at 08:17:23AM +0200, Marco Scardovi wrote:
> Hi Andy,
> as requested I've added the missing Signed-off-by and related commits' messages.
> Let me know if it's everything alright now.

Note, cover letter is not just for a simple comment like the above, it's mainly
for the overview of the series as a whole, what it doing and why. No need to
resend a series, just try to write down one in a reply to this message.

-- 
With Best Regards,
Andy Shevchenko
Re: [PATCH v4 0/6] gpio: acpi: modernize resource management using cleanup.h
Posted by Andy Shevchenko 1 month ago
On Fri, May 08, 2026 at 10:21:11AM +0300, Andy Shevchenko wrote:
> On Fri, May 08, 2026 at 08:17:23AM +0200, Marco Scardovi wrote:
> > Hi Andy,
> > as requested I've added the missing Signed-off-by and related commits' messages.
> > Let me know if it's everything alright now.
> 
> Note, cover letter is not just for a simple comment like the above, it's mainly
> for the overview of the series as a whole, what it doing and why. No need to
> resend a series, just try to write down one in a reply to this message.

Also this is v4 of the series, you need to provide a changelog for each delta
between two sequential versions (here we expect to see a v1->v2, v2->v3, and
v3->v4).

-- 
With Best Regards,
Andy Shevchenko
[PATCH v4 1/6] ACPI: Move DEFINE_FREE(acpi_free) to global header
Posted by Marco Scardovi 1 month ago
Introduce DEFINE_FREE(acpi_free) in include/linux/acpi.h to provide
a standard way to perform automated memory deallocation for ACPI
objects. This enables the use of the __free(acpi_free) attribute
wherever ACPI_FREE() is required.

Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
---
 include/linux/acpi.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 67effb91fa98..f58e704ee850 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -234,6 +234,8 @@ static inline struct acpi_table_header *acpi_get_table_pointer(char *signature,
 }
 DEFINE_FREE(acpi_put_table, struct acpi_table_header *, if (!IS_ERR_OR_NULL(_T)) acpi_put_table(_T))
 
+DEFINE_FREE(acpi_free, void *, if (_T) ACPI_FREE(_T))
+
 int acpi_table_parse(char *id, acpi_tbl_table_handler handler);
 int __init_or_acpilib acpi_table_parse_entries(char *id,
 		unsigned long table_size, int entry_id,
-- 
2.54.0
Re: [PATCH v4 1/6] ACPI: Move DEFINE_FREE(acpi_free) to global header
Posted by Rafael J. Wysocki 1 month ago
On Fri, May 8, 2026 at 8:18 AM Marco Scardovi <mscardovi95@gmail.com> wrote:
>
> Introduce DEFINE_FREE(acpi_free) in include/linux/acpi.h to provide
> a standard way to perform automated memory deallocation for ACPI
> objects. This enables the use of the __free(acpi_free) attribute
> wherever ACPI_FREE() is required.

This goes a bit overboard because the objects needing ACPI_FREE() for
freeing are most of the time allocated in a way that precludes using
__free().

Note that you are expected to initialize the pointer at declaration
time when using __free() and that cannot be done with objects
allocated by ACPICA code in many cases.

> Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
> ---
>  include/linux/acpi.h | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> index 67effb91fa98..f58e704ee850 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -234,6 +234,8 @@ static inline struct acpi_table_header *acpi_get_table_pointer(char *signature,
>  }
>  DEFINE_FREE(acpi_put_table, struct acpi_table_header *, if (!IS_ERR_OR_NULL(_T)) acpi_put_table(_T))
>
> +DEFINE_FREE(acpi_free, void *, if (_T) ACPI_FREE(_T))
> +
>  int acpi_table_parse(char *id, acpi_tbl_table_handler handler);
>  int __init_or_acpilib acpi_table_parse_entries(char *id,
>                 unsigned long table_size, int entry_id,
> --
> 2.54.0
>
>
[PATCH v4 2/6] gpiolib: Move DEFINE_FREE(free_gpio_desc) to driver header
Posted by Marco Scardovi 1 month ago
Define the free_gpio_desc cleanup handler in include/linux/gpio/driver.h.
This allows drivers to use the __free(free_gpio_desc) attribute for
automated deallocation of GPIO descriptors obtained via
gpiochip_request_own_desc().

Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
---
 include/linux/gpio/driver.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 17511434ed07..7ee65b49056d 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -807,6 +807,8 @@ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *gc,
 					    enum gpiod_flags dflags);
 void gpiochip_free_own_desc(struct gpio_desc *desc);
 
+DEFINE_FREE(free_gpio_desc, struct gpio_desc *, if (!IS_ERR_OR_NULL(_T)) gpiochip_free_own_desc(_T))
+
 struct gpio_desc *
 gpio_device_get_desc(struct gpio_device *gdev, unsigned int hwnum);
 
-- 
2.54.0
[PATCH v4 3/6] gpio: acpi: ignore out-of-range pins in acpi_gpiochip_alloc_event()
Posted by Marco Scardovi 1 month ago
Add a check to verify that the pin index retrieved from ACPI is within
the valid range for the GPIO chip (pin < chip->ngpio). If the pin is
out of range, an error is logged and the function returns early to
avoid invalid memory access.

Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
---
 drivers/gpio/gpiolib-acpi-core.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c
index eb8a40cfb7a9..e53d68578024 100644
--- a/drivers/gpio/gpiolib-acpi-core.c
+++ b/drivers/gpio/gpiolib-acpi-core.c
@@ -370,6 +370,11 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
 	handle = ACPI_HANDLE(chip->parent);
 	pin = agpio->pin_table[0];
 
+	if (pin >= chip->ngpio) {
+		dev_err(chip->parent, "Failed to request GPIO for pin 0x%04X, out of range\n", pin);
+		return AE_OK;
+	}
+
 	if (pin <= 255) {
 		char ev_name[8];
 		sprintf(ev_name, "_%c%02X",
-- 
2.54.0
[PATCH v4 4/6] gpio: acpi: use guard(mutex) for conn_lock
Posted by Marco Scardovi 1 month ago
Replace manual mutex_lock() and mutex_unlock() calls in
acpi_gpio_adr_space_handler() with the guard(mutex) helper. This
ensures the conn_lock is automatically released when exiting the
scope, preventing potential deadlocks and simplifying the logic.

Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
---
 drivers/gpio/gpiolib-acpi-core.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c
index e53d68578024..33d6c3b6cdf0 100644
--- a/drivers/gpio/gpiolib-acpi-core.c
+++ b/drivers/gpio/gpiolib-acpi-core.c
@@ -1123,7 +1123,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
 		u16 word, shift;
 		bool found;
 
-		mutex_lock(&achip->conn_lock);
+		guard(mutex)(&achip->conn_lock);
 
 		found = false;
 		list_for_each_entry(conn, &achip->conns, node) {
@@ -1155,17 +1155,15 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
 		if (!found) {
 			desc = acpi_request_own_gpiod(chip, agpio, i, "ACPI:OpRegion");
 			if (IS_ERR(desc)) {
-				mutex_unlock(&achip->conn_lock);
 				status = AE_ERROR;
-				goto out;
+				break;
 			}
 
 			conn = kzalloc_obj(*conn);
 			if (!conn) {
 				gpiochip_free_own_desc(desc);
-				mutex_unlock(&achip->conn_lock);
 				status = AE_NO_MEMORY;
-				goto out;
+				break;
 			}
 
 			conn->pin = pin;
@@ -1173,8 +1171,6 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
 			list_add_tail(&conn->node, &achip->conns);
 		}
 
-		mutex_unlock(&achip->conn_lock);
-
 		/*
 		 * For the cases when OperationRegion() consists of more than
 		 * 64 bits calculate the word and bit shift to use that one to
-- 
2.54.0
[PATCH v4 5/6] gpio: acpi: use cleanup.h for automated resource deallocation
Posted by Marco Scardovi 1 month ago
Refactor acpi_gpiochip_alloc_event() and acpi_gpio_adr_space_handler()
to use the __free() macro for GPIO descriptors and ACPI resources.
This simplifies error handling by removing manual cleanup calls and
reducing the need for goto labels.

Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
---
 drivers/gpio/gpiolib-acpi-core.c | 40 +++++++++++---------------------
 1 file changed, 14 insertions(+), 26 deletions(-)

diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c
index 33d6c3b6cdf0..c9b12e24de14 100644
--- a/drivers/gpio/gpiolib-acpi-core.c
+++ b/drivers/gpio/gpiolib-acpi-core.c
@@ -397,31 +397,27 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
 
 	desc = acpi_request_own_gpiod(chip, agpio, 0, "ACPI:Event");
 	if (IS_ERR(desc)) {
-		dev_err(chip->parent,
-			"Failed to request GPIO for pin 0x%04X, err %pe\n",
-			pin, desc);
+		dev_err(chip->parent, "Failed to request GPIO for pin 0x%04X, err %pe\n", pin, desc);
 		return AE_OK;
 	}
 
+	struct gpio_desc *desc_guard __free(free_gpio_desc) = desc;
+
 	ret = gpiochip_lock_as_irq(chip, pin);
 	if (ret) {
-		dev_err(chip->parent,
-			"Failed to lock GPIO pin 0x%04X as interrupt, err %d\n",
-			pin, ret);
-		goto fail_free_desc;
+		dev_err(chip->parent, "Failed to lock GPIO pin 0x%04X as interrupt, err %d\n", pin, ret);
+		return AE_OK;
 	}
 
 	irq = gpiod_to_irq(desc);
 	if (irq < 0) {
-		dev_err(chip->parent,
-			"Failed to translate GPIO pin 0x%04X to IRQ, err %d\n",
-			pin, irq);
-		goto fail_unlock_irq;
+		dev_err(chip->parent, "Failed to translate GPIO pin 0x%04X to IRQ, err %d\n", pin, irq);
+		goto err_unlock;
 	}
 
 	event = kzalloc_obj(*event);
 	if (!event)
-		goto fail_unlock_irq;
+		goto err_unlock;
 
 	event->irqflags = IRQF_ONESHOT;
 	if (agpio->triggering == ACPI_LEVEL_SENSITIVE) {
@@ -449,17 +445,15 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
 	event->irq = irq;
 	event->irq_is_wake = acpi_gpio_irq_is_wake(chip->parent, agpio);
 	event->pin = pin;
-	event->desc = desc;
+	/* Transfer ownership to event, prevent auto-free */
+	event->desc = no_free_ptr(desc_guard);
 
 	list_add_tail(&event->node, &acpi_gpio->events);
 
 	return AE_OK;
 
-fail_unlock_irq:
+err_unlock:
 	gpiochip_unlock_as_irq(chip, pin);
-fail_free_desc:
-	gpiochip_free_own_desc(desc);
-
 	return AE_OK;
 }
 
@@ -1091,7 +1085,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
 	struct acpi_gpio_chip *achip = region_context;
 	struct gpio_chip *chip = achip->chip;
 	struct acpi_resource_gpio *agpio;
-	struct acpi_resource *ares;
+	struct acpi_resource *ares __free(acpi_free) = NULL;
 	u16 pin_index = address;
 	acpi_status status;
 	int length;
@@ -1102,18 +1096,14 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
 	if (ACPI_FAILURE(status))
 		return status;
 
-	if (WARN_ON(ares->type != ACPI_RESOURCE_TYPE_GPIO)) {
-		ACPI_FREE(ares);
+	if (WARN_ON(ares->type != ACPI_RESOURCE_TYPE_GPIO))
 		return AE_BAD_PARAMETER;
-	}
 
 	agpio = &ares->data.gpio;
 
 	if (WARN_ON(agpio->io_restriction == ACPI_IO_RESTRICT_INPUT &&
-	    function == ACPI_WRITE)) {
-		ACPI_FREE(ares);
+	    function == ACPI_WRITE))
 		return AE_BAD_PARAMETER;
-	}
 
 	length = min(agpio->pin_table_length, pin_index + bits);
 	for (i = pin_index; i < length; ++i) {
@@ -1189,8 +1179,6 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
 		}
 	}
 
-out:
-	ACPI_FREE(ares);
 	return status;
 }
 
-- 
2.54.0
Re: [PATCH v4 5/6] gpio: acpi: use cleanup.h for automated resource deallocation
Posted by Rafael J. Wysocki 1 month ago
On Fri, May 8, 2026 at 8:18 AM Marco Scardovi <mscardovi95@gmail.com> wrote:
>
> Refactor acpi_gpiochip_alloc_event() and acpi_gpio_adr_space_handler()
> to use the __free() macro for GPIO descriptors and ACPI resources.
> This simplifies error handling by removing manual cleanup calls and
> reducing the need for goto labels.
>
> Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
> ---
>  drivers/gpio/gpiolib-acpi-core.c | 40 +++++++++++---------------------
>  1 file changed, 14 insertions(+), 26 deletions(-)
>
> diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c
> index 33d6c3b6cdf0..c9b12e24de14 100644
> --- a/drivers/gpio/gpiolib-acpi-core.c
> +++ b/drivers/gpio/gpiolib-acpi-core.c
> @@ -397,31 +397,27 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
>
>         desc = acpi_request_own_gpiod(chip, agpio, 0, "ACPI:Event");
>         if (IS_ERR(desc)) {
> -               dev_err(chip->parent,
> -                       "Failed to request GPIO for pin 0x%04X, err %pe\n",
> -                       pin, desc);
> +               dev_err(chip->parent, "Failed to request GPIO for pin 0x%04X, err %pe\n", pin, desc);
>                 return AE_OK;
>         }
>
> +       struct gpio_desc *desc_guard __free(free_gpio_desc) = desc;
> +
>         ret = gpiochip_lock_as_irq(chip, pin);
>         if (ret) {
> -               dev_err(chip->parent,
> -                       "Failed to lock GPIO pin 0x%04X as interrupt, err %d\n",
> -                       pin, ret);
> -               goto fail_free_desc;
> +               dev_err(chip->parent, "Failed to lock GPIO pin 0x%04X as interrupt, err %d\n", pin, ret);
> +               return AE_OK;
>         }
>
>         irq = gpiod_to_irq(desc);
>         if (irq < 0) {
> -               dev_err(chip->parent,
> -                       "Failed to translate GPIO pin 0x%04X to IRQ, err %d\n",
> -                       pin, irq);
> -               goto fail_unlock_irq;
> +               dev_err(chip->parent, "Failed to translate GPIO pin 0x%04X to IRQ, err %d\n", pin, irq);
> +               goto err_unlock;

You are not supposed to mix up cleanup.h stuff with gotos.

>         }
>
>         event = kzalloc_obj(*event);
>         if (!event)
> -               goto fail_unlock_irq;
> +               goto err_unlock;
>
>         event->irqflags = IRQF_ONESHOT;
>         if (agpio->triggering == ACPI_LEVEL_SENSITIVE) {
> @@ -449,17 +445,15 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
>         event->irq = irq;
>         event->irq_is_wake = acpi_gpio_irq_is_wake(chip->parent, agpio);
>         event->pin = pin;
> -       event->desc = desc;
> +       /* Transfer ownership to event, prevent auto-free */
> +       event->desc = no_free_ptr(desc_guard);
>
>         list_add_tail(&event->node, &acpi_gpio->events);
>
>         return AE_OK;
>
> -fail_unlock_irq:
> +err_unlock:
>         gpiochip_unlock_as_irq(chip, pin);
> -fail_free_desc:
> -       gpiochip_free_own_desc(desc);
> -
>         return AE_OK;
>  }
>
> @@ -1091,7 +1085,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
>         struct acpi_gpio_chip *achip = region_context;
>         struct gpio_chip *chip = achip->chip;
>         struct acpi_resource_gpio *agpio;
> -       struct acpi_resource *ares;
> +       struct acpi_resource *ares __free(acpi_free) = NULL;

Nope, that's not how you use __free().

>         u16 pin_index = address;
>         acpi_status status;
>         int length;
> @@ -1102,18 +1096,14 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
>         if (ACPI_FAILURE(status))
>                 return status;
>
> -       if (WARN_ON(ares->type != ACPI_RESOURCE_TYPE_GPIO)) {
> -               ACPI_FREE(ares);
> +       if (WARN_ON(ares->type != ACPI_RESOURCE_TYPE_GPIO))
>                 return AE_BAD_PARAMETER;
> -       }
>
>         agpio = &ares->data.gpio;
>
>         if (WARN_ON(agpio->io_restriction == ACPI_IO_RESTRICT_INPUT &&
> -           function == ACPI_WRITE)) {
> -               ACPI_FREE(ares);
> +           function == ACPI_WRITE))
>                 return AE_BAD_PARAMETER;
> -       }
>
>         length = min(agpio->pin_table_length, pin_index + bits);
>         for (i = pin_index; i < length; ++i) {
> @@ -1189,8 +1179,6 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
>                 }
>         }
>
> -out:
> -       ACPI_FREE(ares);
>         return status;
>  }
>
[PATCH v4 6/6] gpio: acpi: sort header inclusion alphabetically
Posted by Marco Scardovi 1 month ago
Reorder the #include directives in gpiolib-acpi-core.c to follow
alphabetical order. This improves code readability and ensures
consistency with kernel coding style for header management.

Signed-off-by: Marco Scardovi <mscardovi95@gmail.com>
---
 drivers/gpio/gpiolib-acpi-core.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c
index c9b12e24de14..7b324dd4ae67 100644
--- a/drivers/gpio/gpiolib-acpi-core.c
+++ b/drivers/gpio/gpiolib-acpi-core.c
@@ -8,12 +8,14 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/cleanup.h>
 #include <linux/dmi.h>
 #include <linux/errno.h>
 #include <linux/export.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/mutex.h>
+#include <linux/slab.h>
 #include <linux/pinctrl/pinctrl.h>
 
 #include <linux/gpio/consumer.h>
-- 
2.54.0