Commit | Line | Data |
---|---|---|
e7fd4179 DT |
1 | /****************************************************************************** |
2 | ******************************************************************************* | |
3 | ** | |
4 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | |
7fe2b319 | 5 | ** Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved. |
e7fd4179 DT |
6 | ** |
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" | |
597d0cae | 16 | #include "user.h" |
8fa1de38 | 17 | #include "ast.h" |
e7fd4179 DT |
18 | |
19 | #define WAKE_ASTS 0 | |
20 | ||
21 | static struct list_head ast_queue; | |
22 | static spinlock_t ast_queue_lock; | |
23 | static struct task_struct * astd_task; | |
24 | static unsigned long astd_wakeflags; | |
90135925 | 25 | static struct mutex astd_running; |
e7fd4179 DT |
26 | |
27 | ||
28 | void dlm_del_ast(struct dlm_lkb *lkb) | |
29 | { | |
30 | spin_lock(&ast_queue_lock); | |
31 | if (lkb->lkb_ast_type & (AST_COMP | AST_BAST)) | |
32 | list_del(&lkb->lkb_astqueue); | |
33 | spin_unlock(&ast_queue_lock); | |
34 | } | |
35 | ||
7fe2b319 | 36 | void dlm_add_ast(struct dlm_lkb *lkb, int type, int mode) |
e7fd4179 | 37 | { |
597d0cae | 38 | if (lkb->lkb_flags & DLM_IFL_USER) { |
7fe2b319 | 39 | dlm_user_add_ast(lkb, type, mode); |
597d0cae DT |
40 | return; |
41 | } | |
42 | ||
e7fd4179 DT |
43 | spin_lock(&ast_queue_lock); |
44 | if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) { | |
45 | kref_get(&lkb->lkb_ref); | |
46 | list_add_tail(&lkb->lkb_astqueue, &ast_queue); | |
7fe2b319 | 47 | lkb->lkb_ast_first = type; |
e7fd4179 | 48 | } |
7fe2b319 DT |
49 | |
50 | /* sanity check, this should not happen */ | |
51 | ||
52 | if ((type == AST_COMP) && (lkb->lkb_ast_type & AST_COMP)) | |
53 | log_print("repeat cast %d castmode %d lock %x %s", | |
54 | mode, lkb->lkb_castmode, | |
55 | lkb->lkb_id, lkb->lkb_resource->res_name); | |
56 | ||
e7fd4179 | 57 | lkb->lkb_ast_type |= type; |
7fe2b319 DT |
58 | if (type == AST_BAST) |
59 | lkb->lkb_bastmode = mode; | |
60 | else | |
61 | lkb->lkb_castmode = mode; | |
e7fd4179 DT |
62 | spin_unlock(&ast_queue_lock); |
63 | ||
64 | set_bit(WAKE_ASTS, &astd_wakeflags); | |
65 | wake_up_process(astd_task); | |
66 | } | |
67 | ||
68 | static void process_asts(void) | |
69 | { | |
70 | struct dlm_ls *ls = NULL; | |
71 | struct dlm_rsb *r = NULL; | |
72 | struct dlm_lkb *lkb; | |
7fe2b319 DT |
73 | void (*castfn) (void *astparam); |
74 | void (*bastfn) (void *astparam, int mode); | |
75 | int type, first, bastmode, castmode, do_bast, do_cast, last_castmode; | |
722d7421 AM |
76 | |
77 | repeat: | |
78 | spin_lock(&ast_queue_lock); | |
79 | list_for_each_entry(lkb, &ast_queue, lkb_astqueue) { | |
80 | r = lkb->lkb_resource; | |
81 | ls = r->res_ls; | |
e7fd4179 | 82 | |
722d7421 AM |
83 | if (dlm_locking_stopped(ls)) |
84 | continue; | |
e7fd4179 | 85 | |
722d7421 AM |
86 | list_del(&lkb->lkb_astqueue); |
87 | type = lkb->lkb_ast_type; | |
88 | lkb->lkb_ast_type = 0; | |
7fe2b319 DT |
89 | first = lkb->lkb_ast_first; |
90 | lkb->lkb_ast_first = 0; | |
722d7421 | 91 | bastmode = lkb->lkb_bastmode; |
7fe2b319 DT |
92 | castmode = lkb->lkb_castmode; |
93 | castfn = lkb->lkb_astfn; | |
94 | bastfn = lkb->lkb_bastfn; | |
722d7421 | 95 | spin_unlock(&ast_queue_lock); |
e7fd4179 | 96 | |
7fe2b319 DT |
97 | do_cast = (type & AST_COMP) && castfn; |
98 | do_bast = (type & AST_BAST) && bastfn; | |
99 | ||
100 | /* Skip a bast if its blocking mode is compatible with the | |
101 | granted mode of the preceding cast. */ | |
102 | ||
103 | if (do_bast) { | |
104 | if (first == AST_COMP) | |
105 | last_castmode = castmode; | |
106 | else | |
107 | last_castmode = lkb->lkb_castmode_done; | |
108 | if (dlm_modes_compat(bastmode, last_castmode)) | |
109 | do_bast = 0; | |
110 | } | |
111 | ||
112 | if (first == AST_COMP) { | |
113 | if (do_cast) | |
114 | castfn(lkb->lkb_astparam); | |
115 | if (do_bast) | |
116 | bastfn(lkb->lkb_astparam, bastmode); | |
117 | } else if (first == AST_BAST) { | |
118 | if (do_bast) | |
119 | bastfn(lkb->lkb_astparam, bastmode); | |
120 | if (do_cast) | |
121 | castfn(lkb->lkb_astparam); | |
122 | } else { | |
123 | log_error(ls, "bad ast_first %d ast_type %d", | |
124 | first, type); | |
125 | } | |
126 | ||
127 | if (do_cast) | |
128 | lkb->lkb_castmode_done = castmode; | |
129 | if (do_bast) | |
130 | lkb->lkb_bastmode_done = bastmode; | |
e7fd4179 DT |
131 | |
132 | /* this removes the reference added by dlm_add_ast | |
133 | and may result in the lkb being freed */ | |
134 | dlm_put_lkb(lkb); | |
135 | ||
d61e9aac | 136 | cond_resched(); |
722d7421 | 137 | goto repeat; |
e7fd4179 | 138 | } |
722d7421 | 139 | spin_unlock(&ast_queue_lock); |
e7fd4179 DT |
140 | } |
141 | ||
142 | static inline int no_asts(void) | |
143 | { | |
144 | int ret; | |
145 | ||
146 | spin_lock(&ast_queue_lock); | |
147 | ret = list_empty(&ast_queue); | |
148 | spin_unlock(&ast_queue_lock); | |
149 | return ret; | |
150 | } | |
151 | ||
152 | static int dlm_astd(void *data) | |
153 | { | |
154 | while (!kthread_should_stop()) { | |
155 | set_current_state(TASK_INTERRUPTIBLE); | |
156 | if (!test_bit(WAKE_ASTS, &astd_wakeflags)) | |
157 | schedule(); | |
158 | set_current_state(TASK_RUNNING); | |
159 | ||
90135925 | 160 | mutex_lock(&astd_running); |
e7fd4179 DT |
161 | if (test_and_clear_bit(WAKE_ASTS, &astd_wakeflags)) |
162 | process_asts(); | |
90135925 | 163 | mutex_unlock(&astd_running); |
e7fd4179 DT |
164 | } |
165 | return 0; | |
166 | } | |
167 | ||
168 | void dlm_astd_wake(void) | |
169 | { | |
170 | if (!no_asts()) { | |
171 | set_bit(WAKE_ASTS, &astd_wakeflags); | |
172 | wake_up_process(astd_task); | |
173 | } | |
174 | } | |
175 | ||
176 | int dlm_astd_start(void) | |
177 | { | |
178 | struct task_struct *p; | |
179 | int error = 0; | |
180 | ||
181 | INIT_LIST_HEAD(&ast_queue); | |
182 | spin_lock_init(&ast_queue_lock); | |
90135925 | 183 | mutex_init(&astd_running); |
e7fd4179 DT |
184 | |
185 | p = kthread_run(dlm_astd, NULL, "dlm_astd"); | |
186 | if (IS_ERR(p)) | |
187 | error = PTR_ERR(p); | |
188 | else | |
189 | astd_task = p; | |
190 | return error; | |
191 | } | |
192 | ||
193 | void dlm_astd_stop(void) | |
194 | { | |
195 | kthread_stop(astd_task); | |
196 | } | |
197 | ||
198 | void dlm_astd_suspend(void) | |
199 | { | |
90135925 | 200 | mutex_lock(&astd_running); |
e7fd4179 DT |
201 | } |
202 | ||
203 | void dlm_astd_resume(void) | |
204 | { | |
90135925 | 205 | mutex_unlock(&astd_running); |
e7fd4179 DT |
206 | } |
207 |