]>
Commit | Line | Data |
---|---|---|
24ef1815 JB |
1 | /* -*- mode: c; c-basic-offset: 8; -*- |
2 | * vim: noexpandtab sw=8 ts=8 sts=0: | |
3 | * | |
4 | * stackglue.c | |
5 | * | |
6 | * Code which implements an OCFS2 specific interface to underlying | |
7 | * cluster stacks. | |
8 | * | |
9 | * Copyright (C) 2007 Oracle. All rights reserved. | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU General Public | |
13 | * License as published by the Free Software Foundation, version 2. | |
14 | * | |
15 | * This program is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 | * General Public License for more details. | |
19 | */ | |
20 | ||
286eaa95 JB |
21 | #include <linux/list.h> |
22 | #include <linux/spinlock.h> | |
23 | #include <linux/module.h> | |
4670c46d | 24 | #include <linux/slab.h> |
6953b4c0 | 25 | #include <linux/kmod.h> |
4670c46d | 26 | |
286eaa95 | 27 | #include "stackglue.h" |
4670c46d | 28 | |
286eaa95 JB |
29 | static struct ocfs2_locking_protocol *lproto; |
30 | static DEFINE_SPINLOCK(ocfs2_stack_lock); | |
31 | static LIST_HEAD(ocfs2_stack_list); | |
19fdb624 | 32 | |
286eaa95 JB |
33 | /* |
34 | * The stack currently in use. If not null, active_stack->sp_count > 0, | |
35 | * the module is pinned, and the locking protocol cannot be changed. | |
36 | */ | |
37 | static struct ocfs2_stack_plugin *active_stack; | |
38 | ||
39 | static struct ocfs2_stack_plugin *ocfs2_stack_lookup(const char *name) | |
40 | { | |
41 | struct ocfs2_stack_plugin *p; | |
42 | ||
43 | assert_spin_locked(&ocfs2_stack_lock); | |
44 | ||
45 | list_for_each_entry(p, &ocfs2_stack_list, sp_list) { | |
46 | if (!strcmp(p->sp_name, name)) | |
47 | return p; | |
48 | } | |
49 | ||
50 | return NULL; | |
51 | } | |
52 | ||
53 | static int ocfs2_stack_driver_request(const char *name) | |
54 | { | |
55 | int rc; | |
56 | struct ocfs2_stack_plugin *p; | |
57 | ||
58 | spin_lock(&ocfs2_stack_lock); | |
59 | ||
60 | if (active_stack) { | |
61 | /* | |
62 | * If the active stack isn't the one we want, it cannot | |
63 | * be selected right now. | |
64 | */ | |
65 | if (!strcmp(active_stack->sp_name, name)) | |
66 | rc = 0; | |
67 | else | |
68 | rc = -EBUSY; | |
69 | goto out; | |
70 | } | |
71 | ||
72 | p = ocfs2_stack_lookup(name); | |
73 | if (!p || !try_module_get(p->sp_owner)) { | |
74 | rc = -ENOENT; | |
75 | goto out; | |
76 | } | |
77 | ||
78 | /* Ok, the stack is pinned */ | |
79 | p->sp_count++; | |
80 | active_stack = p; | |
81 | ||
82 | rc = 0; | |
83 | ||
84 | out: | |
85 | spin_unlock(&ocfs2_stack_lock); | |
86 | return rc; | |
87 | } | |
88 | ||
89 | /* | |
90 | * This function looks up the appropriate stack and makes it active. If | |
91 | * there is no stack, it tries to load it. It will fail if the stack still | |
92 | * cannot be found. It will also fail if a different stack is in use. | |
93 | */ | |
94 | static int ocfs2_stack_driver_get(const char *name) | |
95 | { | |
96 | int rc; | |
97 | ||
98 | rc = ocfs2_stack_driver_request(name); | |
99 | if (rc == -ENOENT) { | |
100 | request_module("ocfs2_stack_%s", name); | |
101 | rc = ocfs2_stack_driver_request(name); | |
102 | } | |
103 | ||
104 | if (rc == -ENOENT) { | |
105 | printk(KERN_ERR | |
106 | "ocfs2: Cluster stack driver \"%s\" cannot be found\n", | |
107 | name); | |
108 | } else if (rc == -EBUSY) { | |
109 | printk(KERN_ERR | |
110 | "ocfs2: A different cluster stack driver is in use\n"); | |
111 | } | |
112 | ||
113 | return rc; | |
114 | } | |
24ef1815 | 115 | |
286eaa95 JB |
116 | static void ocfs2_stack_driver_put(void) |
117 | { | |
118 | spin_lock(&ocfs2_stack_lock); | |
119 | BUG_ON(active_stack == NULL); | |
120 | BUG_ON(active_stack->sp_count == 0); | |
121 | ||
122 | active_stack->sp_count--; | |
123 | if (!active_stack->sp_count) { | |
124 | module_put(active_stack->sp_owner); | |
125 | active_stack = NULL; | |
126 | } | |
127 | spin_unlock(&ocfs2_stack_lock); | |
128 | } | |
129 | ||
130 | int ocfs2_stack_glue_register(struct ocfs2_stack_plugin *plugin) | |
131 | { | |
132 | int rc; | |
133 | ||
134 | spin_lock(&ocfs2_stack_lock); | |
135 | if (!ocfs2_stack_lookup(plugin->sp_name)) { | |
136 | plugin->sp_count = 0; | |
137 | plugin->sp_proto = lproto; | |
138 | list_add(&plugin->sp_list, &ocfs2_stack_list); | |
139 | printk(KERN_INFO "ocfs2: Registered cluster interface %s\n", | |
140 | plugin->sp_name); | |
141 | rc = 0; | |
142 | } else { | |
143 | printk(KERN_ERR "ocfs2: Stack \"%s\" already registered\n", | |
144 | plugin->sp_name); | |
145 | rc = -EEXIST; | |
146 | } | |
147 | spin_unlock(&ocfs2_stack_lock); | |
148 | ||
149 | return rc; | |
150 | } | |
151 | EXPORT_SYMBOL_GPL(ocfs2_stack_glue_register); | |
152 | ||
153 | void ocfs2_stack_glue_unregister(struct ocfs2_stack_plugin *plugin) | |
154 | { | |
155 | struct ocfs2_stack_plugin *p; | |
156 | ||
157 | spin_lock(&ocfs2_stack_lock); | |
158 | p = ocfs2_stack_lookup(plugin->sp_name); | |
159 | if (p) { | |
160 | BUG_ON(p != plugin); | |
161 | BUG_ON(plugin == active_stack); | |
162 | BUG_ON(plugin->sp_count != 0); | |
163 | list_del_init(&plugin->sp_list); | |
164 | printk(KERN_INFO "ocfs2: Unregistered cluster interface %s\n", | |
165 | plugin->sp_name); | |
166 | } else { | |
167 | printk(KERN_ERR "Stack \"%s\" is not registered\n", | |
168 | plugin->sp_name); | |
169 | } | |
170 | spin_unlock(&ocfs2_stack_lock); | |
171 | } | |
172 | EXPORT_SYMBOL_GPL(ocfs2_stack_glue_unregister); | |
173 | ||
174 | void ocfs2_stack_glue_set_locking_protocol(struct ocfs2_locking_protocol *proto) | |
175 | { | |
176 | struct ocfs2_stack_plugin *p; | |
177 | ||
178 | BUG_ON(proto == NULL); | |
179 | ||
180 | spin_lock(&ocfs2_stack_lock); | |
181 | BUG_ON(active_stack != NULL); | |
182 | ||
183 | lproto = proto; | |
184 | list_for_each_entry(p, &ocfs2_stack_list, sp_list) { | |
185 | p->sp_proto = lproto; | |
186 | } | |
187 | ||
188 | spin_unlock(&ocfs2_stack_lock); | |
189 | } | |
190 | EXPORT_SYMBOL_GPL(ocfs2_stack_glue_set_locking_protocol); | |
7431cd7e | 191 | |
24ef1815 | 192 | |
553aa7e4 JB |
193 | int ocfs2_dlm_lock(struct ocfs2_cluster_connection *conn, |
194 | int mode, | |
195 | union ocfs2_dlm_lksb *lksb, | |
196 | u32 flags, | |
197 | void *name, | |
198 | unsigned int namelen, | |
199 | void *astarg) | |
200 | { | |
286eaa95 | 201 | BUG_ON(lproto == NULL); |
bd3e7610 | 202 | |
286eaa95 JB |
203 | return active_stack->sp_ops->dlm_lock(conn, mode, lksb, flags, |
204 | name, namelen, astarg); | |
24ef1815 | 205 | } |
286eaa95 | 206 | EXPORT_SYMBOL_GPL(ocfs2_dlm_lock); |
24ef1815 | 207 | |
553aa7e4 JB |
208 | int ocfs2_dlm_unlock(struct ocfs2_cluster_connection *conn, |
209 | union ocfs2_dlm_lksb *lksb, | |
210 | u32 flags, | |
211 | void *astarg) | |
212 | { | |
286eaa95 | 213 | BUG_ON(lproto == NULL); |
553aa7e4 | 214 | |
286eaa95 | 215 | return active_stack->sp_ops->dlm_unlock(conn, lksb, flags, astarg); |
8f2c9c1b | 216 | } |
286eaa95 | 217 | EXPORT_SYMBOL_GPL(ocfs2_dlm_unlock); |
8f2c9c1b | 218 | |
553aa7e4 JB |
219 | int ocfs2_dlm_lock_status(union ocfs2_dlm_lksb *lksb) |
220 | { | |
286eaa95 | 221 | return active_stack->sp_ops->lock_status(lksb); |
553aa7e4 | 222 | } |
286eaa95 | 223 | EXPORT_SYMBOL_GPL(ocfs2_dlm_lock_status); |
553aa7e4 | 224 | |
8f2c9c1b JB |
225 | /* |
226 | * Why don't we cast to ocfs2_meta_lvb? The "clean" answer is that we | |
227 | * don't cast at the glue level. The real answer is that the header | |
228 | * ordering is nigh impossible. | |
229 | */ | |
553aa7e4 JB |
230 | void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb) |
231 | { | |
286eaa95 | 232 | return active_stack->sp_ops->lock_lvb(lksb); |
cf0acdcd | 233 | } |
286eaa95 | 234 | EXPORT_SYMBOL_GPL(ocfs2_dlm_lvb); |
cf0acdcd | 235 | |
553aa7e4 JB |
236 | void ocfs2_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb) |
237 | { | |
286eaa95 | 238 | active_stack->sp_ops->dump_lksb(lksb); |
553aa7e4 | 239 | } |
286eaa95 | 240 | EXPORT_SYMBOL_GPL(ocfs2_dlm_dump_lksb); |
553aa7e4 | 241 | |
4670c46d JB |
242 | int ocfs2_cluster_connect(const char *group, |
243 | int grouplen, | |
244 | void (*recovery_handler)(int node_num, | |
245 | void *recovery_data), | |
246 | void *recovery_data, | |
247 | struct ocfs2_cluster_connection **conn) | |
248 | { | |
249 | int rc = 0; | |
250 | struct ocfs2_cluster_connection *new_conn; | |
4670c46d JB |
251 | |
252 | BUG_ON(group == NULL); | |
253 | BUG_ON(conn == NULL); | |
254 | BUG_ON(recovery_handler == NULL); | |
255 | ||
256 | if (grouplen > GROUP_NAME_MAX) { | |
257 | rc = -EINVAL; | |
258 | goto out; | |
259 | } | |
260 | ||
261 | new_conn = kzalloc(sizeof(struct ocfs2_cluster_connection), | |
262 | GFP_KERNEL); | |
263 | if (!new_conn) { | |
264 | rc = -ENOMEM; | |
265 | goto out; | |
266 | } | |
267 | ||
268 | memcpy(new_conn->cc_name, group, grouplen); | |
269 | new_conn->cc_namelen = grouplen; | |
270 | new_conn->cc_recovery_handler = recovery_handler; | |
271 | new_conn->cc_recovery_data = recovery_data; | |
272 | ||
273 | /* Start the new connection at our maximum compatibility level */ | |
286eaa95 JB |
274 | new_conn->cc_version = lproto->lp_max_version; |
275 | ||
276 | /* This will pin the stack driver if successful */ | |
277 | rc = ocfs2_stack_driver_get("o2cb"); | |
278 | if (rc) | |
279 | goto out_free; | |
4670c46d | 280 | |
286eaa95 | 281 | rc = active_stack->sp_ops->connect(new_conn); |
553aa7e4 | 282 | if (rc) { |
286eaa95 | 283 | ocfs2_stack_driver_put(); |
4670c46d JB |
284 | goto out_free; |
285 | } | |
286 | ||
4670c46d JB |
287 | *conn = new_conn; |
288 | ||
289 | out_free: | |
553aa7e4 | 290 | if (rc) |
4670c46d | 291 | kfree(new_conn); |
4670c46d JB |
292 | |
293 | out: | |
294 | return rc; | |
295 | } | |
286eaa95 | 296 | EXPORT_SYMBOL_GPL(ocfs2_cluster_connect); |
4670c46d | 297 | |
286eaa95 JB |
298 | /* If hangup_pending is 0, the stack driver will be dropped */ |
299 | int ocfs2_cluster_disconnect(struct ocfs2_cluster_connection *conn, | |
300 | int hangup_pending) | |
553aa7e4 JB |
301 | { |
302 | int ret; | |
303 | ||
304 | BUG_ON(conn == NULL); | |
305 | ||
286eaa95 | 306 | ret = active_stack->sp_ops->disconnect(conn, hangup_pending); |
553aa7e4 JB |
307 | |
308 | /* XXX Should we free it anyway? */ | |
286eaa95 | 309 | if (!ret) { |
553aa7e4 | 310 | kfree(conn); |
286eaa95 JB |
311 | if (!hangup_pending) |
312 | ocfs2_stack_driver_put(); | |
313 | } | |
553aa7e4 JB |
314 | |
315 | return ret; | |
316 | } | |
286eaa95 | 317 | EXPORT_SYMBOL_GPL(ocfs2_cluster_disconnect); |
553aa7e4 | 318 | |
6953b4c0 JB |
319 | void ocfs2_cluster_hangup(const char *group, int grouplen) |
320 | { | |
321 | BUG_ON(group == NULL); | |
322 | BUG_ON(group[grouplen] != '\0'); | |
323 | ||
286eaa95 JB |
324 | active_stack->sp_ops->hangup(group, grouplen); |
325 | ||
326 | /* cluster_disconnect() was called with hangup_pending==1 */ | |
327 | ocfs2_stack_driver_put(); | |
19fdb624 | 328 | } |
286eaa95 | 329 | EXPORT_SYMBOL_GPL(ocfs2_cluster_hangup); |
19fdb624 | 330 | |
553aa7e4 JB |
331 | int ocfs2_cluster_this_node(unsigned int *node) |
332 | { | |
286eaa95 | 333 | return active_stack->sp_ops->this_node(node); |
553aa7e4 | 334 | } |
286eaa95 | 335 | EXPORT_SYMBOL_GPL(ocfs2_cluster_this_node); |
553aa7e4 | 336 | |
286eaa95 JB |
337 | |
338 | static int __init ocfs2_stack_glue_init(void) | |
24ef1815 | 339 | { |
286eaa95 JB |
340 | return 0; |
341 | } | |
24ef1815 | 342 | |
286eaa95 JB |
343 | static void __exit ocfs2_stack_glue_exit(void) |
344 | { | |
345 | lproto = NULL; | |
24ef1815 JB |
346 | } |
347 | ||
286eaa95 JB |
348 | MODULE_AUTHOR("Oracle"); |
349 | MODULE_DESCRIPTION("ocfs2 cluter stack glue layer"); | |
350 | MODULE_LICENSE("GPL"); | |
351 | module_init(ocfs2_stack_glue_init); | |
352 | module_exit(ocfs2_stack_glue_exit); |