Scripts, patches and fun with them

These two weeks have been great fun, working with some Coccinelle scripts and sending in patches.

So lets look at a few scripts. These may look a bit too structured for a blog but wanted to keep it understandable thats why its so :P.

Aim : This script removes null test on values that cannot be null as they are assigned the value that has the form &a->b (add the offset of b to the address of a where a is a valid pointer) or are assigned using get_drvdata functions.
Purpose : This helped in removal of good amount of code within the NULL test block in some instances and also reduces unnecessary checks.
Coccinelle script :
@r@
expression e,f;
identifier g,y;
statement S1,S2;
position p1,p2;
identifier accessor =~ “get_drvdata”;
@@

e =@p1 &f->g
<+… \(f->y\|accessor(f)\)
…+>
if (e@p2 != NULL || …)
S1 else S2

@bad@
expression e,e2;
position r.p1,r.p2;
@@

… when != e =@p1 e2
e@p2

@depends on !bad@
expression e,e1,e2;
position r.p1,r.p2;
@@

* e =@p1 e2
… when != e = e1
when != &e
* e@p2

Aim: This patch removes magicnumbers and replaces them by existing constants:
Purpose: This will encourage use of the defined constants and help in better readability of the code for developers.
Coccinelle script:
@r@
type T;
T E;
identifier fld;
identifier c;
@@

E->fld & c

@s@
constant C;
identifier r.c;
@@

#define c C

@@
r.T E;
identifier r.fld;
identifier r.c;
constant s.C;
@@

E->fld &
– C
+ c

Aim: This patch eliminates NULL test after alloc_bootmem functions as they never return a NULL.
Purpose: Unnecessary code within NULL test is done away with as NULL values or ERR is never returned by alloc_bootmem functions. Also, useless checks are no longer performed.
Coccinelle Script:
@@
expression E;
statement S;
@@

E = \(alloc_bootmem\|alloc_bootmem_low\|alloc_bootmem_pages\|alloc_bootmem_low_pages\)(…)
… when != E
(
– BUG_ON (E == NULL);
|
– if (E == NULL) S
)

@@
expression E,E1;
@@

E = \(alloc_bootmem\|alloc_bootmem_low\|alloc_bootmem_pages\|alloc_bootmem_low_pages\)(…)
… when != E
– memset(E,0,E1);

Aim: Free memory allocated using kmem_cache_zalloc using kmem_cache_free rather than kfree.
Purpose: This will ensure proper deallocation of the cached content by calling cache_from_obj to get the kmem_cache and then free it.
Coccinelle Script:
@@
expression x,E,c;
@@

x = \(kmem_cache_alloc\|kmem_cache_zalloc\|kmem_cache_alloc_node\)(c,…)
… when != x = E
when != &x
?-kfree(x)
+kmem_cache_free(c,x)

An important point, as no mistake is a small mistake!

I encountered an interesting case in Coccinelle due to a change in language semantics. Earlier, if a specified string was used with “declarer” it used to match only that declaration but now it declares a metavariable that can match any declarer. So, we should use “declarer name” instead.

This is matching any declarer (thing like DEFINE_MUTEX, etc) and hence I ended up with 435 cases and was perplexed that how can so many instances endup using spin_lock instead of a mutex_lock.
initial::
@def@
declarer DEFINE_MUTEX;
identifier m;
@@

DEFINE_MUTEX(m);

@@
identifier def.m;
@@

(
– spin_lock(&m)
+ mutex_lock(&m)
|
– spin_unlock(&m)
+ mutex_unlock(&m)
)

But, then I realized the problem and found the right cases where a lock is defined as a mutex lock but is used with spin_lock πŸ™‚ .
final::
@def@
declarer name DEFINE_MUTEX;
identifier m;
@@

DEFINE_MUTEX(m);

@@
identifier def.m;
@@

(
– spin_lock(&m)
+ mutex_lock(&m)
|
– spin_unlock(&m)
+ mutex_unlock(&m)
)

I have added the managed interfaces for kasprintf and kvasprintf that help in allocating resource managed space and copying an existing formatted string into it.Β Here is the patch and yeah its accepted. My first two official managed interfaces πŸ˜€

Woof!! It was interesting to work with these patches and tackle the issues πŸ™‚ But, there are many more to go. πŸ˜›
Will keep you posted about more…Bye

Interesting scripts and points encountered

These days I have been working with some Coccinelle semantic patches and fixing different bugs.
I have used a simple semantic patch to transform cases of if(expression) BUG() to BUG_ON(expression).
Here is the Coccinelle script for it:

@@
expression e;
@@
-if (e) BUG();
+BUG_ON(e);

I have worked with some patches that correct the argument to a memory allocation function when the allocated data is a double pointer and erroneously the elements are sizeof the struct instead of pointer. I have hardened the semantic patch with all four modes. Here is the basic patch for the transformation:

@disable sizeof_type_expr@
type T;
T **x;
@@

x =

<+…sizeof(
– T
+ *x
)…+>

I have also had some patches fixing bugs involving converting !x & y to !(x & y). The semantic patch used for it is:

@@ expression E1,E2; @@
(
!E1 & !E2
|
– !E1 & E2
+ !(E1 & E2)
)

I had added a managed interface devm_gpio_request_array which allocates multiple GPIOs in a single call in a managed manner but the function addition was already in queue. It was however fun coding up my first devm function :P.

Many unmanaged to managed interface conversion patches have been applied :). Also, I learnt an important point while introducing managed interfaces in the ASoC driver. Using the managed functions within the ASoC level probe functions doesn’t work as devm_ is only usable as part of the driver model binding and unbinding. All the resource allocation needs to be moved into the device level probe (which is a better thing anyway) before it is converted to devm. So, I set out to analyze the various types of probe functions to find which probe functions already use devm. A list of the various probe functions using devm functions and having possibilities of some conversions was made using Coccinelle. Also, I am looking at some uses of managed interfaces in the remove functions understanding the usage as it is a bit stange.

Thanks Julia and the awesome Linux community for being the best mentors and guides and letting me experiment and learn SOOO much πŸ™‚