Skip to content

Commit 3946e07

Browse files
Bartosz Golaszewskigregkh
authored andcommitted
gpio: free irqs that are still requested when the chip is being removed
[ Upstream commit ec8b6f5 ] If we remove a GPIO chip that is also an interrupt controller with users not having freed some interrupts, we'll end up leaking resources as indicated by the following warning: remove_proc_entry: removing non-empty directory 'irq/30', leaking at least 'gpio' As there's no way of notifying interrupt users about the irqchip going away and the interrupt subsystem is not plugged into the driver model and so not all cases can be handled by devlinks, we need to make sure to free all interrupts before the complete the removal of the provider. Reviewed-by: Herve Codina <[email protected]> Tested-by: Herve Codina <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Bartosz Golaszewski <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent e26cbab commit 3946e07

File tree

1 file changed

+41
-0
lines changed

1 file changed

+41
-0
lines changed

drivers/gpio/gpiolib.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/idr.h>
1515
#include <linux/interrupt.h>
1616
#include <linux/irq.h>
17+
#include <linux/irqdesc.h>
1718
#include <linux/kernel.h>
1819
#include <linux/list.h>
1920
#include <linux/lockdep.h>
@@ -713,6 +714,45 @@ bool gpiochip_line_is_valid(const struct gpio_chip *gc,
713714
}
714715
EXPORT_SYMBOL_GPL(gpiochip_line_is_valid);
715716

717+
static void gpiod_free_irqs(struct gpio_desc *desc)
718+
{
719+
int irq = gpiod_to_irq(desc);
720+
struct irq_desc *irqd = irq_to_desc(irq);
721+
void *cookie;
722+
723+
for (;;) {
724+
/*
725+
* Make sure the action doesn't go away while we're
726+
* dereferencing it. Retrieve and store the cookie value.
727+
* If the irq is freed after we release the lock, that's
728+
* alright - the underlying maple tree lookup will return NULL
729+
* and nothing will happen in free_irq().
730+
*/
731+
scoped_guard(mutex, &irqd->request_mutex) {
732+
if (!irq_desc_has_action(irqd))
733+
return;
734+
735+
cookie = irqd->action->dev_id;
736+
}
737+
738+
free_irq(irq, cookie);
739+
}
740+
}
741+
742+
/*
743+
* The chip is going away but there may be users who had requested interrupts
744+
* on its GPIO lines who have no idea about its removal and have no way of
745+
* being notified about it. We need to free any interrupts still in use here or
746+
* we'll leak memory and resources (like procfs files).
747+
*/
748+
static void gpiochip_free_remaining_irqs(struct gpio_chip *gc)
749+
{
750+
struct gpio_desc *desc;
751+
752+
for_each_gpio_desc_with_flag(gc, desc, FLAG_USED_AS_IRQ)
753+
gpiod_free_irqs(desc);
754+
}
755+
716756
static void gpiodev_release(struct device *dev)
717757
{
718758
struct gpio_device *gdev = to_gpio_device(dev);
@@ -1125,6 +1165,7 @@ void gpiochip_remove(struct gpio_chip *gc)
11251165
/* FIXME: should the legacy sysfs handling be moved to gpio_device? */
11261166
gpiochip_sysfs_unregister(gdev);
11271167
gpiochip_free_hogs(gc);
1168+
gpiochip_free_remaining_irqs(gc);
11281169

11291170
scoped_guard(mutex, &gpio_devices_lock)
11301171
list_del_rcu(&gdev->list);

0 commit comments

Comments
 (0)