[Part II] Macros module init/exit, Boilerplate code and Linux Kernel

So, as I said in my last blog, I will explain about transformation semantic patch which can be used after matching module init/exit part. Before I go in to the detail, I would like to clear some points. Someone asked me about the use of * in the semantic patch of my last blog post. So, I thought I should add it in this blog too. Basically we use * for something of interest. For example in our case we just want to check if actually there are some cases present which do nothing except register/unregister in module init/exit. One can’t use * with +/-. Following is an output of the semantic patch explained in last blog post.

diff -u -p ./lib/ts_fsm.c /tmp/nothing/lib/ts_fsm.c
--- ./lib/ts_fsm.c
+++ /tmp/nothing/lib/ts_fsm.c
@@ -327,12 +327,10 @@ static struct ts_ops fsm_ops = {
static int __init init_fsm(void)
{
- return textsearch_register(&fsm_ops);
}
static void __exit exit_fsm(void)
{
- textsearch_unregister(&fsm_ops);
}
MODULE_LICENSE("GPL");

Now lets continue from where we left in last blog post. So, after matching cases, we need to remove functions of module init/exit along with declarations of module-init/module_exit. Also, we need to add helper macros like module_platform_driver. We can do that in individual cases by matching register/unregister functions. Here, is an example of such semantic patch for cases where we can use helper macro module_platform_driver.

@r@
declarer name module_init;
identifier f;
@@
module_init(f);

@s@
declarer name module_exit;
identifier e;
@@
module_exit(e);

@a@
identifier r.f;
identifier x;
@@
static f(…) {return platform_driver_register(&x); }

@b depends on a@
identifier s.e,a.x;
@@
static e(…) { platform_driver_unregister(&x); }

@t depends on r && a@
identifier r.f;
@@
-module_init(f);

@v depends on s && a && b@
declarer name module_platform_driver;
identifier s.e, a.x;
@@
-module_exit(e);
+module_platform_driver(x);

@c depends on b@
identifier r.f, a.x;
@@
-static f(…) { return platform_driver_register(&x); }

@d depends on c@
identifier s.e, a.x;
@@

-static e(…) { platform_driver_unregister(&x); }

In first four rules of the semantic patch we are doing matching and then depending on these 4 rules we are doing transformation. This semantic patch can be used for any such cases. Only thing which one need to change is names of register/unregister functions and helper macro. Interesting, right! Best part is those algorithms which are used by Julia in developing a tool. Because Coccinelle is very fast. And I think that’s the beauty of Coccinelle ­čÖé In last 2 weeks, I worked on some ether device API functions too. But may be one separate blog will be good to explain them. So, this will be the subject of my next blog. Till then stay connected. Stay happy. Ttyl.

[Part I] Macros module init/exit, Boilerplate code and Linux Kernel

Hii

Lets talk about boiler plate code today. I worked on cases of boiler plate code in Linux kernel during last few days. I am going to divide this particular topic in 2 blog posts. In this post, I will talk about boiler plate code, cases of them and how can we find them in the kernel using Coccinelle. In the second post, I will talk about how Coccinelle can help to handle such cases.

Boiler plate code:

Boilerplate code is any seemingly repetitive code that shows up again and again in order to get some result that seems like it ought to be much simpler. Basically boilerplate code or boilerplate is the sections of code that have to be included in many places with little or no alteration.

Bolier plate code and init/exit macros:

In kernel macro module_init can either be called during do_initcalls (if builtin) or at module insertion time (if a module). Macro module_exit is used to wrap the driver clean-up code with cleanup_module when used with rmmod and the driver is a module. If the driver is statically compiled into the kernel, module_exit has no effect. There can only be one module_init and one module_exit per module. In 70% of cases drivers don’t do anything special in module init/exit. So, such bolier plate code can be eliminated using some helper macros like module_platform_driver, module_pci_driver, module_pcmcia_driver etc. Here, is an example of such code form kernel:


static int __init snirm710_init(void)
{
return platform_driver_register(&snirm710_driver);
}
static void __exit snirm710_exit(void)
{
platform_driver_unregister(&snirm710_driver);
}
module_init(snirm710_init);
module_exit(snirm710_exit);

[From file drivers/scsi/sni_53c710.c]

Basically these helper macros are defined for drivers whose init and exit paths does only register and unregister. Sometimes we have unnecessary print statements and code in module init/exit too. In such cases we can use these helper macros too. Currently there are some such general macros and driver specific helper macros presented in the kernel. And many more such opportunities are there.

Macros module init/exit and Coccinelle

Generally we can use following Coccinelle semantic patch to match the module init/exit associated functions and statements.

@r@
declarer name module_init;
identifier f;
@@
module_init(f);

@s@
declarer name module_exit;
identifier f;
@@
module_exit(f);

@a@
identifier r.f;
statement S;
@@
f(…) { S }

@depends on a@
identifier s.f;
statement S;
@@
f(…) {
*S
}

@b@
identifier s.f;
statement S;
@@
f(…) { S }

@depends on b@
identifier r.f;
statement S;
@@
f(…) {
*S
}

So, after getting output of this semantic patch I analyzed all cases. And grouped them together accordingly. I grouped them in with categories like old macro and new macro means cases where we can use already defined helper macro and where we need to define new macros respectively. I am thinking to put that file on my github along with some coccinelle scripts so that others can use it. I am going to handle most of them. I have sent some patches and will sent for all those cases where old macro can be used. For the new macro cases, I will send patches introducing some of those macros which can handle maximum cases and such cases are already present there.

Note that above script can help with matching things only. For the transformation one need to be more specific in the script. I will talk about those scripts and some intersting stuff regarding the same in my next post.

Till then stay tuned!