diff options
author | Joel Becker <joel.becker@oracle.com> | 2008-02-01 18:03:57 -0500 |
---|---|---|
committer | Mark Fasheh <mfasheh@suse.com> | 2008-04-18 11:56:05 -0400 |
commit | 286eaa95c5c5915a6b72cc3f0a2534161fd7928b (patch) | |
tree | dce03b619389cc5b5e2508b30ca3e1411401cf4e /fs/ocfs2/stackglue.c | |
parent | e3dad42bf993a0f24eb6e46152356c9b119c15e8 (diff) |
ocfs2: Break out stackglue into modules.
We define the ocfs2_stack_plugin structure to represent a stack driver.
The o2cb stack code is split into stack_o2cb.c. This becomes the
ocfs2_stack_o2cb.ko module.
The stackglue generic functions are similarly split into the
ocfs2_stackglue.ko module. This module now provides an interface to
register drivers. The ocfs2_stack_o2cb driver registers itself. As
part of this interface, ocfs2_stackglue can load drivers on demand.
This is accomplished in ocfs2_cluster_connect().
ocfs2_cluster_disconnect() is now notified when a _hangup() is pending.
If a hangup is pending, it will not release the driver module and will
let _hangup() do that.
Signed-off-by: Joel Becker <joel.becker@oracle.com>
Diffstat (limited to 'fs/ocfs2/stackglue.c')
-rw-r--r-- | fs/ocfs2/stackglue.c | 238 |
1 files changed, 214 insertions, 24 deletions
diff --git a/fs/ocfs2/stackglue.c b/fs/ocfs2/stackglue.c index e197367b6bd6..1978c9cff0e9 100644 --- a/fs/ocfs2/stackglue.c +++ b/fs/ocfs2/stackglue.c | |||
@@ -18,17 +18,176 @@ | |||
18 | * General Public License for more details. | 18 | * General Public License for more details. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/list.h> | ||
22 | #include <linux/spinlock.h> | ||
23 | #include <linux/module.h> | ||
21 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
22 | #include <linux/kmod.h> | 25 | #include <linux/kmod.h> |
23 | 26 | ||
24 | /* Needed for AOP_TRUNCATED_PAGE in mlog_errno() */ | 27 | #include "stackglue.h" |
25 | #include <linux/fs.h> | ||
26 | 28 | ||
27 | #include "cluster/masklog.h" | 29 | static struct ocfs2_locking_protocol *lproto; |
30 | static DEFINE_SPINLOCK(ocfs2_stack_lock); | ||
31 | static LIST_HEAD(ocfs2_stack_list); | ||
28 | 32 | ||
29 | #include "stackglue.h" | 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 | } | ||
30 | 115 | ||
31 | struct ocfs2_locking_protocol *stack_glue_lproto; | 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); | ||
32 | 191 | ||
33 | 192 | ||
34 | int ocfs2_dlm_lock(struct ocfs2_cluster_connection *conn, | 193 | int ocfs2_dlm_lock(struct ocfs2_cluster_connection *conn, |
@@ -39,26 +198,29 @@ int ocfs2_dlm_lock(struct ocfs2_cluster_connection *conn, | |||
39 | unsigned int namelen, | 198 | unsigned int namelen, |
40 | void *astarg) | 199 | void *astarg) |
41 | { | 200 | { |
42 | BUG_ON(stack_glue_lproto == NULL); | 201 | BUG_ON(lproto == NULL); |
43 | 202 | ||
44 | return o2cb_stack_ops.dlm_lock(conn, mode, lksb, flags, | 203 | return active_stack->sp_ops->dlm_lock(conn, mode, lksb, flags, |
45 | name, namelen, astarg); | 204 | name, namelen, astarg); |
46 | } | 205 | } |
206 | EXPORT_SYMBOL_GPL(ocfs2_dlm_lock); | ||
47 | 207 | ||
48 | int ocfs2_dlm_unlock(struct ocfs2_cluster_connection *conn, | 208 | int ocfs2_dlm_unlock(struct ocfs2_cluster_connection *conn, |
49 | union ocfs2_dlm_lksb *lksb, | 209 | union ocfs2_dlm_lksb *lksb, |
50 | u32 flags, | 210 | u32 flags, |
51 | void *astarg) | 211 | void *astarg) |
52 | { | 212 | { |
53 | BUG_ON(stack_glue_lproto == NULL); | 213 | BUG_ON(lproto == NULL); |
54 | 214 | ||
55 | return o2cb_stack_ops.dlm_unlock(conn, lksb, flags, astarg); | 215 | return active_stack->sp_ops->dlm_unlock(conn, lksb, flags, astarg); |
56 | } | 216 | } |
217 | EXPORT_SYMBOL_GPL(ocfs2_dlm_unlock); | ||
57 | 218 | ||
58 | int ocfs2_dlm_lock_status(union ocfs2_dlm_lksb *lksb) | 219 | int ocfs2_dlm_lock_status(union ocfs2_dlm_lksb *lksb) |
59 | { | 220 | { |
60 | return o2cb_stack_ops.lock_status(lksb); | 221 | return active_stack->sp_ops->lock_status(lksb); |
61 | } | 222 | } |
223 | EXPORT_SYMBOL_GPL(ocfs2_dlm_lock_status); | ||
62 | 224 | ||
63 | /* | 225 | /* |
64 | * Why don't we cast to ocfs2_meta_lvb? The "clean" answer is that we | 226 | * Why don't we cast to ocfs2_meta_lvb? The "clean" answer is that we |
@@ -67,13 +229,15 @@ int ocfs2_dlm_lock_status(union ocfs2_dlm_lksb *lksb) | |||
67 | */ | 229 | */ |
68 | void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb) | 230 | void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb) |
69 | { | 231 | { |
70 | return o2cb_stack_ops.lock_lvb(lksb); | 232 | return active_stack->sp_ops->lock_lvb(lksb); |
71 | } | 233 | } |
234 | EXPORT_SYMBOL_GPL(ocfs2_dlm_lvb); | ||
72 | 235 | ||
73 | void ocfs2_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb) | 236 | void ocfs2_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb) |
74 | { | 237 | { |
75 | o2cb_stack_ops.dump_lksb(lksb); | 238 | active_stack->sp_ops->dump_lksb(lksb); |
76 | } | 239 | } |
240 | EXPORT_SYMBOL_GPL(ocfs2_dlm_dump_lksb); | ||
77 | 241 | ||
78 | int ocfs2_cluster_connect(const char *group, | 242 | int ocfs2_cluster_connect(const char *group, |
79 | int grouplen, | 243 | int grouplen, |
@@ -107,11 +271,16 @@ int ocfs2_cluster_connect(const char *group, | |||
107 | new_conn->cc_recovery_data = recovery_data; | 271 | new_conn->cc_recovery_data = recovery_data; |
108 | 272 | ||
109 | /* Start the new connection at our maximum compatibility level */ | 273 | /* Start the new connection at our maximum compatibility level */ |
110 | new_conn->cc_version = stack_glue_lproto->lp_max_version; | 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; | ||
111 | 280 | ||
112 | rc = o2cb_stack_ops.connect(new_conn); | 281 | rc = active_stack->sp_ops->connect(new_conn); |
113 | if (rc) { | 282 | if (rc) { |
114 | mlog_errno(rc); | 283 | ocfs2_stack_driver_put(); |
115 | goto out_free; | 284 | goto out_free; |
116 | } | 285 | } |
117 | 286 | ||
@@ -124,39 +293,60 @@ out_free: | |||
124 | out: | 293 | out: |
125 | return rc; | 294 | return rc; |
126 | } | 295 | } |
296 | EXPORT_SYMBOL_GPL(ocfs2_cluster_connect); | ||
127 | 297 | ||
128 | int ocfs2_cluster_disconnect(struct ocfs2_cluster_connection *conn) | 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) | ||
129 | { | 301 | { |
130 | int ret; | 302 | int ret; |
131 | 303 | ||
132 | BUG_ON(conn == NULL); | 304 | BUG_ON(conn == NULL); |
133 | 305 | ||
134 | ret = o2cb_stack_ops.disconnect(conn); | 306 | ret = active_stack->sp_ops->disconnect(conn, hangup_pending); |
135 | 307 | ||
136 | /* XXX Should we free it anyway? */ | 308 | /* XXX Should we free it anyway? */ |
137 | if (!ret) | 309 | if (!ret) { |
138 | kfree(conn); | 310 | kfree(conn); |
311 | if (!hangup_pending) | ||
312 | ocfs2_stack_driver_put(); | ||
313 | } | ||
139 | 314 | ||
140 | return ret; | 315 | return ret; |
141 | } | 316 | } |
317 | EXPORT_SYMBOL_GPL(ocfs2_cluster_disconnect); | ||
142 | 318 | ||
143 | void ocfs2_cluster_hangup(const char *group, int grouplen) | 319 | void ocfs2_cluster_hangup(const char *group, int grouplen) |
144 | { | 320 | { |
145 | BUG_ON(group == NULL); | 321 | BUG_ON(group == NULL); |
146 | BUG_ON(group[grouplen] != '\0'); | 322 | BUG_ON(group[grouplen] != '\0'); |
147 | 323 | ||
148 | o2cb_stack_ops.hangup(group, grouplen); | 324 | active_stack->sp_ops->hangup(group, grouplen); |
325 | |||
326 | /* cluster_disconnect() was called with hangup_pending==1 */ | ||
327 | ocfs2_stack_driver_put(); | ||
149 | } | 328 | } |
329 | EXPORT_SYMBOL_GPL(ocfs2_cluster_hangup); | ||
150 | 330 | ||
151 | int ocfs2_cluster_this_node(unsigned int *node) | 331 | int ocfs2_cluster_this_node(unsigned int *node) |
152 | { | 332 | { |
153 | return o2cb_stack_ops.this_node(node); | 333 | return active_stack->sp_ops->this_node(node); |
154 | } | 334 | } |
335 | EXPORT_SYMBOL_GPL(ocfs2_cluster_this_node); | ||
155 | 336 | ||
156 | void ocfs2_stack_glue_set_locking_protocol(struct ocfs2_locking_protocol *proto) | 337 | |
338 | static int __init ocfs2_stack_glue_init(void) | ||
157 | { | 339 | { |
158 | BUG_ON(proto != NULL); | 340 | return 0; |
341 | } | ||
159 | 342 | ||
160 | stack_glue_lproto = proto; | 343 | static void __exit ocfs2_stack_glue_exit(void) |
344 | { | ||
345 | lproto = NULL; | ||
161 | } | 346 | } |
162 | 347 | ||
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); | ||