Size: 9682
Comment:
|
← Revision 71 as of 2019-03-13 15:19:05 ⇥
Size: 11396
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 6: | Line 6: |
I'm a researcher at Inria, in Paris France. I develop the tool [http://coccinelle.lip6.fr Coccinelle], which allows easy matching and transformation of C code. Coccinelle has been designed with the goal of contributing to Linux development, but it can also be used on other C code. | I'm a researcher at Inria, in Paris France. I develop the tool [[http://coccinelle.lip6.fr|Coccinelle]], which allows easy matching and transformation of C code. Coccinelle has been designed with the goal of contributing to Linux development, but it can also be used on other C code. |
Line 8: | Line 8: |
Please write to me directly if you would like to apply to the Coccinelle OPW project. | Please write to me directly if you would like to apply to the Coccinelle Outreachy project. == Overview == This page is organized into two parts. The first part is about learning to use Coccinelle. The second part has some small tasks that are relevant for the documentation project. If you are interested in working on the Coccinelle project, you should do some work from both parts. For the Coccinelle part, it would be a good idea to start with the first challenge problem, to check that you know how to use the tool properly. The remaining challenge problems can be done in any order. It is not obligatory to do all of them. You may find other things that can be done with Coccinelle. Sources of inspiration may be the results of checkpatch and patches that have been applied to the kernel in the past. Any kind of problem that occurs over and over might be amenable to being solved with Coccinelle. These challenge problems may apply to many files in the kernel. Pick a few files, and send patches for those. Once they have been accepted, consider moving on to another challenge problem. You will get a better understanding of Coccinelle if you use it for many different things than if you use it do one thing over and over. There are many examples of uses of Coccinelle, in previous patches, in the kernel source tree in the scripts/coccinelle directory, and at [[https://github.com/coccinelle/coccinellery|coccinellery]]. If you use a script that is already in the Linux kernel, you don't need to include the script in your commit log, but rather something like Generated-by: scripts/coccinelle/misc/badty.cocci == Tutorial == A tutorial for Coccinelle is available [[https://pages.lip6.fr/Julia.Lawall/tutorial.pdf|here]]. These are slides that are intended to be presented, but they may be understandable independently of the presentation. Please note that the tutorial focuses on the source code of Linux 3.2, and so the patches created in doing the exercises of the tutorial are not suitable for submission to the ooutreachy-kernel mailing list. Doing the tutorial also does not count as a contribution to the project. |
Line 12: | Line 26: |
The following semantic patch introduces the use of the managed version of kzalloc in some very constrained cases: | Consider the following function, from drivers/staging/most/hdm-dim2/dim2_sysfs.c (Note that this file no longer exists. If you want to experiment with this code, just create a new .c file containing this function definition.) |
Line 15: | Line 29: |
@platform@ identifier p, probefn, removefn; |
static ssize_t bus_kobj_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) { ssize_t ret; struct medialb_bus *bus = container_of(kobj, struct medialb_bus, kobj_group); struct bus_attr *xattr = container_of(attr, struct bus_attr, attr); if (!xattr->store) return -EIO; ret = xattr->store(bus, buf, count); return ret; } }}} In this function, the last two lines could be compressed into one, as: {{{ static ssize_t bus_kobj_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) { ssize_t ret; struct medialb_bus *bus = container_of(kobj, struct medialb_bus, kobj_group); struct bus_attr *xattr = container_of(attr, struct bus_attr, attr); if (!xattr->store) return -EIO; return xattr->store(bus, buf, count); } }}} The following semantic patch makes this change: {{{ |
Line 18: | Line 67: |
struct platform_driver p = { .probe = probefn, .remove = removefn, }; @other_things depends on platform@ |
local idexpression ret; expression e; |
Line 26: | Line 71: |
( iio_device_alloc(...) | iio_trigger_alloc(...) | iio_device_register(...) | request_region(...) | request_mem_region(...) | request_irq(...) | dma_alloc_coherent(...) | dma_alloc_noncoherent(...) | dma_declare_coherent_memory(...) | dma_pool_create(...) | pci_enable_device(...) | pci_pin_device(...) | ioport_map(...) | ioremap(...) | ioremap_nocache(...) | pcim_iomap(...) | pcim_iomap_table(...) | pcim_iomap_regions(...) | regulator_get(...) | regulator_bulk_get(...) | regulator_register(...) | clk_get(...) | pinctrl_get(...) | pwm_get(...) | usb_get_phy(...) | acpi_dma_controller_register(...) | spi_register_master(...) | gpio_request(...) | gpio_request_one(...) ) @prb depends on !other_things@ identifier platform.probefn, pdev; expression e, e1, e2; @@ probefn(struct platform_device *pdev, ...) { <+... - e = kzalloc(e1, e2) + e = devm_kzalloc(&pdev->dev, e1, e2) ... ?-kfree(e); ...+> } @rem depends on prb@ identifier platform.removefn; expression e; @@ removefn(...) { <... - kfree(e); ...> } |
-ret = +return e; -return ret; |
Line 83: | Line 79: |
1. Read about the use of devm functions in Documentation/driver-model/devres.txt. Any recent version is fine. 1. Download and install Coccinelle. If you are using Linux, it should be available in your package manager. Any recent version is fine. 1. Download staging-next 1. Save the above semantic patch in a file kzalloc.cocci 1. Run Coccinelle on kzalloc.cocci and staging-next, ie spatch --sp-file kzalloc.cocci --no-includes --dir {your staging-next path} > kzalloc.out. This may take some time. Don't worry if there are some error messages. 1. Study the results in kzalloc.out carefully and submit a patch based on one case where you think that the transformation was done properly. |
1. Download and install Coccinelle. If you are using Linux, it should be available in your package manager. Any recent version is fine to start with, but you may need to get the most recent version, which is 1.0.4. This is available on the Coccinelle webpage (coccinelle.lip6.fr) and on github. 1. Download staging-testing 1. Save the above semantic patch in a file ret.cocci 1. Run Coccinelle on ret.cocci and staging-testing, ie spatch --sp-file ret.cocci --no-includes --dir {your staging-testing path}/drivers/staging > ret.out. This may take some time. |
Line 90: | Line 85: |
This semantic patch is not very robust, in that there is no guarantee that the kfree that is removed in the remove function is freeing the data that was kzalloced in the probe function. Some things to watch out for are as follows: | Do you find the result satisfactory? If so, submit some patches. If not, let us know! |
Line 92: | Line 88: |
1. Does the file already use devm functions? If so, any kzalloc and kfree that this semantic patch finds are probably still there for a reason. 1. Does the file contain calls to kfree that are not in the probe and remove functions. If so, could they affect the kzalloced data? If so, more thought may be required as to whether the kfrees are needed, and if they should be transformed to devm_kfree for early release of the devm allocated data. 1. Does the transformation affect both a probe function and a remove function, or only a probe function? If there is no transformation to a remove function, is the kfree somewhere else? Is there a reason why the allocated data should not be freed? Again, more thought may be needed. |
Your code may now declare some variables that are never used. Remove them before submitting your patch. If you do submit a patch based on the use of Coccinelle, please mention Coccinelle in your patch, and the semantic patch that you used. What happens in the above semantic patch if you replace local idexpression by identifier or expression? Try these extra variants and see if there are any differences in the results. |
Line 98: | Line 96: |
One of the checkpatch errors is "do not use assignment in if condition". And example of this is the following code, from drivers/staging/cxt1e1/sbeproc.c: | Parentheses are not needed around the right hand side of an assignment, like in value = (FLASH_CMD_STATUS_REG_READ << 24);. Write a semantic patch to remove these parentheses. |
Line 100: | Line 98: |
{{{ if (!(bip = OS_kmalloc(sizeof(struct sbe_brd_info)))) return -ENOMEM; }}} |
One could consider that parentheses might be useful in the case of eg rising = (dir == IIO_EV_DIR_RISING); because there could be a confusion between the different kinds of =. Extend your semantic patch using a disjunction so that it does not report on such cases. |
Line 105: | Line 100: |
Write a semantic patch to find and fix such cases, eg producing the following patch for the above example: {{{ - if (!(bip = OS_kmalloc(sizeof(struct sbe_brd_info)))) + bip = OS_kmalloc(sizeof(struct sbe_brd_info)); + if (!bip) return -ENOMEM; }}} Apply your semantic patch to the Linux staging directory and submit patches based on your results. Take case that your result is as you would like it to look if you were making the transformation by hand. If it is not, consider whether you should extend your semantic patch in some way to improve the result. Include a concise version of the semantic patch that you have used in your commit message. |
Other kinds of code do not need parentheses, such as a->b in &(a->b), function arguments, and the argument of return. |
Line 118: | Line 104: |
If a variable has value 0, then there is no point in combining it with other things with |, as for any x, 0 | x is just x. The following semantic patch finds this problem. | Some functions return NULL as a return value on failure. NULL can be tested for as !x, NULL == x, or x == NULL. When NULL represents failure, eg of an allocation, !x is commonly used. The following are some functions that commonly follow this strategy: |
Line 121: | Line 107: |
@@ expression x,e,e1; statement S; @@ if (x == 0) { ... when != x = e1 when != while(...) S when != for(...;...;...) S ( * x |= e | * x | e ) ... when any } |
kmalloc devm_kzalloc kmalloc_array devm_ioremap usb_alloc_urb alloc_netdev dev_alloc_skb |
Line 139: | Line 116: |
1. Apply the semantic patch to the Linux kernel and make some corresponding changes by hand. Note that the result of a semantic patch that uses * is something like a patch with a - at the beginning of any line that contains a match of the starred pattern. 1. Consider how you could extend the semantic patch to fix the code rather than just finding possible occurrences of the problem. Hint: it may work best to change the first "..." to <... and to change the "... when any" to just ...>. |
Write a semantic patch to clean up the tests on the results of one or more of these functions. |
Line 144: | Line 120: |
The Linux kernel provides a number of specific printing functions, eg for net devices and for devices in general. The goal of this challenge problem is to use Coccinelle to convert the use of the generic functions, eg pr_debug, to the net device ones, eg netdev_dbg. The challenge in doing this is to find a net_device typed pointer that can be used as the first argument of the netdev printing function. Often such a pointer is accessible from on of the parameters of the function enclosing the call. | Kmalloc and variants normally produce a backtrace when there is not enough memory, so it is not necessary to print an error message that provides only this information. Write a semantic patch that removes such print statements. Note that doing so may results in an if that has only one statement in a branch, so the surrounding braces should also be removed in this case |
Line 146: | Line 122: |
Your semantic patch should consist of three rules: 1. To find a call to eg pr_debug and the structures in the parameter list of its enclosing function. 1. To find the net_device field in one of these structures. 1. To transform the call to add the reference to the field. An implementation of the first rule is shown below. It considers only pr_debug: {{{ @r exists@ identifier f,s,i; position p; @@ f(...,struct s *i,...) { <+... pr_debug@p(...) ...+> } }}} Implement the other two rules for the pr_debug case. Consider how to extend the semantic patch to other pr_ functions. Hint: Give spatch the additional arguments --all-includes and -I path_to_your_kernel/include. This will allow it to find more structure type definitions from header files. Using the latest version of Coccinelle, from the Coccinelle web page (http://coccinelle.lip6.fr/distrib/coccinelle-1.0.0-rc20.tgz) may give better performance. |
'''Hint''': A metavariable declared as constant char[] c; matches any string constant. |
Line 173: | Line 126: |
A number of people have proposed patches that fix spacing issues between certain kinds of tokens, such as the need for a space after an if or an extra space after the name of a function in a function call. Making such small changes is probably pretty easy to do by hand, but using Coccinelle for it permits to illustrate some extra features of Coccinelle. | The Linux kernel coding style guidelines discourage the use of typedefs for struct types. There are several opportunities for using Coccinelle here. |
Line 175: | Line 128: |
The following semantic patch finds cases where there is not exactly one space between if and the following (, and reconstructs the if when the problem occurs. | * You can write a semantic patch to find such typedefs. Typedefs are often found in header files. To be sure that Coccinelle looks at all available header files, use the argument --include-headers. Note also that the name set by a typedef matches a metavariable of type '''type'''. * If you find such a typedef, to remove it, you need to adjust all the uses. This can be done using a semantic patch. * You can also fully automate the process. Note that the name of a typedef typically ends in _t and thus that name is not directly suitable as a name for the struct type. You will need to use python code to remove the _t. The file coccinelle/demos/pythontococci.cocci can help in doing this, as it shows how to declare a variable in python code and then use it in pattern matching code. By default, Coccinelle only works on .c files, including only .h files that have the same name as the .c file. Typedefs, however are likely to be in .h files. You can try the argument --all-includes, to try to include the .h files in the treatment of each .c file. That will make it possible to update both the typedef and its uses. To work on the .h files individually, you can use the option --include-headers. In that case you will have to update the uses of the types separately, by hand or with another semantic patch. == Coccinelle challenge problem 6 == The file include/linux/list.h contains many functions and macros for manipulating lists. For example, when some expression l points into a list, ie has type struct list_head *, then list_entry(l, type, member) can be used to access the current list element, rather than using container_of. Make a semantic patch to use list_entry when possible. When you find a change opportunity, consider whether some other nearby code could also be reimplemented to use a list operator. '''Hint:''' A metavariable declares as struct list_head *l; will only match an expression of type struct list_head *. == Coccinelle challenge problem 7 == list_for_each is a macro that iterates over the elements of a (doubly linked) list. list_entry is a function that takes as argument a list pointer and returns the structure that is pointed to. list_for_each_entry is a macro that iterates over the structures in the list, rather than exposing the list spine. Often a list is only used for its entries, and thus list_for_each_entry can be used instead of the composition of list_for_each and list_entry. An exmple of the transformation is as follows (commit 711584ea4c8ce): |
Line 178: | Line 149: |
@r@ position p1,p2; statement S1,S2; @@ ( if@p1 (@p2 ...) S1 else S2 | if@p1 (@p2 ...) S1 ) @script:python@ p1 << r.p1; p2 << r.p2; @@ l1 = int (p1[0].line) l2 = int (p2[0].line) c1 = int (p1[0].column_end) c2 = int (p2[0].column) if (l1 == l2 and c1 + 1 == c2): cocci.include_match(False) @@ position r.p1; statement S1,S2; @@ ( - if@p1 ( + if ( ...) S1 else S2 | - if@p1 ( + if ( ...) S1 ) |
- list_for_each(p, &hci_cb_list) { - struct hci_cb *cb = list_entry(p, struct hci_cb, list); + list_for_each_entry(cb, &hci_cb_list, list) { if (cb->security_cfm) cb->security_cfm(conn, status, encrypt); } |
Line 217: | Line 157: |
The semantic patch consists of three rules. | An criterion for the transformation is that p should not be used in the loop body. |
Line 219: | Line 159: |
1. The rule r simply matches every if, with either a then and an else branch, or only a then branch. It uses one "position variable", p1, to record the position of the if token, and another, p2, to record the position of the open parenthesis. 1. The second rule contains python code that checks whether there is exactly one space between the if and the open parenthesis. If this is the case, the pair of values of p1 and p2 are discarded, as though they had never matched. 1. The third rule removes the if and the open parenthesis and then puts it back, taking advantage of the fact that the Coccinelle pretty printer puts a space between if and an open parenthesis. |
Note that in this example, the variable holding the result of list_entry is only defined inside the loop in the old code. Since that variable is moved up into the loop header, its declaration has to be moved up as well. At the same time, the variable p is no longer used inside the loop, and is indeed no longer used in the function at all, and thus its declaration can be dropped completely. You can automate as much of this as you like. |
Line 223: | Line 161: |
The result of this semantic patch is not always satisfactory, in that it may cause the introduction of extra braces. Coccinelle is not able to realize that this transformation amounts to just replacing a single statement by a single statement, and thus if the if is an immediate child of another if, while, etc, with no surrounding braces, it adds some. One way not to be bothered by these cases (while introducing false negatives, ie overlooked cases) would be to put a function call or assignment pattern just before the if in the first rule. | There are currently few opportunities for this transformation in staging drivers. |
Line 225: | Line 163: |
This semantic patch is rather slow. Consider why that would be the case. | == Coccinelle challenge problem 8 == |
Line 227: | Line 165: |
Extend the semantic patch to address other cases, such as no space between ) and { in an if. | Sometimes a variable is declared and at the same time initialized to the result of calling some function, and thus function does some simple task, such as accessing a structure field. If the value of this function call doesn't change, the variable can be used rather than calling the function again. Write a semantic patch to detect, and potentially correct, these issues. == Other Coccinelle challenge problems == You can also try the [[http://kernelnewbies.org/JuliaLawall_round8|Coccinelle challenge problems from round 8]], [[http://kernelnewbies.org/JuliaLawall_round9|Coccinelle challenge problems from round 9]], and [[http://kernelnewbies.org/JuliaLawall_round10|Coccinelle challenge problems from round 10]]. |
Line 231: | Line 174: |
Email: [[MailTo(Julia.Lawall AT lip6 DOT fr)]] | Email: <<MailTo(Julia.Lawall AT lip6 DOT fr)>> |
Line 235: | Line 178: |
Questions about using Coccinelle should go to the Coccinelle mailing list: [[MailTo(cocci AT systeme DOT lip6 DOT fr)]] | Questions about using Coccinelle should go to the Coccinelle mailing list: <<MailTo(cocci AT systeme DOT lip6 DOT fr)>> |
About Me
I'm a researcher at Inria, in Paris France. I develop the tool Coccinelle, which allows easy matching and transformation of C code. Coccinelle has been designed with the goal of contributing to Linux development, but it can also be used on other C code.
Please write to me directly if you would like to apply to the Coccinelle Outreachy project.
Overview
This page is organized into two parts. The first part is about learning to use Coccinelle. The second part has some small tasks that are relevant for the documentation project. If you are interested in working on the Coccinelle project, you should do some work from both parts.
For the Coccinelle part, it would be a good idea to start with the first challenge problem, to check that you know how to use the tool properly. The remaining challenge problems can be done in any order. It is not obligatory to do all of them. You may find other things that can be done with Coccinelle. Sources of inspiration may be the results of checkpatch and patches that have been applied to the kernel in the past. Any kind of problem that occurs over and over might be amenable to being solved with Coccinelle.
These challenge problems may apply to many files in the kernel. Pick a few files, and send patches for those. Once they have been accepted, consider moving on to another challenge problem. You will get a better understanding of Coccinelle if you use it for many different things than if you use it do one thing over and over.
There are many examples of uses of Coccinelle, in previous patches, in the kernel source tree in the scripts/coccinelle directory, and at coccinellery. If you use a script that is already in the Linux kernel, you don't need to include the script in your commit log, but rather something like Generated-by: scripts/coccinelle/misc/badty.cocci
Tutorial
A tutorial for Coccinelle is available here. These are slides that are intended to be presented, but they may be understandable independently of the presentation. Please note that the tutorial focuses on the source code of Linux 3.2, and so the patches created in doing the exercises of the tutorial are not suitable for submission to the ooutreachy-kernel mailing list. Doing the tutorial also does not count as a contribution to the project.
Coccinelle challenge problem 1
Consider the following function, from drivers/staging/most/hdm-dim2/dim2_sysfs.c (Note that this file no longer exists. If you want to experiment with this code, just create a new .c file containing this function definition.)
static ssize_t bus_kobj_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) { ssize_t ret; struct medialb_bus *bus = container_of(kobj, struct medialb_bus, kobj_group); struct bus_attr *xattr = container_of(attr, struct bus_attr, attr); if (!xattr->store) return -EIO; ret = xattr->store(bus, buf, count); return ret; }
In this function, the last two lines could be compressed into one, as:
static ssize_t bus_kobj_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) { ssize_t ret; struct medialb_bus *bus = container_of(kobj, struct medialb_bus, kobj_group); struct bus_attr *xattr = container_of(attr, struct bus_attr, attr); if (!xattr->store) return -EIO; return xattr->store(bus, buf, count); }
The following semantic patch makes this change:
@@ local idexpression ret; expression e; @@ -ret = +return e; -return ret;
Do the following:
- Download and install Coccinelle. If you are using Linux, it should be available in your package manager. Any recent version is fine to start
with, but you may need to get the most recent version, which is 1.0.4. This is available on the Coccinelle webpage (coccinelle.lip6.fr) and on github.
- Download staging-testing
- Save the above semantic patch in a file ret.cocci
Run Coccinelle on ret.cocci and staging-testing, ie spatch --sp-file ret.cocci --no-includes --dir {your staging-testing path}/drivers/staging > ret.out. This may take some time.
Do you find the result satisfactory? If so, submit some patches. If not, let us know!
Your code may now declare some variables that are never used. Remove them before submitting your patch.
If you do submit a patch based on the use of Coccinelle, please mention Coccinelle in your patch, and the semantic patch that you used.
What happens in the above semantic patch if you replace local idexpression by identifier or expression? Try these extra variants and see if there are any differences in the results.
Coccinelle challenge problem 2
Parentheses are not needed around the right hand side of an assignment, like in value = (FLASH_CMD_STATUS_REG_READ << 24);. Write a semantic patch to remove these parentheses.
One could consider that parentheses might be useful in the case of eg rising = (dir == IIO_EV_DIR_RISING); because there could be a confusion between the different kinds of =. Extend your semantic patch using a disjunction so that it does not report on such cases.
Other kinds of code do not need parentheses, such as a->b in &(a->b), function arguments, and the argument of return.
Coccinelle challenge problem 3
Some functions return NULL as a return value on failure. NULL can be tested for as !x, NULL == x, or x == NULL. When NULL represents failure, eg of an allocation, !x is commonly used. The following are some functions that commonly follow this strategy:
kmalloc devm_kzalloc kmalloc_array devm_ioremap usb_alloc_urb alloc_netdev dev_alloc_skb
Write a semantic patch to clean up the tests on the results of one or more of these functions.
Coccinelle challenge problem 4
Kmalloc and variants normally produce a backtrace when there is not enough memory, so it is not necessary to print an error message that provides only this information. Write a semantic patch that removes such print statements. Note that doing so may results in an if that has only one statement in a branch, so the surrounding braces should also be removed in this case
Hint: A metavariable declared as constant char[] c; matches any string constant.
Coccinelle challenge problem 5
The Linux kernel coding style guidelines discourage the use of typedefs for struct types. There are several opportunities for using Coccinelle here.
You can write a semantic patch to find such typedefs. Typedefs are often found in header files. To be sure that Coccinelle looks at all available header files, use the argument --include-headers. Note also that the name set by a typedef matches a metavariable of type type.
- If you find such a typedef, to remove it, you need to adjust all the uses. This can be done using a semantic patch.
- You can also fully automate the process. Note that the name of a typedef typically ends in _t and thus that name is not directly suitable as a name for the struct type. You will need to use python code to remove the _t. The file coccinelle/demos/pythontococci.cocci can help in doing this, as it shows how to declare a variable in python code and then use it in pattern matching code.
By default, Coccinelle only works on .c files, including only .h files that have the same name as the .c file. Typedefs, however are likely to be in .h files. You can try the argument --all-includes, to try to include the .h files in the treatment of each .c file. That will make it possible to update both the typedef and its uses. To work on the .h files individually, you can use the option --include-headers. In that case you will have to update the uses of the types separately, by hand or with another semantic patch.
Coccinelle challenge problem 6
The file include/linux/list.h contains many functions and macros for manipulating lists. For example, when some expression l points into a list, ie has type struct list_head *, then list_entry(l, type, member) can be used to access the current list element, rather than using container_of. Make a semantic patch to use list_entry when possible. When you find a change opportunity, consider whether some other nearby code could also be reimplemented to use a list operator.
Hint: A metavariable declares as struct list_head *l; will only match an expression of type struct list_head *.
Coccinelle challenge problem 7
list_for_each is a macro that iterates over the elements of a (doubly linked) list. list_entry is a function that takes as argument a list pointer and returns the structure that is pointed to. list_for_each_entry is a macro that iterates over the structures in the list, rather than exposing the list spine.
Often a list is only used for its entries, and thus list_for_each_entry can be used instead of the composition of list_for_each and list_entry.
An exmple of the transformation is as follows (commit 711584ea4c8ce):
- list_for_each(p, &hci_cb_list) { - struct hci_cb *cb = list_entry(p, struct hci_cb, list); + list_for_each_entry(cb, &hci_cb_list, list) { if (cb->security_cfm) cb->security_cfm(conn, status, encrypt); }
An criterion for the transformation is that p should not be used in the loop body.
Note that in this example, the variable holding the result of list_entry is only defined inside the loop in the old code. Since that variable is moved up into the loop header, its declaration has to be moved up as well. At the same time, the variable p is no longer used inside the loop, and is indeed no longer used in the function at all, and thus its declaration can be dropped completely. You can automate as much of this as you like.
There are currently few opportunities for this transformation in staging drivers.
Coccinelle challenge problem 8
Sometimes a variable is declared and at the same time initialized to the result of calling some function, and thus function does some simple task, such as accessing a structure field. If the value of this function call doesn't change, the variable can be used rather than calling the function again. Write a semantic patch to detect, and potentially correct, these issues.
Other Coccinelle challenge problems
You can also try the Coccinelle challenge problems from round 8, Coccinelle challenge problems from round 9, and Coccinelle challenge problems from round 10.
Contact info
Email: <Julia.Lawall AT lip6 DOT fr>
My IRC handle is jlawall.
Questions about using Coccinelle should go to the Coccinelle mailing list: <cocci AT systeme DOT lip6 DOT fr>