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/build_bug.h> 8 #include <linux/spinlock.h> 9 10 /* 11 * Test that helper macros work as expected. 12 */ 13 static void __used test_common_helpers(void) 14 { 15 BUILD_BUG_ON(context_unsafe(3) != 3); /* plain expression */ 16 BUILD_BUG_ON(context_unsafe((void)2; 3) != 3); /* does not swallow semi-colon */ 17 BUILD_BUG_ON(context_unsafe((void)2, 3) != 3); /* does not swallow commas */ 18 context_unsafe(do { } while (0)); /* works with void statements */ 19 } 20 21 #define TEST_SPINLOCK_COMMON(class, type, type_init, type_lock, type_unlock, type_trylock, op) \ 22 struct test_##class##_data { \ 23 type lock; \ 24 int counter __guarded_by(&lock); \ 25 int *pointer __pt_guarded_by(&lock); \ 26 }; \ 27 static void __used test_##class##_init(struct test_##class##_data *d) \ 28 { \ 29 type_init(&d->lock); \ 30 d->counter = 0; \ 31 } \ 32 static void __used test_##class(struct test_##class##_data *d) \ 33 { \ 34 unsigned long flags; \ 35 d->pointer++; \ 36 type_lock(&d->lock); \ 37 op(d->counter); \ 38 op(*d->pointer); \ 39 type_unlock(&d->lock); \ 40 type_lock##_irq(&d->lock); \ 41 op(d->counter); \ 42 op(*d->pointer); \ 43 type_unlock##_irq(&d->lock); \ 44 type_lock##_bh(&d->lock); \ 45 op(d->counter); \ 46 op(*d->pointer); \ 47 type_unlock##_bh(&d->lock); \ 48 type_lock##_irqsave(&d->lock, flags); \ 49 op(d->counter); \ 50 op(*d->pointer); \ 51 type_unlock##_irqrestore(&d->lock, flags); \ 52 } \ 53 static void __used test_##class##_trylock(struct test_##class##_data *d) \ 54 { \ 55 if (type_trylock(&d->lock)) { \ 56 op(d->counter); \ 57 type_unlock(&d->lock); \ 58 } \ 59 } \ 60 static void __used test_##class##_assert(struct test_##class##_data *d) \ 61 { \ 62 lockdep_assert_held(&d->lock); \ 63 op(d->counter); \ 64 } \ 65 static void __used test_##class##_guard(struct test_##class##_data *d) \ 66 { \ 67 { guard(class)(&d->lock); op(d->counter); } \ 68 { guard(class##_irq)(&d->lock); op(d->counter); } \ 69 { guard(class##_irqsave)(&d->lock); op(d->counter); } \ 70 } 71 72 #define TEST_OP_RW(x) (x)++ 73 #define TEST_OP_RO(x) ((void)(x)) 74 75 TEST_SPINLOCK_COMMON(raw_spinlock, 76 raw_spinlock_t, 77 raw_spin_lock_init, 78 raw_spin_lock, 79 raw_spin_unlock, 80 raw_spin_trylock, 81 TEST_OP_RW); 82 static void __used test_raw_spinlock_trylock_extra(struct test_raw_spinlock_data *d) 83 { 84 unsigned long flags; 85 86 if (raw_spin_trylock_irq(&d->lock)) { 87 d->counter++; 88 raw_spin_unlock_irq(&d->lock); 89 } 90 if (raw_spin_trylock_irqsave(&d->lock, flags)) { 91 d->counter++; 92 raw_spin_unlock_irqrestore(&d->lock, flags); 93 } 94 scoped_cond_guard(raw_spinlock_try, return, &d->lock) { 95 d->counter++; 96 } 97 } 98 99 TEST_SPINLOCK_COMMON(spinlock, 100 spinlock_t, 101 spin_lock_init, 102 spin_lock, 103 spin_unlock, 104 spin_trylock, 105 TEST_OP_RW); 106 static void __used test_spinlock_trylock_extra(struct test_spinlock_data *d) 107 { 108 unsigned long flags; 109 110 if (spin_trylock_irq(&d->lock)) { 111 d->counter++; 112 spin_unlock_irq(&d->lock); 113 } 114 if (spin_trylock_irqsave(&d->lock, flags)) { 115 d->counter++; 116 spin_unlock_irqrestore(&d->lock, flags); 117 } 118 scoped_cond_guard(spinlock_try, return, &d->lock) { 119 d->counter++; 120 } 121 } 122 123 TEST_SPINLOCK_COMMON(write_lock, 124 rwlock_t, 125 rwlock_init, 126 write_lock, 127 write_unlock, 128 write_trylock, 129 TEST_OP_RW); 130 static void __used test_write_trylock_extra(struct test_write_lock_data *d) 131 { 132 unsigned long flags; 133 134 if (write_trylock_irqsave(&d->lock, flags)) { 135 d->counter++; 136 write_unlock_irqrestore(&d->lock, flags); 137 } 138 } 139 140 TEST_SPINLOCK_COMMON(read_lock, 141 rwlock_t, 142 rwlock_init, 143 read_lock, 144 read_unlock, 145 read_trylock, 146 TEST_OP_RO); 147