summaryrefslogtreecommitdiffstats
path: root/scripts/coccinelle/locks
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 10:05:51 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 10:05:51 +0000
commit5d1646d90e1f2cceb9f0828f4b28318cd0ec7744 (patch)
treea94efe259b9009378be6d90eb30d2b019d95c194 /scripts/coccinelle/locks
parentInitial commit. (diff)
downloadlinux-upstream/5.10.209.tar.xz
linux-upstream/5.10.209.zip
Adding upstream version 5.10.209.upstream/5.10.209upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'scripts/coccinelle/locks')
-rw-r--r--scripts/coccinelle/locks/call_kern.cocci106
-rw-r--r--scripts/coccinelle/locks/double_lock.cocci93
-rw-r--r--scripts/coccinelle/locks/flags.cocci81
-rw-r--r--scripts/coccinelle/locks/mini_lock.cocci99
4 files changed, 379 insertions, 0 deletions
diff --git a/scripts/coccinelle/locks/call_kern.cocci b/scripts/coccinelle/locks/call_kern.cocci
new file mode 100644
index 000000000..5ca0d81b0
--- /dev/null
+++ b/scripts/coccinelle/locks/call_kern.cocci
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/// Find functions that refer to GFP_KERNEL but are called with locks held.
+//# The proposed change of converting the GFP_KERNEL is not necessarily the
+//# correct one. It may be desired to unlock the lock, or to not call the
+//# function under the lock in the first place.
+///
+// Confidence: Moderate
+// Copyright: (C) 2012 Nicolas Palix.
+// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.
+// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual patch
+virtual context
+virtual org
+virtual report
+
+@gfp exists@
+identifier fn;
+position p;
+@@
+
+fn(...) {
+ ... when != read_unlock_irq(...)
+ when != write_unlock_irq(...)
+ when != read_unlock_irqrestore(...)
+ when != write_unlock_irqrestore(...)
+ when != spin_unlock(...)
+ when != spin_unlock_irq(...)
+ when != spin_unlock_irqrestore(...)
+ when != local_irq_enable(...)
+ when any
+ GFP_KERNEL@p
+ ... when any
+}
+
+@locked exists@
+identifier gfp.fn;
+position p1,p2;
+@@
+
+(
+read_lock_irq@p1
+|
+write_lock_irq@p1
+|
+read_lock_irqsave@p1
+|
+write_lock_irqsave@p1
+|
+spin_lock@p1
+|
+spin_trylock@p1
+|
+spin_lock_irq@p1
+|
+spin_lock_irqsave@p1
+|
+local_irq_disable@p1
+)
+ (...)
+... when != read_unlock_irq(...)
+ when != write_unlock_irq(...)
+ when != read_unlock_irqrestore(...)
+ when != write_unlock_irqrestore(...)
+ when != spin_unlock(...)
+ when != spin_unlock_irq(...)
+ when != spin_unlock_irqrestore(...)
+ when != local_irq_enable(...)
+fn@p2(...)
+
+@depends on locked && patch@
+position gfp.p;
+@@
+
+- GFP_KERNEL@p
++ GFP_ATOMIC
+
+@depends on locked && !patch@
+position gfp.p;
+@@
+
+* GFP_KERNEL@p
+
+@script:python depends on !patch && org@
+p << gfp.p;
+fn << gfp.fn;
+p1 << locked.p1;
+p2 << locked.p2;
+@@
+
+cocci.print_main("lock",p1)
+cocci.print_secs("call",p2)
+cocci.print_secs("GFP_KERNEL",p)
+
+@script:python depends on !patch && report@
+p << gfp.p;
+fn << gfp.fn;
+p1 << locked.p1;
+p2 << locked.p2;
+@@
+
+msg = "ERROR: function %s called on line %s inside lock on line %s but uses GFP_KERNEL" % (fn,p2[0].line,p1[0].line)
+coccilib.report.print_report(p[0], msg)
diff --git a/scripts/coccinelle/locks/double_lock.cocci b/scripts/coccinelle/locks/double_lock.cocci
new file mode 100644
index 000000000..9e88a5789
--- /dev/null
+++ b/scripts/coccinelle/locks/double_lock.cocci
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/// Find double locks. False positives may occur when some paths cannot
+/// occur at execution, due to the values of variables, and when there is
+/// an intervening function call that releases the lock.
+///
+// Confidence: Moderate
+// Copyright: (C) 2010 Nicolas Palix, DIKU.
+// Copyright: (C) 2010 Julia Lawall, DIKU.
+// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual org
+virtual report
+
+@locked@
+position p1;
+expression E1;
+position p;
+@@
+
+(
+mutex_lock@p1
+|
+mutex_trylock@p1
+|
+spin_lock@p1
+|
+spin_trylock@p1
+|
+read_lock@p1
+|
+read_trylock@p1
+|
+write_lock@p1
+|
+write_trylock@p1
+) (E1@p,...);
+
+@balanced@
+position p1 != locked.p1;
+position locked.p;
+identifier lock,unlock;
+expression x <= locked.E1;
+expression E,locked.E1;
+expression E2;
+@@
+
+if (E) {
+ <+... when != E1
+ lock(E1@p,...)
+ ...+>
+}
+... when != E1
+ when != \(x = E2\|&x\)
+ when forall
+if (E) {
+ <+... when != E1
+ unlock@p1(E1,...)
+ ...+>
+}
+
+@r depends on !balanced exists@
+expression x <= locked.E1;
+expression locked.E1;
+expression E2;
+identifier lock;
+position locked.p,p1,p2;
+@@
+
+lock@p1 (E1@p,...);
+... when != E1
+ when != \(x = E2\|&x\)
+lock@p2 (E1,...);
+
+@script:python depends on org@
+p1 << r.p1;
+p2 << r.p2;
+lock << r.lock;
+@@
+
+cocci.print_main(lock,p1)
+cocci.print_secs("second lock",p2)
+
+@script:python depends on report@
+p1 << r.p1;
+p2 << r.p2;
+lock << r.lock;
+@@
+
+msg = "second lock on line %s" % (p2[0].line)
+coccilib.report.print_report(p1[0],msg)
diff --git a/scripts/coccinelle/locks/flags.cocci b/scripts/coccinelle/locks/flags.cocci
new file mode 100644
index 000000000..7f990cd55
--- /dev/null
+++ b/scripts/coccinelle/locks/flags.cocci
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/// Find nested lock+irqsave functions that use the same flags variables
+///
+// Confidence: High
+// Copyright: (C) 2010-2012 Nicolas Palix.
+// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.
+// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual context
+virtual org
+virtual report
+
+@r exists@
+expression lock1,lock2,flags;
+position p1,p2;
+@@
+
+(
+spin_lock_irqsave@p1(lock1,flags)
+|
+read_lock_irqsave@p1(lock1,flags)
+|
+write_lock_irqsave@p1(lock1,flags)
+)
+... when != flags
+(
+spin_lock_irqsave(lock1,flags)
+|
+read_lock_irqsave(lock1,flags)
+|
+write_lock_irqsave(lock1,flags)
+|
+spin_lock_irqsave@p2(lock2,flags)
+|
+read_lock_irqsave@p2(lock2,flags)
+|
+write_lock_irqsave@p2(lock2,flags)
+)
+
+@d exists@
+expression f <= r.flags;
+expression lock1,lock2,flags;
+position r.p1, r.p2;
+@@
+
+(
+*spin_lock_irqsave@p1(lock1,flags)
+|
+*read_lock_irqsave@p1(lock1,flags)
+|
+*write_lock_irqsave@p1(lock1,flags)
+)
+... when != f
+(
+*spin_lock_irqsave@p2(lock2,flags)
+|
+*read_lock_irqsave@p2(lock2,flags)
+|
+*write_lock_irqsave@p2(lock2,flags)
+)
+
+// ----------------------------------------------------------------------
+
+@script:python depends on d && org@
+p1 << r.p1;
+p2 << r.p2;
+@@
+
+cocci.print_main("original lock",p1)
+cocci.print_secs("nested lock+irqsave that reuses flags",p2)
+
+@script:python depends on d && report@
+p1 << r.p1;
+p2 << r.p2;
+@@
+
+msg="ERROR: nested lock+irqsave that reuses flags from line %s." % (p1[0].line)
+coccilib.report.print_report(p2[0], msg)
diff --git a/scripts/coccinelle/locks/mini_lock.cocci b/scripts/coccinelle/locks/mini_lock.cocci
new file mode 100644
index 000000000..c3ad098f4
--- /dev/null
+++ b/scripts/coccinelle/locks/mini_lock.cocci
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/// Find missing unlocks. This semantic match considers the specific case
+/// where the unlock is missing from an if branch, and there is a lock
+/// before the if and an unlock after the if. False positives are due to
+/// cases where the if branch represents a case where the function is
+/// supposed to exit with the lock held, or where there is some preceding
+/// function call that releases the lock.
+///
+// Confidence: Moderate
+// Copyright: (C) 2010-2012 Nicolas Palix.
+// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.
+// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual context
+virtual org
+virtual report
+
+@prelocked@
+position p1,p;
+expression E1;
+@@
+
+(
+mutex_lock@p1
+|
+mutex_trylock@p1
+|
+spin_lock@p1
+|
+spin_trylock@p1
+|
+read_lock@p1
+|
+read_trylock@p1
+|
+write_lock@p1
+|
+write_trylock@p1
+|
+read_lock_irq@p1
+|
+write_lock_irq@p1
+|
+read_lock_irqsave@p1
+|
+write_lock_irqsave@p1
+|
+spin_lock_irq@p1
+|
+spin_lock_irqsave@p1
+) (E1@p,...);
+
+@looped@
+position r;
+@@
+
+for(...;...;...) { <+... return@r ...; ...+> }
+
+@err exists@
+expression E1;
+position prelocked.p;
+position up != prelocked.p1;
+position r!=looped.r;
+identifier lock,unlock;
+@@
+
+*lock(E1@p,...);
+... when != E1
+ when any
+if (...) {
+ ... when != E1
+* return@r ...;
+}
+... when != E1
+ when any
+*unlock@up(E1,...);
+
+@script:python depends on org@
+p << prelocked.p1;
+lock << err.lock;
+unlock << err.unlock;
+p2 << err.r;
+@@
+
+cocci.print_main(lock,p)
+cocci.print_secs(unlock,p2)
+
+@script:python depends on report@
+p << prelocked.p1;
+lock << err.lock;
+unlock << err.unlock;
+p2 << err.r;
+@@
+
+msg = "preceding lock on line %s" % (p[0].line)
+coccilib.report.print_report(p2[0],msg)