[PATCH v2 2/6] gpiolib: free the label of lines released after their chip was removed

From: Adrian Ambrozewicz

Date: Fri Oct 16 2026 - 05:29:47 EST


gpiod_free_commit() only drops the consumer label while the chip is
still there:

if (guard.gc && test_bit(GPIOD_FLAG_REQUESTED, &flags)) {
...
desc_set_label(desc, NULL);

A line that is still requested when gpiochip_remove() runs, for instance
by a character device line request that user space keeps open, is
released only afterwards, when gdev->chip is already NULL. Its label is
then never freed, as gpiodev_release() frees the descriptor array but
not the labels, and kmemleak reports one object per such line:

unreferenced object (size 32):
comm "gpio-hold"
backtrace:
desc_set_label
gpiod_request_commit
gpiod_request
linereq_create
gpio_ioctl

Commit 1f2bcb8c8ccd ("gpio: protect the descriptor label with SRCU")
cleared the label unconditionally; it moved under the chip check with
the removal of gpio_lock. Return early only for a line that is not
requested on a live chip, and clear the label before the chip check, so
that it is also freed when the chip is gone. The ->free() callback, the
flags update and the line state notification still need the chip and
stay under the check; with the chip gone, no character device file can
receive the notification any more.

The label is now often freed just before the last reference to the GPIO
device goes away, which depends on gpiodev_release() waiting for pending
label frees (previous patch).

Reproduced with gpio-sim: request a line through the character device,
set the chip's configfs "live" attribute to 0 while the request is open,
then close it. Without this change kmemleak reports between 15 and 30
such objects after 30 cycles; with it, none after 100.

Fixes: 35b545332b80 ("gpio: remove gpio_lock")
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: LLM
Signed-off-by: Adrian Ambrozewicz <aambrozewicz@xxxxxxxxxx>
---
Changes in v2:
- Return early for a line that is not requested on a live chip and clear
the label once, before the chip check, so now before ->free() (Andy).
- kmemleak report cut down (Andy).
- Assisted-by tag.

drivers/gpio/gpiolib.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 1984f3416437..31ccdd373765 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -2666,7 +2666,12 @@ void gpiod_free_commit(struct gpio_desc *desc)

flags = READ_ONCE(desc->flags);

- if (guard.gc && test_bit(GPIOD_FLAG_REQUESTED, &flags)) {
+ if (guard.gc && !test_bit(GPIOD_FLAG_REQUESTED, &flags))
+ return;
+
+ desc_set_label(desc, NULL);
+
+ if (guard.gc) {
if (guard.gc->free)
guard.gc->free(guard.gc, gpiod_hwgpio(desc));

@@ -2683,7 +2688,6 @@ void gpiod_free_commit(struct gpio_desc *desc)
#ifdef CONFIG_OF_DYNAMIC
WRITE_ONCE(desc->hog, NULL);
#endif
- desc_set_label(desc, NULL);
WRITE_ONCE(desc->flags, flags);
#ifdef CONFIG_GPIO_CDEV
WRITE_ONCE(desc->debounce_period_us, 0);
--
2.43.0