]> git.proxmox.com Git - mirror_corosync.git/blob - exec/service.c
config: Don't free pointers used by transports
[mirror_corosync.git] / exec / service.c
1 /*
2 * Copyright (c) 2006 MontaVista Software, Inc.
3 * Copyright (c) 2006-2012 Red Hat, Inc.
4 *
5 * All rights reserved.
6 *
7 * Author: Steven Dake (sdake@redhat.com)
8 *
9 * This software licensed under BSD license, the text of which follows:
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are met:
13 *
14 * - Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * - Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 * - Neither the name of the MontaVista Software, Inc. nor the names of its
20 * contributors may be used to endorse or promote products derived from this
21 * software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33 * THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #include <config.h>
37
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include <corosync/swab.h>
42 #include <corosync/totem/totem.h>
43
44 #include <corosync/corotypes.h>
45 #include "util.h"
46 #include <corosync/logsys.h>
47 #include <corosync/icmap.h>
48
49 #include "timer.h"
50 #include <corosync/totem/totempg.h>
51 #include <corosync/totem/totemip.h>
52 #include "main.h"
53 #include "service.h"
54
55 #include <qb/qbipcs.h>
56 #include <qb/qbloop.h>
57
58 LOGSYS_DECLARE_SUBSYS ("SERV");
59
60 static struct default_service default_services[] = {
61 {
62 .name = "corosync_cmap",
63 .ver = 0,
64 .loader = cmap_get_service_engine_ver0
65 },
66 {
67 .name = "corosync_cfg",
68 .ver = 0,
69 .loader = cfg_get_service_engine_ver0
70 },
71 {
72 .name = "corosync_cpg",
73 .ver = 0,
74 .loader = cpg_get_service_engine_ver0
75 },
76 {
77 .name = "corosync_pload",
78 .ver = 0,
79 .loader = pload_get_service_engine_ver0
80 },
81 #ifdef HAVE_MONITORING
82 {
83 .name = "corosync_mon",
84 .ver = 0,
85 .loader = mon_get_service_engine_ver0
86 },
87 #endif
88 #ifdef HAVE_WATCHDOG
89 {
90 .name = "corosync_wd",
91 .ver = 0,
92 .loader = wd_get_service_engine_ver0
93 },
94 #endif
95 {
96 .name = "corosync_quorum",
97 .ver = 0,
98 .loader = vsf_quorum_get_service_engine_ver0
99 },
100 };
101
102 /*
103 * service exit and unlink schedwrk handler data structure
104 */
105 struct seus_handler_data {
106 int service_engine;
107 struct corosync_api_v1 *api;
108 };
109
110 struct corosync_service_engine *corosync_service[SERVICES_COUNT_MAX];
111
112 const char *service_stats_rx[SERVICES_COUNT_MAX][SERVICE_HANDLER_MAXIMUM_COUNT];
113 const char *service_stats_tx[SERVICES_COUNT_MAX][SERVICE_HANDLER_MAXIMUM_COUNT];
114
115 static void (*service_unlink_all_complete) (void) = NULL;
116
117 char *corosync_service_link_and_init (
118 struct corosync_api_v1 *corosync_api,
119 struct default_service *service)
120 {
121 struct corosync_service_engine *service_engine;
122 int fn;
123 char *name_sufix;
124 char key_name[ICMAP_KEYNAME_MAXLEN];
125 char *init_result;
126
127 /*
128 * Initialize service
129 */
130 service_engine = service->loader();
131
132 corosync_service[service_engine->id] = service_engine;
133
134 if (service_engine->config_init_fn) {
135 service_engine->config_init_fn (corosync_api);
136 }
137
138 if (service_engine->exec_init_fn) {
139 init_result = service_engine->exec_init_fn (corosync_api);
140 if (init_result) {
141 return (init_result);
142 }
143 }
144
145 /*
146 * Store service in cmap db
147 */
148 snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "internal_configuration.service.%u.name", service_engine->id);
149 icmap_set_string(key_name, service->name);
150
151 snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "internal_configuration.service.%u.ver", service_engine->id);
152 icmap_set_uint32(key_name, service->ver);
153
154 name_sufix = strrchr (service->name, '_');
155 if (name_sufix)
156 name_sufix++;
157 else
158 name_sufix = (char*)service->name;
159
160 snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "runtime.services.%s.service_id", name_sufix);
161 icmap_set_uint16(key_name, service_engine->id);
162
163 for (fn = 0; fn < service_engine->exec_engine_count; fn++) {
164 snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "runtime.services.%s.%d.tx", name_sufix, fn);
165 icmap_set_uint64(key_name, 0);
166 service_stats_tx[service_engine->id][fn] = strdup(key_name);
167
168 snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "runtime.services.%s.%d.rx", name_sufix, fn);
169 icmap_set_uint64(key_name, 0);
170 service_stats_rx[service_engine->id][fn] = strdup(key_name);
171 }
172
173 log_printf (LOGSYS_LEVEL_NOTICE,
174 "Service engine loaded: %s [%d]", service_engine->name, service_engine->id);
175 init_result = (char *)cs_ipcs_service_init(service_engine);
176 if (init_result != NULL) {
177 return (init_result);
178 }
179
180 return NULL;
181 }
182
183 static int service_priority_max(void)
184 {
185 int lpc = 0, max = 0;
186 for(; lpc < SERVICES_COUNT_MAX; lpc++) {
187 if(corosync_service[lpc] != NULL && corosync_service[lpc]->priority > max) {
188 max = corosync_service[lpc]->priority;
189 }
190 }
191 return max;
192 }
193
194 /*
195 * use the force
196 */
197 static unsigned int
198 corosync_service_unlink_and_exit_priority (
199 struct corosync_api_v1 *corosync_api,
200 int lowest_priority,
201 int *current_priority,
202 int *current_service_engine)
203 {
204 unsigned short service_id;
205 int res;
206
207 for(; *current_priority >= lowest_priority; *current_priority = *current_priority - 1) {
208 for(*current_service_engine = 0;
209 *current_service_engine < SERVICES_COUNT_MAX;
210 *current_service_engine = *current_service_engine + 1) {
211
212 if(corosync_service[*current_service_engine] == NULL ||
213 corosync_service[*current_service_engine]->priority != *current_priority) {
214 continue;
215 }
216
217 /*
218 * find service handle and unload it if possible.
219 *
220 * If the service engine's exec_exit_fn returns -1 indicating
221 * it was busy, this function returns -1 and can be called again
222 * at a later time (usually via the schedwrk api).
223 */
224 service_id = corosync_service[*current_service_engine]->id;
225
226 if (corosync_service[service_id]->exec_exit_fn) {
227 res = corosync_service[service_id]->exec_exit_fn ();
228 if (res == -1) {
229 return (-1);
230 }
231 }
232
233 /*
234 * Exit all ipc connections dependent on this service
235 */
236 cs_ipcs_service_destroy (*current_service_engine);
237
238 log_printf(LOGSYS_LEVEL_NOTICE,
239 "Service engine unloaded: %s",
240 corosync_service[*current_service_engine]->name);
241
242 corosync_service[*current_service_engine] = NULL;
243
244 /*
245 * Call should call this function again
246 */
247 return (1);
248 }
249 }
250 /*
251 * We finish unlink of all services -> no need to call this function again
252 */
253 return (0);
254 }
255
256 static unsigned int service_unlink_and_exit (
257 struct corosync_api_v1 *corosync_api,
258 const char *service_name,
259 unsigned int service_ver)
260 {
261 unsigned short service_id;
262 char *name_sufix;
263 int res;
264 const char *iter_key_name;
265 icmap_iter_t iter;
266 char key_name[ICMAP_KEYNAME_MAXLEN];
267 unsigned int found_service_ver;
268 char *found_service_name;
269 int service_found;
270
271 name_sufix = strrchr (service_name, '_');
272 if (name_sufix)
273 name_sufix++;
274 else
275 name_sufix = (char*)service_name;
276
277
278 service_found = 0;
279 found_service_name = NULL;
280 iter = icmap_iter_init("internal_configuration.service.");
281 while ((iter_key_name = icmap_iter_next(iter, NULL, NULL)) != NULL) {
282 res = sscanf(iter_key_name, "internal_configuration.service.%hu.%s", &service_id, key_name);
283 if (res != 2) {
284 continue;
285 }
286
287 snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "internal_configuration.service.%hu.name", service_id);
288 if (icmap_get_string(key_name, &found_service_name) != CS_OK) {
289 continue;
290 }
291
292 snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "internal_configuration.service.%u.ver", service_id);
293 if (icmap_get_uint32(key_name, &found_service_ver) != CS_OK) {
294 free(found_service_name);
295 continue;
296 }
297
298 if (service_ver == found_service_ver && strcmp(found_service_name, service_name) == 0) {
299 free(found_service_name);
300 service_found = 1;
301 break;
302 }
303 free(found_service_name);
304 }
305 icmap_iter_finalize(iter);
306
307 if (service_found && service_id < SERVICES_COUNT_MAX
308 && corosync_service[service_id] != NULL) {
309
310 if (corosync_service[service_id]->exec_exit_fn) {
311 res = corosync_service[service_id]->exec_exit_fn ();
312 if (res == -1) {
313 return (-1);
314 }
315 }
316
317 log_printf(LOGSYS_LEVEL_NOTICE,
318 "Service engine unloaded: %s",
319 corosync_service[service_id]->name);
320
321 corosync_service[service_id] = NULL;
322
323 cs_ipcs_service_destroy (service_id);
324
325 snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "internal_configuration.service.%u.handle", service_id);
326 icmap_delete(key_name);
327 snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "internal_configuration.service.%u.name", service_id);
328 icmap_delete(key_name);
329 snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "internal_configuration.service.%u.ver", service_id);
330 icmap_delete(key_name);
331 }
332
333 return (0);
334 }
335
336 /*
337 * Links default services into the executive
338 */
339 unsigned int corosync_service_defaults_link_and_init (struct corosync_api_v1 *corosync_api)
340 {
341 unsigned int i;
342 char *error;
343
344 for (i = 0;
345 i < sizeof (default_services) / sizeof (struct default_service); i++) {
346
347 default_services[i].loader();
348 error = corosync_service_link_and_init (
349 corosync_api,
350 &default_services[i]);
351 if (error) {
352 log_printf(LOGSYS_LEVEL_ERROR,
353 "Service engine '%s' failed to load for reason '%s'",
354 default_services[i].name,
355 error);
356 corosync_exit_error (COROSYNC_DONE_SERVICE_ENGINE_INIT);
357 }
358 }
359
360 return (0);
361 }
362
363 static void service_exit_schedwrk_handler (void *data) {
364 int res;
365 static int current_priority = 0;
366 static int current_service_engine = 0;
367 static int called = 0;
368 struct seus_handler_data *cb_data = (struct seus_handler_data *)data;
369 struct corosync_api_v1 *api = (struct corosync_api_v1 *)cb_data->api;
370
371 if (called == 0) {
372 log_printf(LOGSYS_LEVEL_NOTICE,
373 "Unloading all Corosync service engines.");
374 current_priority = service_priority_max ();
375 called = 1;
376 }
377
378 res = corosync_service_unlink_and_exit_priority (
379 api,
380 0,
381 &current_priority,
382 &current_service_engine);
383 if (res == 0) {
384 service_unlink_all_complete();
385 return;
386 }
387
388 qb_loop_job_add(cs_poll_handle_get(),
389 QB_LOOP_HIGH,
390 data,
391 service_exit_schedwrk_handler);
392 }
393
394 void corosync_service_unlink_all (
395 struct corosync_api_v1 *api,
396 void (*unlink_all_complete) (void))
397 {
398 static int called = 0;
399 static struct seus_handler_data cb_data;
400
401 assert (api);
402
403 service_unlink_all_complete = unlink_all_complete;
404
405 if (called) {
406 return;
407 }
408 if (called == 0) {
409 called = 1;
410 }
411
412 cb_data.api = api;
413
414 qb_loop_job_add(cs_poll_handle_get(),
415 QB_LOOP_HIGH,
416 &cb_data,
417 service_exit_schedwrk_handler);
418 }
419
420 struct service_unlink_and_exit_data {
421 hdb_handle_t handle;
422 struct corosync_api_v1 *api;
423 const char *name;
424 unsigned int ver;
425 };
426
427 static void service_unlink_and_exit_schedwrk_handler (void *data)
428 {
429 struct service_unlink_and_exit_data *service_unlink_and_exit_data =
430 data;
431 int res;
432
433 res = service_unlink_and_exit (
434 service_unlink_and_exit_data->api,
435 service_unlink_and_exit_data->name,
436 service_unlink_and_exit_data->ver);
437
438 if (res == 0) {
439 free (service_unlink_and_exit_data);
440 } else {
441 qb_loop_job_add(cs_poll_handle_get(),
442 QB_LOOP_HIGH,
443 data,
444 service_unlink_and_exit_schedwrk_handler);
445 }
446 }
447
448 typedef int (*schedwrk_cast) (const void *);
449
450 unsigned int corosync_service_unlink_and_exit (
451 struct corosync_api_v1 *api,
452 const char *service_name,
453 unsigned int service_ver)
454 {
455 struct service_unlink_and_exit_data *service_unlink_and_exit_data;
456
457 assert (api);
458 service_unlink_and_exit_data = malloc (sizeof (struct service_unlink_and_exit_data));
459 service_unlink_and_exit_data->api = api;
460 service_unlink_and_exit_data->name = strdup (service_name);
461 service_unlink_and_exit_data->ver = service_ver;
462
463 qb_loop_job_add(cs_poll_handle_get(),
464 QB_LOOP_HIGH,
465 service_unlink_and_exit_data,
466 service_unlink_and_exit_schedwrk_handler);
467 return (0);
468 }