bugfix GFP_KERNEL -> GFP_ATOMIC in spin_locked region
Subsystems (7)
PATCH 1/1 bugfix GFP_KERNEL -> GFP_ATOMIC in spin_locked region
In a few files a function such as usb_submit_urb is taking GFP_KERNEL as an argument whereas this function call is inside a spin_lock_irqsave region of code. Documentation says that it must be GFP_ATOMIC instead.
Me and my colleagues have made a tool targeting program transformations in device drivers. We have designed a scripting language for specifying easily program transformations and a transformation engine for performing them. In the spirit of Linux development practice, the language is based on the patch syntax. We call our scripts "semantic patches" because as opposed to traditional patches, our semantic patches do not work at the line level but on a high level representation of the C program.
FYI here is our semantic patch detecting invalid use of GFP_KERNEL and fixing the problem:
@@
identifier fn;
@@
spin_lock_irqsave(...)
... when != spin_unlock_irqrestore(...)
fn(...,
- GFP_KERNEL
+ GFP_ATOMIC
,...
)
And now the real patch resulting from the automated transformation:
net/wan/lmc/lmc_main.c | 2 +- scsi/megaraid/megaraid_mm.c | 2 +- usb/serial/io_ti.c | 2 +- usb/serial/ti_usb_3410_5052.c | 2 +- usb/serial/whiteheat.c | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-)
drivers/net/wan/lmc/lmc_main.c +1 -1
@@ -483,7 +483,7 @@ #endif /* end ifdef _DBG_EVENTLOG */break ; } - data =kmalloc (xc.len,GFP_KERNEL ); + data =kmalloc (xc.len,GFP_ATOMIC );if (data =0x0 ){printk (KERN_WARNING "%s: Failed to allocate memory for copy\n" , dev->name); ret = -ENOMEM ;
drivers/scsi/megaraid/megaraid_mm.c +1 -1
@@ -547,7 +547,7 @@ mraid_mm_attach_buf(mraid_mmadp_t *adp, kioc->pool_index = right_pool; kioc->free_buf =1 ; - kioc->buf_vaddr =pci_pool_alloc (pool->handle,GFP_KERNEL , + kioc->buf_vaddr =pci_pool_alloc (pool->handle,GFP_ATOMIC , &kioc->buf_paddr);spin_unlock_irqrestore (&pool->lock, flags);
drivers/usb/serial/io_ti.c +1 -1
@@ -2351,7 +2351,7 @@ static int restart_read(struct edgeport_ urb->complete = edge_bulk_in_callback; urb->context = edge_port; urb->dev = edge_port->port->serial->dev; - status =usb_submit_urb (urb,GFP_KERNEL ); + status =usb_submit_urb (urb,GFP_ATOMIC ); } edge_port->ep_read_urb_state =EDGE_READ_URB_RUNNING ; edge_port->shadow_mcr |=MCR_RTS ;
drivers/usb/serial/ti_usb_3410_5052.c +1 -1
@@ -1559,7 +1559,7 @@ static int ti_restart_read(struct ti_por urb->complete = ti_bulk_in_callback; urb->context = tport; urb->dev = tport->tp_port->serial->dev; - status =usb_submit_urb (urb,GFP_KERNEL ); + status =usb_submit_urb (urb,GFP_ATOMIC ); } tport->tp_read_urb_state =TI_READ_URB_RUNNING ;
drivers/usb/serial/whiteheat.c +3 -3
@@ -1116,7 +1116,7 @@ static int firm_send_command (struct usbmemcpy (&transfer_buffer[1 ], data, datasize); command_port->write_urb->transfer_buffer_length = datasize +1 ; command_port->write_urb->dev = port->serial->dev; - retval =usb_submit_urb (command_port->write_urb,GFP_KERNEL ); + retval =usb_submit_urb (command_port->write_urb,GFP_ATOMIC );if (retval) {dbg ("%s - submit urb failed" , __FUNCTION__); goto exit;
@@ -1316,7 +1316,7 @@ static int start_command_port(struct usbusb_clear_halt (serial->dev, command_port->read_urb->pipe); command_port->read_urb->dev = serial->dev; - retval =usb_submit_urb (command_port->read_urb,GFP_KERNEL ); + retval =usb_submit_urb (command_port->read_urb,GFP_ATOMIC );if (retval) {err ("%s - failed submitting read urb, error %d" , __FUNCTION__, retval); goto exit;
@@ -1363,7 +1363,7 @@ static int start_port_read(struct usb_se wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); urb = wrap->urb; urb->dev = port->serial->dev; - retval =usb_submit_urb (urb,GFP_KERNEL ); + retval =usb_submit_urb (urb,GFP_ATOMIC );if (retval) {list_add (tmp, &info->rx_urbs_free);list_for_each_safe (tmp, tmp2, &info->rx_urbs_submitted) {
_______________________________________________
Kernel-janitors mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/kernel-janitors
Quoted 22 lines · On Mon, 04 Jun 2007 18:25:28 +0200 Yoann Padioleau <[email protected]> wrote:
In a few files a function such as
usb_submit_urbis takingGFP_KERNELas an argument whereas this function call is inside aspin_lock_irqsaveregion of code. Documentation says that it must beGFP_ATOMICinstead.Me and my colleagues have made a tool targeting program transformations in device drivers. We have designed a scripting language for specifying easily program transformations and a transformation engine for performing them. In the spirit of Linux development practice, the language is based on the patch syntax. We call our scripts "semantic patches" because as opposed to traditional patches, our semantic patches do not work at the line level but on a high level representation of the C program.
FYI here is our semantic patch detecting invalid use of
GFP_KERNELand fixing the problem:@@
identifier fn;
@@
Quoted 7 lines
spin_lock_irqsave(...)
... when !=spin_unlock_irqrestore(...)
fn(...,
-GFP_KERNEL
+GFP_ATOMIC
,...
)
I think I read that paper.
Quoted 8 lines
And now the real patch resulting from the automated transformation:
net/wan/lmc/lmc_main.c | 2 +- scsi/megaraid/megaraid_mm.c | 2 +- usb/serial/io_ti.c | 2 +- usb/serial/ti_usb_3410_5052.c | 2 +- usb/serial/whiteheat.c | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-)
This patch covers three areas of maintainer responsibility, so poor old me has to split it up and redo the changelogs. Oh well.
Quoted 6 lines
drivers/net/wan/lmc/lmc_main.c +0
-0
drivers/net/wan/lmc/lmc_main.c #endif /* end ifdef _DBG_EVENTLOG */ · line 489
Quoted 8 lines
drivers/net/wan/lmc/lmc_main.c +1
-1@@ -483,7 +483,7 @@ #endif /* end ifdef _DBG_EVENTLOG */break ; } - data =kmalloc (xc.len,GFP_KERNEL ); + data =kmalloc (xc.len,GFP_ATOMIC );if (data =0x0 ){printk (KERN_WARNING "%s: Failed to allocate memory for copy\n" , dev->name); ret = -ENOMEM ;
A few lines later we do:
if(copy_from_user(data, xc.data, xc.len))
which also is illegal under spinlock.
Frankly, I think that a better use of this tool would be to just report on the errors, let humans fix them up.
Nobody maintains this ATM code afaik.
drivers/scsi/megaraid/megaraid_mm.c mraid_mm_attach_buf(mraid_mmadp_t *adp, · line 552
Quoted 11 lines
index e075a52..edee220 100644
drivers/scsi/megaraid/megaraid_mm.c +1
-1@@ -547,7 +547,7 @@ mraid_mm_attach_buf(mraid_mmadp_t *adp, kioc->pool_index = right_pool; kioc->free_buf =1 ; - kioc->buf_vaddr =pci_pool_alloc (pool->handle,GFP_KERNEL , + kioc->buf_vaddr =pci_pool_alloc (pool->handle,GFP_ATOMIC , &kioc->buf_paddr);spin_unlock_irqrestore (&pool->lock, flags);
Again, a better fix would probably be to move the pci_pool_alloc() to before the spin_lock_irqsave(), so we can continue to use the stronger GFP_KERNEL.
But the locking in there looks basically nonsensical or wrong anyway. It appears that local variable `right_pool' cannot be validly used unless we're holding pool->lock for the whole duration.
Somebody does maintain the megaraid driver, but I'm not sure who, and the MAINTAINERS file isn't very useful. So I'll spray it around a bit. We definitely have bugs in there.
Quoted 49 lines
drivers/usb/serial/io_ti.c +1
-1@@ -2351,7 +2351,7 @@ static int restart_read(struct edgeport_ urb->complete = edge_bulk_in_callback; urb->context = edge_port; urb->dev = edge_port->port->serial->dev; - status =usb_submit_urb (urb,GFP_KERNEL ); + status =usb_submit_urb (urb,GFP_ATOMIC ); } edge_port->ep_read_urb_state =EDGE_READ_URB_RUNNING ; edge_port->shadow_mcr |=MCR_RTS ;drivers/usb/serial/ti_usb_3410_5052.c +1
-1@@ -1559,7 +1559,7 @@ static int ti_restart_read(struct ti_por urb->complete = ti_bulk_in_callback; urb->context = tport; urb->dev = tport->tp_port->serial->dev; - status =usb_submit_urb (urb,GFP_KERNEL ); + status =usb_submit_urb (urb,GFP_ATOMIC ); } tport->tp_read_urb_state =TI_READ_URB_RUNNING ;drivers/usb/serial/whiteheat.c +2
-2@@ -1116,7 +1116,7 @@ static int firm_send_command (struct usbmemcpy (&transfer_buffer[1 ], data, datasize); command_port->write_urb->transfer_buffer_length = datasize +1 ; command_port->write_urb->dev = port->serial->dev; - retval =usb_submit_urb (command_port->write_urb,GFP_KERNEL ); + retval =usb_submit_urb (command_port->write_urb,GFP_ATOMIC );if (retval) {dbg ("%s - submit urb failed" , __FUNCTION__); goto exit;@@ -1316,7 +1316,7 @@ static int start_command_port(struct usbusb_clear_halt (serial->dev, command_port->read_urb->pipe); command_port->read_urb->dev = serial->dev; - retval =usb_submit_urb (command_port->read_urb,GFP_KERNEL ); + retval =usb_submit_urb (command_port->read_urb,GFP_ATOMIC );if (retval) {err ("%s - failed submitting read urb, error %d" , __FUNCTION__, retval); goto exit;
drivers/usb/serial/whiteheat.c static int start_port_read(struct usb_se · line 1369
Quoted 8 lines
drivers/usb/serial/whiteheat.c +1
-1@@ -1363,7 +1363,7 @@ static int start_port_read(struct usb_se wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); urb = wrap->urb; urb->dev = port->serial->dev; - retval =usb_submit_urb (urb,GFP_KERNEL ); + retval =usb_submit_urb (urb,GFP_ATOMIC );if (retval) {list_add (tmp, &info->rx_urbs_free);list_for_each_safe (tmp, tmp2, &info->rx_urbs_submitted) {
This part might make sense so I'll queue it for the USB guys to look at.
_______________________________________________
Kernel-janitors mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/kernel-janitors
Quoted 51 lines · On Mon, 4 Jun 2007 21:00:18 -0700 Andrew Morton <[email protected]>…
Quoted 51 lines
drivers/usb/serial/io_ti.c +1
-1@@ -2351,7 +2351,7 @@ static int restart_read(struct edgeport_ urb->complete = edge_bulk_in_callback; urb->context = edge_port; urb->dev = edge_port->port->serial->dev; - status =usb_submit_urb (urb,GFP_KERNEL ); + status =usb_submit_urb (urb,GFP_ATOMIC ); } edge_port->ep_read_urb_state =EDGE_READ_URB_RUNNING ; edge_port->shadow_mcr |=MCR_RTS ;drivers/usb/serial/ti_usb_3410_5052.c +1
-1@@ -1559,7 +1559,7 @@ static int ti_restart_read(struct ti_por urb->complete = ti_bulk_in_callback; urb->context = tport; urb->dev = tport->tp_port->serial->dev; - status =usb_submit_urb (urb,GFP_KERNEL ); + status =usb_submit_urb (urb,GFP_ATOMIC ); } tport->tp_read_urb_state =TI_READ_URB_RUNNING ;drivers/usb/serial/whiteheat.c +2
-2@@ -1116,7 +1116,7 @@ static int firm_send_command (struct usbmemcpy (&transfer_buffer[1 ], data, datasize); command_port->write_urb->transfer_buffer_length = datasize +1 ; command_port->write_urb->dev = port->serial->dev; - retval =usb_submit_urb (command_port->write_urb,GFP_KERNEL ); + retval =usb_submit_urb (command_port->write_urb,GFP_ATOMIC );if (retval) {dbg ("%s - submit urb failed" , __FUNCTION__); goto exit;@@ -1316,7 +1316,7 @@ static int start_command_port(struct usbusb_clear_halt (serial->dev, command_port->read_urb->pipe); command_port->read_urb->dev = serial->dev; - retval =usb_submit_urb (command_port->read_urb,GFP_KERNEL ); + retval =usb_submit_urb (command_port->read_urb,GFP_ATOMIC );if (retval) {err ("%s - failed submitting read urb, error %d" , __FUNCTION__, retval); goto exit;@@ -1363,7 +1363,7 @@ static int start_port_read(struct usb_se wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); urb = wrap->urb;
Quoted 10 lines
drivers/usb/serial/whiteheat.c static int start_port_read(struct usb_se · line 1369
Quoted 6 lines
drivers/usb/serial/whiteheat.c +1
-1urb->dev = port->serial->dev; - retval =usb_submit_urb (urb,GFP_KERNEL ); + retval =usb_submit_urb (urb,GFP_ATOMIC );if (retval) {list_add (tmp, &info->rx_urbs_free);list_for_each_safe (tmp, tmp2, &info->rx_urbs_submitted) {This part might make sense so I'll queue it for the USB guys to look at.
Everything in USB appears to already be fixed, apart from the io_ti.c bug.
_______________________________________________
Kernel-janitors mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/kernel-janitors
Am Dienstag, 5. Juni 2007 06:08 schrieb Andrew Morton:
Quoted 1 line
Everything in USB appears to already be fixed, apart from the
io_ti.cbug.
Yes, that's a bug. I've queued a patch.
Regards
Oliver
_______________________________________________
Kernel-janitors mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/kernel-janitors
Quoted 10 lines · Andrew Morton
Quoted 7 lines
net/wan/lmc/lmc_main.c | 2 +- scsi/megaraid/megaraid_mm.c | 2 +- usb/serial/io_ti.c | 2 +- usb/serial/ti_usb_3410_5052.c | 2 +- usb/serial/whiteheat.c | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-)This patch covers three areas of maintainer responsibility, so poor old me has to split it up and redo the changelogs. Oh well.
Sorry.
For modifications that crosscut the kernel it is not very practical to look each time for the maintainer. We plan to send a patch that replaces some calls to kmalloc/memset with kzalloc; do we have to split it for each maintainer ?
Quoted 16 lines
drivers/net/wan/lmc/lmc_main.c #endif /* end ifdef _DBG_EVENTLOG */ · line 489
Quoted 13 lines
drivers/net/wan/lmc/lmc_main.c +1
-1@@ -483,7 +483,7 @@ #endif /* end ifdef _DBG_EVENTLOG */break ; } - data =kmalloc (xc.len,GFP_KERNEL ); + data =kmalloc (xc.len,GFP_ATOMIC );if (data =0x0 ){printk (KERN_WARNING "%s: Failed to allocate memory for copy\n" , dev->name); ret = -ENOMEM ;A few lines later we do:
Quoted 3 lines
if(copy_from_user(data, xc.data, xc.len))which also is illegal under spinlock.
I have launched my tool to detect such situations and I get this (in a diff-like format).
tmp/output.c renamed from home/pad/kernels/git/linux-2.6/arch/cris/arch-v10/drivers/gpio.c +0 -2
@@ -776,7 +776,7 @@/* bits set in *arg is set to input, * *arg updated with current input pins. */ -if (copy_from_user (&val, (unsigned long *)arg,sizeof (val))) { ret = -EFAULT ;break ;
@@ -789,7 +789,7 @@/* bits set in *arg is set to output, * *arg updated with current output pins. */ -if (copy_from_user (&val, (unsigned long *)arg,sizeof (val))) { ret = -EFAULT ;break ;
tmp/output.c renamed from home/pad/kernels/git/linux-2.6/arch/mips/au1000/common/power.c +0 -1
@@ -330,7 +330,7 @@spin_unlock_irqrestore (&pm_lock, flags);return -EFAULT ; } -if (copy_from_user (buf, buffer, *len)) {spin_unlock_irqrestore (&pm_lock, flags);return -EFAULT ; }
and some cases in lmc_main.c
Quoted 4 lines
Frankly, I think that a better use of this tool would be to just report on the errors, let humans fix them up.
Ok. Do you have a preference on the format ? a <file>:<line> format ?
Is there a place that gathered all those implicit programming rules (that copy_from_user must not be called inside a spinlock, etc) so that I can translate them in a script for our tool.
_______________________________________________
Kernel-janitors mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/kernel-janitors
Am Dienstag, 5. Juni 2007 13:05 schrieb Yoann Padioleau:
Quoted 5 lines
Ok. Do you have a preference on the format ? a <file>:<line> format ?
Is there a place that gathered all those implicit programming rules (that
copy_from_usermust not be called inside a spinlock, etc) so that I can translate them in a script for our tool.
How much C does your tool understand? You might basically test for code paths that go to "might_sleep()"
Regards
Oliver
_______________________________________________
Kernel-janitors mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/kernel-janitors
Quoted 8 lines · Oliver Neukum
Am Dienstag, 5. Juni 2007 13:05 schrieb Yoann Padioleau:
Quoted 5 lines
Ok. Do you have a preference on the format ? a <file>:<line> format ?
Is there a place that gathered all those implicit programming rules (that
copy_from_usermust not be called inside a spinlock, etc) so that I can translate them in a script for our tool.How much C does your tool understand?
The tool understands almost all the C language but the analysis we do for the moment are intra-procedural so when we look for
spin_lock();
...
copy_from_user();
it can detect cases and code paths only when the two function calls are in the same function. It could be extended but it would require to do a full analysis of the kernel source. Maybe if some functions of the library have an attribute in their prototype in the .h such as
__might_sleep copy_from_user();
it could help.
Quoted 2 lines
You might basically
test for code paths that go to "might_sleep()"
Ok, thanks. If you know other implicit programming rules, I would be glad to know them, or if you know places where thus rules are written.
BTW at one point I think the Linux community were using advanced static analysis tools such as the one made by Dawson Engler (now Coverity). The communitty have stopped using such tools ? Isn't the role of sparse to detect bugs such as the dangerous copy_from_user() inside spinlocked region ?
Quoted 8 lines
Regards
Oliver_______________________________________________
Kernel-janitors mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/kernel-janitors
_______________________________________________
Kernel-janitors mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/kernel-janitors
Quoted 34 lines · On Tue, 05 Jun 2007 18:31:42 +0200 Yoann Padioleau wrote:
Quoted 8 lines · Oliver Neukum
Am Dienstag, 5. Juni 2007 13:05 schrieb Yoann Padioleau:
Quoted 5 lines
Ok. Do you have a preference on the format ? a <file>:<line> format ?
Is there a place that gathered all those implicit programming rules (that
copy_from_usermust not be called inside a spinlock, etc) so that I can translate them in a script for our tool.How much C does your tool understand?
The tool understands almost all the C language but the analysis we do for the moment are intra-procedural so when we look for
spin_lock();
...
copy_from_user();it can detect cases and code paths only when the two function calls are in the same function. It could be extended but it would require to do a full analysis of the kernel source. Maybe if some functions of the library have an attribute in their prototype in the .h such as
__might_sleepcopy_from_user();it could help.
Quoted 2 lines
You might basically
test for code paths that go to "might_sleep()"Ok, thanks. If you know other implicit programming rules, I would be glad to know them, or if you know places where thus rules are written.
Quoted 6 lines
BTW at one point I think the Linux community were using advanced static analysis tools such as the one made by Dawson Engler (now Coverity). The communitty have stopped using such tools ? Isn't the role of sparse to detect bugs such as the dangerous
copy_from_user()inside spinlocked region ?
There are a few people who have registered for access to the Coverity database and occasionally go thru it looking for bugs and then posting fixes.
sparse can check for unbalanced locking, but it needs annotations for those AFAIK.
---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***
_______________________________________________
Kernel-janitors mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/kernel-janitors
Quoted 10 lines · On Tue, 05 Jun 2007 13:05:18 +0200 Yoann Padioleau <[email protected]> wrote:
Quoted 8 lines · Andrew Morton
Quoted 7 lines
net/wan/lmc/lmc_main.c | 2 +- scsi/megaraid/megaraid_mm.c | 2 +- usb/serial/io_ti.c | 2 +- usb/serial/ti_usb_3410_5052.c | 2 +- usb/serial/whiteheat.c | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-)
Quoted 7 lines
Quoted 2 lines
This patch covers three areas of maintainer responsibility, so poor old me has to split it up and redo the changelogs. Oh well.
Sorry.
For modifications that crosscut the kernel it is not very practical to look each time for the maintainer.
That's OK - I can take care of that
Quoted 3 lines
We plan to send a patch that
replaces some calls to kmalloc/memset with kzalloc; do we have to split it for each maintainer ?
Per subsystem: yes, please. That maps pretty well onto per-subdirectory so I'd suggest that each patch only affect the files in a single directory.
Quoted 54 lines
Quoted 16 lines
drivers/net/wan/lmc/lmc_main.c #endif /* end ifdef _DBG_EVENTLOG */ · line 489
Quoted 13 lines
drivers/net/wan/lmc/lmc_main.c +1
-1@@ -483,7 +483,7 @@ #endif /* end ifdef _DBG_EVENTLOG */break ; } - data =kmalloc (xc.len,GFP_KERNEL ); + data =kmalloc (xc.len,GFP_ATOMIC );if (data =0x0 ){printk (KERN_WARNING "%s: Failed to allocate memory for copy\n" , dev->name); ret = -ENOMEM ;A few lines later we do:
Quoted 3 lines
if(copy_from_user(data, xc.data, xc.len))which also is illegal under spinlock.
I have launched my tool to detect such situations and I get this (in a diff-like format).
tmp/output.c renamed from home/pad/kernels/git/linux-2.6/arch/cris/arch-v10/drivers/gpio.c +0
-2@@ -776,7 +776,7 @@/* bits set in *arg is set to input, * *arg updated with current input pins. */ -if (copy_from_user (&val, (unsigned long *)arg,sizeof (val))) { ret = -EFAULT ;break ;@@ -789,7 +789,7 @@/* bits set in *arg is set to output, * *arg updated with current output pins. */ -if (copy_from_user (&val, (unsigned long *)arg,sizeof (val))) { ret = -EFAULT ;break ;tmp/output.c renamed from home/pad/kernels/git/linux-2.6/arch/mips/au1000/common/power.c +0
-1@@ -330,7 +330,7 @@spin_unlock_irqrestore (&pm_lock, flags);return -EFAULT ; } -if (copy_from_user (buf, buffer, *len)) {spin_unlock_irqrestore (&pm_lock, flags);return -EFAULT ; }
Quoted 1 line
and some cases in
lmc_main.c
OK.
Quoted 7 lines
Quoted 5 lines
Frankly, I think that a better use of this tool would be to just report on the errors, let humans fix them up.
Ok. Do you have a preference on the format ? a <file>:<line> format ?
file-n-line is good. If it can quote the relevant test then that's better
- line numbers change often.
Please always work against the very latest Linus git tree,
Quoted 3 lines
Is there a place that gathered all those implicit programming rules (that
copy_from_usermust not be called inside a spinlock, etc) so that I can translate them in a script for our tool.
Not that I can think of, sorry.
_______________________________________________
Kernel-janitors mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/kernel-janitors