]>
Commit | Line | Data |
---|---|---|
e7fd4179 DT |
1 | /****************************************************************************** |
2 | ******************************************************************************* | |
3 | ** | |
4 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | |
51409340 | 5 | ** Copyright (C) 2004-2008 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 <linux/kernel.h> | |
15 | #include <linux/module.h> | |
16 | #include <linux/configfs.h> | |
5a0e3ad6 | 17 | #include <linux/slab.h> |
44be6fdf DT |
18 | #include <linux/in.h> |
19 | #include <linux/in6.h> | |
20 | #include <net/ipv6.h> | |
e7fd4179 DT |
21 | #include <net/sock.h> |
22 | ||
23 | #include "config.h" | |
1c032c03 | 24 | #include "lowcomms.h" |
e7fd4179 DT |
25 | |
26 | /* | |
27 | * /config/dlm/<cluster>/spaces/<space>/nodes/<node>/nodeid | |
28 | * /config/dlm/<cluster>/spaces/<space>/nodes/<node>/weight | |
29 | * /config/dlm/<cluster>/comms/<comm>/nodeid | |
30 | * /config/dlm/<cluster>/comms/<comm>/local | |
31 | * /config/dlm/<cluster>/comms/<comm>/addr | |
32 | * The <cluster> level is useless, but I haven't figured out how to avoid it. | |
33 | */ | |
34 | ||
35 | static struct config_group *space_list; | |
36 | static struct config_group *comm_list; | |
51409340 | 37 | static struct dlm_comm *local_comm; |
e7fd4179 | 38 | |
51409340 DT |
39 | struct dlm_clusters; |
40 | struct dlm_cluster; | |
41 | struct dlm_spaces; | |
42 | struct dlm_space; | |
43 | struct dlm_comms; | |
44 | struct dlm_comm; | |
45 | struct dlm_nodes; | |
46 | struct dlm_node; | |
e7fd4179 | 47 | |
f89ab861 | 48 | static struct config_group *make_cluster(struct config_group *, const char *); |
e7fd4179 DT |
49 | static void drop_cluster(struct config_group *, struct config_item *); |
50 | static void release_cluster(struct config_item *); | |
f89ab861 | 51 | static struct config_group *make_space(struct config_group *, const char *); |
e7fd4179 DT |
52 | static void drop_space(struct config_group *, struct config_item *); |
53 | static void release_space(struct config_item *); | |
f89ab861 | 54 | static struct config_item *make_comm(struct config_group *, const char *); |
e7fd4179 DT |
55 | static void drop_comm(struct config_group *, struct config_item *); |
56 | static void release_comm(struct config_item *); | |
f89ab861 | 57 | static struct config_item *make_node(struct config_group *, const char *); |
e7fd4179 DT |
58 | static void drop_node(struct config_group *, struct config_item *); |
59 | static void release_node(struct config_item *); | |
60 | ||
d200778e DT |
61 | static ssize_t show_cluster(struct config_item *i, struct configfs_attribute *a, |
62 | char *buf); | |
63 | static ssize_t store_cluster(struct config_item *i, | |
64 | struct configfs_attribute *a, | |
65 | const char *buf, size_t len); | |
e7fd4179 DT |
66 | static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a, |
67 | char *buf); | |
68 | static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a, | |
69 | const char *buf, size_t len); | |
70 | static ssize_t show_node(struct config_item *i, struct configfs_attribute *a, | |
71 | char *buf); | |
72 | static ssize_t store_node(struct config_item *i, struct configfs_attribute *a, | |
73 | const char *buf, size_t len); | |
74 | ||
51409340 DT |
75 | static ssize_t comm_nodeid_read(struct dlm_comm *cm, char *buf); |
76 | static ssize_t comm_nodeid_write(struct dlm_comm *cm, const char *buf, | |
77 | size_t len); | |
78 | static ssize_t comm_local_read(struct dlm_comm *cm, char *buf); | |
79 | static ssize_t comm_local_write(struct dlm_comm *cm, const char *buf, | |
80 | size_t len); | |
81 | static ssize_t comm_addr_write(struct dlm_comm *cm, const char *buf, | |
82 | size_t len); | |
83 | static ssize_t node_nodeid_read(struct dlm_node *nd, char *buf); | |
84 | static ssize_t node_nodeid_write(struct dlm_node *nd, const char *buf, | |
85 | size_t len); | |
86 | static ssize_t node_weight_read(struct dlm_node *nd, char *buf); | |
87 | static ssize_t node_weight_write(struct dlm_node *nd, const char *buf, | |
88 | size_t len); | |
89 | ||
90 | struct dlm_cluster { | |
d200778e DT |
91 | struct config_group group; |
92 | unsigned int cl_tcp_port; | |
93 | unsigned int cl_buffer_size; | |
94 | unsigned int cl_rsbtbl_size; | |
95 | unsigned int cl_lkbtbl_size; | |
96 | unsigned int cl_dirtbl_size; | |
97 | unsigned int cl_recover_timer; | |
98 | unsigned int cl_toss_secs; | |
99 | unsigned int cl_scan_secs; | |
100 | unsigned int cl_log_debug; | |
6ed7257b | 101 | unsigned int cl_protocol; |
3ae1acf9 | 102 | unsigned int cl_timewarn_cs; |
d200778e DT |
103 | }; |
104 | ||
105 | enum { | |
106 | CLUSTER_ATTR_TCP_PORT = 0, | |
107 | CLUSTER_ATTR_BUFFER_SIZE, | |
108 | CLUSTER_ATTR_RSBTBL_SIZE, | |
109 | CLUSTER_ATTR_LKBTBL_SIZE, | |
110 | CLUSTER_ATTR_DIRTBL_SIZE, | |
111 | CLUSTER_ATTR_RECOVER_TIMER, | |
112 | CLUSTER_ATTR_TOSS_SECS, | |
113 | CLUSTER_ATTR_SCAN_SECS, | |
114 | CLUSTER_ATTR_LOG_DEBUG, | |
6ed7257b | 115 | CLUSTER_ATTR_PROTOCOL, |
3ae1acf9 | 116 | CLUSTER_ATTR_TIMEWARN_CS, |
d200778e DT |
117 | }; |
118 | ||
119 | struct cluster_attribute { | |
120 | struct configfs_attribute attr; | |
51409340 DT |
121 | ssize_t (*show)(struct dlm_cluster *, char *); |
122 | ssize_t (*store)(struct dlm_cluster *, const char *, size_t); | |
d200778e DT |
123 | }; |
124 | ||
51409340 | 125 | static ssize_t cluster_set(struct dlm_cluster *cl, unsigned int *cl_field, |
5416b704 | 126 | int *info_field, int check_zero, |
d200778e DT |
127 | const char *buf, size_t len) |
128 | { | |
129 | unsigned int x; | |
130 | ||
131 | if (!capable(CAP_SYS_ADMIN)) | |
132 | return -EACCES; | |
133 | ||
134 | x = simple_strtoul(buf, NULL, 0); | |
135 | ||
136 | if (check_zero && !x) | |
137 | return -EINVAL; | |
138 | ||
139 | *cl_field = x; | |
140 | *info_field = x; | |
141 | ||
142 | return len; | |
143 | } | |
144 | ||
d200778e | 145 | #define CLUSTER_ATTR(name, check_zero) \ |
51409340 | 146 | static ssize_t name##_write(struct dlm_cluster *cl, const char *buf, size_t len) \ |
d200778e DT |
147 | { \ |
148 | return cluster_set(cl, &cl->cl_##name, &dlm_config.ci_##name, \ | |
149 | check_zero, buf, len); \ | |
150 | } \ | |
51409340 | 151 | static ssize_t name##_read(struct dlm_cluster *cl, char *buf) \ |
d200778e DT |
152 | { \ |
153 | return snprintf(buf, PAGE_SIZE, "%u\n", cl->cl_##name); \ | |
154 | } \ | |
155 | static struct cluster_attribute cluster_attr_##name = \ | |
156 | __CONFIGFS_ATTR(name, 0644, name##_read, name##_write) | |
157 | ||
158 | CLUSTER_ATTR(tcp_port, 1); | |
159 | CLUSTER_ATTR(buffer_size, 1); | |
160 | CLUSTER_ATTR(rsbtbl_size, 1); | |
161 | CLUSTER_ATTR(lkbtbl_size, 1); | |
162 | CLUSTER_ATTR(dirtbl_size, 1); | |
163 | CLUSTER_ATTR(recover_timer, 1); | |
164 | CLUSTER_ATTR(toss_secs, 1); | |
165 | CLUSTER_ATTR(scan_secs, 1); | |
166 | CLUSTER_ATTR(log_debug, 0); | |
6ed7257b | 167 | CLUSTER_ATTR(protocol, 0); |
3ae1acf9 | 168 | CLUSTER_ATTR(timewarn_cs, 1); |
d200778e DT |
169 | |
170 | static struct configfs_attribute *cluster_attrs[] = { | |
171 | [CLUSTER_ATTR_TCP_PORT] = &cluster_attr_tcp_port.attr, | |
172 | [CLUSTER_ATTR_BUFFER_SIZE] = &cluster_attr_buffer_size.attr, | |
173 | [CLUSTER_ATTR_RSBTBL_SIZE] = &cluster_attr_rsbtbl_size.attr, | |
174 | [CLUSTER_ATTR_LKBTBL_SIZE] = &cluster_attr_lkbtbl_size.attr, | |
175 | [CLUSTER_ATTR_DIRTBL_SIZE] = &cluster_attr_dirtbl_size.attr, | |
176 | [CLUSTER_ATTR_RECOVER_TIMER] = &cluster_attr_recover_timer.attr, | |
177 | [CLUSTER_ATTR_TOSS_SECS] = &cluster_attr_toss_secs.attr, | |
178 | [CLUSTER_ATTR_SCAN_SECS] = &cluster_attr_scan_secs.attr, | |
179 | [CLUSTER_ATTR_LOG_DEBUG] = &cluster_attr_log_debug.attr, | |
6ed7257b | 180 | [CLUSTER_ATTR_PROTOCOL] = &cluster_attr_protocol.attr, |
3ae1acf9 | 181 | [CLUSTER_ATTR_TIMEWARN_CS] = &cluster_attr_timewarn_cs.attr, |
d200778e DT |
182 | NULL, |
183 | }; | |
184 | ||
e7fd4179 DT |
185 | enum { |
186 | COMM_ATTR_NODEID = 0, | |
187 | COMM_ATTR_LOCAL, | |
188 | COMM_ATTR_ADDR, | |
189 | }; | |
190 | ||
191 | struct comm_attribute { | |
192 | struct configfs_attribute attr; | |
51409340 DT |
193 | ssize_t (*show)(struct dlm_comm *, char *); |
194 | ssize_t (*store)(struct dlm_comm *, const char *, size_t); | |
e7fd4179 DT |
195 | }; |
196 | ||
197 | static struct comm_attribute comm_attr_nodeid = { | |
198 | .attr = { .ca_owner = THIS_MODULE, | |
199 | .ca_name = "nodeid", | |
200 | .ca_mode = S_IRUGO | S_IWUSR }, | |
201 | .show = comm_nodeid_read, | |
202 | .store = comm_nodeid_write, | |
203 | }; | |
204 | ||
205 | static struct comm_attribute comm_attr_local = { | |
206 | .attr = { .ca_owner = THIS_MODULE, | |
207 | .ca_name = "local", | |
208 | .ca_mode = S_IRUGO | S_IWUSR }, | |
209 | .show = comm_local_read, | |
210 | .store = comm_local_write, | |
211 | }; | |
212 | ||
213 | static struct comm_attribute comm_attr_addr = { | |
214 | .attr = { .ca_owner = THIS_MODULE, | |
215 | .ca_name = "addr", | |
216 | .ca_mode = S_IRUGO | S_IWUSR }, | |
217 | .store = comm_addr_write, | |
218 | }; | |
219 | ||
220 | static struct configfs_attribute *comm_attrs[] = { | |
221 | [COMM_ATTR_NODEID] = &comm_attr_nodeid.attr, | |
222 | [COMM_ATTR_LOCAL] = &comm_attr_local.attr, | |
223 | [COMM_ATTR_ADDR] = &comm_attr_addr.attr, | |
224 | NULL, | |
225 | }; | |
226 | ||
227 | enum { | |
228 | NODE_ATTR_NODEID = 0, | |
229 | NODE_ATTR_WEIGHT, | |
230 | }; | |
231 | ||
232 | struct node_attribute { | |
233 | struct configfs_attribute attr; | |
51409340 DT |
234 | ssize_t (*show)(struct dlm_node *, char *); |
235 | ssize_t (*store)(struct dlm_node *, const char *, size_t); | |
e7fd4179 DT |
236 | }; |
237 | ||
238 | static struct node_attribute node_attr_nodeid = { | |
239 | .attr = { .ca_owner = THIS_MODULE, | |
240 | .ca_name = "nodeid", | |
241 | .ca_mode = S_IRUGO | S_IWUSR }, | |
242 | .show = node_nodeid_read, | |
243 | .store = node_nodeid_write, | |
244 | }; | |
245 | ||
246 | static struct node_attribute node_attr_weight = { | |
247 | .attr = { .ca_owner = THIS_MODULE, | |
248 | .ca_name = "weight", | |
249 | .ca_mode = S_IRUGO | S_IWUSR }, | |
250 | .show = node_weight_read, | |
251 | .store = node_weight_write, | |
252 | }; | |
253 | ||
254 | static struct configfs_attribute *node_attrs[] = { | |
255 | [NODE_ATTR_NODEID] = &node_attr_nodeid.attr, | |
256 | [NODE_ATTR_WEIGHT] = &node_attr_weight.attr, | |
257 | NULL, | |
258 | }; | |
259 | ||
51409340 | 260 | struct dlm_clusters { |
e7fd4179 DT |
261 | struct configfs_subsystem subsys; |
262 | }; | |
263 | ||
51409340 | 264 | struct dlm_spaces { |
e7fd4179 DT |
265 | struct config_group ss_group; |
266 | }; | |
267 | ||
51409340 | 268 | struct dlm_space { |
e7fd4179 DT |
269 | struct config_group group; |
270 | struct list_head members; | |
90135925 | 271 | struct mutex members_lock; |
e7fd4179 DT |
272 | int members_count; |
273 | }; | |
274 | ||
51409340 | 275 | struct dlm_comms { |
e7fd4179 DT |
276 | struct config_group cs_group; |
277 | }; | |
278 | ||
51409340 | 279 | struct dlm_comm { |
e7fd4179 DT |
280 | struct config_item item; |
281 | int nodeid; | |
282 | int local; | |
283 | int addr_count; | |
284 | struct sockaddr_storage *addr[DLM_MAX_ADDR_COUNT]; | |
285 | }; | |
286 | ||
51409340 | 287 | struct dlm_nodes { |
e7fd4179 DT |
288 | struct config_group ns_group; |
289 | }; | |
290 | ||
51409340 | 291 | struct dlm_node { |
e7fd4179 DT |
292 | struct config_item item; |
293 | struct list_head list; /* space->members */ | |
294 | int nodeid; | |
295 | int weight; | |
d44e0fc7 | 296 | int new; |
e7fd4179 DT |
297 | }; |
298 | ||
299 | static struct configfs_group_operations clusters_ops = { | |
300 | .make_group = make_cluster, | |
301 | .drop_item = drop_cluster, | |
302 | }; | |
303 | ||
304 | static struct configfs_item_operations cluster_ops = { | |
305 | .release = release_cluster, | |
d200778e DT |
306 | .show_attribute = show_cluster, |
307 | .store_attribute = store_cluster, | |
e7fd4179 DT |
308 | }; |
309 | ||
310 | static struct configfs_group_operations spaces_ops = { | |
311 | .make_group = make_space, | |
312 | .drop_item = drop_space, | |
313 | }; | |
314 | ||
315 | static struct configfs_item_operations space_ops = { | |
316 | .release = release_space, | |
317 | }; | |
318 | ||
319 | static struct configfs_group_operations comms_ops = { | |
320 | .make_item = make_comm, | |
321 | .drop_item = drop_comm, | |
322 | }; | |
323 | ||
324 | static struct configfs_item_operations comm_ops = { | |
325 | .release = release_comm, | |
326 | .show_attribute = show_comm, | |
327 | .store_attribute = store_comm, | |
328 | }; | |
329 | ||
330 | static struct configfs_group_operations nodes_ops = { | |
331 | .make_item = make_node, | |
332 | .drop_item = drop_node, | |
333 | }; | |
334 | ||
335 | static struct configfs_item_operations node_ops = { | |
336 | .release = release_node, | |
337 | .show_attribute = show_node, | |
338 | .store_attribute = store_node, | |
339 | }; | |
340 | ||
341 | static struct config_item_type clusters_type = { | |
342 | .ct_group_ops = &clusters_ops, | |
343 | .ct_owner = THIS_MODULE, | |
344 | }; | |
345 | ||
346 | static struct config_item_type cluster_type = { | |
347 | .ct_item_ops = &cluster_ops, | |
d200778e | 348 | .ct_attrs = cluster_attrs, |
e7fd4179 DT |
349 | .ct_owner = THIS_MODULE, |
350 | }; | |
351 | ||
352 | static struct config_item_type spaces_type = { | |
353 | .ct_group_ops = &spaces_ops, | |
354 | .ct_owner = THIS_MODULE, | |
355 | }; | |
356 | ||
357 | static struct config_item_type space_type = { | |
358 | .ct_item_ops = &space_ops, | |
359 | .ct_owner = THIS_MODULE, | |
360 | }; | |
361 | ||
362 | static struct config_item_type comms_type = { | |
363 | .ct_group_ops = &comms_ops, | |
364 | .ct_owner = THIS_MODULE, | |
365 | }; | |
366 | ||
367 | static struct config_item_type comm_type = { | |
368 | .ct_item_ops = &comm_ops, | |
369 | .ct_attrs = comm_attrs, | |
370 | .ct_owner = THIS_MODULE, | |
371 | }; | |
372 | ||
373 | static struct config_item_type nodes_type = { | |
374 | .ct_group_ops = &nodes_ops, | |
375 | .ct_owner = THIS_MODULE, | |
376 | }; | |
377 | ||
378 | static struct config_item_type node_type = { | |
379 | .ct_item_ops = &node_ops, | |
380 | .ct_attrs = node_attrs, | |
381 | .ct_owner = THIS_MODULE, | |
382 | }; | |
383 | ||
27eccf46 | 384 | static struct dlm_cluster *config_item_to_cluster(struct config_item *i) |
e7fd4179 | 385 | { |
51409340 DT |
386 | return i ? container_of(to_config_group(i), struct dlm_cluster, group) : |
387 | NULL; | |
e7fd4179 DT |
388 | } |
389 | ||
27eccf46 | 390 | static struct dlm_space *config_item_to_space(struct config_item *i) |
e7fd4179 | 391 | { |
51409340 DT |
392 | return i ? container_of(to_config_group(i), struct dlm_space, group) : |
393 | NULL; | |
e7fd4179 DT |
394 | } |
395 | ||
27eccf46 | 396 | static struct dlm_comm *config_item_to_comm(struct config_item *i) |
e7fd4179 | 397 | { |
51409340 | 398 | return i ? container_of(i, struct dlm_comm, item) : NULL; |
e7fd4179 DT |
399 | } |
400 | ||
27eccf46 | 401 | static struct dlm_node *config_item_to_node(struct config_item *i) |
e7fd4179 | 402 | { |
51409340 | 403 | return i ? container_of(i, struct dlm_node, item) : NULL; |
e7fd4179 DT |
404 | } |
405 | ||
f89ab861 JB |
406 | static struct config_group *make_cluster(struct config_group *g, |
407 | const char *name) | |
e7fd4179 | 408 | { |
51409340 DT |
409 | struct dlm_cluster *cl = NULL; |
410 | struct dlm_spaces *sps = NULL; | |
411 | struct dlm_comms *cms = NULL; | |
e7fd4179 DT |
412 | void *gps = NULL; |
413 | ||
573c24c4 DT |
414 | cl = kzalloc(sizeof(struct dlm_cluster), GFP_NOFS); |
415 | gps = kcalloc(3, sizeof(struct config_group *), GFP_NOFS); | |
416 | sps = kzalloc(sizeof(struct dlm_spaces), GFP_NOFS); | |
417 | cms = kzalloc(sizeof(struct dlm_comms), GFP_NOFS); | |
e7fd4179 DT |
418 | |
419 | if (!cl || !gps || !sps || !cms) | |
420 | goto fail; | |
421 | ||
422 | config_group_init_type_name(&cl->group, name, &cluster_type); | |
423 | config_group_init_type_name(&sps->ss_group, "spaces", &spaces_type); | |
424 | config_group_init_type_name(&cms->cs_group, "comms", &comms_type); | |
425 | ||
426 | cl->group.default_groups = gps; | |
427 | cl->group.default_groups[0] = &sps->ss_group; | |
428 | cl->group.default_groups[1] = &cms->cs_group; | |
429 | cl->group.default_groups[2] = NULL; | |
430 | ||
d200778e DT |
431 | cl->cl_tcp_port = dlm_config.ci_tcp_port; |
432 | cl->cl_buffer_size = dlm_config.ci_buffer_size; | |
433 | cl->cl_rsbtbl_size = dlm_config.ci_rsbtbl_size; | |
434 | cl->cl_lkbtbl_size = dlm_config.ci_lkbtbl_size; | |
435 | cl->cl_dirtbl_size = dlm_config.ci_dirtbl_size; | |
436 | cl->cl_recover_timer = dlm_config.ci_recover_timer; | |
437 | cl->cl_toss_secs = dlm_config.ci_toss_secs; | |
438 | cl->cl_scan_secs = dlm_config.ci_scan_secs; | |
439 | cl->cl_log_debug = dlm_config.ci_log_debug; | |
0b7cac0f | 440 | cl->cl_protocol = dlm_config.ci_protocol; |
84d8cd69 | 441 | cl->cl_timewarn_cs = dlm_config.ci_timewarn_cs; |
d200778e | 442 | |
e7fd4179 DT |
443 | space_list = &sps->ss_group; |
444 | comm_list = &cms->cs_group; | |
f89ab861 | 445 | return &cl->group; |
e7fd4179 DT |
446 | |
447 | fail: | |
448 | kfree(cl); | |
449 | kfree(gps); | |
450 | kfree(sps); | |
451 | kfree(cms); | |
a6795e9e | 452 | return ERR_PTR(-ENOMEM); |
e7fd4179 DT |
453 | } |
454 | ||
455 | static void drop_cluster(struct config_group *g, struct config_item *i) | |
456 | { | |
27eccf46 | 457 | struct dlm_cluster *cl = config_item_to_cluster(i); |
e7fd4179 DT |
458 | struct config_item *tmp; |
459 | int j; | |
460 | ||
461 | for (j = 0; cl->group.default_groups[j]; j++) { | |
462 | tmp = &cl->group.default_groups[j]->cg_item; | |
463 | cl->group.default_groups[j] = NULL; | |
464 | config_item_put(tmp); | |
465 | } | |
466 | ||
467 | space_list = NULL; | |
468 | comm_list = NULL; | |
469 | ||
470 | config_item_put(i); | |
471 | } | |
472 | ||
473 | static void release_cluster(struct config_item *i) | |
474 | { | |
27eccf46 | 475 | struct dlm_cluster *cl = config_item_to_cluster(i); |
e7fd4179 DT |
476 | kfree(cl->group.default_groups); |
477 | kfree(cl); | |
478 | } | |
479 | ||
f89ab861 | 480 | static struct config_group *make_space(struct config_group *g, const char *name) |
e7fd4179 | 481 | { |
51409340 DT |
482 | struct dlm_space *sp = NULL; |
483 | struct dlm_nodes *nds = NULL; | |
e7fd4179 DT |
484 | void *gps = NULL; |
485 | ||
573c24c4 DT |
486 | sp = kzalloc(sizeof(struct dlm_space), GFP_NOFS); |
487 | gps = kcalloc(2, sizeof(struct config_group *), GFP_NOFS); | |
488 | nds = kzalloc(sizeof(struct dlm_nodes), GFP_NOFS); | |
e7fd4179 DT |
489 | |
490 | if (!sp || !gps || !nds) | |
491 | goto fail; | |
492 | ||
493 | config_group_init_type_name(&sp->group, name, &space_type); | |
494 | config_group_init_type_name(&nds->ns_group, "nodes", &nodes_type); | |
495 | ||
496 | sp->group.default_groups = gps; | |
497 | sp->group.default_groups[0] = &nds->ns_group; | |
498 | sp->group.default_groups[1] = NULL; | |
499 | ||
500 | INIT_LIST_HEAD(&sp->members); | |
90135925 | 501 | mutex_init(&sp->members_lock); |
e7fd4179 | 502 | sp->members_count = 0; |
f89ab861 | 503 | return &sp->group; |
e7fd4179 DT |
504 | |
505 | fail: | |
506 | kfree(sp); | |
507 | kfree(gps); | |
508 | kfree(nds); | |
a6795e9e | 509 | return ERR_PTR(-ENOMEM); |
e7fd4179 DT |
510 | } |
511 | ||
512 | static void drop_space(struct config_group *g, struct config_item *i) | |
513 | { | |
27eccf46 | 514 | struct dlm_space *sp = config_item_to_space(i); |
e7fd4179 DT |
515 | struct config_item *tmp; |
516 | int j; | |
517 | ||
518 | /* assert list_empty(&sp->members) */ | |
519 | ||
520 | for (j = 0; sp->group.default_groups[j]; j++) { | |
521 | tmp = &sp->group.default_groups[j]->cg_item; | |
522 | sp->group.default_groups[j] = NULL; | |
523 | config_item_put(tmp); | |
524 | } | |
525 | ||
526 | config_item_put(i); | |
527 | } | |
528 | ||
529 | static void release_space(struct config_item *i) | |
530 | { | |
27eccf46 | 531 | struct dlm_space *sp = config_item_to_space(i); |
e7fd4179 DT |
532 | kfree(sp->group.default_groups); |
533 | kfree(sp); | |
534 | } | |
535 | ||
f89ab861 | 536 | static struct config_item *make_comm(struct config_group *g, const char *name) |
e7fd4179 | 537 | { |
51409340 | 538 | struct dlm_comm *cm; |
e7fd4179 | 539 | |
573c24c4 | 540 | cm = kzalloc(sizeof(struct dlm_comm), GFP_NOFS); |
e7fd4179 | 541 | if (!cm) |
a6795e9e | 542 | return ERR_PTR(-ENOMEM); |
e7fd4179 DT |
543 | |
544 | config_item_init_type_name(&cm->item, name, &comm_type); | |
545 | cm->nodeid = -1; | |
546 | cm->local = 0; | |
547 | cm->addr_count = 0; | |
f89ab861 | 548 | return &cm->item; |
e7fd4179 DT |
549 | } |
550 | ||
551 | static void drop_comm(struct config_group *g, struct config_item *i) | |
552 | { | |
27eccf46 | 553 | struct dlm_comm *cm = config_item_to_comm(i); |
e7fd4179 DT |
554 | if (local_comm == cm) |
555 | local_comm = NULL; | |
1c032c03 | 556 | dlm_lowcomms_close(cm->nodeid); |
e7fd4179 DT |
557 | while (cm->addr_count--) |
558 | kfree(cm->addr[cm->addr_count]); | |
559 | config_item_put(i); | |
560 | } | |
561 | ||
562 | static void release_comm(struct config_item *i) | |
563 | { | |
27eccf46 | 564 | struct dlm_comm *cm = config_item_to_comm(i); |
e7fd4179 DT |
565 | kfree(cm); |
566 | } | |
567 | ||
f89ab861 | 568 | static struct config_item *make_node(struct config_group *g, const char *name) |
e7fd4179 | 569 | { |
27eccf46 | 570 | struct dlm_space *sp = config_item_to_space(g->cg_item.ci_parent); |
51409340 | 571 | struct dlm_node *nd; |
e7fd4179 | 572 | |
573c24c4 | 573 | nd = kzalloc(sizeof(struct dlm_node), GFP_NOFS); |
e7fd4179 | 574 | if (!nd) |
a6795e9e | 575 | return ERR_PTR(-ENOMEM); |
e7fd4179 DT |
576 | |
577 | config_item_init_type_name(&nd->item, name, &node_type); | |
578 | nd->nodeid = -1; | |
579 | nd->weight = 1; /* default weight of 1 if none is set */ | |
d44e0fc7 | 580 | nd->new = 1; /* set to 0 once it's been read by dlm_nodeid_list() */ |
e7fd4179 | 581 | |
90135925 | 582 | mutex_lock(&sp->members_lock); |
e7fd4179 DT |
583 | list_add(&nd->list, &sp->members); |
584 | sp->members_count++; | |
90135925 | 585 | mutex_unlock(&sp->members_lock); |
e7fd4179 | 586 | |
f89ab861 | 587 | return &nd->item; |
e7fd4179 DT |
588 | } |
589 | ||
590 | static void drop_node(struct config_group *g, struct config_item *i) | |
591 | { | |
27eccf46 AM |
592 | struct dlm_space *sp = config_item_to_space(g->cg_item.ci_parent); |
593 | struct dlm_node *nd = config_item_to_node(i); | |
e7fd4179 | 594 | |
90135925 | 595 | mutex_lock(&sp->members_lock); |
e7fd4179 DT |
596 | list_del(&nd->list); |
597 | sp->members_count--; | |
90135925 | 598 | mutex_unlock(&sp->members_lock); |
e7fd4179 DT |
599 | |
600 | config_item_put(i); | |
601 | } | |
602 | ||
603 | static void release_node(struct config_item *i) | |
604 | { | |
27eccf46 | 605 | struct dlm_node *nd = config_item_to_node(i); |
e7fd4179 DT |
606 | kfree(nd); |
607 | } | |
608 | ||
51409340 | 609 | static struct dlm_clusters clusters_root = { |
e7fd4179 DT |
610 | .subsys = { |
611 | .su_group = { | |
612 | .cg_item = { | |
613 | .ci_namebuf = "dlm", | |
614 | .ci_type = &clusters_type, | |
615 | }, | |
616 | }, | |
617 | }, | |
618 | }; | |
619 | ||
30727174 | 620 | int __init dlm_config_init(void) |
e7fd4179 DT |
621 | { |
622 | config_group_init(&clusters_root.subsys.su_group); | |
e6bd07ae | 623 | mutex_init(&clusters_root.subsys.su_mutex); |
e7fd4179 DT |
624 | return configfs_register_subsystem(&clusters_root.subsys); |
625 | } | |
626 | ||
627 | void dlm_config_exit(void) | |
628 | { | |
629 | configfs_unregister_subsystem(&clusters_root.subsys); | |
630 | } | |
631 | ||
632 | /* | |
633 | * Functions for user space to read/write attributes | |
634 | */ | |
635 | ||
d200778e DT |
636 | static ssize_t show_cluster(struct config_item *i, struct configfs_attribute *a, |
637 | char *buf) | |
638 | { | |
27eccf46 | 639 | struct dlm_cluster *cl = config_item_to_cluster(i); |
d200778e DT |
640 | struct cluster_attribute *cla = |
641 | container_of(a, struct cluster_attribute, attr); | |
642 | return cla->show ? cla->show(cl, buf) : 0; | |
643 | } | |
644 | ||
645 | static ssize_t store_cluster(struct config_item *i, | |
646 | struct configfs_attribute *a, | |
647 | const char *buf, size_t len) | |
648 | { | |
27eccf46 | 649 | struct dlm_cluster *cl = config_item_to_cluster(i); |
d200778e DT |
650 | struct cluster_attribute *cla = |
651 | container_of(a, struct cluster_attribute, attr); | |
652 | return cla->store ? cla->store(cl, buf, len) : -EINVAL; | |
653 | } | |
654 | ||
e7fd4179 DT |
655 | static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a, |
656 | char *buf) | |
657 | { | |
27eccf46 | 658 | struct dlm_comm *cm = config_item_to_comm(i); |
e7fd4179 DT |
659 | struct comm_attribute *cma = |
660 | container_of(a, struct comm_attribute, attr); | |
661 | return cma->show ? cma->show(cm, buf) : 0; | |
662 | } | |
663 | ||
664 | static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a, | |
665 | const char *buf, size_t len) | |
666 | { | |
27eccf46 | 667 | struct dlm_comm *cm = config_item_to_comm(i); |
e7fd4179 DT |
668 | struct comm_attribute *cma = |
669 | container_of(a, struct comm_attribute, attr); | |
670 | return cma->store ? cma->store(cm, buf, len) : -EINVAL; | |
671 | } | |
672 | ||
51409340 | 673 | static ssize_t comm_nodeid_read(struct dlm_comm *cm, char *buf) |
e7fd4179 DT |
674 | { |
675 | return sprintf(buf, "%d\n", cm->nodeid); | |
676 | } | |
677 | ||
51409340 DT |
678 | static ssize_t comm_nodeid_write(struct dlm_comm *cm, const char *buf, |
679 | size_t len) | |
e7fd4179 DT |
680 | { |
681 | cm->nodeid = simple_strtol(buf, NULL, 0); | |
682 | return len; | |
683 | } | |
684 | ||
51409340 | 685 | static ssize_t comm_local_read(struct dlm_comm *cm, char *buf) |
e7fd4179 DT |
686 | { |
687 | return sprintf(buf, "%d\n", cm->local); | |
688 | } | |
689 | ||
51409340 DT |
690 | static ssize_t comm_local_write(struct dlm_comm *cm, const char *buf, |
691 | size_t len) | |
e7fd4179 DT |
692 | { |
693 | cm->local= simple_strtol(buf, NULL, 0); | |
694 | if (cm->local && !local_comm) | |
695 | local_comm = cm; | |
696 | return len; | |
697 | } | |
698 | ||
51409340 | 699 | static ssize_t comm_addr_write(struct dlm_comm *cm, const char *buf, size_t len) |
e7fd4179 DT |
700 | { |
701 | struct sockaddr_storage *addr; | |
702 | ||
703 | if (len != sizeof(struct sockaddr_storage)) | |
704 | return -EINVAL; | |
705 | ||
706 | if (cm->addr_count >= DLM_MAX_ADDR_COUNT) | |
707 | return -ENOSPC; | |
708 | ||
573c24c4 | 709 | addr = kzalloc(sizeof(*addr), GFP_NOFS); |
e7fd4179 DT |
710 | if (!addr) |
711 | return -ENOMEM; | |
712 | ||
713 | memcpy(addr, buf, len); | |
714 | cm->addr[cm->addr_count++] = addr; | |
715 | return len; | |
716 | } | |
717 | ||
718 | static ssize_t show_node(struct config_item *i, struct configfs_attribute *a, | |
719 | char *buf) | |
720 | { | |
27eccf46 | 721 | struct dlm_node *nd = config_item_to_node(i); |
e7fd4179 DT |
722 | struct node_attribute *nda = |
723 | container_of(a, struct node_attribute, attr); | |
724 | return nda->show ? nda->show(nd, buf) : 0; | |
725 | } | |
726 | ||
727 | static ssize_t store_node(struct config_item *i, struct configfs_attribute *a, | |
728 | const char *buf, size_t len) | |
729 | { | |
27eccf46 | 730 | struct dlm_node *nd = config_item_to_node(i); |
e7fd4179 DT |
731 | struct node_attribute *nda = |
732 | container_of(a, struct node_attribute, attr); | |
733 | return nda->store ? nda->store(nd, buf, len) : -EINVAL; | |
734 | } | |
735 | ||
51409340 | 736 | static ssize_t node_nodeid_read(struct dlm_node *nd, char *buf) |
e7fd4179 DT |
737 | { |
738 | return sprintf(buf, "%d\n", nd->nodeid); | |
739 | } | |
740 | ||
51409340 DT |
741 | static ssize_t node_nodeid_write(struct dlm_node *nd, const char *buf, |
742 | size_t len) | |
e7fd4179 DT |
743 | { |
744 | nd->nodeid = simple_strtol(buf, NULL, 0); | |
745 | return len; | |
746 | } | |
747 | ||
51409340 | 748 | static ssize_t node_weight_read(struct dlm_node *nd, char *buf) |
e7fd4179 DT |
749 | { |
750 | return sprintf(buf, "%d\n", nd->weight); | |
751 | } | |
752 | ||
51409340 DT |
753 | static ssize_t node_weight_write(struct dlm_node *nd, const char *buf, |
754 | size_t len) | |
e7fd4179 DT |
755 | { |
756 | nd->weight = simple_strtol(buf, NULL, 0); | |
757 | return len; | |
758 | } | |
759 | ||
760 | /* | |
761 | * Functions for the dlm to get the info that's been configured | |
762 | */ | |
763 | ||
51409340 | 764 | static struct dlm_space *get_space(char *name) |
e7fd4179 | 765 | { |
3168b078 SS |
766 | struct config_item *i; |
767 | ||
e7fd4179 DT |
768 | if (!space_list) |
769 | return NULL; | |
3168b078 | 770 | |
e6bd07ae | 771 | mutex_lock(&space_list->cg_subsys->su_mutex); |
3fe6c5ce | 772 | i = config_group_find_item(space_list, name); |
e6bd07ae | 773 | mutex_unlock(&space_list->cg_subsys->su_mutex); |
3168b078 | 774 | |
27eccf46 | 775 | return config_item_to_space(i); |
e7fd4179 DT |
776 | } |
777 | ||
51409340 | 778 | static void put_space(struct dlm_space *sp) |
e7fd4179 DT |
779 | { |
780 | config_item_put(&sp->group.cg_item); | |
781 | } | |
782 | ||
44be6fdf DT |
783 | static int addr_compare(struct sockaddr_storage *x, struct sockaddr_storage *y) |
784 | { | |
785 | switch (x->ss_family) { | |
786 | case AF_INET: { | |
787 | struct sockaddr_in *sinx = (struct sockaddr_in *)x; | |
788 | struct sockaddr_in *siny = (struct sockaddr_in *)y; | |
789 | if (sinx->sin_addr.s_addr != siny->sin_addr.s_addr) | |
790 | return 0; | |
791 | if (sinx->sin_port != siny->sin_port) | |
792 | return 0; | |
793 | break; | |
794 | } | |
795 | case AF_INET6: { | |
796 | struct sockaddr_in6 *sinx = (struct sockaddr_in6 *)x; | |
797 | struct sockaddr_in6 *siny = (struct sockaddr_in6 *)y; | |
798 | if (!ipv6_addr_equal(&sinx->sin6_addr, &siny->sin6_addr)) | |
799 | return 0; | |
800 | if (sinx->sin6_port != siny->sin6_port) | |
801 | return 0; | |
802 | break; | |
803 | } | |
804 | default: | |
805 | return 0; | |
806 | } | |
807 | return 1; | |
808 | } | |
809 | ||
51409340 | 810 | static struct dlm_comm *get_comm(int nodeid, struct sockaddr_storage *addr) |
e7fd4179 DT |
811 | { |
812 | struct config_item *i; | |
51409340 | 813 | struct dlm_comm *cm = NULL; |
e7fd4179 DT |
814 | int found = 0; |
815 | ||
816 | if (!comm_list) | |
817 | return NULL; | |
818 | ||
e6bd07ae | 819 | mutex_lock(&clusters_root.subsys.su_mutex); |
e7fd4179 DT |
820 | |
821 | list_for_each_entry(i, &comm_list->cg_children, ci_entry) { | |
27eccf46 | 822 | cm = config_item_to_comm(i); |
e7fd4179 DT |
823 | |
824 | if (nodeid) { | |
825 | if (cm->nodeid != nodeid) | |
826 | continue; | |
827 | found = 1; | |
3168b078 | 828 | config_item_get(i); |
e7fd4179 DT |
829 | break; |
830 | } else { | |
44be6fdf | 831 | if (!cm->addr_count || !addr_compare(cm->addr[0], addr)) |
e7fd4179 DT |
832 | continue; |
833 | found = 1; | |
3168b078 | 834 | config_item_get(i); |
e7fd4179 DT |
835 | break; |
836 | } | |
837 | } | |
e6bd07ae | 838 | mutex_unlock(&clusters_root.subsys.su_mutex); |
e7fd4179 | 839 | |
3168b078 | 840 | if (!found) |
e7fd4179 DT |
841 | cm = NULL; |
842 | return cm; | |
843 | } | |
844 | ||
51409340 | 845 | static void put_comm(struct dlm_comm *cm) |
e7fd4179 DT |
846 | { |
847 | config_item_put(&cm->item); | |
848 | } | |
849 | ||
850 | /* caller must free mem */ | |
d44e0fc7 DT |
851 | int dlm_nodeid_list(char *lsname, int **ids_out, int *ids_count_out, |
852 | int **new_out, int *new_count_out) | |
e7fd4179 | 853 | { |
51409340 DT |
854 | struct dlm_space *sp; |
855 | struct dlm_node *nd; | |
d44e0fc7 DT |
856 | int i = 0, rv = 0, ids_count = 0, new_count = 0; |
857 | int *ids, *new; | |
e7fd4179 DT |
858 | |
859 | sp = get_space(lsname); | |
860 | if (!sp) | |
861 | return -EEXIST; | |
862 | ||
90135925 | 863 | mutex_lock(&sp->members_lock); |
e7fd4179 | 864 | if (!sp->members_count) { |
d44e0fc7 DT |
865 | rv = -EINVAL; |
866 | printk(KERN_ERR "dlm: zero members_count\n"); | |
e7fd4179 DT |
867 | goto out; |
868 | } | |
869 | ||
d44e0fc7 DT |
870 | ids_count = sp->members_count; |
871 | ||
573c24c4 | 872 | ids = kcalloc(ids_count, sizeof(int), GFP_NOFS); |
e7fd4179 DT |
873 | if (!ids) { |
874 | rv = -ENOMEM; | |
875 | goto out; | |
876 | } | |
877 | ||
d44e0fc7 | 878 | list_for_each_entry(nd, &sp->members, list) { |
e7fd4179 | 879 | ids[i++] = nd->nodeid; |
d44e0fc7 DT |
880 | if (nd->new) |
881 | new_count++; | |
882 | } | |
883 | ||
884 | if (ids_count != i) | |
885 | printk(KERN_ERR "dlm: bad nodeid count %d %d\n", ids_count, i); | |
886 | ||
887 | if (!new_count) | |
888 | goto out_ids; | |
889 | ||
573c24c4 | 890 | new = kcalloc(new_count, sizeof(int), GFP_NOFS); |
d44e0fc7 DT |
891 | if (!new) { |
892 | kfree(ids); | |
893 | rv = -ENOMEM; | |
894 | goto out; | |
895 | } | |
e7fd4179 | 896 | |
d44e0fc7 DT |
897 | i = 0; |
898 | list_for_each_entry(nd, &sp->members, list) { | |
899 | if (nd->new) { | |
900 | new[i++] = nd->nodeid; | |
901 | nd->new = 0; | |
902 | } | |
903 | } | |
904 | *new_count_out = new_count; | |
905 | *new_out = new; | |
e7fd4179 | 906 | |
d44e0fc7 DT |
907 | out_ids: |
908 | *ids_count_out = ids_count; | |
e7fd4179 DT |
909 | *ids_out = ids; |
910 | out: | |
90135925 | 911 | mutex_unlock(&sp->members_lock); |
e7fd4179 DT |
912 | put_space(sp); |
913 | return rv; | |
914 | } | |
915 | ||
916 | int dlm_node_weight(char *lsname, int nodeid) | |
917 | { | |
51409340 DT |
918 | struct dlm_space *sp; |
919 | struct dlm_node *nd; | |
e7fd4179 DT |
920 | int w = -EEXIST; |
921 | ||
922 | sp = get_space(lsname); | |
923 | if (!sp) | |
924 | goto out; | |
925 | ||
90135925 | 926 | mutex_lock(&sp->members_lock); |
e7fd4179 DT |
927 | list_for_each_entry(nd, &sp->members, list) { |
928 | if (nd->nodeid != nodeid) | |
929 | continue; | |
930 | w = nd->weight; | |
931 | break; | |
932 | } | |
90135925 | 933 | mutex_unlock(&sp->members_lock); |
e7fd4179 DT |
934 | put_space(sp); |
935 | out: | |
936 | return w; | |
937 | } | |
938 | ||
939 | int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr) | |
940 | { | |
51409340 | 941 | struct dlm_comm *cm = get_comm(nodeid, NULL); |
e7fd4179 DT |
942 | if (!cm) |
943 | return -EEXIST; | |
944 | if (!cm->addr_count) | |
945 | return -ENOENT; | |
946 | memcpy(addr, cm->addr[0], sizeof(*addr)); | |
947 | put_comm(cm); | |
948 | return 0; | |
949 | } | |
950 | ||
951 | int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid) | |
952 | { | |
51409340 | 953 | struct dlm_comm *cm = get_comm(0, addr); |
e7fd4179 DT |
954 | if (!cm) |
955 | return -EEXIST; | |
956 | *nodeid = cm->nodeid; | |
957 | put_comm(cm); | |
958 | return 0; | |
959 | } | |
960 | ||
961 | int dlm_our_nodeid(void) | |
962 | { | |
963 | return local_comm ? local_comm->nodeid : 0; | |
964 | } | |
965 | ||
966 | /* num 0 is first addr, num 1 is second addr */ | |
967 | int dlm_our_addr(struct sockaddr_storage *addr, int num) | |
968 | { | |
969 | if (!local_comm) | |
970 | return -1; | |
971 | if (num + 1 > local_comm->addr_count) | |
972 | return -1; | |
973 | memcpy(addr, local_comm->addr[num], sizeof(*addr)); | |
974 | return 0; | |
975 | } | |
976 | ||
977 | /* Config file defaults */ | |
978 | #define DEFAULT_TCP_PORT 21064 | |
979 | #define DEFAULT_BUFFER_SIZE 4096 | |
980 | #define DEFAULT_RSBTBL_SIZE 256 | |
981 | #define DEFAULT_LKBTBL_SIZE 1024 | |
982 | #define DEFAULT_DIRTBL_SIZE 512 | |
983 | #define DEFAULT_RECOVER_TIMER 5 | |
984 | #define DEFAULT_TOSS_SECS 10 | |
985 | #define DEFAULT_SCAN_SECS 5 | |
99fc6487 | 986 | #define DEFAULT_LOG_DEBUG 0 |
6ed7257b | 987 | #define DEFAULT_PROTOCOL 0 |
3ae1acf9 | 988 | #define DEFAULT_TIMEWARN_CS 500 /* 5 sec = 500 centiseconds */ |
e7fd4179 DT |
989 | |
990 | struct dlm_config_info dlm_config = { | |
68c817a1 DT |
991 | .ci_tcp_port = DEFAULT_TCP_PORT, |
992 | .ci_buffer_size = DEFAULT_BUFFER_SIZE, | |
993 | .ci_rsbtbl_size = DEFAULT_RSBTBL_SIZE, | |
994 | .ci_lkbtbl_size = DEFAULT_LKBTBL_SIZE, | |
995 | .ci_dirtbl_size = DEFAULT_DIRTBL_SIZE, | |
996 | .ci_recover_timer = DEFAULT_RECOVER_TIMER, | |
997 | .ci_toss_secs = DEFAULT_TOSS_SECS, | |
99fc6487 | 998 | .ci_scan_secs = DEFAULT_SCAN_SECS, |
6ed7257b | 999 | .ci_log_debug = DEFAULT_LOG_DEBUG, |
3ae1acf9 DT |
1000 | .ci_protocol = DEFAULT_PROTOCOL, |
1001 | .ci_timewarn_cs = DEFAULT_TIMEWARN_CS | |
e7fd4179 DT |
1002 | }; |
1003 |