lglock.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /*
  2. * Specialised local-global spinlock. Can only be declared as global variables
  3. * to avoid overhead and keep things simple (and we don't want to start using
  4. * these inside dynamically allocated structures).
  5. *
  6. * "local/global locks" (lglocks) can be used to:
  7. *
  8. * - Provide fast exclusive access to per-CPU data, with exclusive access to
  9. * another CPU's data allowed but possibly subject to contention, and to
  10. * provide very slow exclusive access to all per-CPU data.
  11. * - Or to provide very fast and scalable read serialisation, and to provide
  12. * very slow exclusive serialisation of data (not necessarily per-CPU data).
  13. *
  14. * Brlocks are also implemented as a short-hand notation for the latter use
  15. * case.
  16. *
  17. * Copyright 2009, 2010, Nick Piggin, Novell Inc.
  18. */
  19. #ifndef __LINUX_LGLOCK_H
  20. #define __LINUX_LGLOCK_H
  21. #include <linux/spinlock.h>
  22. #include <linux/lockdep.h>
  23. #include <linux/percpu.h>
  24. /* can make br locks by using local lock for read side, global lock for write */
  25. #define br_lock_init(name) name##_lock_init()
  26. #define br_read_lock(name) name##_local_lock()
  27. #define br_read_unlock(name) name##_local_unlock()
  28. #define br_write_lock(name) name##_global_lock_online()
  29. #define br_write_unlock(name) name##_global_unlock_online()
  30. #define DECLARE_BRLOCK(name) DECLARE_LGLOCK(name)
  31. #define DEFINE_BRLOCK(name) DEFINE_LGLOCK(name)
  32. #define lg_lock_init(name) name##_lock_init()
  33. #define lg_local_lock(name) name##_local_lock()
  34. #define lg_local_unlock(name) name##_local_unlock()
  35. #define lg_local_lock_cpu(name, cpu) name##_local_lock_cpu(cpu)
  36. #define lg_local_unlock_cpu(name, cpu) name##_local_unlock_cpu(cpu)
  37. #define lg_global_lock(name) name##_global_lock()
  38. #define lg_global_unlock(name) name##_global_unlock()
  39. #define lg_global_lock_online(name) name##_global_lock_online()
  40. #define lg_global_unlock_online(name) name##_global_unlock_online()
  41. #ifdef CONFIG_DEBUG_LOCK_ALLOC
  42. #define LOCKDEP_INIT_MAP lockdep_init_map
  43. #define DEFINE_LGLOCK_LOCKDEP(name) \
  44. struct lock_class_key name##_lock_key; \
  45. struct lockdep_map name##_lock_dep_map; \
  46. EXPORT_SYMBOL(name##_lock_dep_map)
  47. #else
  48. #define LOCKDEP_INIT_MAP(a, b, c, d)
  49. #define DEFINE_LGLOCK_LOCKDEP(name)
  50. #endif
  51. #define DECLARE_LGLOCK(name) \
  52. extern void name##_lock_init(void); \
  53. extern void name##_local_lock(void); \
  54. extern void name##_local_unlock(void); \
  55. extern void name##_local_lock_cpu(int cpu); \
  56. extern void name##_local_unlock_cpu(int cpu); \
  57. extern void name##_global_lock(void); \
  58. extern void name##_global_unlock(void); \
  59. extern void name##_global_lock_online(void); \
  60. extern void name##_global_unlock_online(void); \
  61. #define DEFINE_LGLOCK(name) \
  62. \
  63. DEFINE_PER_CPU(arch_spinlock_t, name##_lock); \
  64. DEFINE_LGLOCK_LOCKDEP(name); \
  65. \
  66. void name##_lock_init(void) { \
  67. int i; \
  68. LOCKDEP_INIT_MAP(&name##_lock_dep_map, #name, &name##_lock_key, 0); \
  69. for_each_possible_cpu(i) { \
  70. arch_spinlock_t *lock; \
  71. lock = &per_cpu(name##_lock, i); \
  72. *lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; \
  73. } \
  74. } \
  75. EXPORT_SYMBOL(name##_lock_init); \
  76. \
  77. void name##_local_lock(void) { \
  78. arch_spinlock_t *lock; \
  79. preempt_disable(); \
  80. rwlock_acquire_read(&name##_lock_dep_map, 0, 0, _THIS_IP_); \
  81. lock = &__get_cpu_var(name##_lock); \
  82. arch_spin_lock(lock); \
  83. } \
  84. EXPORT_SYMBOL(name##_local_lock); \
  85. \
  86. void name##_local_unlock(void) { \
  87. arch_spinlock_t *lock; \
  88. rwlock_release(&name##_lock_dep_map, 1, _THIS_IP_); \
  89. lock = &__get_cpu_var(name##_lock); \
  90. arch_spin_unlock(lock); \
  91. preempt_enable(); \
  92. } \
  93. EXPORT_SYMBOL(name##_local_unlock); \
  94. \
  95. void name##_local_lock_cpu(int cpu) { \
  96. arch_spinlock_t *lock; \
  97. preempt_disable(); \
  98. rwlock_acquire_read(&name##_lock_dep_map, 0, 0, _THIS_IP_); \
  99. lock = &per_cpu(name##_lock, cpu); \
  100. arch_spin_lock(lock); \
  101. } \
  102. EXPORT_SYMBOL(name##_local_lock_cpu); \
  103. \
  104. void name##_local_unlock_cpu(int cpu) { \
  105. arch_spinlock_t *lock; \
  106. rwlock_release(&name##_lock_dep_map, 1, _THIS_IP_); \
  107. lock = &per_cpu(name##_lock, cpu); \
  108. arch_spin_unlock(lock); \
  109. preempt_enable(); \
  110. } \
  111. EXPORT_SYMBOL(name##_local_unlock_cpu); \
  112. \
  113. void name##_global_lock_online(void) { \
  114. int i; \
  115. preempt_disable(); \
  116. rwlock_acquire(&name##_lock_dep_map, 0, 0, _RET_IP_); \
  117. for_each_online_cpu(i) { \
  118. arch_spinlock_t *lock; \
  119. lock = &per_cpu(name##_lock, i); \
  120. arch_spin_lock(lock); \
  121. } \
  122. } \
  123. EXPORT_SYMBOL(name##_global_lock_online); \
  124. \
  125. void name##_global_unlock_online(void) { \
  126. int i; \
  127. rwlock_release(&name##_lock_dep_map, 1, _RET_IP_); \
  128. for_each_online_cpu(i) { \
  129. arch_spinlock_t *lock; \
  130. lock = &per_cpu(name##_lock, i); \
  131. arch_spin_unlock(lock); \
  132. } \
  133. preempt_enable(); \
  134. } \
  135. EXPORT_SYMBOL(name##_global_unlock_online); \
  136. \
  137. void name##_global_lock(void) { \
  138. int i; \
  139. preempt_disable(); \
  140. rwlock_acquire(&name##_lock_dep_map, 0, 0, _RET_IP_); \
  141. for_each_online_cpu(i) { \
  142. arch_spinlock_t *lock; \
  143. lock = &per_cpu(name##_lock, i); \
  144. arch_spin_lock(lock); \
  145. } \
  146. } \
  147. EXPORT_SYMBOL(name##_global_lock); \
  148. \
  149. void name##_global_unlock(void) { \
  150. int i; \
  151. rwlock_release(&name##_lock_dep_map, 1, _RET_IP_); \
  152. for_each_online_cpu(i) { \
  153. arch_spinlock_t *lock; \
  154. lock = &per_cpu(name##_lock, i); \
  155. arch_spin_unlock(lock); \
  156. } \
  157. preempt_enable(); \
  158. } \
  159. EXPORT_SYMBOL(name##_global_unlock);
  160. #endif