2 * Copyright (c) 2006 MontaVista Software, Inc.
3 * Copyright (c) 2006-2012 Red Hat, Inc.
7 * Author: Steven Dake (sdake@redhat.com)
9 * This software licensed under BSD license, the text of which follows:
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are met:
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.
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.
41 #include <corosync/swab.h>
42 #include <corosync/totem/totem.h>
44 #include <corosync/corotypes.h>
46 #include <corosync/logsys.h>
47 #include <corosync/icmap.h>
50 #include <corosync/totem/totempg.h>
51 #include <corosync/totem/totemip.h>
55 #include <qb/qbipcs.h>
56 #include <qb/qbloop.h>
58 LOGSYS_DECLARE_SUBSYS ("SERV");
60 static struct default_service default_services
[] = {
62 .name
= "corosync_cmap",
64 .loader
= cmap_get_service_engine_ver0
67 .name
= "corosync_cfg",
69 .loader
= cfg_get_service_engine_ver0
72 .name
= "corosync_cpg",
74 .loader
= cpg_get_service_engine_ver0
77 .name
= "corosync_pload",
79 .loader
= pload_get_service_engine_ver0
81 #ifdef HAVE_MONITORING
83 .name
= "corosync_mon",
85 .loader
= mon_get_service_engine_ver0
90 .name
= "corosync_wd",
92 .loader
= wd_get_service_engine_ver0
96 .name
= "corosync_quorum",
98 .loader
= vsf_quorum_get_service_engine_ver0
103 * service exit and unlink schedwrk handler data structure
105 struct seus_handler_data
{
107 struct corosync_api_v1
*api
;
110 struct corosync_service_engine
*corosync_service
[SERVICES_COUNT_MAX
];
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
];
115 static void (*service_unlink_all_complete
) (void) = NULL
;
117 char *corosync_service_link_and_init (
118 struct corosync_api_v1
*corosync_api
,
119 struct default_service
*service
)
121 struct corosync_service_engine
*service_engine
;
124 char key_name
[ICMAP_KEYNAME_MAXLEN
];
130 service_engine
= service
->loader();
132 corosync_service
[service_engine
->id
] = service_engine
;
134 if (service_engine
->config_init_fn
) {
135 service_engine
->config_init_fn (corosync_api
);
138 if (service_engine
->exec_init_fn
) {
139 init_result
= service_engine
->exec_init_fn (corosync_api
);
141 return (init_result
);
146 * Store service in cmap db
148 snprintf(key_name
, ICMAP_KEYNAME_MAXLEN
, "internal_configuration.service.%u.name", service_engine
->id
);
149 icmap_set_string(key_name
, service
->name
);
151 snprintf(key_name
, ICMAP_KEYNAME_MAXLEN
, "internal_configuration.service.%u.ver", service_engine
->id
);
152 icmap_set_uint32(key_name
, service
->ver
);
154 name_sufix
= strrchr (service
->name
, '_');
158 name_sufix
= (char*)service
->name
;
160 snprintf(key_name
, ICMAP_KEYNAME_MAXLEN
, "runtime.services.%s.service_id", name_sufix
);
161 icmap_set_uint16(key_name
, service_engine
->id
);
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
);
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
);
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
);
183 static int service_priority_max(void)
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
;
198 corosync_service_unlink_and_exit_priority (
199 struct corosync_api_v1
*corosync_api
,
201 int *current_priority
,
202 int *current_service_engine
)
204 unsigned short service_id
;
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) {
212 if(corosync_service
[*current_service_engine
] == NULL
||
213 corosync_service
[*current_service_engine
]->priority
!= *current_priority
) {
218 * find service handle and unload it if possible.
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).
224 service_id
= corosync_service
[*current_service_engine
]->id
;
226 if (corosync_service
[service_id
]->exec_exit_fn
) {
227 res
= corosync_service
[service_id
]->exec_exit_fn ();
234 * Exit all ipc connections dependent on this service
236 cs_ipcs_service_destroy (*current_service_engine
);
238 log_printf(LOGSYS_LEVEL_NOTICE
,
239 "Service engine unloaded: %s",
240 corosync_service
[*current_service_engine
]->name
);
242 corosync_service
[*current_service_engine
] = NULL
;
245 * Call should call this function again
251 * We finish unlink of all services -> no need to call this function again
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
)
261 unsigned short service_id
;
264 const char *iter_key_name
;
266 char key_name
[ICMAP_KEYNAME_MAXLEN
];
267 unsigned int found_service_ver
;
268 char *found_service_name
;
271 name_sufix
= strrchr (service_name
, '_');
275 name_sufix
= (char*)service_name
;
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
);
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
) {
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
);
298 if (service_ver
== found_service_ver
&& strcmp(found_service_name
, service_name
) == 0) {
299 free(found_service_name
);
303 free(found_service_name
);
305 icmap_iter_finalize(iter
);
307 if (service_found
&& service_id
< SERVICES_COUNT_MAX
308 && corosync_service
[service_id
] != NULL
) {
310 if (corosync_service
[service_id
]->exec_exit_fn
) {
311 res
= corosync_service
[service_id
]->exec_exit_fn ();
317 log_printf(LOGSYS_LEVEL_NOTICE
,
318 "Service engine unloaded: %s",
319 corosync_service
[service_id
]->name
);
321 corosync_service
[service_id
] = NULL
;
323 cs_ipcs_service_destroy (service_id
);
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
);
337 * Links default services into the executive
339 unsigned int corosync_service_defaults_link_and_init (struct corosync_api_v1
*corosync_api
)
345 i
< sizeof (default_services
) / sizeof (struct default_service
); i
++) {
347 default_services
[i
].loader();
348 error
= corosync_service_link_and_init (
350 &default_services
[i
]);
352 log_printf(LOGSYS_LEVEL_ERROR
,
353 "Service engine '%s' failed to load for reason '%s'",
354 default_services
[i
].name
,
356 corosync_exit_error (COROSYNC_DONE_SERVICE_ENGINE_INIT
);
363 static void service_exit_schedwrk_handler (void *data
) {
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
;
372 log_printf(LOGSYS_LEVEL_NOTICE
,
373 "Unloading all Corosync service engines.");
374 current_priority
= service_priority_max ();
378 res
= corosync_service_unlink_and_exit_priority (
382 ¤t_service_engine
);
384 service_unlink_all_complete();
388 qb_loop_job_add(cs_poll_handle_get(),
391 service_exit_schedwrk_handler
);
394 void corosync_service_unlink_all (
395 struct corosync_api_v1
*api
,
396 void (*unlink_all_complete
) (void))
398 static int called
= 0;
399 static struct seus_handler_data cb_data
;
403 service_unlink_all_complete
= unlink_all_complete
;
414 qb_loop_job_add(cs_poll_handle_get(),
417 service_exit_schedwrk_handler
);
420 struct service_unlink_and_exit_data
{
422 struct corosync_api_v1
*api
;
427 static void service_unlink_and_exit_schedwrk_handler (void *data
)
429 struct service_unlink_and_exit_data
*service_unlink_and_exit_data
=
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
);
439 free (service_unlink_and_exit_data
);
441 qb_loop_job_add(cs_poll_handle_get(),
444 service_unlink_and_exit_schedwrk_handler
);
448 typedef int (*schedwrk_cast
) (const void *);
450 unsigned int corosync_service_unlink_and_exit (
451 struct corosync_api_v1
*api
,
452 const char *service_name
,
453 unsigned int service_ver
)
455 struct service_unlink_and_exit_data
*service_unlink_and_exit_data
;
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
;
463 qb_loop_job_add(cs_poll_handle_get(),
465 service_unlink_and_exit_data
,
466 service_unlink_and_exit_schedwrk_handler
);