All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] pps: clients: gpio: fix interrupt handling order in remove path
@ 2025-05-27  5:33 Eliav Farber
  2025-05-27  8:00 ` Rodolfo Giometti
  0 siblings, 1 reply; 5+ messages in thread
From: Eliav Farber @ 2025-05-27  5:33 UTC (permalink / raw)
  To: giometti, gregkh, mschmidt, calvin, u.kleine-koenig, tglx,
	farbere, linux-kernel
  Cc: jonnyc

The interrupt handler in pps_gpio_probe() is registered after calling
pps_register_source() using devm_request_irq(). However, in the
corresponding remove function, pps_unregister_source() is called before
the IRQ is freed, since devm-managed resources are released after the
remove function completes.

This creates a potential race condition where an interrupt may occur
after the PPS source is unregistered but before the handler is removed,
possibly leading to a kernel panic.

To prevent this, switch from devm-managed IRQ registration to manual
management by using request_irq() and calling free_irq() explicitly in
the remove path before unregistering the PPS source. This ensures the
interrupt handler is safely removed before deactivating the PPS source.

Signed-off-by: Eliav Farber <farbere@amazon.com>
---
 drivers/pps/clients/pps-gpio.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c
index 374ceefd6f2a..2866636b0554 100644
--- a/drivers/pps/clients/pps-gpio.c
+++ b/drivers/pps/clients/pps-gpio.c
@@ -210,8 +210,8 @@ static int pps_gpio_probe(struct platform_device *pdev)
 	}
 
 	/* register IRQ interrupt handler */
-	ret = devm_request_irq(dev, data->irq, pps_gpio_irq_handler,
-			get_irqf_trigger_flags(data), data->info.name, data);
+	ret = request_irq(data->irq, pps_gpio_irq_handler,
+			  get_irqf_trigger_flags(data), data->info.name, data);
 	if (ret) {
 		pps_unregister_source(data->pps);
 		dev_err(dev, "failed to acquire IRQ %d\n", data->irq);
@@ -228,6 +228,7 @@ static void pps_gpio_remove(struct platform_device *pdev)
 {
 	struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
 
+	free_irq(data->irq, data);
 	pps_unregister_source(data->pps);
 	timer_delete_sync(&data->echo_timer);
 	/* reset echo pin in any case */
-- 
2.47.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH] pps: clients: gpio: fix interrupt handling order in remove path
  2025-05-27  5:33 Eliav Farber
@ 2025-05-27  8:00 ` Rodolfo Giometti
  0 siblings, 0 replies; 5+ messages in thread
From: Rodolfo Giometti @ 2025-05-27  8:00 UTC (permalink / raw)
  To: Eliav Farber
  Cc: jonnyc, gregkh, mschmidt, calvin, u.kleine-koenig, tglx,
	linux-kernel

On 27/05/25 07:33, Eliav Farber wrote:
> The interrupt handler in pps_gpio_probe() is registered after calling
> pps_register_source() using devm_request_irq(). However, in the
> corresponding remove function, pps_unregister_source() is called before
> the IRQ is freed, since devm-managed resources are released after the
> remove function completes.
> 
> This creates a potential race condition where an interrupt may occur
> after the PPS source is unregistered but before the handler is removed,
> possibly leading to a kernel panic.
> 
> To prevent this, switch from devm-managed IRQ registration to manual
> management by using request_irq() and calling free_irq() explicitly in
> the remove path before unregistering the PPS source. This ensures the
> interrupt handler is safely removed before deactivating the PPS source.
> 
> Signed-off-by: Eliav Farber <farbere@amazon.com>
> ---
>   drivers/pps/clients/pps-gpio.c | 5 +++--
>   1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c
> index 374ceefd6f2a..2866636b0554 100644
> --- a/drivers/pps/clients/pps-gpio.c
> +++ b/drivers/pps/clients/pps-gpio.c
> @@ -210,8 +210,8 @@ static int pps_gpio_probe(struct platform_device *pdev)
>   	}
>   
>   	/* register IRQ interrupt handler */
> -	ret = devm_request_irq(dev, data->irq, pps_gpio_irq_handler,
> -			get_irqf_trigger_flags(data), data->info.name, data);
> +	ret = request_irq(data->irq, pps_gpio_irq_handler,
> +			  get_irqf_trigger_flags(data), data->info.name, data);
>   	if (ret) {
>   		pps_unregister_source(data->pps);
>   		dev_err(dev, "failed to acquire IRQ %d\n", data->irq);
> @@ -228,6 +228,7 @@ static void pps_gpio_remove(struct platform_device *pdev)
>   {
>   	struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
>   
> +	free_irq(data->irq, data);

Why not just use devm_free_irq()?

>   	pps_unregister_source(data->pps);
>   	timer_delete_sync(&data->echo_timer);
>   	/* reset echo pin in any case */

Ciao,

Rodolfo

-- 
GNU/Linux Solutions                  e-mail: giometti@enneenne.com
Linux Device Driver                          giometti@linux.it
Embedded Systems                     phone:  +39 349 2432127
UNIX programming


^ permalink raw reply	[flat|nested] 5+ messages in thread

* RE: [PATCH] pps: clients: gpio: fix interrupt handling order in remove path
@ 2025-05-27  9:11 Farber, Eliav
  2025-05-27 10:19 ` Rodolfo Giometti
  0 siblings, 1 reply; 5+ messages in thread
From: Farber, Eliav @ 2025-05-27  9:11 UTC (permalink / raw)
  To: Rodolfo Giometti
  Cc: Chocron, Jonathan, gregkh@linuxfoundation.org,
	mschmidt@redhat.com, calvin@wbinvd.org, tglx@linutronix.de,
	linux-kernel@vger.kernel.org

>> @@ -228,6 +228,7 @@ static void pps_gpio_remove(struct platform_device *pdev)
>>   {
>>       struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
>>
>> +     free_irq(data->irq, data);
>
> Why not just use devm_free_irq()?

As far as I understand, the main purpose of devm_*() is to provide
hands-off resource management. devm_request_irq() is intended to
eliminate the need for explicit cleanup in the remove() function by
automatically freeing the IRQ after remove() returns.

In my opinion, calling devm_free_irq() undermines the benefit of using
devm_request_irq() in the first place. If I need to explicitly free the
IRQ during remove(), then I’m no longer relying on devm’s automatic
cleanup - I’m effectively reverting to manual resource management while
still using devm-style registration, which I find unnecessary.

That said, if you still favor devm_free_irq(), I’ll revise the patch
accordingly.

Regards, Eliav



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] pps: clients: gpio: fix interrupt handling order in remove path
  2025-05-27  9:11 [PATCH] pps: clients: gpio: fix interrupt handling order in remove path Farber, Eliav
@ 2025-05-27 10:19 ` Rodolfo Giometti
  2025-05-27 10:24   ` gregkh
  0 siblings, 1 reply; 5+ messages in thread
From: Rodolfo Giometti @ 2025-05-27 10:19 UTC (permalink / raw)
  To: Farber, Eliav
  Cc: Chocron, Jonathan, gregkh@linuxfoundation.org,
	mschmidt@redhat.com, calvin@wbinvd.org, tglx@linutronix.de,
	linux-kernel@vger.kernel.org

On 27/05/25 11:11, Farber, Eliav wrote:
>>> @@ -228,6 +228,7 @@ static void pps_gpio_remove(struct platform_device *pdev)
>>>    {
>>>        struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
>>>
>>> +     free_irq(data->irq, data);
>>
>> Why not just use devm_free_irq()?
> 
> As far as I understand, the main purpose of devm_*() is to provide
> hands-off resource management. devm_request_irq() is intended to
> eliminate the need for explicit cleanup in the remove() function by
> automatically freeing the IRQ after remove() returns.

In linux/kernel/irq/devres.c we can read:

/**
  *      devm_free_irq - free an interrupt
  *      @dev: device to free interrupt for
  *      @irq: Interrupt line to free
  *      @dev_id: Device identity to free
  *
  *      Except for the extra @dev argument, this function takes the
  *      same arguments and performs the same function as free_irq().
  *      This function instead of free_irq() should be used to manually
  *      free IRQs allocated with devm_request_irq().
  */

> In my opinion, calling devm_free_irq() undermines the benefit of using
> devm_request_irq() in the first place. If I need to explicitly free the
> IRQ during remove(), then I’m no longer relying on devm’s automatic
> cleanup - I’m effectively reverting to manual resource management while
> still using devm-style registration, which I find unnecessary.
> 
> That said, if you still favor devm_free_irq(), I’ll revise the patch
> accordingly.

Since devm_free_irq() works exactly as free_irq() and can be used to manually 
free IRQs allocated with devm_request_irq(), I think it is less invasive. Isn't 
it? :-)

Ciao,

Rodolfo

-- 
GNU/Linux Solutions                  e-mail: giometti@enneenne.com
Linux Device Driver                          giometti@linux.it
Embedded Systems                     phone:  +39 349 2432127
UNIX programming


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] pps: clients: gpio: fix interrupt handling order in remove path
  2025-05-27 10:19 ` Rodolfo Giometti
@ 2025-05-27 10:24   ` gregkh
  0 siblings, 0 replies; 5+ messages in thread
From: gregkh @ 2025-05-27 10:24 UTC (permalink / raw)
  To: Rodolfo Giometti
  Cc: Farber, Eliav, Chocron, Jonathan, mschmidt@redhat.com,
	calvin@wbinvd.org, tglx@linutronix.de,
	linux-kernel@vger.kernel.org

On Tue, May 27, 2025 at 12:19:16PM +0200, Rodolfo Giometti wrote:
> On 27/05/25 11:11, Farber, Eliav wrote:
> > > > @@ -228,6 +228,7 @@ static void pps_gpio_remove(struct platform_device *pdev)
> > > >    {
> > > >        struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
> > > > 
> > > > +     free_irq(data->irq, data);
> > > 
> > > Why not just use devm_free_irq()?
> > 
> > As far as I understand, the main purpose of devm_*() is to provide
> > hands-off resource management. devm_request_irq() is intended to
> > eliminate the need for explicit cleanup in the remove() function by
> > automatically freeing the IRQ after remove() returns.
> 
> In linux/kernel/irq/devres.c we can read:
> 
> /**
>  *      devm_free_irq - free an interrupt
>  *      @dev: device to free interrupt for
>  *      @irq: Interrupt line to free
>  *      @dev_id: Device identity to free
>  *
>  *      Except for the extra @dev argument, this function takes the
>  *      same arguments and performs the same function as free_irq().
>  *      This function instead of free_irq() should be used to manually
>  *      free IRQs allocated with devm_request_irq().
>  */
> 
> > In my opinion, calling devm_free_irq() undermines the benefit of using
> > devm_request_irq() in the first place. If I need to explicitly free the
> > IRQ during remove(), then I’m no longer relying on devm’s automatic
> > cleanup - I’m effectively reverting to manual resource management while
> > still using devm-style registration, which I find unnecessary.
> > 
> > That said, if you still favor devm_free_irq(), I’ll revise the patch
> > accordingly.
> 
> Since devm_free_irq() works exactly as free_irq() and can be used to
> manually free IRQs allocated with devm_request_irq(), I think it is less
> invasive. Isn't it? :-)

Not always, no.  irq handling is tricky, and devm for irqs is a huge
source of bugs as how do you really know when your irq is going to be
removed from the system?   If you don't want to use devm calls, don't,
there's no requirement to do so.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2025-05-27 10:24 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-27  9:11 [PATCH] pps: clients: gpio: fix interrupt handling order in remove path Farber, Eliav
2025-05-27 10:19 ` Rodolfo Giometti
2025-05-27 10:24   ` gregkh
  -- strict thread matches above, loose matches on Subject: below --
2025-05-27  5:33 Eliav Farber
2025-05-27  8:00 ` Rodolfo Giometti

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.