1 // SPDX-License-Identifier: GPL-2.0-only 2 #include <linux/module.h> 3 4 /* validate @native and @pcp counter values match @expected */ 5 #define CHECK(native, pcp, expected) \ 6 do { \ 7 WARN((native) != (expected), \ 8 "raw %ld (0x%lx) != expected %lld (0x%llx)", \ 9 (native), (native), \ 10 (long long)(expected), (long long)(expected)); \ 11 WARN(__this_cpu_read(pcp) != (expected), \ 12 "pcp %ld (0x%lx) != expected %lld (0x%llx)", \ 13 __this_cpu_read(pcp), __this_cpu_read(pcp), \ 14 (long long)(expected), (long long)(expected)); \ 15 } while (0) 16 17 static DEFINE_PER_CPU(long, long_counter); 18 static DEFINE_PER_CPU(unsigned long, ulong_counter); 19 20 static int __init percpu_test_init(void) 21 { 22 /* 23 * volatile prevents compiler from optimizing it uses, otherwise the 24 * +ul_one/-ul_one below would replace with inc/dec instructions. 25 */ 26 volatile unsigned int ui_one = 1; 27 long l = 0; 28 unsigned long ul = 0; 29 30 pr_info("percpu test start\n"); 31 32 preempt_disable(); 33 34 l += -1; 35 __this_cpu_add(long_counter, -1); 36 CHECK(l, long_counter, -1); 37 38 l += 1; 39 __this_cpu_add(long_counter, 1); 40 CHECK(l, long_counter, 0); 41 42 ul = 0; 43 __this_cpu_write(ulong_counter, 0); 44 45 ul += 1UL; 46 __this_cpu_add(ulong_counter, 1UL); 47 CHECK(ul, ulong_counter, 1); 48 49 ul += -1UL; 50 __this_cpu_add(ulong_counter, -1UL); 51 CHECK(ul, ulong_counter, 0); 52 53 ul += -(unsigned long)1; 54 __this_cpu_add(ulong_counter, -(unsigned long)1); 55 CHECK(ul, ulong_counter, -1); 56 57 ul = 0; 58 __this_cpu_write(ulong_counter, 0); 59 60 ul -= 1; 61 __this_cpu_dec(ulong_counter); 62 CHECK(ul, ulong_counter, -1); 63 CHECK(ul, ulong_counter, ULONG_MAX); 64 65 l += -ui_one; 66 __this_cpu_add(long_counter, -ui_one); 67 CHECK(l, long_counter, 0xffffffff); 68 69 l += ui_one; 70 __this_cpu_add(long_counter, ui_one); 71 CHECK(l, long_counter, (long)0x100000000LL); 72 73 74 l = 0; 75 __this_cpu_write(long_counter, 0); 76 77 l -= ui_one; 78 __this_cpu_sub(long_counter, ui_one); 79 CHECK(l, long_counter, -1); 80 81 l = 0; 82 __this_cpu_write(long_counter, 0); 83 84 l += ui_one; 85 __this_cpu_add(long_counter, ui_one); 86 CHECK(l, long_counter, 1); 87 88 l += -ui_one; 89 __this_cpu_add(long_counter, -ui_one); 90 CHECK(l, long_counter, (long)0x100000000LL); 91 92 l = 0; 93 __this_cpu_write(long_counter, 0); 94 95 l -= ui_one; 96 this_cpu_sub(long_counter, ui_one); 97 CHECK(l, long_counter, -1); 98 CHECK(l, long_counter, ULONG_MAX); 99 100 ul = 0; 101 __this_cpu_write(ulong_counter, 0); 102 103 ul += ui_one; 104 __this_cpu_add(ulong_counter, ui_one); 105 CHECK(ul, ulong_counter, 1); 106 107 ul = 0; 108 __this_cpu_write(ulong_counter, 0); 109 110 ul -= ui_one; 111 __this_cpu_sub(ulong_counter, ui_one); 112 CHECK(ul, ulong_counter, -1); 113 CHECK(ul, ulong_counter, ULONG_MAX); 114 115 ul = 3; 116 __this_cpu_write(ulong_counter, 3); 117 118 ul = this_cpu_sub_return(ulong_counter, ui_one); 119 CHECK(ul, ulong_counter, 2); 120 121 ul = __this_cpu_sub_return(ulong_counter, ui_one); 122 CHECK(ul, ulong_counter, 1); 123 124 preempt_enable(); 125 126 pr_info("percpu test done\n"); 127 return -EAGAIN; /* Fail will directly unload the module */ 128 } 129 130 static void __exit percpu_test_exit(void) 131 { 132 } 133 134 module_init(percpu_test_init) 135 module_exit(percpu_test_exit) 136 137 MODULE_LICENSE("GPL"); 138 MODULE_AUTHOR("Greg Thelen"); 139 MODULE_DESCRIPTION("percpu operations test"); 140
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.