[PATCH] genirq/devres: Simplify API devm_free_irq() implementation

Zijun Hu posted 1 patch 1 month, 1 week ago
There is a newer version of this series
kernel/irq/devres.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
[PATCH] genirq/devres: Simplify API devm_free_irq() implementation
Posted by Zijun Hu 1 month, 1 week ago
From: Zijun Hu <quic_zijuhu@quicinc.com>

Simplify devm_free_irq() implementation by dedicated API devres_release()
which have below advantages than current devres_destroy() + free_irq().

It is simpler if devm_free_irq() is undoing what any devm_request_irq()
variant did, otherwise, it can avoid wrong and undesired free_irq().

Signed-off-by: Zijun Hu <quic_zijuhu@quicinc.com>
---
linux-next tree has similar fixes as shown below:
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?id=0ee4dcafda9576910559f0471a3d6891daf9ab92
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?id=9bd133f05b1dca5ca4399a76d04d0f6f4d454e44
---
 kernel/irq/devres.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/kernel/irq/devres.c b/kernel/irq/devres.c
index b3e98668f4dd..eb16a58e0322 100644
--- a/kernel/irq/devres.c
+++ b/kernel/irq/devres.c
@@ -141,9 +141,8 @@ void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id)
 {
 	struct irq_devres match_data = { irq, dev_id };
 
-	WARN_ON(devres_destroy(dev, devm_irq_release, devm_irq_match,
+	WARN_ON(devres_release(dev, devm_irq_release, devm_irq_match,
 			       &match_data));
-	free_irq(irq, dev_id);
 }
 EXPORT_SYMBOL(devm_free_irq);
 

---
base-commit: 9bd133f05b1dca5ca4399a76d04d0f6f4d454e44
change-id: 20241017-devres_kernel_fix-4b29be51bded

Best regards,
-- 
Zijun Hu <quic_zijuhu@quicinc.com>
Re: [PATCH] genirq/devres: Simplify API devm_free_irq() implementation
Posted by Thomas Gleixner 1 month, 1 week ago
On Thu, Oct 17 2024 at 23:16, Zijun Hu wrote:
> From: Zijun Hu <quic_zijuhu@quicinc.com>
>
> Simplify devm_free_irq() implementation by dedicated API devres_release()
> which have below advantages than current devres_destroy() + free_irq().
>
> It is simpler if devm_free_irq() is undoing what any devm_request_irq()
> variant did, otherwise, it can avoid wrong and undesired free_irq().

This is confusing at best. What's the wrong an undesired free_irq()?

Thanks,

        tglx
Re: [PATCH] genirq/devres: Simplify API devm_free_irq() implementation
Posted by Zijun Hu 1 month, 1 week ago
On 2024/10/18 04:33, Thomas Gleixner wrote:
> On Thu, Oct 17 2024 at 23:16, Zijun Hu wrote:
>> From: Zijun Hu <quic_zijuhu@quicinc.com>
>>
>> Simplify devm_free_irq() implementation by dedicated API devres_release()
>> which have below advantages than current devres_destroy() + free_irq().
>>
>> It is simpler if devm_free_irq() is undoing what any devm_request_irq()
>> variant did, otherwise, it can avoid wrong and undesired free_irq().
> 
> This is confusing at best. What's the wrong an undesired free_irq()?
> 

thanks for code review.

for current devm_free_irq(..., irq_A, ...):
it is undesired if irq_A is requested by request_irq().
it is wrong and dangerous if irq_A was never requested.

sorry to have confused commit message.
any suggestion to correct it ? (^^)

> Thanks,
> 
>         tglx
Re: [PATCH] genirq/devres: Simplify API devm_free_irq() implementation
Posted by Thomas Gleixner 1 month, 1 week ago
On Fri, Oct 18 2024 at 06:36, Zijun Hu wrote:
> On 2024/10/18 04:33, Thomas Gleixner wrote:
>>> It is simpler if devm_free_irq() is undoing what any devm_request_irq()
>>> variant did, otherwise, it can avoid wrong and undesired free_irq().
>> 
>> This is confusing at best. What's the wrong an undesired free_irq()?
>> 
> for current devm_free_irq(..., irq_A, ...):
> it is undesired if irq_A is requested by request_irq().
> it is wrong and dangerous if irq_A was never requested.

There is nothing dangerous about it if it was never requested.
free_irq() won't find a irq action which matches devid and do nothing
than emitting a warning.

But that's not relevant either because there is no matching devres entry
when the interrupt was not requested via devres_request_irq(), so
free_irq() will not be reached because devres_destroy() will return
-ENOENT.

So all this change does is changing the logic from:

devres_free_irq()
    if (devres_destroy())
        return;
    free_irq();
    
to
    devres_release()

where devres_release() does the same thing as the above, i.e. it looks
up the devres for a match and if found, it removes and frees the devres
pointer and invokes the release function which in turn invokes
free_irq().

So in terms of code logic this is exactly the same and does neither
avoid or prevent anything.

All it does is sparing a single line of code.

Thanks,

        tglx
Re: [PATCH] genirq/devres: Simplify API devm_free_irq() implementation
Posted by quic_zijuhu 1 month, 1 week ago
On 10/18/2024 4:57 PM, Thomas Gleixner wrote:
> On Fri, Oct 18 2024 at 06:36, Zijun Hu wrote:
>> On 2024/10/18 04:33, Thomas Gleixner wrote:
>>>> It is simpler if devm_free_irq() is undoing what any devm_request_irq()
>>>> variant did, otherwise, it can avoid wrong and undesired free_irq().
>>>
>>> This is confusing at best. What's the wrong an undesired free_irq()?
>>>
>> for current devm_free_irq(..., irq_A, ...):
>> it is undesired if irq_A is requested by request_irq().
>> it is wrong and dangerous if irq_A was never requested.
> 
> There is nothing dangerous about it if it was never requested.
> free_irq() won't find a irq action which matches devid and do nothing
> than emitting a warning.
> 

you are right. it is not dangerous but a unnecessary call of free_irq().

> But that's not relevant either because there is no matching devres entry
> when the interrupt was not requested via devres_request_irq(), so
> free_irq() will not be reached because devres_destroy() will return
> -ENOENT.
> 
no, WARN_ON(devres_destroy()) doesn't return, the next free_irq() will
be still reached.

> So all this change does is changing the logic from:
> 
> devres_free_irq()
>     if (devres_destroy())
>         return;
>     free_irq();
>     
> to
>     devres_release()
> 

if irq to free was ever requested by devm_request_irq()
then both logic is exactly same.

otherwise, actually change devres_free_irq()'s logic from

if (irq is not requested by devm_request_irq() {
	warn;
}
free_irq()

To

if (irq is not requested by devm_request_irq() {
	warn;
	return;
}


> where devres_release() does the same thing as the above, i.e. it looks
> up the devres for a match and if found, it removes and frees the devres
> pointer and invokes the release function which in turn invokes
> free_irq().
> 
> So in terms of code logic this is exactly the same and does neither
> avoid or prevent anything.
> 
> All it does is sparing a single line of code.
> 
> Thanks,
> 
>         tglx
> 
> 
> 
>
Re: [PATCH] genirq/devres: Simplify API devm_free_irq() implementation
Posted by Thomas Gleixner 1 month, 1 week ago
On Fri, Oct 18 2024 at 17:28, quic zijuhu wrote:
> On 10/18/2024 4:57 PM, Thomas Gleixner wrote:
> if irq to free was ever requested by devm_request_irq()
> then both logic is exactly same.
>
> otherwise, actually change devres_free_irq()'s logic from
>
> if (irq is not requested by devm_request_irq() {
> 	warn;
> }
> free_irq()
>
> To
>
> if (irq is not requested by devm_request_irq() {
> 	warn;
> 	return;
> }
>

Ah, you are right. I thought there is a return there.

So you want to explain it maybe this way:

   If devres_destroy() does not find a matching devres entry, then
   devm_free_irq() emits a warning and tries to free the interrupt.

   That's wrong as devm_free_irq() should only undo what
   devm_request_irq() set up.

   Replace devres_destroy() with a call to devres_release() which only
   invokes the release function (free_irq()) in case that a matching
   devres entry was found.

Or something like that.

Thanks,

        tglx
Re: [PATCH] genirq/devres: Simplify API devm_free_irq() implementation
Posted by Zijun Hu 1 month, 1 week ago
On 2024/10/18 18:58, Thomas Gleixner wrote:
> On Fri, Oct 18 2024 at 17:28, quic zijuhu wrote:
>> On 10/18/2024 4:57 PM, Thomas Gleixner wrote:
>> if irq to free was ever requested by devm_request_irq()
>> then both logic is exactly same.

[snip]

>> if (irq is not requested by devm_request_irq() {
>> 	warn;
>> 	return;
>> }
>>
> 
> Ah, you are right. I thought there is a return there.
> 
> So you want to explain it maybe this way:
> 
>    If devres_destroy() does not find a matching devres entry, then
>    devm_free_irq() emits a warning and tries to free the interrupt.
> 
>    That's wrong as devm_free_irq() should only undo what
>    devm_request_irq() set up.
> 
>    Replace devres_destroy() with a call to devres_release() which only
>    invokes the release function (free_irq()) in case that a matching
>    devres entry was found.
> 

thank you. good proposal, let me update commit base on it and send v2.

> Or something like that.
> 
> Thanks,
> 
>         tglx