* [PATCH v3 0/6] gpiolib: fix chip removal with lines still requested from user space
@ 2026-10-20 13:00 Adrian Ambrozewicz
2026-10-20 13:00 ` [PATCH v3 1/6] gpiolib: wait for pending label frees before cleaning up desc_srcu Adrian Ambrozewicz
` (5 more replies)
0 siblings, 6 replies; 9+ messages in thread
From: Adrian Ambrozewicz @ 2026-10-20 13:00 UTC (permalink / raw)
To: Bartosz Golaszewski, Linus Walleij
Cc: Bartosz Golaszewski, Kent Gibson, Paul E. McKenney, Herve Codina,
Jia Jia, Andy Shevchenko, linux-gpio, linux-kernel
Removing a GPIO chip while user space holds a line request, as when a
hot-pluggable GPIO controller goes away, leaks the line labels (patch 2)
and IRQ names (patch 5), frees IRQs a second time (patches 3, 6) and
lets a blocked read() stall the removal (patch 4). Patch 1 makes
gpiodev_release() wait for pending label frees; without it,
cleanup_srcu_struct() can warn, more often with patch 2.
Patch 6 changes the order in gpiochip_remove() for in-kernel users too:
the IRQs they leave requested are now freed after the chip pointer is
cleared, when gpiod_*() calls on the chip fail.
User-visible change: a read() blocked when the chip is removed returns
the queued events, if any, and then fails with -ENODEV, instead of
staying blocked until a signal or an event.
For stable: patch 2 needs patch 1; patches 3, 5 and 6 fix a commit from
6.13 that 6.12.y also has; patch 4 applies to 6.12.y, older trees need a
different change.
Tested under QEMU (x86_64, 4 vCPUs) with gpio-sim and a test-only chip
on the hierarchical irqchip, on lockdep, kmemleak and KASAN builds:
each reproducer warns, leaks or hangs without its patch and passes with
it. v2 has the details.
An LLM assistant helped with the analysis, the reproducers and the
drafts, hence the Assisted-by tags; I reviewed and tested every change.
Changes in v3:
- Rebased on gpio/for-current.
- Patch 6: return early when there is no ->to_irq(); drop the comment
in lineevent_free() (Kent).
- Shorter commit messages (Kent, Bartosz).
- Sashiko's finding on v2 6/6, the gpiochip_add_data_with_key() error
path after the character device is registered, is on mainline too; I
plan to send a fix for it on top of this series.
- Link to v2: https://lore.kernel.org/r/20261016-gpiolib-chip-removal-v2-0-aambrozewicz@nvidia.com
- Link to v1: https://lore.kernel.org/r/20261012-gpiolib-chip-removal-v1-0-aambrozewicz@nvidia.com
Adrian Ambrozewicz (6):
gpiolib: wait for pending label frees before cleaning up desc_srcu
gpiolib: free the label of lines released after their chip was removed
gpiolib: cdev: do not free line IRQs again after the chip is removed
gpiolib: cdev: don't sleep in the SRCU read section in read()
gpiolib: cdev: don't leak the IRQ name when the chip is removed
gpiolib: let the character device free its IRQs first on chip removal
drivers/gpio/gpiolib-cdev.c | 145 +++++++++++++++++++++++++++---------
drivers/gpio/gpiolib.c | 38 ++++++++--
2 files changed, 138 insertions(+), 45 deletions(-)
base-commit: 974d2712cb15014019595799b3ed68fef5fe9695
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 1/6] gpiolib: wait for pending label frees before cleaning up desc_srcu
2026-10-20 13:00 [PATCH v3 0/6] gpiolib: fix chip removal with lines still requested from user space Adrian Ambrozewicz
@ 2026-10-20 13:00 ` Adrian Ambrozewicz
2026-10-20 13:00 ` [PATCH v3 2/6] gpiolib: free the label of lines released after their chip was removed Adrian Ambrozewicz
` (4 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Adrian Ambrozewicz @ 2026-10-20 13:00 UTC (permalink / raw)
To: Bartosz Golaszewski, Linus Walleij
Cc: Bartosz Golaszewski, Kent Gibson, Paul E. McKenney, Herve Codina,
Jia Jia, Andy Shevchenko, linux-gpio, linux-kernel, stable
desc_set_label() frees the old label with call_srcu() on
gdev->desc_srcu, and gpiodev_release() calls synchronize_srcu() before
cleanup_srcu_struct(). synchronize_srcu() waits for a grace period, not
for queued callbacks. Once the srcu_struct uses per-CPU callback lists,
a label freed by gpiochip_free_hogs() can still be pending, and
cleanup_srcu_struct() warns:
WARNING: kernel/rcu/srcutree.c:706 at cleanup_srcu_struct+0x239/0x330, CPU#0: init/1
Call Trace:
gpiodev_release
device_release
kobject_put
devres_release_all
device_release_driver_internal
platform_device_unregister
gpio_sim_device_deactivate
Use srcu_barrier(), which waits for them.
Reproduced with a hogged gpio-sim line, setting the chip live and back
on a 4-CPU guest with srcutree.convert_to_big=1: it warns within 60
cycles; with this change, 1000 cycles pass.
Fixes: a86d27693066 ("gpiolib: fix the speed of descriptor label setting with SRCU")
Cc: stable@vger.kernel.org
Reviewed-by: Paul E. McKenney <paulmck@kernel.org>
Assisted-by: LLM
Signed-off-by: Adrian Ambrozewicz <aambrozewicz@nvidia.com>
---
drivers/gpio/gpiolib.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 6932278cdb9f..e5326c472a54 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -895,7 +895,7 @@ static void gpiodev_release(struct device *dev)
struct gpio_device *gdev = to_gpio_device(dev);
/* Call pending kfree()s for descriptor labels. */
- synchronize_srcu(&gdev->desc_srcu);
+ srcu_barrier(&gdev->desc_srcu);
cleanup_srcu_struct(&gdev->desc_srcu);
ida_free(&gpio_ida, gdev->id);
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 2/6] gpiolib: free the label of lines released after their chip was removed
2026-10-20 13:00 [PATCH v3 0/6] gpiolib: fix chip removal with lines still requested from user space Adrian Ambrozewicz
2026-10-20 13:00 ` [PATCH v3 1/6] gpiolib: wait for pending label frees before cleaning up desc_srcu Adrian Ambrozewicz
@ 2026-10-20 13:00 ` Adrian Ambrozewicz
2026-10-20 13:19 ` sashiko-bot
2026-10-20 13:00 ` [PATCH v3 3/6] gpiolib: cdev: do not free line IRQs again after the chip is removed Adrian Ambrozewicz
` (3 subsequent siblings)
5 siblings, 1 reply; 9+ messages in thread
From: Adrian Ambrozewicz @ 2026-10-20 13:00 UTC (permalink / raw)
To: Bartosz Golaszewski, Linus Walleij
Cc: Bartosz Golaszewski, Kent Gibson, Paul E. McKenney, Herve Codina,
Jia Jia, Andy Shevchenko, linux-gpio, linux-kernel, stable
gpiod_free_commit() drops the consumer label only while the chip is
still there. A line that user space keeps requested across
gpiochip_remove() is released when gdev->chip is already NULL, and its
label leaks:
unreferenced object (size 32):
comm "gpio-hold"
backtrace (crc 7ff222d9):
desc_set_label
gpiod_request_commit
gpiod_request
linereq_create
gpio_ioctl
Clear the label before the chip check. The ->free() callback, the flags
update and the line state notification need the chip and stay under it.
Reproduced with gpio-sim: request a line, set the chip's "live"
attribute to 0, then close the request. kmemleak reports up to 30 such
objects after 30 cycles; with this change, none after 100.
Fixes: 35b545332b80 ("gpio: remove gpio_lock")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Adrian Ambrozewicz <aambrozewicz@nvidia.com>
---
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 e5326c472a54..e923512febf1 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));
@@ -2685,7 +2690,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
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 3/6] gpiolib: cdev: do not free line IRQs again after the chip is removed
2026-10-20 13:00 [PATCH v3 0/6] gpiolib: fix chip removal with lines still requested from user space Adrian Ambrozewicz
2026-10-20 13:00 ` [PATCH v3 1/6] gpiolib: wait for pending label frees before cleaning up desc_srcu Adrian Ambrozewicz
2026-10-20 13:00 ` [PATCH v3 2/6] gpiolib: free the label of lines released after their chip was removed Adrian Ambrozewicz
@ 2026-10-20 13:00 ` Adrian Ambrozewicz
2026-10-20 13:00 ` [PATCH v3 4/6] gpiolib: cdev: don't sleep in the SRCU read section in read() Adrian Ambrozewicz
` (2 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Adrian Ambrozewicz @ 2026-10-20 13:00 UTC (permalink / raw)
To: Bartosz Golaszewski, Linus Walleij
Cc: Bartosz Golaszewski, Kent Gibson, Paul E. McKenney, Herve Codina,
Jia Jia, Andy Shevchenko, linux-gpio, linux-kernel, stable
Since commit ec8b6f55b981 ("gpio: free irqs that are still requested
when the chip is being removed"), gpiochip_remove() frees the IRQs
still installed on the chip's lines. A line request or v1 line event
kept open across the removal frees its IRQ again on release. If the
mapping is gone, that can touch freed memory, as reported with
virtio-gpio; if the number was reused, free_irq() warns:
Trying to free already-free IRQ 28
WARNING: kernel/irq/manage.c:1881 at free_irq+0x193/0x2d0, CPU#2: gpio-hold/111
Call Trace:
linereq_free
linereq_release
__fput
Stop edge detection from the device notifier that gpiochip_remove()
calls, under config_mutex so that it does not race a reconfiguration.
Free the IRQ there only if it still has an action, as gpiochip_remove()
frees only those on lines flagged as used for IRQs. The release path
then finds nothing left to free.
Reproduced with gpio-sim: remove the chip under an open request with
edge detection, set it up again and request the same line, then close
the first request. Every cycle warns; with this change, 100 cycles pass.
Fixes: ec8b6f55b981 ("gpio: free irqs that are still requested when the chip is being removed")
Reported-by: Jia Jia <physicalmtea@gmail.com>
Closes: https://lore.kernel.org/all/20260817070429.157993-1-physicalmtea@gmail.com/
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Adrian Ambrozewicz <aambrozewicz@nvidia.com>
---
drivers/gpio/gpiolib-cdev.c | 57 ++++++++++++++++++++++++++-----------
1 file changed, 40 insertions(+), 17 deletions(-)
diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index f4d78113ade2..6350b2fca8a7 100644
--- a/drivers/gpio/gpiolib-cdev.c
+++ b/drivers/gpio/gpiolib-cdev.c
@@ -544,17 +544,6 @@ struct linereq {
GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE | \
GPIO_V2_LINE_EDGE_FLAGS)
-static int linereq_unregistered_notify(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- struct linereq *lr = container_of(nb, struct linereq,
- device_unregistered_nb);
-
- wake_up_poll(&lr->wait, EPOLLIN | EPOLLERR);
-
- return NOTIFY_OK;
-}
-
static void linereq_put_event(struct linereq *lr,
struct gpio_v2_line_event *le)
{
@@ -609,6 +598,21 @@ static inline void free_irq_label(const char *label)
kfree(label);
}
+/*
+ * gpiochip_remove() frees the interrupts still requested on the lines of the
+ * chip being removed, so once the chip is going away the IRQ may no longer be
+ * ours to free.
+ */
+static void free_line_irq(unsigned int irq, void *dev_id)
+{
+ const char *name = NULL;
+
+ if (irq && irq_has_action(irq))
+ name = free_irq(irq, dev_id);
+
+ free_irq_label(name);
+}
+
#ifdef CONFIG_HTE
static enum hte_return process_hw_ts_thread(void *p)
@@ -974,10 +978,8 @@ static u32 gpio_v2_line_config_debounce_period(struct gpio_v2_line_config *lc,
static void edge_detector_stop(struct line *line)
{
- if (line->irq) {
- free_irq_label(free_irq(line->irq, line));
- line->irq = 0;
- }
+ free_line_irq(line->irq, line);
+ line->irq = 0;
#ifdef CONFIG_HTE
if (READ_ONCE(line->edflags) & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE)
@@ -992,6 +994,25 @@ static void edge_detector_stop(struct line *line)
/* do not change line->level - see comment in debounced_value() */
}
+static int linereq_unregistered_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct linereq *lr = container_of(nb, struct linereq, device_unregistered_nb);
+
+ /*
+ * Stop edge detection now rather than when the request is released:
+ * by then the IRQ numbers of the removed chip may be in use again.
+ */
+ scoped_guard(mutex, &lr->config_mutex) {
+ for (unsigned int i = 0; i < lr->num_lines; i++)
+ edge_detector_stop(&lr->lines[i]);
+ }
+
+ wake_up_poll(&lr->wait, EPOLLIN | EPOLLERR);
+
+ return NOTIFY_OK;
+}
+
static int edge_detector_fifo_init(struct linereq *req)
{
if (kfifo_initialized(&req->events))
@@ -1787,6 +1808,9 @@ static int lineevent_unregistered_notify(struct notifier_block *nb,
struct lineevent_state *le = container_of(nb, struct lineevent_state,
device_unregistered_nb);
+ free_line_irq(le->irq, le);
+ le->irq = 0;
+
wake_up_poll(&le->wait, EPOLLIN | EPOLLERR);
return NOTIFY_OK;
@@ -1866,8 +1890,7 @@ static void lineevent_free(struct lineevent_state *le)
if (le->device_unregistered_nb.notifier_call)
blocking_notifier_chain_unregister(&le->gdev->device_notifier,
&le->device_unregistered_nb);
- if (le->irq)
- free_irq_label(free_irq(le->irq, le));
+ free_line_irq(le->irq, le);
if (le->desc)
gpiod_free(le->desc);
kfree(le->label);
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 4/6] gpiolib: cdev: don't sleep in the SRCU read section in read()
2026-10-20 13:00 [PATCH v3 0/6] gpiolib: fix chip removal with lines still requested from user space Adrian Ambrozewicz
` (2 preceding siblings ...)
2026-10-20 13:00 ` [PATCH v3 3/6] gpiolib: cdev: do not free line IRQs again after the chip is removed Adrian Ambrozewicz
@ 2026-10-20 13:00 ` Adrian Ambrozewicz
2026-10-20 13:00 ` [PATCH v3 5/6] gpiolib: cdev: don't leak the IRQ name when the chip is removed Adrian Ambrozewicz
2026-10-20 13:00 ` [PATCH v3 6/6] gpiolib: let the character device free its IRQs first on chip removal Adrian Ambrozewicz
5 siblings, 0 replies; 9+ messages in thread
From: Adrian Ambrozewicz @ 2026-10-20 13:00 UTC (permalink / raw)
To: Bartosz Golaszewski, Linus Walleij
Cc: Bartosz Golaszewski, Kent Gibson, Paul E. McKenney, Herve Codina,
Jia Jia, Andy Shevchenko, linux-gpio, linux-kernel, stable
linereq_read(), lineevent_read() and lineinfo_watch_read() stay in the
gdev->srcu read section while they sleep waiting for an event, so
gpiochip_remove() blocks in synchronize_srcu() until an event arrives
or the reader is signalled. The device lock is held meanwhile, which
also blocks device_shutdown():
task:init state:D stack:0 pid:1 tgid:1 ppid:0
Call Trace:
__synchronize_srcu
gpiochip_remove
devres_release_all
device_release_driver_internal
platform_device_unregister
gpio_sim_device_deactivate
Check the chip in a scoped SRCU section only; nothing after the check
dereferences it. End the wait once the chip is gone, and return -ENODEV
if there is no event to report.
Reproduced with gpio-sim: setting "live" to 0 hangs while a reader is
blocked in read() on a line request; with this change, the write
returns at once and read() fails with -ENODEV.
Fixes: bdbbae241a04 ("gpiolib: protect the GPIO device against being dropped while in use by user-space")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Adrian Ambrozewicz <aambrozewicz@nvidia.com>
---
drivers/gpio/gpiolib-cdev.c | 50 ++++++++++++++++++++++++++-----------
1 file changed, 35 insertions(+), 15 deletions(-)
diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index 6350b2fca8a7..c5869e3f7767 100644
--- a/drivers/gpio/gpiolib-cdev.c
+++ b/drivers/gpio/gpiolib-cdev.c
@@ -1507,6 +1507,20 @@ static __poll_t linereq_poll(struct file *file,
return events;
}
+/*
+ * For the read() paths, which must not stay in the SRCU read section while
+ * sleeping: that would stall gpiochip_remove() until an event arrives.
+ */
+static int gpiodev_check_chip(struct gpio_device *gdev)
+{
+ guard(srcu)(&gdev->srcu);
+
+ if (!rcu_access_pointer(gdev->chip))
+ return -ENODEV;
+
+ return 0;
+}
+
static ssize_t linereq_read(struct file *file, char __user *buf,
size_t count, loff_t *f_ps)
{
@@ -1515,10 +1529,9 @@ static ssize_t linereq_read(struct file *file, char __user *buf,
ssize_t bytes_read = 0;
int ret;
- guard(srcu)(&lr->gdev->srcu);
-
- if (!rcu_access_pointer(lr->gdev->chip))
- return -ENODEV;
+ ret = gpiodev_check_chip(lr->gdev);
+ if (ret)
+ return ret;
if (count < sizeof(le))
return -EINVAL;
@@ -1533,9 +1546,12 @@ static ssize_t linereq_read(struct file *file, char __user *buf,
return -EAGAIN;
ret = wait_event_interruptible_locked(lr->wait,
- !kfifo_is_empty(&lr->events));
+ !kfifo_is_empty(&lr->events) ||
+ !rcu_access_pointer(lr->gdev->chip));
if (ret)
return ret;
+ if (kfifo_is_empty(&lr->events))
+ return -ENODEV;
}
if (kfifo_out(&lr->events, &le, 1) != 1) {
@@ -1830,10 +1846,9 @@ static ssize_t lineevent_read(struct file *file, char __user *buf,
ssize_t ge_size;
int ret;
- guard(srcu)(&le->gdev->srcu);
-
- if (!rcu_access_pointer(le->gdev->chip))
- return -ENODEV;
+ ret = gpiodev_check_chip(le->gdev);
+ if (ret)
+ return ret;
/*
* When compatible system call is being used the struct gpioevent_data,
@@ -1861,9 +1876,12 @@ static ssize_t lineevent_read(struct file *file, char __user *buf,
return -EAGAIN;
ret = wait_event_interruptible_locked(le->wait,
- !kfifo_is_empty(&le->events));
+ !kfifo_is_empty(&le->events) ||
+ !rcu_access_pointer(le->gdev->chip));
if (ret)
return ret;
+ if (kfifo_is_empty(&le->events))
+ return -ENODEV;
}
if (kfifo_out(&le->events, &ge, 1) != 1) {
@@ -2607,10 +2625,9 @@ static ssize_t lineinfo_watch_read(struct file *file, char __user *buf,
int ret;
size_t event_size;
- guard(srcu)(&cdev->gdev->srcu);
-
- if (!rcu_access_pointer(cdev->gdev->chip))
- return -ENODEV;
+ ret = gpiodev_check_chip(cdev->gdev);
+ if (ret)
+ return ret;
#ifndef CONFIG_GPIO_CDEV_V1
event_size = sizeof(struct gpio_v2_line_info_changed);
@@ -2628,9 +2645,12 @@ static ssize_t lineinfo_watch_read(struct file *file, char __user *buf,
return -EAGAIN;
ret = wait_event_interruptible_locked(cdev->wait,
- !kfifo_is_empty(&cdev->events));
+ !kfifo_is_empty(&cdev->events) ||
+ !rcu_access_pointer(cdev->gdev->chip));
if (ret)
return ret;
+ if (kfifo_is_empty(&cdev->events))
+ return -ENODEV;
}
#ifdef CONFIG_GPIO_CDEV_V1
/* must be after kfifo check so watch_abi_version is set */
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 5/6] gpiolib: cdev: don't leak the IRQ name when the chip is removed
2026-10-20 13:00 [PATCH v3 0/6] gpiolib: fix chip removal with lines still requested from user space Adrian Ambrozewicz
` (3 preceding siblings ...)
2026-10-20 13:00 ` [PATCH v3 4/6] gpiolib: cdev: don't sleep in the SRCU read section in read() Adrian Ambrozewicz
@ 2026-10-20 13:00 ` Adrian Ambrozewicz
2026-10-20 13:00 ` [PATCH v3 6/6] gpiolib: let the character device free its IRQs first on chip removal Adrian Ambrozewicz
5 siblings, 0 replies; 9+ messages in thread
From: Adrian Ambrozewicz @ 2026-10-20 13:00 UTC (permalink / raw)
To: Bartosz Golaszewski, Linus Walleij
Cc: Bartosz Golaszewski, Kent Gibson, Paul E. McKenney, Herve Codina,
Jia Jia, Andy Shevchenko, linux-gpio, linux-kernel, stable
The character device requests line IRQs with a copy of the consumer
label as the name, and frees the name that free_irq() returns. When
gpiochip_remove() frees the IRQ first, it drops that name and the copy
leaks:
unreferenced object (size 8):
comm "gpio-hold"
backtrace (crc dc8eac94):
kstrdup
kstrdup_and_replace
edge_detector_setup
linereq_create
gpio_ioctl
Keep the name with the line or v1 line event, and free it there,
whoever freed the IRQ.
Reproduced with gpio-sim: remove the chip under an open request with
edge detection and a consumer label. kmemleak reports up to 23 such
objects after 30 cycles; with this change, none after 100.
Fixes: ec8b6f55b981 ("gpio: free irqs that are still requested when the chip is being removed")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Adrian Ambrozewicz <aambrozewicz@nvidia.com>
---
drivers/gpio/gpiolib-cdev.c | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index c5869e3f7767..cf23b5296fd1 100644
--- a/drivers/gpio/gpiolib-cdev.c
+++ b/drivers/gpio/gpiolib-cdev.c
@@ -399,6 +399,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
* @desc: the GPIO descriptor for this line.
* @req: the corresponding line request
* @irq: the interrupt triggered in response to events on this GPIO
+ * @irq_label: the name @irq was requested with
* @edflags: the edge flags, GPIO_V2_LINE_FLAG_EDGE_RISING and/or
* GPIO_V2_LINE_FLAG_EDGE_FALLING, indicating the edge detection applied
* @timestamp_ns: cache for the timestamp storing it between hardirq and
@@ -422,6 +423,7 @@ struct line {
*/
struct linereq *req;
unsigned int irq;
+ char *irq_label;
/*
* The flags for the active edge detector configuration.
*
@@ -601,16 +603,18 @@ static inline void free_irq_label(const char *label)
/*
* gpiochip_remove() frees the interrupts still requested on the lines of the
* chip being removed, so once the chip is going away the IRQ may no longer be
- * ours to free.
+ * ours to free. The label is kept by the caller as free_irq() is then not the
+ * one returning it.
*/
-static void free_line_irq(unsigned int irq, void *dev_id)
+static void free_line_irq(unsigned int irq, void *dev_id, char **label)
{
- const char *name = NULL;
+ const char *name = *label;
if (irq && irq_has_action(irq))
- name = free_irq(irq, dev_id);
+ free_irq(irq, dev_id);
free_irq_label(name);
+ *label = NULL;
}
#ifdef CONFIG_HTE
@@ -936,6 +940,7 @@ static int debounce_setup(struct line *line, unsigned int debounce_period_us)
return ret;
}
line->irq = irq;
+ line->irq_label = label;
} else {
ret = hte_edge_setup(line, GPIO_V2_LINE_FLAG_EDGE_BOTH);
if (ret)
@@ -978,7 +983,7 @@ static u32 gpio_v2_line_config_debounce_period(struct gpio_v2_line_config *lc,
static void edge_detector_stop(struct line *line)
{
- free_line_irq(line->irq, line);
+ free_line_irq(line->irq, line, &line->irq_label);
line->irq = 0;
#ifdef CONFIG_HTE
@@ -1078,6 +1083,7 @@ static int edge_detector_setup(struct line *line,
}
line->irq = irq;
+ line->irq_label = label;
return 0;
}
@@ -1776,6 +1782,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip)
* @desc: the GPIO descriptor held by this event
* @eflags: the event flags this line was requested with
* @irq: the interrupt that trigger in response to events on this GPIO
+ * @irq_label: the name @irq was requested with
* @wait: wait queue that handles blocking reads of events
* @device_unregistered_nb: notifier block for receiving gdev unregister events
* @events: KFIFO for the GPIO events
@@ -1789,6 +1796,7 @@ struct lineevent_state {
struct gpio_desc *desc;
u32 eflags;
int irq;
+ char *irq_label;
wait_queue_head_t wait;
struct notifier_block device_unregistered_nb;
DECLARE_KFIFO(events, struct gpioevent_data, 16);
@@ -1824,7 +1832,7 @@ static int lineevent_unregistered_notify(struct notifier_block *nb,
struct lineevent_state *le = container_of(nb, struct lineevent_state,
device_unregistered_nb);
- free_line_irq(le->irq, le);
+ free_line_irq(le->irq, le, &le->irq_label);
le->irq = 0;
wake_up_poll(&le->wait, EPOLLIN | EPOLLERR);
@@ -1908,7 +1916,7 @@ static void lineevent_free(struct lineevent_state *le)
if (le->device_unregistered_nb.notifier_call)
blocking_notifier_chain_unregister(&le->gdev->device_notifier,
&le->device_unregistered_nb);
- free_line_irq(le->irq, le);
+ free_line_irq(le->irq, le, &le->irq_label);
if (le->desc)
gpiod_free(le->desc);
kfree(le->label);
@@ -2147,6 +2155,7 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
}
le->irq = irq;
+ le->irq_label = label;
FD_PREPARE(fdf, O_RDONLY | O_CLOEXEC,
anon_inode_getfile("gpio-event", &lineevent_fileops, le,
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 6/6] gpiolib: let the character device free its IRQs first on chip removal
2026-10-20 13:00 [PATCH v3 0/6] gpiolib: fix chip removal with lines still requested from user space Adrian Ambrozewicz
` (4 preceding siblings ...)
2026-10-20 13:00 ` [PATCH v3 5/6] gpiolib: cdev: don't leak the IRQ name when the chip is removed Adrian Ambrozewicz
@ 2026-10-20 13:00 ` Adrian Ambrozewicz
2026-10-20 13:23 ` sashiko-bot
5 siblings, 1 reply; 9+ messages in thread
From: Adrian Ambrozewicz @ 2026-10-20 13:00 UTC (permalink / raw)
To: Bartosz Golaszewski, Linus Walleij
Cc: Bartosz Golaszewski, Kent Gibson, Paul E. McKenney, Herve Codina,
Jia Jia, Andy Shevchenko, linux-gpio, linux-kernel, stable
gpiochip_remove() force-frees the remaining IRQs, removes the irqchip,
and only then calls the device notifier on which the character device
frees its own IRQs. The character device can then free an IRQ it no
longer owns: after its mapping was disposed of and the number reused, or
from a release that races gpiod_free_irqs() and
gpiochip_irqchip_remove(). free_irq() then warns "Trying to free
already-free IRQ" or uses a disposed descriptor.
Call the notifier once the chip pointer is cleared and the SRCU grace
period has elapsed, when no ioctl can request IRQs any more, and free
the remaining IRQs after it. Have the release paths free their IRQs
before unregistering from the notifier, under the lock its callback
takes (config_mutex, or a new mutex for v1 line events). Herve Codina
first proposed calling the notifier earlier.
IRQs that in-kernel users leave requested are now freed after the chip
pointer is cleared, when gpiod_*() calls on the chip fail.
Reproduced with a test-only chip on the hierarchical irqchip: both races
warn in all 30 cycles; with this change, none does.
Link: https://lore.kernel.org/all/20240227113426.253232-1-herve.codina@bootlin.com/
Fixes: ec8b6f55b981 ("gpio: free irqs that are still requested when the chip is being removed")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Adrian Ambrozewicz <aambrozewicz@nvidia.com>
---
drivers/gpio/gpiolib-cdev.c | 35 +++++++++++++++++++++++++++--------
drivers/gpio/gpiolib.c | 28 +++++++++++++++++++++++-----
2 files changed, 50 insertions(+), 13 deletions(-)
diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index cf23b5296fd1..cd59af0c56dd 100644
--- a/drivers/gpio/gpiolib-cdev.c
+++ b/drivers/gpio/gpiolib-cdev.c
@@ -1583,19 +1583,29 @@ static void linereq_free(struct linereq *lr)
{
unsigned int i;
+ /*
+ * Stop edge detection while still registered for the notification, so
+ * that gpiochip_remove() does not get past it until the IRQs are freed.
+ */
+ scoped_guard(mutex, &lr->config_mutex) {
+ for (i = 0; i < lr->num_lines; i++) {
+ if (lr->lines[i].desc)
+ edge_detector_stop(&lr->lines[i]);
+ }
+ }
+
if (lr->device_unregistered_nb.notifier_call)
blocking_notifier_chain_unregister(&lr->gdev->device_notifier,
&lr->device_unregistered_nb);
for (i = 0; i < lr->num_lines; i++) {
- if (lr->lines[i].desc) {
- edge_detector_stop(&lr->lines[i]);
+ if (lr->lines[i].desc)
gpiod_free(lr->lines[i].desc);
- }
}
kfifo_free(&lr->events);
kfree(lr->label);
gpio_device_put(lr->gdev);
+ mutex_destroy(&lr->config_mutex);
kvfree(lr);
}
@@ -1666,6 +1676,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip)
if (!lr)
return -ENOMEM;
lr->num_lines = ulr.num_lines;
+ mutex_init(&lr->config_mutex);
lr->gdev = gpio_device_get(gdev);
@@ -1683,7 +1694,6 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip)
return -ENOMEM;
}
- mutex_init(&lr->config_mutex);
init_waitqueue_head(&lr->wait);
INIT_KFIFO(lr->events);
lr->event_buffer_size = ulr.event_buffer_size;
@@ -1783,6 +1793,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip)
* @eflags: the event flags this line was requested with
* @irq: the interrupt that trigger in response to events on this GPIO
* @irq_label: the name @irq was requested with
+ * @irq_lock: serializes freeing @irq on release and on chip removal
* @wait: wait queue that handles blocking reads of events
* @device_unregistered_nb: notifier block for receiving gdev unregister events
* @events: KFIFO for the GPIO events
@@ -1797,6 +1808,8 @@ struct lineevent_state {
u32 eflags;
int irq;
char *irq_label;
+ /* release vs. chip removal notifier */
+ struct mutex irq_lock;
wait_queue_head_t wait;
struct notifier_block device_unregistered_nb;
DECLARE_KFIFO(events, struct gpioevent_data, 16);
@@ -1832,8 +1845,10 @@ static int lineevent_unregistered_notify(struct notifier_block *nb,
struct lineevent_state *le = container_of(nb, struct lineevent_state,
device_unregistered_nb);
- free_line_irq(le->irq, le, &le->irq_label);
- le->irq = 0;
+ scoped_guard(mutex, &le->irq_lock) {
+ free_line_irq(le->irq, le, &le->irq_label);
+ le->irq = 0;
+ }
wake_up_poll(&le->wait, EPOLLIN | EPOLLERR);
@@ -1913,14 +1928,18 @@ static ssize_t lineevent_read(struct file *file, char __user *buf,
static void lineevent_free(struct lineevent_state *le)
{
+ scoped_guard(mutex, &le->irq_lock) {
+ free_line_irq(le->irq, le, &le->irq_label);
+ le->irq = 0;
+ }
if (le->device_unregistered_nb.notifier_call)
blocking_notifier_chain_unregister(&le->gdev->device_notifier,
&le->device_unregistered_nb);
- free_line_irq(le->irq, le, &le->irq_label);
if (le->desc)
gpiod_free(le->desc);
kfree(le->label);
gpio_device_put(le->gdev);
+ mutex_destroy(&le->irq_lock);
kfree(le);
}
@@ -2092,6 +2111,7 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
le = kzalloc_obj(*le);
if (!le)
return -ENOMEM;
+ mutex_init(&le->irq_lock);
le->gdev = gpio_device_get(gdev);
if (eventreq.consumer_label[0] != '\0') {
@@ -2827,5 +2847,4 @@ void gpiolib_cdev_unregister(struct gpio_device *gdev)
{
destroy_workqueue(gdev->line_state_wq);
cdev_device_del(&gdev->chrdev, &gdev->dev);
- blocking_notifier_call_chain(&gdev->device_notifier, 0, NULL);
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index e923512febf1..5eb53f8c5d34 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -851,11 +851,22 @@ bool gpiochip_line_is_valid(const struct gpio_chip *gc,
}
EXPORT_SYMBOL_GPL(gpiochip_line_is_valid);
-static void gpiod_free_irqs(struct gpio_desc *desc)
+static void gpiod_free_irqs(struct gpio_chip *gc, struct gpio_desc *desc)
{
- int irq = gpiod_to_irq(desc);
- struct irq_desc *irqd = irq_to_desc(irq);
+ struct irq_desc *irqd;
void *cookie;
+ int irq;
+
+ /* Called with gdev->chip already NULL, so gpiod_to_irq() can't be used. */
+ if (!gc->to_irq)
+ return;
+ irq = gc->to_irq(gc, gpiod_hwgpio(desc));
+ if (irq <= 0)
+ return;
+
+ irqd = irq_to_desc(irq);
+ if (!irqd)
+ return;
for (;;) {
/*
@@ -887,7 +898,7 @@ static void gpiochip_free_remaining_irqs(struct gpio_chip *gc)
struct gpio_desc *desc;
for_each_gpio_desc_with_flag(gc, desc, GPIOD_FLAG_USED_AS_IRQ)
- gpiod_free_irqs(desc);
+ gpiod_free_irqs(gc, desc);
}
static void gpiodev_release(struct device *dev)
@@ -1422,7 +1433,6 @@ void gpiochip_remove(struct gpio_chip *gc)
/* FIXME: should the legacy sysfs handling be moved to gpio_device? */
gpiochip_sysfs_unregister(gc);
gpiochip_free_hogs(gc);
- gpiochip_free_remaining_irqs(gc);
scoped_guard(mutex, &gpio_devices_lock)
list_del_rcu(&gdev->list);
@@ -1431,6 +1441,14 @@ void gpiochip_remove(struct gpio_chip *gc)
/* Numb the device, cancelling all outstanding operations */
rcu_assign_pointer(gdev->chip, NULL);
synchronize_srcu(&gdev->srcu);
+
+ /*
+ * No new interrupts can be requested through the character device now.
+ * Have it free the ones it holds before forcibly freeing the rest, and
+ * both before the irqchip and its mappings go away.
+ */
+ blocking_notifier_call_chain(&gdev->device_notifier, 0, NULL);
+ gpiochip_free_remaining_irqs(gc);
gpio_device_teardown_shared(gdev);
gpiochip_irqchip_remove(gc);
acpi_gpiochip_remove(gc);
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v3 2/6] gpiolib: free the label of lines released after their chip was removed
2026-10-20 13:00 ` [PATCH v3 2/6] gpiolib: free the label of lines released after their chip was removed Adrian Ambrozewicz
@ 2026-10-20 13:19 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-10-20 13:19 UTC (permalink / raw)
To: Adrian Ambrozewicz; +Cc: linux-gpio
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] gpiolib: premature label clear in gpiod_free_commit() before gc->free()
--
commit edc5ef8f1a27a83fd784e08207b698b98a88ea6d
Author: Adrian Ambrozewicz <aambrozewicz@nvidia.com>
gpiolib: free the label of lines released after their chip was removed
This commit moves desc_set_label(desc, NULL) in gpiod_free_commit() ahead of
the guard.gc check so that consumer labels are still freed when a requested
line is released after gpiochip_remove() has cleared gdev->chip.
> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> index e5326c472a544..e923512febf15 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));
[Severity: High]
Can clearing desc->label before invoking guard.gc->free() and before clearing
GPIOD_FLAG_REQUESTED cause a concurrent for_each_hwgpio() or
for_each_requested_gpio() caller to pass ERR_PTR(-ENOMEM) to kfree()?
In drivers/gpio/gpiolib.c:gpiod_free_commit(), desc_set_label(desc, NULL) now
runs before guard.gc->free() and before GPIOD_FLAG_REQUESTED is cleared via
WRITE_ONCE(desc->flags, flags). Because guard.gc->free() can sleep or block on
driver locks (such as &chip->lock in gpio_sim_free(), &pctldev->mutex in
pinctrl_gpio_free(), or bus transfers in I2C/SPI/USB GPIO drivers), this leaves
a window where GPIOD_FLAG_REQUESTED is still set while desc->label is NULL.
For example, in drivers/gpio/gpio-sim.c:gpio_sim_dbg_show():
guard(mutex)(&chip->lock);
for_each_hwgpio(gc, i, label)
If gpiod_free_commit() clears desc->label and then blocks on &chip->lock in
gpio_sim_free() while gpio_sim_dbg_show() (or another caller such as
intel_restore_hostown() or lp_gpio_resume()) iterates the lines,
drivers/gpio/gpiolib.c:gpiochip_dup_line_label() will see GPIOD_FLAG_REQUESTED
still set:
if (!test_bit(GPIOD_FLAG_REQUESTED, &desc->flags))
return NULL;
guard(srcu)(&desc->gdev->desc_srcu);
label = kstrdup(gpiod_get_label(desc), GFP_KERNEL);
if (!label)
return ERR_PTR(-ENOMEM);
Since gpiod_get_label(desc) is already NULL, kstrdup(NULL, GFP_KERNEL) returns
NULL and gpiochip_dup_line_label() returns ERR_PTR(-ENOMEM).
Then in include/linux/gpio/driver.h:for_each_hwgpio_in_range():
#define for_each_hwgpio_in_range(_chip, _i, _base, _size, _label) \
for (CLASS(_gpiochip_for_each_data, _data)(&_label, &_i); \
_i < _size; \
_i++, kfree(_label), _label = NULL) \
for_each_if(!IS_ERR(_label = gpiochip_dup_line_label(_chip, _base + _i)))
for_each_if(!IS_ERR(_label = ...)) skips the loop body and the loop increment
calls kfree(ERR_PTR(-ENOMEM)). In addition, gpiolib_dbg_show() can observe
GPIOD_FLAG_REQUESTED with a NULL label and print (null) while guard.gc->free()
sleeps.
Should desc_set_label(desc, NULL) instead remain after guard.gc->free() (or run
after the if (guard.gc) block)?
> @@ -2685,7 +2690,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);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020-gpiolib-chip-removal-v3-0-aambrozewicz@nvidia.com?part=2
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 6/6] gpiolib: let the character device free its IRQs first on chip removal
2026-10-20 13:00 ` [PATCH v3 6/6] gpiolib: let the character device free its IRQs first on chip removal Adrian Ambrozewicz
@ 2026-10-20 13:23 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-10-20 13:23 UTC (permalink / raw)
To: Adrian Ambrozewicz; +Cc: linux-gpio
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] gpiolib: cdev: negative gpiod_get_value_cansleep() treated as rising edge
--
commit 526f1d7ea8a308d5657aec9728c6582d403f73c5
Author: Adrian Ambrozewicz <aambrozewicz@nvidia.com>
gpiolib: let the character device free its IRQs first on chip removal
This commit reorders GPIO chip removal so that the device notifier runs
after gdev->chip is cleared and before remaining IRQs and the irqchip are
freed, while synchronizing character device release paths with the
notifier.
Link: https://lore.kernel.org/all/20240227113426.253232-1-herve.codina@bootlin.com/
> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> index e923512febf15..5eb53f8c5d34c 100644
> --- a/drivers/gpio/gpiolib.c
> +++ b/drivers/gpio/gpiolib.c
[ ... ]
> @@ -1422,7 +1433,6 @@ void gpiochip_remove(struct gpio_chip *gc)
> /* FIXME: should the legacy sysfs handling be moved to gpio_device? */
> gpiochip_sysfs_unregister(gc);
> gpiochip_free_hogs(gc);
> - gpiochip_free_remaining_irqs(gc);
>
> scoped_guard(mutex, &gpio_devices_lock)
> list_del_rcu(&gdev->list);
> @@ -1431,6 +1441,14 @@ void gpiochip_remove(struct gpio_chip *gc)
> /* Numb the device, cancelling all outstanding operations */
> rcu_assign_pointer(gdev->chip, NULL);
> synchronize_srcu(&gdev->srcu);
> +
> + /*
> + * No new interrupts can be requested through the character device now.
> + * Have it free the ones it holds before forcibly freeing the rest, and
> + * both before the irqchip and its mappings go away.
> + */
> + blocking_notifier_call_chain(&gdev->device_notifier, 0, NULL);
> + gpiochip_free_remaining_irqs(gc);
> gpio_device_teardown_shared(gdev);
> gpiochip_irqchip_remove(gc);
> acpi_gpiochip_remove(gc);
[Severity: Medium]
With character device IRQs now freed in the notifier callback after
rcu_assign_pointer(gdev->chip, NULL), can an in-flight dual-edge interrupt
handler queue a spurious rising-edge event to userspace?
Previously, gpiochip_free_remaining_irqs() stopped and synchronized all
GPIOD_FLAG_USED_AS_IRQ handlers before gdev->chip was cleared. With this
change, if edge_irq_thread() or lineevent_irq_thread() runs between
rcu_assign_pointer(gdev->chip, NULL) and free_irq() in the notifier,
gpiod_get_value_cansleep() returns -ENODEV.
In drivers/gpio/gpiolib-cdev.c, edge_irq_thread() passes the return value
directly to line_event_id():
switch (READ_ONCE(line->edflags) & GPIO_V2_LINE_EDGE_FLAGS) {
case GPIO_V2_LINE_FLAG_EDGE_BOTH:
le.id = line_event_id(gpiod_get_value_cansleep(line->desc));
break;
where line_event_id() treats any non-zero value as
GPIO_V2_LINE_EVENT_RISING_EDGE. Similarly, lineevent_irq_thread() checks:
if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE
&& le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) {
int level = gpiod_get_value_cansleep(le->desc);
if (level)
/* Emit low-to-high event */
ge.id = GPIOEVENT_EVENT_RISING_EDGE;
Unlike debounce_work_func(), which drops the event when level < 0, both
threaded IRQ handlers treat -ENODEV as a logical high level and push a
rising-edge event into the kfifo.
Should edge_irq_thread() and lineevent_irq_thread() also check for a
negative return from gpiod_get_value_cansleep() and drop the event?
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020-gpiolib-chip-removal-v3-0-aambrozewicz@nvidia.com?part=6
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-10-20 13:23 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-20 13:00 [PATCH v3 0/6] gpiolib: fix chip removal with lines still requested from user space Adrian Ambrozewicz
2026-10-20 13:00 ` [PATCH v3 1/6] gpiolib: wait for pending label frees before cleaning up desc_srcu Adrian Ambrozewicz
2026-10-20 13:00 ` [PATCH v3 2/6] gpiolib: free the label of lines released after their chip was removed Adrian Ambrozewicz
2026-10-20 13:19 ` sashiko-bot
2026-10-20 13:00 ` [PATCH v3 3/6] gpiolib: cdev: do not free line IRQs again after the chip is removed Adrian Ambrozewicz
2026-10-20 13:00 ` [PATCH v3 4/6] gpiolib: cdev: don't sleep in the SRCU read section in read() Adrian Ambrozewicz
2026-10-20 13:00 ` [PATCH v3 5/6] gpiolib: cdev: don't leak the IRQ name when the chip is removed Adrian Ambrozewicz
2026-10-20 13:00 ` [PATCH v3 6/6] gpiolib: let the character device free its IRQs first on chip removal Adrian Ambrozewicz
2026-10-20 13:23 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox