ast.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /******************************************************************************
  3. *******************************************************************************
  4. **
  5. ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
  6. ** Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
  7. **
  8. **
  9. *******************************************************************************
  10. ******************************************************************************/
  11. #include <trace/events/dlm.h>
  12. #include "dlm_internal.h"
  13. #include "lvb_table.h"
  14. #include "memory.h"
  15. #include "lock.h"
  16. #include "user.h"
  17. #include "ast.h"
  18. static void dlm_run_callback(uint32_t ls_id, uint32_t lkb_id, int8_t mode,
  19. uint32_t flags, uint8_t sb_flags, int sb_status,
  20. struct dlm_lksb *lksb,
  21. void (*astfn)(void *astparam),
  22. void (*bastfn)(void *astparam, int mode),
  23. void *astparam, const char *res_name,
  24. size_t res_length)
  25. {
  26. if (flags & DLM_CB_BAST) {
  27. trace_dlm_bast(ls_id, lkb_id, mode, res_name, res_length);
  28. bastfn(astparam, mode);
  29. } else if (flags & DLM_CB_CAST) {
  30. trace_dlm_ast(ls_id, lkb_id, sb_flags, sb_status, res_name,
  31. res_length);
  32. lksb->sb_status = sb_status;
  33. lksb->sb_flags = sb_flags;
  34. astfn(astparam);
  35. }
  36. }
  37. static void dlm_do_callback(struct dlm_callback *cb)
  38. {
  39. dlm_run_callback(cb->ls_id, cb->lkb_id, cb->mode, cb->flags,
  40. cb->sb_flags, cb->sb_status, cb->lkb_lksb,
  41. cb->astfn, cb->bastfn, cb->astparam,
  42. cb->res_name, cb->res_length);
  43. dlm_free_cb(cb);
  44. }
  45. static void dlm_callback_work(struct work_struct *work)
  46. {
  47. struct dlm_callback *cb = container_of(work, struct dlm_callback, work);
  48. dlm_do_callback(cb);
  49. }
  50. bool dlm_may_skip_callback(struct dlm_lkb *lkb, uint32_t flags, int mode,
  51. int status, uint32_t sbflags, int *copy_lvb)
  52. {
  53. struct dlm_rsb *rsb = lkb->lkb_resource;
  54. struct dlm_ls *ls = rsb->res_ls;
  55. int prev_mode;
  56. if (copy_lvb)
  57. *copy_lvb = 0;
  58. if (flags & DLM_CB_BAST) {
  59. /* if cb is a bast, it should be skipped if the blocking mode is
  60. * compatible with the last granted mode
  61. */
  62. if (lkb->lkb_last_cast_cb_mode != -1) {
  63. if (dlm_modes_compat(mode, lkb->lkb_last_cast_cb_mode)) {
  64. log_debug(ls, "skip %x bast mode %d for cast mode %d",
  65. lkb->lkb_id, mode,
  66. lkb->lkb_last_cast_cb_mode);
  67. return true;
  68. }
  69. }
  70. /*
  71. * Suppress some redundant basts here, do more on removal.
  72. * Don't even add a bast if the callback just before it
  73. * is a bast for the same mode or a more restrictive mode.
  74. * (the addional > PR check is needed for PR/CW inversion)
  75. */
  76. if (lkb->lkb_last_cb_mode != -1 &&
  77. lkb->lkb_last_cb_flags & DLM_CB_BAST) {
  78. prev_mode = lkb->lkb_last_cb_mode;
  79. if ((prev_mode == mode) ||
  80. (prev_mode > mode && prev_mode > DLM_LOCK_PR)) {
  81. log_debug(ls, "skip %x add bast mode %d for bast mode %d",
  82. lkb->lkb_id, mode, prev_mode);
  83. return true;
  84. }
  85. }
  86. lkb->lkb_last_bast_time = ktime_get();
  87. lkb->lkb_last_bast_cb_mode = mode;
  88. } else if (flags & DLM_CB_CAST) {
  89. if (test_bit(DLM_DFL_USER_BIT, &lkb->lkb_dflags)) {
  90. prev_mode = lkb->lkb_last_cast_cb_mode;
  91. if (!status && lkb->lkb_lksb->sb_lvbptr &&
  92. dlm_lvb_operations[prev_mode + 1][mode + 1]) {
  93. if (copy_lvb)
  94. *copy_lvb = 1;
  95. }
  96. }
  97. lkb->lkb_last_cast_cb_mode = mode;
  98. lkb->lkb_last_cast_time = ktime_get();
  99. }
  100. lkb->lkb_last_cb_mode = mode;
  101. lkb->lkb_last_cb_flags = flags;
  102. return false;
  103. }
  104. int dlm_get_cb(struct dlm_lkb *lkb, uint32_t flags, int mode,
  105. int status, uint32_t sbflags,
  106. struct dlm_callback **cb)
  107. {
  108. struct dlm_rsb *rsb = lkb->lkb_resource;
  109. struct dlm_ls *ls = rsb->res_ls;
  110. *cb = dlm_allocate_cb();
  111. if (WARN_ON_ONCE(!*cb))
  112. return -ENOMEM;
  113. /* for tracing */
  114. (*cb)->lkb_id = lkb->lkb_id;
  115. (*cb)->ls_id = ls->ls_global_id;
  116. memcpy((*cb)->res_name, rsb->res_name, rsb->res_length);
  117. (*cb)->res_length = rsb->res_length;
  118. (*cb)->flags = flags;
  119. (*cb)->mode = mode;
  120. (*cb)->sb_status = status;
  121. (*cb)->sb_flags = (sbflags & 0x000000FF);
  122. (*cb)->lkb_lksb = lkb->lkb_lksb;
  123. return 0;
  124. }
  125. static int dlm_get_queue_cb(struct dlm_lkb *lkb, uint32_t flags, int mode,
  126. int status, uint32_t sbflags,
  127. struct dlm_callback **cb)
  128. {
  129. int rv;
  130. rv = dlm_get_cb(lkb, flags, mode, status, sbflags, cb);
  131. if (rv)
  132. return rv;
  133. (*cb)->astfn = lkb->lkb_astfn;
  134. (*cb)->bastfn = lkb->lkb_bastfn;
  135. (*cb)->astparam = lkb->lkb_astparam;
  136. INIT_WORK(&(*cb)->work, dlm_callback_work);
  137. return 0;
  138. }
  139. void dlm_add_cb(struct dlm_lkb *lkb, uint32_t flags, int mode, int status,
  140. uint32_t sbflags)
  141. {
  142. struct dlm_rsb *rsb = lkb->lkb_resource;
  143. struct dlm_ls *ls = rsb->res_ls;
  144. struct dlm_callback *cb;
  145. int rv;
  146. if (test_bit(DLM_DFL_USER_BIT, &lkb->lkb_dflags)) {
  147. dlm_user_add_ast(lkb, flags, mode, status, sbflags);
  148. return;
  149. }
  150. if (dlm_may_skip_callback(lkb, flags, mode, status, sbflags, NULL))
  151. return;
  152. spin_lock_bh(&ls->ls_cb_lock);
  153. if (test_bit(LSFL_CB_DELAY, &ls->ls_flags)) {
  154. rv = dlm_get_queue_cb(lkb, flags, mode, status, sbflags, &cb);
  155. if (!rv)
  156. list_add(&cb->list, &ls->ls_cb_delay);
  157. } else {
  158. if (test_bit(LSFL_SOFTIRQ, &ls->ls_flags)) {
  159. dlm_run_callback(ls->ls_global_id, lkb->lkb_id, mode, flags,
  160. sbflags, status, lkb->lkb_lksb,
  161. lkb->lkb_astfn, lkb->lkb_bastfn,
  162. lkb->lkb_astparam, rsb->res_name,
  163. rsb->res_length);
  164. } else {
  165. rv = dlm_get_queue_cb(lkb, flags, mode, status, sbflags, &cb);
  166. if (!rv)
  167. queue_work(ls->ls_callback_wq, &cb->work);
  168. }
  169. }
  170. spin_unlock_bh(&ls->ls_cb_lock);
  171. }
  172. int dlm_callback_start(struct dlm_ls *ls)
  173. {
  174. if (!test_bit(LSFL_FS, &ls->ls_flags) ||
  175. test_bit(LSFL_SOFTIRQ, &ls->ls_flags))
  176. return 0;
  177. ls->ls_callback_wq = alloc_ordered_workqueue("dlm_callback",
  178. WQ_HIGHPRI | WQ_MEM_RECLAIM);
  179. if (!ls->ls_callback_wq) {
  180. log_print("can't start dlm_callback workqueue");
  181. return -ENOMEM;
  182. }
  183. return 0;
  184. }
  185. void dlm_callback_stop(struct dlm_ls *ls)
  186. {
  187. if (ls->ls_callback_wq)
  188. destroy_workqueue(ls->ls_callback_wq);
  189. }
  190. void dlm_callback_suspend(struct dlm_ls *ls)
  191. {
  192. if (!test_bit(LSFL_FS, &ls->ls_flags))
  193. return;
  194. spin_lock_bh(&ls->ls_cb_lock);
  195. set_bit(LSFL_CB_DELAY, &ls->ls_flags);
  196. spin_unlock_bh(&ls->ls_cb_lock);
  197. if (ls->ls_callback_wq)
  198. flush_workqueue(ls->ls_callback_wq);
  199. }
  200. #define MAX_CB_QUEUE 25
  201. void dlm_callback_resume(struct dlm_ls *ls)
  202. {
  203. struct dlm_callback *cb, *safe;
  204. int count = 0, sum = 0;
  205. bool empty;
  206. if (!test_bit(LSFL_FS, &ls->ls_flags))
  207. return;
  208. more:
  209. spin_lock_bh(&ls->ls_cb_lock);
  210. list_for_each_entry_safe(cb, safe, &ls->ls_cb_delay, list) {
  211. list_del(&cb->list);
  212. if (test_bit(LSFL_SOFTIRQ, &ls->ls_flags))
  213. dlm_do_callback(cb);
  214. else
  215. queue_work(ls->ls_callback_wq, &cb->work);
  216. count++;
  217. if (count == MAX_CB_QUEUE)
  218. break;
  219. }
  220. empty = list_empty(&ls->ls_cb_delay);
  221. if (empty)
  222. clear_bit(LSFL_CB_DELAY, &ls->ls_flags);
  223. spin_unlock_bh(&ls->ls_cb_lock);
  224. sum += count;
  225. if (!empty) {
  226. count = 0;
  227. cond_resched();
  228. goto more;
  229. }
  230. if (sum)
  231. log_rinfo(ls, "%s %d", __func__, sum);
  232. }