projects/linux·blob master · refs

633 lines · 14.5 KiB

1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Compile-only tests for common patterns that should not generate false
4 * positive errors when compiled with Clang's context analysis.
5 */
6
7#include <linux/bit_spinlock.h>
8#include <linux/build_bug.h>
9#include <linux/local_lock.h>
10#include <linux/mutex.h>
11#include <linux/percpu.h>
12#include <linux/rcupdate.h>
13#include <linux/rwsem.h>
14#include <linux/seqlock.h>
15#include <linux/spinlock.h>
16#include <linux/srcu.h>
17#include <linux/ww_mutex.h>
18
19/*
20 * Test that helper macros work as expected.
21 */
22static void __used test_common_helpers(void)
23{
24 BUILD_BUG_ON(context_unsafe(3) != 3); /* plain expression */
25 BUILD_BUG_ON(context_unsafe((void)2; 3) != 3); /* does not swallow semi-colon */
26 BUILD_BUG_ON(context_unsafe((void)2, 3) != 3); /* does not swallow commas */
27 context_unsafe(do { } while (0)); /* works with void statements */
28}
29
30#define TEST_SPINLOCK_COMMON(class, type, type_init, type_lock, type_unlock, type_trylock, op) \
31 struct test_##class##_data { \
32 type lock; \
33 int counter __guarded_by(&lock); \
34 int *pointer __pt_guarded_by(&lock); \
35 }; \
36 static void __used test_##class##_init(struct test_##class##_data *d) \
37 { \
38 guard(type_init)(&d->lock); \
39 d->counter = 0; \
40 } \
41 static void __used test_##class(struct test_##class##_data *d) \
42 { \
43 unsigned long flags; \
44 d->pointer++; \
45 type_lock(&d->lock); \
46 op(d->counter); \
47 op(*d->pointer); \
48 type_unlock(&d->lock); \
49 type_lock##_irq(&d->lock); \
50 op(d->counter); \
51 op(*d->pointer); \
52 type_unlock##_irq(&d->lock); \
53 type_lock##_bh(&d->lock); \
54 op(d->counter); \
55 op(*d->pointer); \
56 type_unlock##_bh(&d->lock); \
57 type_lock##_irqsave(&d->lock, flags); \
58 op(d->counter); \
59 op(*d->pointer); \
60 type_unlock##_irqrestore(&d->lock, flags); \
61 } \
62 static void __used test_##class##_trylock(struct test_##class##_data *d) \
63 { \
64 if (type_trylock(&d->lock)) { \
65 op(d->counter); \
66 type_unlock(&d->lock); \
67 } \
68 } \
69 static void __used test_##class##_assert(struct test_##class##_data *d) \
70 { \
71 lockdep_assert_held(&d->lock); \
72 op(d->counter); \
73 } \
74 static void __used test_##class##_guard(struct test_##class##_data *d) \
75 { \
76 { guard(class)(&d->lock); op(d->counter); } \
77 { guard(class##_irq)(&d->lock); op(d->counter); } \
78 { guard(class##_irqsave)(&d->lock); op(d->counter); } \
79 }
80
81#define TEST_OP_RW(x) (x)++
82#define TEST_OP_RO(x) ((void)(x))
83
84TEST_SPINLOCK_COMMON(raw_spinlock,
85 raw_spinlock_t,
86 raw_spinlock_init,
87 raw_spin_lock,
88 raw_spin_unlock,
89 raw_spin_trylock,
90 TEST_OP_RW);
91static void __used test_raw_spinlock_trylock_extra(struct test_raw_spinlock_data *d)
92{
93 unsigned long flags;
94
95 data_race(d->counter++); /* no warning */
96
97 if (raw_spin_trylock_irq(&d->lock)) {
98 d->counter++;
99 raw_spin_unlock_irq(&d->lock);
100 }
101 if (raw_spin_trylock_irqsave(&d->lock, flags)) {
102 d->counter++;
103 raw_spin_unlock_irqrestore(&d->lock, flags);
104 }
105 scoped_cond_guard(raw_spinlock_try, return, &d->lock) {
106 d->counter++;
107 }
108}
109
110TEST_SPINLOCK_COMMON(spinlock,
111 spinlock_t,
112 spinlock_init,
113 spin_lock,
114 spin_unlock,
115 spin_trylock,
116 TEST_OP_RW);
117static void __used test_spinlock_trylock_extra(struct test_spinlock_data *d)
118{
119 unsigned long flags;
120
121 if (spin_trylock_irq(&d->lock)) {
122 d->counter++;
123 spin_unlock_irq(&d->lock);
124 }
125 if (spin_trylock_irqsave(&d->lock, flags)) {
126 d->counter++;
127 spin_unlock_irqrestore(&d->lock, flags);
128 }
129 scoped_cond_guard(spinlock_try, return, &d->lock) {
130 d->counter++;
131 }
132}
133
134TEST_SPINLOCK_COMMON(write_lock,
135 rwlock_t,
136 rwlock_init,
137 write_lock,
138 write_unlock,
139 write_trylock,
140 TEST_OP_RW);
141static void __used test_write_trylock_extra(struct test_write_lock_data *d)
142{
143 unsigned long flags;
144
145 if (write_trylock_irqsave(&d->lock, flags)) {
146 d->counter++;
147 write_unlock_irqrestore(&d->lock, flags);
148 }
149}
150
151TEST_SPINLOCK_COMMON(read_lock,
152 rwlock_t,
153 rwlock_init,
154 read_lock,
155 read_unlock,
156 read_trylock,
157 TEST_OP_RO);
158
159struct test_mutex_data {
160 struct mutex mtx;
161 int counter __guarded_by(&mtx);
162
163 struct mutex mtx2;
164 int anyread __guarded_by(&mtx, &mtx2);
165 int *anyptr __pt_guarded_by(&mtx, &mtx2);
166};
167
168static void __used test_mutex_init(struct test_mutex_data *d)
169{
170 guard(mutex_init)(&d->mtx);
171 d->counter = 0;
172}
173
174static void __used test_mutex_lock(struct test_mutex_data *d)
175{
176 mutex_lock(&d->mtx);
177 d->counter++;
178 mutex_unlock(&d->mtx);
179 mutex_lock_io(&d->mtx);
180 d->counter++;
181 mutex_unlock(&d->mtx);
182}
183
184static void __used test_mutex_trylock(struct test_mutex_data *d, atomic_t *a)
185{
186 if (!mutex_lock_interruptible(&d->mtx)) {
187 d->counter++;
188 mutex_unlock(&d->mtx);
189 }
190 if (!mutex_lock_killable(&d->mtx)) {
191 d->counter++;
192 mutex_unlock(&d->mtx);
193 }
194 if (mutex_trylock(&d->mtx)) {
195 d->counter++;
196 mutex_unlock(&d->mtx);
197 }
198 if (atomic_dec_and_mutex_lock(a, &d->mtx)) {
199 d->counter++;
200 mutex_unlock(&d->mtx);
201 }
202}
203
204static void __used test_mutex_assert(struct test_mutex_data *d)
205{
206 lockdep_assert_held(&d->mtx);
207 d->counter++;
208}
209
210static void __used test_mutex_guard(struct test_mutex_data *d)
211{
212 guard(mutex)(&d->mtx);
213 d->counter++;
214}
215
216static void __used test_mutex_cond_guard(struct test_mutex_data *d)
217{
218 scoped_cond_guard(mutex_try, return, &d->mtx) {
219 d->counter++;
220 }
221 scoped_cond_guard(mutex_intr, return, &d->mtx) {
222 d->counter++;
223 }
224}
225
226static void __used test_mutex_multiguard(struct test_mutex_data *d)
227{
228 mutex_lock(&d->mtx);
229 (void)d->anyread;
230 (void)*d->anyptr;
231 mutex_unlock(&d->mtx);
232
233 mutex_lock(&d->mtx2);
234 (void)d->anyread;
235 (void)*d->anyptr;
236 mutex_unlock(&d->mtx2);
237
238 mutex_lock(&d->mtx);
239 mutex_lock(&d->mtx2);
240 d->anyread++;
241 (*d->anyptr)++;
242 mutex_unlock(&d->mtx2);
243 mutex_unlock(&d->mtx);
244}
245
246struct test_seqlock_data {
247 seqlock_t sl;
248 int counter __guarded_by(&sl);
249};
250
251static void __used test_seqlock_init(struct test_seqlock_data *d)
252{
253 guard(seqlock_init)(&d->sl);
254 d->counter = 0;
255}
256
257static void __used test_seqlock_reader(struct test_seqlock_data *d)
258{
259 unsigned int seq;
260
261 do {
262 seq = read_seqbegin(&d->sl);
263 (void)d->counter;
264 } while (read_seqretry(&d->sl, seq));
265}
266
267static void __used test_seqlock_writer(struct test_seqlock_data *d)
268{
269 unsigned long flags;
270
271 write_seqlock(&d->sl);
272 d->counter++;
273 write_sequnlock(&d->sl);
274
275 write_seqlock_irq(&d->sl);
276 d->counter++;
277 write_sequnlock_irq(&d->sl);
278
279 write_seqlock_bh(&d->sl);
280 d->counter++;
281 write_sequnlock_bh(&d->sl);
282
283 write_seqlock_irqsave(&d->sl, flags);
284 d->counter++;
285 write_sequnlock_irqrestore(&d->sl, flags);
286}
287
288static void __used test_seqlock_scoped(struct test_seqlock_data *d)
289{
290 scoped_seqlock_read (&d->sl, ss_lockless) {
291 (void)d->counter;
292 }
293}
294
295struct test_rwsem_data {
296 struct rw_semaphore sem;
297 int counter __guarded_by(&sem);
298};
299
300static void __used test_rwsem_init(struct test_rwsem_data *d)
301{
302 guard(rwsem_init)(&d->sem);
303 d->counter = 0;
304}
305
306static void __used test_rwsem_reader(struct test_rwsem_data *d)
307{
308 down_read(&d->sem);
309 (void)d->counter;
310 up_read(&d->sem);
311
312 if (down_read_trylock(&d->sem)) {
313 (void)d->counter;
314 up_read(&d->sem);
315 }
316}
317
318static void __used test_rwsem_writer(struct test_rwsem_data *d)
319{
320 down_write(&d->sem);
321 d->counter++;
322 up_write(&d->sem);
323
324 down_write(&d->sem);
325 d->counter++;
326 downgrade_write(&d->sem);
327 (void)d->counter;
328 up_read(&d->sem);
329
330 if (down_write_trylock(&d->sem)) {
331 d->counter++;
332 up_write(&d->sem);
333 }
334}
335
336static void __used test_rwsem_assert(struct test_rwsem_data *d)
337{
338 rwsem_assert_held_nolockdep(&d->sem);
339 d->counter++;
340}
341
342static void __used test_rwsem_guard(struct test_rwsem_data *d)
343{
344 { guard(rwsem_read)(&d->sem); (void)d->counter; }
345 { guard(rwsem_write)(&d->sem); d->counter++; }
346}
347
348static void __used test_rwsem_cond_guard(struct test_rwsem_data *d)
349{
350 scoped_cond_guard(rwsem_read_try, return, &d->sem) {
351 (void)d->counter;
352 }
353 scoped_cond_guard(rwsem_write_try, return, &d->sem) {
354 d->counter++;
355 }
356}
357
358struct test_bit_spinlock_data {
359 unsigned long bits;
360 int counter __guarded_by(__bitlock(3, &bits));
361};
362
363static void __used test_bit_spin_lock(struct test_bit_spinlock_data *d)
364{
365 /*
366 * Note, the analysis seems to have false negatives, because it won't
367 * precisely recognize the bit of the fake __bitlock() token.
368 */
369 bit_spin_lock(3, &d->bits);
370 d->counter++;
371 bit_spin_unlock(3, &d->bits);
372
373 bit_spin_lock(3, &d->bits);
374 d->counter++;
375 __bit_spin_unlock(3, &d->bits);
376
377 if (bit_spin_trylock(3, &d->bits)) {
378 d->counter++;
379 bit_spin_unlock(3, &d->bits);
380 }
381}
382
383/*
384 * Test that we can mark a variable guarded by RCU, and we can dereference and
385 * write to the pointer with RCU's primitives.
386 */
387struct test_rcu_data {
388 long __rcu_guarded *data;
389};
390
391static void __used test_rcu_guarded_reader(struct test_rcu_data *d)
392{
393 rcu_read_lock();
394 (void)rcu_dereference(d->data);
395 rcu_read_unlock();
396
397 rcu_read_lock_bh();
398 (void)rcu_dereference(d->data);
399 rcu_read_unlock_bh();
400
401 rcu_read_lock_sched();
402 (void)rcu_dereference(d->data);
403 rcu_read_unlock_sched();
404}
405
406static void __used test_rcu_guard(struct test_rcu_data *d)
407{
408 guard(rcu)();
409 (void)rcu_dereference(d->data);
410}
411
412static void __used test_rcu_guarded_updater(struct test_rcu_data *d)
413{
414 rcu_assign_pointer(d->data, NULL);
415 RCU_INIT_POINTER(d->data, NULL);
416 (void)unrcu_pointer(d->data);
417}
418
419static void wants_rcu_held(void) __must_hold_shared(RCU) { }
420static void wants_rcu_held_bh(void) __must_hold_shared(RCU_BH) { }
421static void wants_rcu_held_sched(void) __must_hold_shared(RCU_SCHED) { }
422
423static void __used test_rcu_lock_variants(void)
424{
425 rcu_read_lock();
426 wants_rcu_held();
427 rcu_read_unlock();
428
429 rcu_read_lock_bh();
430 wants_rcu_held_bh();
431 rcu_read_unlock_bh();
432
433 rcu_read_lock_sched();
434 wants_rcu_held_sched();
435 rcu_read_unlock_sched();
436}
437
438static void __used test_rcu_lock_reentrant(void)
439{
440 rcu_read_lock();
441 rcu_read_lock();
442 rcu_read_lock_bh();
443 rcu_read_lock_bh();
444 rcu_read_lock_sched();
445 rcu_read_lock_sched();
446
447 rcu_read_unlock_sched();
448 rcu_read_unlock_sched();
449 rcu_read_unlock_bh();
450 rcu_read_unlock_bh();
451 rcu_read_unlock();
452 rcu_read_unlock();
453}
454
455static void __used test_rcu_assert_variants(void)
456{
457 lockdep_assert_in_rcu_read_lock();
458 wants_rcu_held();
459
460 lockdep_assert_in_rcu_read_lock_bh();
461 wants_rcu_held_bh();
462
463 lockdep_assert_in_rcu_read_lock_sched();
464 wants_rcu_held_sched();
465}
466
467struct test_srcu_data {
468 struct srcu_struct srcu;
469 long __rcu_guarded *data;
470};
471
472static void __used test_srcu(struct test_srcu_data *d)
473{
474 init_srcu_struct(&d->srcu);
475
476 int idx = srcu_read_lock(&d->srcu);
477 long *data = srcu_dereference(d->data, &d->srcu);
478 (void)data;
479 srcu_read_unlock(&d->srcu, idx);
480
481 rcu_assign_pointer(d->data, NULL);
482}
483
484static void __used test_srcu_guard(struct test_srcu_data *d)
485{
486 { guard(srcu)(&d->srcu); (void)srcu_dereference(d->data, &d->srcu); }
487 { guard(srcu_fast)(&d->srcu); (void)srcu_dereference(d->data, &d->srcu); }
488 { guard(srcu_fast_notrace)(&d->srcu); (void)srcu_dereference(d->data, &d->srcu); }
489}
490
491struct test_local_lock_data {
492 local_lock_t lock;
493 int counter __guarded_by(&lock);
494};
495
496static DEFINE_PER_CPU(struct test_local_lock_data, test_local_lock_data) = {
497 .lock = INIT_LOCAL_LOCK(lock),
498};
499
500static void __used test_local_lock_init(struct test_local_lock_data *d)
501{
502 guard(local_lock_init)(&d->lock);
503 d->counter = 0;
504}
505
506static void __used test_local_lock(void)
507{
508 unsigned long flags;
509
510 local_lock(&test_local_lock_data.lock);
511 this_cpu_add(test_local_lock_data.counter, 1);
512 local_unlock(&test_local_lock_data.lock);
513
514 local_lock_irq(&test_local_lock_data.lock);
515 this_cpu_add(test_local_lock_data.counter, 1);
516 local_unlock_irq(&test_local_lock_data.lock);
517
518 local_lock_irqsave(&test_local_lock_data.lock, flags);
519 this_cpu_add(test_local_lock_data.counter, 1);
520 local_unlock_irqrestore(&test_local_lock_data.lock, flags);
521
522 local_lock_nested_bh(&test_local_lock_data.lock);
523 this_cpu_add(test_local_lock_data.counter, 1);
524 local_unlock_nested_bh(&test_local_lock_data.lock);
525}
526
527static void __used test_local_lock_guard(void)
528{
529 { guard(local_lock)(&test_local_lock_data.lock); this_cpu_add(test_local_lock_data.counter, 1); }
530 { guard(local_lock_irq)(&test_local_lock_data.lock); this_cpu_add(test_local_lock_data.counter, 1); }
531 { guard(local_lock_irqsave)(&test_local_lock_data.lock); this_cpu_add(test_local_lock_data.counter, 1); }
532 { guard(local_lock_nested_bh)(&test_local_lock_data.lock); this_cpu_add(test_local_lock_data.counter, 1); }
533}
534
535struct test_local_trylock_data {
536 local_trylock_t lock;
537 int counter __guarded_by(&lock);
538};
539
540static DEFINE_PER_CPU(struct test_local_trylock_data, test_local_trylock_data) = {
541 .lock = INIT_LOCAL_TRYLOCK(lock),
542};
543
544static void __used test_local_trylock_init(struct test_local_trylock_data *d)
545{
546 guard(local_trylock_init)(&d->lock);
547 d->counter = 0;
548}
549
550static void __used test_local_trylock(void)
551{
552 local_lock(&test_local_trylock_data.lock);
553 this_cpu_add(test_local_trylock_data.counter, 1);
554 local_unlock(&test_local_trylock_data.lock);
555
556 if (local_trylock(&test_local_trylock_data.lock)) {
557 this_cpu_add(test_local_trylock_data.counter, 1);
558 local_unlock(&test_local_trylock_data.lock);
559 }
560}
561
562static DEFINE_WD_CLASS(ww_class);
563
564struct test_ww_mutex_data {
565 struct ww_mutex mtx;
566 int counter __guarded_by(&mtx);
567};
568
569static void __used test_ww_mutex_lock_noctx(struct test_ww_mutex_data *d)
570{
571 if (!ww_mutex_lock(&d->mtx, NULL)) {
572 d->counter++;
573 ww_mutex_unlock(&d->mtx);
574 }
575
576 if (!ww_mutex_lock_interruptible(&d->mtx, NULL)) {
577 d->counter++;
578 ww_mutex_unlock(&d->mtx);
579 }
580
581 if (ww_mutex_trylock(&d->mtx, NULL)) {
582 d->counter++;
583 ww_mutex_unlock(&d->mtx);
584 }
585
586 ww_mutex_lock_slow(&d->mtx, NULL);
587 d->counter++;
588 ww_mutex_unlock(&d->mtx);
589
590 ww_mutex_destroy(&d->mtx);
591}
592
593static void __used test_ww_mutex_lock_ctx(struct test_ww_mutex_data *d)
594{
595 struct ww_acquire_ctx ctx;
596
597 ww_acquire_init(&ctx, &ww_class);
598
599 if (!ww_mutex_lock(&d->mtx, &ctx)) {
600 d->counter++;
601 ww_mutex_unlock(&d->mtx);
602 }
603
604 if (!ww_mutex_lock_interruptible(&d->mtx, &ctx)) {
605 d->counter++;
606 ww_mutex_unlock(&d->mtx);
607 }
608
609 if (ww_mutex_trylock(&d->mtx, &ctx)) {
610 d->counter++;
611 ww_mutex_unlock(&d->mtx);
612 }
613
614 ww_mutex_lock_slow(&d->mtx, &ctx);
615 d->counter++;
616 ww_mutex_unlock(&d->mtx);
617
618 ww_acquire_done(&ctx);
619 ww_acquire_fini(&ctx);
620
621 ww_mutex_destroy(&d->mtx);
622}
623
624static DEFINE_PER_CPU(raw_spinlock_t, test_per_cpu_lock);
625
626static void __used test_per_cpu(int cpu)
627{
628 raw_spin_lock(&per_cpu(test_per_cpu_lock, cpu));
629 raw_spin_unlock(&per_cpu(test_per_cpu_lock, cpu));
630
631 raw_spin_lock(per_cpu_ptr(&test_per_cpu_lock, cpu));
632 raw_spin_unlock(per_cpu_ptr(&test_per_cpu_lock, cpu));
633}