blob: abc49f292454afa387d42a9be4b5437c2ad3f46d [file] [log] [blame]
David Teiglande7fd4172006-01-18 09:30:29 +00001/******************************************************************************
2*******************************************************************************
3**
4** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
David Teigland7fe2b312010-02-24 11:08:18 -06005** Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
David Teiglande7fd4172006-01-18 09:30:29 +00006**
7** This copyrighted material is made available to anyone wishing to use,
8** modify, copy, or redistribute it subject to the terms and conditions
9** of the GNU General Public License v.2.
10**
11*******************************************************************************
12******************************************************************************/
13
14#include "dlm_internal.h"
15#include "lock.h"
David Teigland597d0ca2006-07-12 16:44:04 -050016#include "user.h"
Adrian Bunk8fa1de32007-04-04 17:25:29 +020017#include "ast.h"
David Teiglande7fd4172006-01-18 09:30:29 +000018
19#define WAKE_ASTS 0
20
David Teigland8304d6f2011-02-21 14:58:21 -060021static uint64_t ast_seq_count;
David Teiglande7fd4172006-01-18 09:30:29 +000022static struct list_head ast_queue;
23static spinlock_t ast_queue_lock;
24static struct task_struct * astd_task;
25static unsigned long astd_wakeflags;
David Teigland90135922006-01-20 08:47:07 +000026static struct mutex astd_running;
David Teiglande7fd4172006-01-18 09:30:29 +000027
28
David Teigland8304d6f2011-02-21 14:58:21 -060029static void dlm_dump_lkb_callbacks(struct dlm_lkb *lkb)
30{
31 int i;
32
33 log_print("last_bast %x %llu flags %x mode %d sb %d %x",
34 lkb->lkb_id,
35 (unsigned long long)lkb->lkb_last_bast.seq,
36 lkb->lkb_last_bast.flags,
37 lkb->lkb_last_bast.mode,
38 lkb->lkb_last_bast.sb_status,
39 lkb->lkb_last_bast.sb_flags);
40
41 log_print("last_cast %x %llu flags %x mode %d sb %d %x",
42 lkb->lkb_id,
43 (unsigned long long)lkb->lkb_last_cast.seq,
44 lkb->lkb_last_cast.flags,
45 lkb->lkb_last_cast.mode,
46 lkb->lkb_last_cast.sb_status,
47 lkb->lkb_last_cast.sb_flags);
48
49 for (i = 0; i < DLM_CALLBACKS_SIZE; i++) {
50 log_print("cb %x %llu flags %x mode %d sb %d %x",
51 lkb->lkb_id,
52 (unsigned long long)lkb->lkb_callbacks[i].seq,
53 lkb->lkb_callbacks[i].flags,
54 lkb->lkb_callbacks[i].mode,
55 lkb->lkb_callbacks[i].sb_status,
56 lkb->lkb_callbacks[i].sb_flags);
57 }
58}
59
David Teiglande7fd4172006-01-18 09:30:29 +000060void dlm_del_ast(struct dlm_lkb *lkb)
61{
62 spin_lock(&ast_queue_lock);
David Teigland8304d6f2011-02-21 14:58:21 -060063 if (!list_empty(&lkb->lkb_astqueue))
64 list_del_init(&lkb->lkb_astqueue);
David Teiglande7fd4172006-01-18 09:30:29 +000065 spin_unlock(&ast_queue_lock);
66}
67
David Teigland8304d6f2011-02-21 14:58:21 -060068int dlm_add_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode,
69 int status, uint32_t sbflags, uint64_t seq)
David Teiglande7fd4172006-01-18 09:30:29 +000070{
David Teigland8304d6f2011-02-21 14:58:21 -060071 struct dlm_ls *ls = lkb->lkb_resource->res_ls;
72 uint64_t prev_seq;
73 int prev_mode;
74 int i;
75
76 for (i = 0; i < DLM_CALLBACKS_SIZE; i++) {
77 if (lkb->lkb_callbacks[i].seq)
78 continue;
79
80 /*
81 * Suppress some redundant basts here, do more on removal.
82 * Don't even add a bast if the callback just before it
83 * is a bast for the same mode or a more restrictive mode.
84 * (the addional > PR check is needed for PR/CW inversion)
85 */
86
87 if ((i > 0) && (flags & DLM_CB_BAST) &&
88 (lkb->lkb_callbacks[i-1].flags & DLM_CB_BAST)) {
89
90 prev_seq = lkb->lkb_callbacks[i-1].seq;
91 prev_mode = lkb->lkb_callbacks[i-1].mode;
92
93 if ((prev_mode == mode) ||
94 (prev_mode > mode && prev_mode > DLM_LOCK_PR)) {
95
96 log_debug(ls, "skip %x add bast %llu mode %d "
97 "for bast %llu mode %d",
98 lkb->lkb_id,
99 (unsigned long long)seq,
100 mode,
101 (unsigned long long)prev_seq,
102 prev_mode);
103 return 0;
104 }
105 }
106
107 lkb->lkb_callbacks[i].seq = seq;
108 lkb->lkb_callbacks[i].flags = flags;
109 lkb->lkb_callbacks[i].mode = mode;
110 lkb->lkb_callbacks[i].sb_status = status;
111 lkb->lkb_callbacks[i].sb_flags = (sbflags & 0x000000FF);
112 break;
113 }
114
115 if (i == DLM_CALLBACKS_SIZE) {
116 log_error(ls, "no callbacks %x %llu flags %x mode %d sb %d %x",
117 lkb->lkb_id, (unsigned long long)seq,
118 flags, mode, status, sbflags);
119 dlm_dump_lkb_callbacks(lkb);
120 return -1;
121 }
122
123 return 0;
124}
125
126int dlm_rem_lkb_callback(struct dlm_ls *ls, struct dlm_lkb *lkb,
127 struct dlm_callback *cb, int *resid)
128{
129 int i;
130
131 *resid = 0;
132
133 if (!lkb->lkb_callbacks[0].seq)
134 return -ENOENT;
135
136 /* oldest undelivered cb is callbacks[0] */
137
138 memcpy(cb, &lkb->lkb_callbacks[0], sizeof(struct dlm_callback));
139 memset(&lkb->lkb_callbacks[0], 0, sizeof(struct dlm_callback));
140
141 /* shift others down */
142
143 for (i = 1; i < DLM_CALLBACKS_SIZE; i++) {
144 if (!lkb->lkb_callbacks[i].seq)
145 break;
146 memcpy(&lkb->lkb_callbacks[i-1], &lkb->lkb_callbacks[i],
147 sizeof(struct dlm_callback));
148 memset(&lkb->lkb_callbacks[i], 0, sizeof(struct dlm_callback));
149 (*resid)++;
150 }
151
152 /* if cb is a bast, it should be skipped if the blocking mode is
153 compatible with the last granted mode */
154
155 if ((cb->flags & DLM_CB_BAST) && lkb->lkb_last_cast.seq) {
156 if (dlm_modes_compat(cb->mode, lkb->lkb_last_cast.mode)) {
157 cb->flags |= DLM_CB_SKIP;
158
159 log_debug(ls, "skip %x bast %llu mode %d "
160 "for cast %llu mode %d",
161 lkb->lkb_id,
162 (unsigned long long)cb->seq,
163 cb->mode,
164 (unsigned long long)lkb->lkb_last_cast.seq,
165 lkb->lkb_last_cast.mode);
166 return 0;
167 }
168 }
169
170 if (cb->flags & DLM_CB_CAST) {
171 memcpy(&lkb->lkb_last_cast, cb, sizeof(struct dlm_callback));
172 lkb->lkb_last_cast_time = ktime_get();
173 }
174
175 if (cb->flags & DLM_CB_BAST) {
176 memcpy(&lkb->lkb_last_bast, cb, sizeof(struct dlm_callback));
177 lkb->lkb_last_bast_time = ktime_get();
178 }
179
180 return 0;
181}
182
183void dlm_add_ast(struct dlm_lkb *lkb, uint32_t flags, int mode, int status,
184 uint32_t sbflags)
185{
186 uint64_t seq;
187 int rv;
188
189 spin_lock(&ast_queue_lock);
190
191 seq = ++ast_seq_count;
192
David Teigland597d0ca2006-07-12 16:44:04 -0500193 if (lkb->lkb_flags & DLM_IFL_USER) {
David Teigland8304d6f2011-02-21 14:58:21 -0600194 spin_unlock(&ast_queue_lock);
195 dlm_user_add_ast(lkb, flags, mode, status, sbflags, seq);
David Teigland597d0ca2006-07-12 16:44:04 -0500196 return;
197 }
198
David Teigland8304d6f2011-02-21 14:58:21 -0600199 rv = dlm_add_lkb_callback(lkb, flags, mode, status, sbflags, seq);
200 if (rv < 0) {
201 spin_unlock(&ast_queue_lock);
202 return;
David Teiglande7fd4172006-01-18 09:30:29 +0000203 }
David Teigland7fe2b312010-02-24 11:08:18 -0600204
David Teigland8304d6f2011-02-21 14:58:21 -0600205 if (list_empty(&lkb->lkb_astqueue)) {
206 kref_get(&lkb->lkb_ref);
207 list_add_tail(&lkb->lkb_astqueue, &ast_queue);
208 }
David Teiglande7fd4172006-01-18 09:30:29 +0000209 spin_unlock(&ast_queue_lock);
210
211 set_bit(WAKE_ASTS, &astd_wakeflags);
212 wake_up_process(astd_task);
213}
214
215static void process_asts(void)
216{
217 struct dlm_ls *ls = NULL;
218 struct dlm_rsb *r = NULL;
219 struct dlm_lkb *lkb;
David Teigland7fe2b312010-02-24 11:08:18 -0600220 void (*castfn) (void *astparam);
221 void (*bastfn) (void *astparam, int mode);
David Teigland8304d6f2011-02-21 14:58:21 -0600222 struct dlm_callback callbacks[DLM_CALLBACKS_SIZE];
223 int i, rv, resid;
David Teiglande7fd4172006-01-18 09:30:29 +0000224
Andrew Morton722d7422008-12-23 10:22:56 -0600225repeat:
226 spin_lock(&ast_queue_lock);
227 list_for_each_entry(lkb, &ast_queue, lkb_astqueue) {
228 r = lkb->lkb_resource;
229 ls = r->res_ls;
David Teiglande7fd4172006-01-18 09:30:29 +0000230
Andrew Morton722d7422008-12-23 10:22:56 -0600231 if (dlm_locking_stopped(ls))
232 continue;
David Teiglande7fd4172006-01-18 09:30:29 +0000233
David Teigland8304d6f2011-02-21 14:58:21 -0600234 /* we remove from astqueue list and remove everything in
235 lkb_callbacks before releasing the spinlock so empty
236 lkb_astqueue is always consistent with empty lkb_callbacks */
237
238 list_del_init(&lkb->lkb_astqueue);
239
David Teigland7fe2b312010-02-24 11:08:18 -0600240 castfn = lkb->lkb_astfn;
241 bastfn = lkb->lkb_bastfn;
David Teigland8304d6f2011-02-21 14:58:21 -0600242
243 memset(&callbacks, 0, sizeof(callbacks));
244
245 for (i = 0; i < DLM_CALLBACKS_SIZE; i++) {
246 rv = dlm_rem_lkb_callback(ls, lkb, &callbacks[i], &resid);
247 if (rv < 0)
248 break;
249 }
David Teiglande7fd4172006-01-18 09:30:29 +0000250 spin_unlock(&ast_queue_lock);
David Teiglande7fd4172006-01-18 09:30:29 +0000251
David Teigland8304d6f2011-02-21 14:58:21 -0600252 if (resid) {
253 /* shouldn't happen, for loop should have removed all */
254 log_error(ls, "callback resid %d lkb %x",
255 resid, lkb->lkb_id);
David Teigland7fe2b312010-02-24 11:08:18 -0600256 }
257
David Teigland8304d6f2011-02-21 14:58:21 -0600258 for (i = 0; i < DLM_CALLBACKS_SIZE; i++) {
259 if (!callbacks[i].seq)
260 break;
261 if (callbacks[i].flags & DLM_CB_SKIP) {
262 continue;
263 } else if (callbacks[i].flags & DLM_CB_BAST) {
264 bastfn(lkb->lkb_astparam, callbacks[i].mode);
265 } else if (callbacks[i].flags & DLM_CB_CAST) {
266 lkb->lkb_lksb->sb_status = callbacks[i].sb_status;
267 lkb->lkb_lksb->sb_flags = callbacks[i].sb_flags;
David Teigland7fe2b312010-02-24 11:08:18 -0600268 castfn(lkb->lkb_astparam);
David Teigland8304d6f2011-02-21 14:58:21 -0600269 }
David Teigland7fe2b312010-02-24 11:08:18 -0600270 }
271
David Teigland8304d6f2011-02-21 14:58:21 -0600272 /* removes ref for ast_queue, may cause lkb to be freed */
David Teiglande7fd4172006-01-18 09:30:29 +0000273 dlm_put_lkb(lkb);
274
Steven Whitehoused61e9aa2008-12-10 09:31:02 -0600275 cond_resched();
Andrew Morton722d7422008-12-23 10:22:56 -0600276 goto repeat;
David Teiglande7fd4172006-01-18 09:30:29 +0000277 }
Andrew Morton722d7422008-12-23 10:22:56 -0600278 spin_unlock(&ast_queue_lock);
David Teiglande7fd4172006-01-18 09:30:29 +0000279}
280
281static inline int no_asts(void)
282{
283 int ret;
284
285 spin_lock(&ast_queue_lock);
286 ret = list_empty(&ast_queue);
287 spin_unlock(&ast_queue_lock);
288 return ret;
289}
290
291static int dlm_astd(void *data)
292{
293 while (!kthread_should_stop()) {
294 set_current_state(TASK_INTERRUPTIBLE);
295 if (!test_bit(WAKE_ASTS, &astd_wakeflags))
296 schedule();
297 set_current_state(TASK_RUNNING);
298
David Teigland90135922006-01-20 08:47:07 +0000299 mutex_lock(&astd_running);
David Teiglande7fd4172006-01-18 09:30:29 +0000300 if (test_and_clear_bit(WAKE_ASTS, &astd_wakeflags))
301 process_asts();
David Teigland90135922006-01-20 08:47:07 +0000302 mutex_unlock(&astd_running);
David Teiglande7fd4172006-01-18 09:30:29 +0000303 }
304 return 0;
305}
306
307void dlm_astd_wake(void)
308{
309 if (!no_asts()) {
310 set_bit(WAKE_ASTS, &astd_wakeflags);
311 wake_up_process(astd_task);
312 }
313}
314
315int dlm_astd_start(void)
316{
317 struct task_struct *p;
318 int error = 0;
319
320 INIT_LIST_HEAD(&ast_queue);
321 spin_lock_init(&ast_queue_lock);
David Teigland90135922006-01-20 08:47:07 +0000322 mutex_init(&astd_running);
David Teiglande7fd4172006-01-18 09:30:29 +0000323
324 p = kthread_run(dlm_astd, NULL, "dlm_astd");
325 if (IS_ERR(p))
326 error = PTR_ERR(p);
327 else
328 astd_task = p;
329 return error;
330}
331
332void dlm_astd_stop(void)
333{
334 kthread_stop(astd_task);
335}
336
337void dlm_astd_suspend(void)
338{
David Teigland90135922006-01-20 08:47:07 +0000339 mutex_lock(&astd_running);
David Teiglande7fd4172006-01-18 09:30:29 +0000340}
341
342void dlm_astd_resume(void)
343{
David Teigland90135922006-01-20 08:47:07 +0000344 mutex_unlock(&astd_running);
David Teiglande7fd4172006-01-18 09:30:29 +0000345}
346