corosync 3.1.7
service.c
Go to the documentation of this file.
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>
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"
52#include "main.h"
53#include "service.h"
54
55#include <qb/qbipcs.h>
56#include <qb/qbloop.h>
57
59
60static struct default_service default_services[] = {
61 {
62 .name = "corosync_cmap",
63 .ver = 0,
65 },
66 {
67 .name = "corosync_cfg",
68 .ver = 0,
70 },
71 {
72 .name = "corosync_cpg",
73 .ver = 0,
75 },
76 {
77 .name = "corosync_pload",
78 .ver = 0,
80 },
81#ifdef HAVE_MONITORING
82 {
83 .name = "corosync_mon",
84 .ver = 0,
86 },
87#endif
88#ifdef HAVE_WATCHDOG
89 {
90 .name = "corosync_wd",
91 .ver = 0,
93 },
94#endif
95 {
96 .name = "corosync_quorum",
97 .ver = 0,
99 },
100};
101
102/*
103 * service exit and unlink schedwrk handler data structure
104 */
108};
109
111
114
115static void (*service_unlink_all_complete) (void) = NULL;
116
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
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
183static 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) {
189 }
190 }
191 return max;
192}
193
194/*
195 * use the force
196 */
197static unsigned int
198corosync_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
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
256static 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 }
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
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 */
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();
349 corosync_api,
350 &default_services[i]);
351 if (error) {
353 "Service engine '%s' failed to load for reason '%s'",
354 default_services[i].name,
355 error);
357 }
358 }
359
360 return (0);
361}
362
363static 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) {
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
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
423 const char *name;
424 unsigned int ver;
425};
426
427static void service_unlink_and_exit_schedwrk_handler (void *data)
428{
430 data;
431 int res;
432
433 res = service_unlink_and_exit (
437
438 if (res == 0) {
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
448typedef int (*schedwrk_cast) (const void *);
449
451 struct corosync_api_v1 *api,
452 const char *service_name,
453 unsigned int service_ver)
454{
456
457 assert (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,
466 service_unlink_and_exit_schedwrk_handler);
467 return (0);
468}
#define SERVICE_HANDLER_MAXIMUM_COUNT
Definition: coroapi.h:460
#define SERVICES_COUNT_MAX
Definition: coroapi.h:462
@ CS_OK
Definition: corotypes.h:99
struct corosync_service_engine * cfg_get_service_engine_ver0(void)
Definition: exec/cfg.c:287
struct corosync_service_engine * cmap_get_service_engine_ver0(void)
Definition: exec/cmap.c:284
struct corosync_service_engine * cpg_get_service_engine_ver0(void)
Definition: exec/cpg.c:454
#define corosync_exit_error(err)
Definition: exec/util.h:72
@ COROSYNC_DONE_SERVICE_ENGINE_INIT
Definition: exec/util.h:60
#define max(a, b)
qb_handle_t hdb_handle_t
Definition: hdb.h:52
cs_error_t icmap_get_uint32(const char *key_name, uint32_t *u32)
Definition: icmap.c:892
cs_error_t icmap_delete(const char *key_name)
Delete key from map.
Definition: icmap.c:653
cs_error_t icmap_set_uint16(const char *key_name, uint16_t value)
Definition: icmap.c:585
cs_error_t icmap_set_string(const char *key_name, const char *value)
Definition: icmap.c:627
icmap_iter_t icmap_iter_init(const char *prefix)
Initialize iterator with given prefix.
Definition: icmap.c:1089
const char * icmap_iter_next(icmap_iter_t iter, size_t *value_len, icmap_value_types_t *type)
Return next item in iterator iter.
Definition: icmap.c:1095
qb_map_iter_t * icmap_iter_t
Itterator type.
Definition: icmap.h:123
void icmap_iter_finalize(icmap_iter_t iter)
Finalize iterator.
Definition: icmap.c:1116
cs_error_t icmap_set_uint64(const char *key_name, uint64_t value)
Definition: icmap.c:609
#define ICMAP_KEYNAME_MAXLEN
Maximum length of key in icmap.
Definition: icmap.h:48
cs_error_t icmap_set_uint32(const char *key_name, uint32_t value)
Definition: icmap.c:597
cs_error_t icmap_get_string(const char *key_name, char **str)
Shortcut for icmap_get for string type.
Definition: icmap.c:856
int32_t cs_ipcs_service_destroy(int32_t service_id)
Definition: ipc_glue.c:164
const char * cs_ipcs_service_init(struct corosync_service_engine *service)
Definition: ipc_glue.c:778
#define LOGSYS_LEVEL_ERROR
Definition: logsys.h:72
#define log_printf(level, format, args...)
Definition: logsys.h:332
#define LOGSYS_LEVEL_NOTICE
Definition: logsys.h:74
qb_loop_t * cs_poll_handle_get(void)
Definition: main.c:178
struct corosync_service_engine * mon_get_service_engine_ver0(void)
Definition: mon.c:149
struct corosync_service_engine * pload_get_service_engine_ver0(void)
Definition: pload.c:146
unsigned int corosync_service_unlink_and_exit(struct corosync_api_v1 *api, const char *service_name, unsigned int service_ver)
Unlink and exit a service.
Definition: service.c:450
int(* schedwrk_cast)(const void *)
Definition: service.c:448
unsigned int corosync_service_defaults_link_and_init(struct corosync_api_v1 *corosync_api)
Load all of the default services.
Definition: service.c:339
void corosync_service_unlink_all(struct corosync_api_v1 *api, void(*unlink_all_complete)(void))
Unlink and exit all corosync services.
Definition: service.c:394
const char * service_stats_rx[SERVICES_COUNT_MAX][SERVICE_HANDLER_MAXIMUM_COUNT]
Definition: service.c:112
struct corosync_service_engine * corosync_service[SERVICES_COUNT_MAX]
Definition: service.c:110
LOGSYS_DECLARE_SUBSYS("SERV")
char * corosync_service_link_and_init(struct corosync_api_v1 *corosync_api, struct default_service *service)
Link and initialize a service.
Definition: service.c:117
const char * service_stats_tx[SERVICES_COUNT_MAX][SERVICE_HANDLER_MAXIMUM_COUNT]
Definition: service.c:113
struct corosync_service_engine * vsf_quorum_get_service_engine_ver0(void)
Definition: vsf_quorum.c:236
struct corosync_service_engine * wd_get_service_engine_ver0(void)
Definition: wd.c:146
The corosync_api_v1 struct.
Definition: coroapi.h:225
The corosync_service_engine struct.
Definition: coroapi.h:490
unsigned short id
Definition: coroapi.h:492
int(* config_init_fn)(struct corosync_api_v1 *)
Definition: coroapi.h:508
unsigned short priority
Definition: coroapi.h:493
const char * name
Definition: coroapi.h:491
char *(* exec_init_fn)(struct corosync_api_v1 *)
Definition: coroapi.h:499
int(* exec_exit_fn)(void)
Definition: coroapi.h:500
struct corosync_service_engine *(* loader)(void)
Definition: service.h:45
const char * name
Definition: service.h:43
struct corosync_api_v1 * api
Definition: service.c:107
Totem Single Ring Protocol.