percpu_test.c 3.2 KB

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