Blame view
fs/dlm/ast.c
8.03 KB
e7fd41792 [DLM] The core of... |
1 2 3 4 |
/****************************************************************************** ******************************************************************************* ** ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. |
7fe2b3190 dlm: fix ordering... |
5 |
** Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved. |
e7fd41792 [DLM] The core of... |
6 7 8 9 10 11 12 13 14 15 |
** ** This copyrighted material is made available to anyone wishing to use, ** modify, copy, or redistribute it subject to the terms and conditions ** of the GNU General Public License v.2. ** ******************************************************************************* ******************************************************************************/ #include "dlm_internal.h" #include "lock.h" |
597d0cae0 [DLM] dlm: user l... |
16 |
#include "user.h" |
e7fd41792 [DLM] The core of... |
17 |
|
23e8e1aaa dlm: use workqueu... |
18 19 |
static uint64_t dlm_cb_seq; static spinlock_t dlm_cb_seq_spin; |
e7fd41792 [DLM] The core of... |
20 |
|
8304d6f24 dlm: record full ... |
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
static void dlm_dump_lkb_callbacks(struct dlm_lkb *lkb) { int i; log_print("last_bast %x %llu flags %x mode %d sb %d %x", lkb->lkb_id, (unsigned long long)lkb->lkb_last_bast.seq, lkb->lkb_last_bast.flags, lkb->lkb_last_bast.mode, lkb->lkb_last_bast.sb_status, lkb->lkb_last_bast.sb_flags); log_print("last_cast %x %llu flags %x mode %d sb %d %x", lkb->lkb_id, (unsigned long long)lkb->lkb_last_cast.seq, lkb->lkb_last_cast.flags, lkb->lkb_last_cast.mode, lkb->lkb_last_cast.sb_status, lkb->lkb_last_cast.sb_flags); for (i = 0; i < DLM_CALLBACKS_SIZE; i++) { log_print("cb %x %llu flags %x mode %d sb %d %x", lkb->lkb_id, (unsigned long long)lkb->lkb_callbacks[i].seq, lkb->lkb_callbacks[i].flags, lkb->lkb_callbacks[i].mode, lkb->lkb_callbacks[i].sb_status, lkb->lkb_callbacks[i].sb_flags); } } |
8304d6f24 dlm: record full ... |
51 52 53 54 55 56 |
int dlm_add_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode, int status, uint32_t sbflags, uint64_t seq) { struct dlm_ls *ls = lkb->lkb_resource->res_ls; uint64_t prev_seq; int prev_mode; |
23e8e1aaa dlm: use workqueu... |
57 |
int i, rv; |
8304d6f24 dlm: record full ... |
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
for (i = 0; i < DLM_CALLBACKS_SIZE; i++) { if (lkb->lkb_callbacks[i].seq) continue; /* * Suppress some redundant basts here, do more on removal. * Don't even add a bast if the callback just before it * is a bast for the same mode or a more restrictive mode. * (the addional > PR check is needed for PR/CW inversion) */ if ((i > 0) && (flags & DLM_CB_BAST) && (lkb->lkb_callbacks[i-1].flags & DLM_CB_BAST)) { prev_seq = lkb->lkb_callbacks[i-1].seq; prev_mode = lkb->lkb_callbacks[i-1].mode; if ((prev_mode == mode) || (prev_mode > mode && prev_mode > DLM_LOCK_PR)) { log_debug(ls, "skip %x add bast %llu mode %d " "for bast %llu mode %d", lkb->lkb_id, (unsigned long long)seq, mode, (unsigned long long)prev_seq, prev_mode); |
23e8e1aaa dlm: use workqueu... |
86 87 |
rv = 0; goto out; |
8304d6f24 dlm: record full ... |
88 89 90 91 92 93 94 95 |
} } lkb->lkb_callbacks[i].seq = seq; lkb->lkb_callbacks[i].flags = flags; lkb->lkb_callbacks[i].mode = mode; lkb->lkb_callbacks[i].sb_status = status; lkb->lkb_callbacks[i].sb_flags = (sbflags & 0x000000FF); |
23e8e1aaa dlm: use workqueu... |
96 |
rv = 0; |
8304d6f24 dlm: record full ... |
97 98 99 100 101 102 103 104 |
break; } if (i == DLM_CALLBACKS_SIZE) { log_error(ls, "no callbacks %x %llu flags %x mode %d sb %d %x", lkb->lkb_id, (unsigned long long)seq, flags, mode, status, sbflags); dlm_dump_lkb_callbacks(lkb); |
23e8e1aaa dlm: use workqueu... |
105 106 |
rv = -1; goto out; |
8304d6f24 dlm: record full ... |
107 |
} |
23e8e1aaa dlm: use workqueu... |
108 109 |
out: return rv; |
8304d6f24 dlm: record full ... |
110 111 112 113 |
} int dlm_rem_lkb_callback(struct dlm_ls *ls, struct dlm_lkb *lkb, struct dlm_callback *cb, int *resid) |
e7fd41792 [DLM] The core of... |
114 |
{ |
23e8e1aaa dlm: use workqueu... |
115 |
int i, rv; |
8304d6f24 dlm: record full ... |
116 117 |
*resid = 0; |
23e8e1aaa dlm: use workqueu... |
118 119 120 121 |
if (!lkb->lkb_callbacks[0].seq) { rv = -ENOENT; goto out; } |
8304d6f24 dlm: record full ... |
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
/* oldest undelivered cb is callbacks[0] */ memcpy(cb, &lkb->lkb_callbacks[0], sizeof(struct dlm_callback)); memset(&lkb->lkb_callbacks[0], 0, sizeof(struct dlm_callback)); /* shift others down */ for (i = 1; i < DLM_CALLBACKS_SIZE; i++) { if (!lkb->lkb_callbacks[i].seq) break; memcpy(&lkb->lkb_callbacks[i-1], &lkb->lkb_callbacks[i], sizeof(struct dlm_callback)); memset(&lkb->lkb_callbacks[i], 0, sizeof(struct dlm_callback)); (*resid)++; } /* if cb is a bast, it should be skipped if the blocking mode is compatible with the last granted mode */ if ((cb->flags & DLM_CB_BAST) && lkb->lkb_last_cast.seq) { if (dlm_modes_compat(cb->mode, lkb->lkb_last_cast.mode)) { cb->flags |= DLM_CB_SKIP; log_debug(ls, "skip %x bast %llu mode %d " "for cast %llu mode %d", lkb->lkb_id, (unsigned long long)cb->seq, cb->mode, (unsigned long long)lkb->lkb_last_cast.seq, lkb->lkb_last_cast.mode); |
23e8e1aaa dlm: use workqueu... |
153 154 |
rv = 0; goto out; |
8304d6f24 dlm: record full ... |
155 156 157 158 159 160 161 162 163 164 165 166 |
} } if (cb->flags & DLM_CB_CAST) { memcpy(&lkb->lkb_last_cast, cb, sizeof(struct dlm_callback)); lkb->lkb_last_cast_time = ktime_get(); } if (cb->flags & DLM_CB_BAST) { memcpy(&lkb->lkb_last_bast, cb, sizeof(struct dlm_callback)); lkb->lkb_last_bast_time = ktime_get(); } |
23e8e1aaa dlm: use workqueu... |
167 168 169 |
rv = 0; out: return rv; |
8304d6f24 dlm: record full ... |
170 |
} |
23e8e1aaa dlm: use workqueu... |
171 172 |
void dlm_add_cb(struct dlm_lkb *lkb, uint32_t flags, int mode, int status, uint32_t sbflags) |
8304d6f24 dlm: record full ... |
173 |
{ |
23e8e1aaa dlm: use workqueu... |
174 175 |
struct dlm_ls *ls = lkb->lkb_resource->res_ls; uint64_t new_seq, prev_seq; |
8304d6f24 dlm: record full ... |
176 |
int rv; |
23e8e1aaa dlm: use workqueu... |
177 178 179 |
spin_lock(&dlm_cb_seq_spin); new_seq = ++dlm_cb_seq; spin_unlock(&dlm_cb_seq_spin); |
8304d6f24 dlm: record full ... |
180 |
|
597d0cae0 [DLM] dlm: user l... |
181 |
if (lkb->lkb_flags & DLM_IFL_USER) { |
23e8e1aaa dlm: use workqueu... |
182 |
dlm_user_add_ast(lkb, flags, mode, status, sbflags, new_seq); |
597d0cae0 [DLM] dlm: user l... |
183 184 |
return; } |
23e8e1aaa dlm: use workqueu... |
185 186 |
mutex_lock(&lkb->lkb_cb_mutex); prev_seq = lkb->lkb_callbacks[0].seq; |
8304d6f24 dlm: record full ... |
187 |
|
23e8e1aaa dlm: use workqueu... |
188 189 190 191 192 |
rv = dlm_add_lkb_callback(lkb, flags, mode, status, sbflags, new_seq); if (rv < 0) goto out; if (!prev_seq) { |
e7fd41792 [DLM] The core of... |
193 |
kref_get(&lkb->lkb_ref); |
e7fd41792 [DLM] The core of... |
194 |
|
23e8e1aaa dlm: use workqueu... |
195 196 197 198 199 200 201 202 203 204 |
if (test_bit(LSFL_CB_DELAY, &ls->ls_flags)) { mutex_lock(&ls->ls_cb_mutex); list_add(&lkb->lkb_cb_list, &ls->ls_cb_delay); mutex_unlock(&ls->ls_cb_mutex); } else { queue_work(ls->ls_callback_wq, &lkb->lkb_cb_work); } } out: mutex_unlock(&lkb->lkb_cb_mutex); |
e7fd41792 [DLM] The core of... |
205 |
} |
23e8e1aaa dlm: use workqueu... |
206 |
void dlm_callback_work(struct work_struct *work) |
e7fd41792 [DLM] The core of... |
207 |
{ |
23e8e1aaa dlm: use workqueu... |
208 209 |
struct dlm_lkb *lkb = container_of(work, struct dlm_lkb, lkb_cb_work); struct dlm_ls *ls = lkb->lkb_resource->res_ls; |
7fe2b3190 dlm: fix ordering... |
210 211 |
void (*castfn) (void *astparam); void (*bastfn) (void *astparam, int mode); |
8304d6f24 dlm: record full ... |
212 213 |
struct dlm_callback callbacks[DLM_CALLBACKS_SIZE]; int i, rv, resid; |
722d74219 dlm: fs/dlm/ast.c... |
214 |
|
23e8e1aaa dlm: use workqueu... |
215 |
memset(&callbacks, 0, sizeof(callbacks)); |
e7fd41792 [DLM] The core of... |
216 |
|
23e8e1aaa dlm: use workqueu... |
217 218 219 220 221 222 223 |
mutex_lock(&lkb->lkb_cb_mutex); if (!lkb->lkb_callbacks[0].seq) { /* no callback work exists, shouldn't happen */ log_error(ls, "dlm_callback_work %x no work", lkb->lkb_id); dlm_print_lkb(lkb); dlm_dump_lkb_callbacks(lkb); } |
e7fd41792 [DLM] The core of... |
224 |
|
23e8e1aaa dlm: use workqueu... |
225 226 227 228 229 |
for (i = 0; i < DLM_CALLBACKS_SIZE; i++) { rv = dlm_rem_lkb_callback(ls, lkb, &callbacks[i], &resid); if (rv < 0) break; } |
7fe2b3190 dlm: fix ordering... |
230 |
|
23e8e1aaa dlm: use workqueu... |
231 232 233 234 235 236 237 238 |
if (resid) { /* cbs remain, loop should have removed all, shouldn't happen */ log_error(ls, "dlm_callback_work %x resid %d", lkb->lkb_id, resid); dlm_print_lkb(lkb); dlm_dump_lkb_callbacks(lkb); } mutex_unlock(&lkb->lkb_cb_mutex); |
7fe2b3190 dlm: fix ordering... |
239 |
|
23e8e1aaa dlm: use workqueu... |
240 241 |
castfn = lkb->lkb_astfn; bastfn = lkb->lkb_bastfn; |
7fe2b3190 dlm: fix ordering... |
242 |
|
23e8e1aaa dlm: use workqueu... |
243 244 245 246 247 248 249 250 251 252 253 |
for (i = 0; i < DLM_CALLBACKS_SIZE; i++) { if (!callbacks[i].seq) break; if (callbacks[i].flags & DLM_CB_SKIP) { continue; } else if (callbacks[i].flags & DLM_CB_BAST) { bastfn(lkb->lkb_astparam, callbacks[i].mode); } else if (callbacks[i].flags & DLM_CB_CAST) { lkb->lkb_lksb->sb_status = callbacks[i].sb_status; lkb->lkb_lksb->sb_flags = callbacks[i].sb_flags; castfn(lkb->lkb_astparam); |
7fe2b3190 dlm: fix ordering... |
254 |
} |
e7fd41792 [DLM] The core of... |
255 |
} |
e7fd41792 [DLM] The core of... |
256 |
|
23e8e1aaa dlm: use workqueu... |
257 258 |
/* undo kref_get from dlm_add_callback, may cause lkb to be freed */ dlm_put_lkb(lkb); |
e7fd41792 [DLM] The core of... |
259 |
} |
23e8e1aaa dlm: use workqueu... |
260 |
int dlm_callback_start(struct dlm_ls *ls) |
e7fd41792 [DLM] The core of... |
261 |
{ |
23e8e1aaa dlm: use workqueu... |
262 |
ls->ls_callback_wq = alloc_workqueue("dlm_callback", |
10d1459fa dlm: don't limit ... |
263 264 265 266 |
WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_NON_REENTRANT, 0); |
23e8e1aaa dlm: use workqueu... |
267 268 269 |
if (!ls->ls_callback_wq) { log_print("can't start dlm_callback workqueue"); return -ENOMEM; |
e7fd41792 [DLM] The core of... |
270 271 272 |
} return 0; } |
23e8e1aaa dlm: use workqueu... |
273 |
void dlm_callback_stop(struct dlm_ls *ls) |
e7fd41792 [DLM] The core of... |
274 |
{ |
23e8e1aaa dlm: use workqueu... |
275 276 |
if (ls->ls_callback_wq) destroy_workqueue(ls->ls_callback_wq); |
e7fd41792 [DLM] The core of... |
277 |
} |
23e8e1aaa dlm: use workqueu... |
278 |
void dlm_callback_suspend(struct dlm_ls *ls) |
e7fd41792 [DLM] The core of... |
279 |
{ |
23e8e1aaa dlm: use workqueu... |
280 |
set_bit(LSFL_CB_DELAY, &ls->ls_flags); |
e7fd41792 [DLM] The core of... |
281 |
|
23e8e1aaa dlm: use workqueu... |
282 283 |
if (ls->ls_callback_wq) flush_workqueue(ls->ls_callback_wq); |
e7fd41792 [DLM] The core of... |
284 |
} |
23e8e1aaa dlm: use workqueu... |
285 |
void dlm_callback_resume(struct dlm_ls *ls) |
e7fd41792 [DLM] The core of... |
286 |
{ |
23e8e1aaa dlm: use workqueu... |
287 288 |
struct dlm_lkb *lkb, *safe; int count = 0; |
e7fd41792 [DLM] The core of... |
289 |
|
23e8e1aaa dlm: use workqueu... |
290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
clear_bit(LSFL_CB_DELAY, &ls->ls_flags); if (!ls->ls_callback_wq) return; mutex_lock(&ls->ls_cb_mutex); list_for_each_entry_safe(lkb, safe, &ls->ls_cb_delay, lkb_cb_list) { list_del_init(&lkb->lkb_cb_list); queue_work(ls->ls_callback_wq, &lkb->lkb_cb_work); count++; } mutex_unlock(&ls->ls_cb_mutex); log_debug(ls, "dlm_callback_resume %d", count); |
e7fd41792 [DLM] The core of... |
304 |
} |