1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * protocol.c - protocols between graph engine and restarters 28 * 29 * The graph engine uses restarter_protocol_send_event() to send a 30 * restarter_event_type_t to the restarter. For delegated restarters, 31 * this is published on the GPEC queue for the restarter, which can 32 * then be consumed by the librestart interfaces. For services managed 33 * by svc.startd, the event is stored on the local restarter_queue list, 34 * where it can be dequeued by the restarter. 35 * 36 * The svc.startd restarter uses graph_protocol_send_event() to send 37 * a graph_event_type_t to the graph engine when an instance's states are 38 * updated. 39 * 40 * The graph engine uses restarter_protocol_init_delegate() to 41 * register its interest in a particular delegated restarter's instance 42 * state events. The state_cb() registered on the event channel then 43 * invokes graph_protocol_send_event() to communicate the update to 44 * the graph engine. 45 */ 46 47 #include <assert.h> 48 #include <libintl.h> 49 #include <libsysevent.h> 50 #include <pthread.h> 51 #include <stdarg.h> 52 #include <stdio.h> 53 #include <strings.h> 54 #include <sys/time.h> 55 #include <errno.h> 56 #include <libuutil.h> 57 58 #include <librestart.h> 59 #include <librestart_priv.h> 60 61 #include "protocol.h" 62 #include "startd.h" 63 64 /* Local event queue structures. */ 65 typedef struct graph_protocol_event_queue { 66 uu_list_t *gpeq_event_list; 67 pthread_mutex_t gpeq_lock; 68 } graph_protocol_event_queue_t; 69 70 typedef struct restarter_protocol_event_queue { 71 uu_list_t *rpeq_event_list; 72 pthread_mutex_t rpeq_lock; 73 } restarter_protocol_event_queue_t; 74 75 static uu_list_pool_t *restarter_protocol_event_queue_pool; 76 static restarter_protocol_event_queue_t *restarter_queue; 77 78 static uu_list_pool_t *graph_protocol_event_queue_pool; 79 static graph_protocol_event_queue_t *graph_queue; 80 81 void 82 graph_protocol_init() 83 { 84 graph_protocol_event_queue_pool = startd_list_pool_create( 85 "graph_protocol_events", sizeof (graph_protocol_event_t), 86 offsetof(graph_protocol_event_t, gpe_link), NULL, 87 UU_LIST_POOL_DEBUG); 88 89 graph_queue = startd_zalloc(sizeof (graph_protocol_event_queue_t)); 90 91 (void) pthread_mutex_init(&graph_queue->gpeq_lock, &mutex_attrs); 92 graph_queue->gpeq_event_list = startd_list_create( 93 graph_protocol_event_queue_pool, graph_queue, NULL); 94 } 95 96 /* 97 * "data" will be freed by the consumer 98 */ 99 static void 100 graph_event_enqueue(const char *inst, graph_event_type_t event, 101 protocol_states_t *data) 102 { 103 graph_protocol_event_t *e; 104 105 e = startd_zalloc(sizeof (graph_protocol_event_t)); 106 107 if (inst != NULL) { 108 int size = strlen(inst) + 1; 109 e->gpe_inst = startd_alloc(size); 110 e->gpe_inst_sz = size; 111 (void) strlcpy(e->gpe_inst, inst, size); 112 } 113 e->gpe_type = event; 114 e->gpe_data = data; 115 116 (void) pthread_mutex_init(&e->gpe_lock, &mutex_attrs); 117 118 MUTEX_LOCK(&graph_queue->gpeq_lock); 119 uu_list_node_init(e, &e->gpe_link, graph_protocol_event_queue_pool); 120 if (uu_list_insert_before(graph_queue->gpeq_event_list, NULL, e) == -1) 121 uu_die("failed to enqueue graph event (%s: %s)\n", 122 e->gpe_inst, uu_strerror(uu_error())); 123 124 MUTEX_UNLOCK(&graph_queue->gpeq_lock); 125 } 126 127 void 128 graph_event_release(graph_protocol_event_t *e) 129 { 130 uu_list_node_fini(e, &e->gpe_link, graph_protocol_event_queue_pool); 131 (void) pthread_mutex_destroy(&e->gpe_lock); 132 if (e->gpe_inst != NULL) 133 startd_free(e->gpe_inst, e->gpe_inst_sz); 134 startd_free(e, sizeof (graph_protocol_event_t)); 135 } 136 137 /* 138 * graph_protocol_event_t *graph_event_dequeue() 139 * The caller must hold gu_lock, and is expected to be a single thread. 140 * It is allowed to utilize graph_event_requeue() and abort processing 141 * on the event. If graph_event_requeue() is not called, the caller is 142 * expected to call graph_event_release() when finished. 143 */ 144 graph_protocol_event_t * 145 graph_event_dequeue() 146 { 147 graph_protocol_event_t *e; 148 149 MUTEX_LOCK(&graph_queue->gpeq_lock); 150 151 e = uu_list_first(graph_queue->gpeq_event_list); 152 if (e == NULL) { 153 MUTEX_UNLOCK(&graph_queue->gpeq_lock); 154 return (NULL); 155 } 156 157 if (uu_list_next(graph_queue->gpeq_event_list, e) != NULL) 158 gu->gu_wakeup = 1; 159 uu_list_remove(graph_queue->gpeq_event_list, e); 160 MUTEX_UNLOCK(&graph_queue->gpeq_lock); 161 162 return (e); 163 } 164 165 /* 166 * void graph_event_requeue() 167 * Requeue the event back at the head of the queue. 168 */ 169 void 170 graph_event_requeue(graph_protocol_event_t *e) 171 { 172 assert(e != NULL); 173 174 log_framework(LOG_DEBUG, "Requeing event\n"); 175 176 MUTEX_LOCK(&graph_queue->gpeq_lock); 177 if (uu_list_insert_after(graph_queue->gpeq_event_list, NULL, e) == -1) 178 uu_die("failed to requeue graph event (%s: %s)\n", 179 e->gpe_inst, uu_strerror(uu_error())); 180 181 MUTEX_UNLOCK(&graph_queue->gpeq_lock); 182 } 183 184 void 185 graph_protocol_send_event(const char *inst, graph_event_type_t event, 186 protocol_states_t *data) 187 { 188 graph_event_enqueue(inst, event, data); 189 MUTEX_LOCK(&gu->gu_lock); 190 gu->gu_wakeup = 1; 191 (void) pthread_cond_broadcast(&gu->gu_cv); 192 MUTEX_UNLOCK(&gu->gu_lock); 193 } 194 195 void 196 restarter_protocol_init() 197 { 198 restarter_protocol_event_queue_pool = startd_list_pool_create( 199 "restarter_protocol_events", sizeof (restarter_protocol_event_t), 200 offsetof(restarter_protocol_event_t, rpe_link), NULL, 201 UU_LIST_POOL_DEBUG); 202 203 restarter_queue = startd_zalloc( 204 sizeof (restarter_protocol_event_queue_t)); 205 206 (void) pthread_mutex_init(&restarter_queue->rpeq_lock, &mutex_attrs); 207 restarter_queue->rpeq_event_list = startd_list_create( 208 restarter_protocol_event_queue_pool, restarter_queue, NULL); 209 210 log_framework(LOG_DEBUG, "Initialized restarter protocol\n"); 211 } 212 213 /* 214 * void restarter_event_enqueue() 215 * Enqueue a restarter event. 216 */ 217 static void 218 restarter_event_enqueue(const char *inst, restarter_event_type_t event) 219 { 220 restarter_protocol_event_t *e; 221 int r; 222 223 /* Allocate and populate the event structure. */ 224 e = startd_zalloc(sizeof (restarter_protocol_event_t)); 225 226 e->rpe_inst = startd_alloc(strlen(inst) + 1); 227 (void) strlcpy(e->rpe_inst, inst, strlen(inst)+1); 228 e->rpe_type = event; 229 230 MUTEX_LOCK(&restarter_queue->rpeq_lock); 231 uu_list_node_init(e, &e->rpe_link, restarter_protocol_event_queue_pool); 232 r = uu_list_insert_before(restarter_queue->rpeq_event_list, NULL, e); 233 assert(r == 0); 234 235 MUTEX_UNLOCK(&restarter_queue->rpeq_lock); 236 237 } 238 239 void 240 restarter_event_release(restarter_protocol_event_t *e) 241 { 242 uu_list_node_fini(e, &e->rpe_link, restarter_protocol_event_queue_pool); 243 startd_free(e->rpe_inst, strlen(e->rpe_inst) + 1); 244 startd_free(e, sizeof (restarter_protocol_event_t)); 245 } 246 247 /* 248 * restarter_protocol_event_t *restarter_event_dequeue() 249 * Dequeue a restarter protocol event. The caller is expected to be 250 * a single thread. It is allowed to utilize restarter_event_requeue() 251 * and abort processing on the event. The caller is expected to call 252 * restarter_event_release() when finished. 253 */ 254 restarter_protocol_event_t * 255 restarter_event_dequeue() 256 { 257 restarter_protocol_event_t *e = NULL; 258 259 MUTEX_LOCK(&restarter_queue->rpeq_lock); 260 261 e = uu_list_first(restarter_queue->rpeq_event_list); 262 if (e == NULL) { 263 MUTEX_UNLOCK(&restarter_queue->rpeq_lock); 264 return (NULL); 265 } 266 267 if (uu_list_next(restarter_queue->rpeq_event_list, e) != NULL) 268 ru->restarter_update_wakeup = 1; 269 uu_list_remove(restarter_queue->rpeq_event_list, e); 270 MUTEX_UNLOCK(&restarter_queue->rpeq_lock); 271 272 return (e); 273 } 274 275 static int 276 state_cb(sysevent_t *syse, void *cookie) 277 { 278 char *fmri = (char *)cookie; 279 char *instance_name; 280 nvlist_t *attr_list = NULL; 281 int state, next_state; 282 char str_state[MAX_SCF_STATE_STRING_SZ]; 283 char str_next_state[MAX_SCF_STATE_STRING_SZ]; 284 protocol_states_t *states; 285 int err; 286 ssize_t sz; 287 288 /* 289 * Might fail due to a bad event or a lack of memory. Try 290 * the callback again to see if it goes better the next time. 291 */ 292 if (sysevent_get_attr_list(syse, &attr_list) != 0) 293 return (EAGAIN); 294 295 if ((nvlist_lookup_int32(attr_list, RESTARTER_NAME_STATE, 296 &state) != 0) || 297 (nvlist_lookup_int32(attr_list, RESTARTER_NAME_NEXT_STATE, 298 &next_state) != 0) || 299 (nvlist_lookup_int32(attr_list, RESTARTER_NAME_ERROR, &err) != 0) || 300 (nvlist_lookup_string(attr_list, RESTARTER_NAME_INSTANCE, 301 &instance_name) != 0)) 302 uu_die("%s: can't decode nvlist\n", fmri); 303 304 states = startd_alloc(sizeof (protocol_states_t)); 305 states->ps_state = state; 306 states->ps_state_next = next_state; 307 states->ps_err = err; 308 309 graph_protocol_send_event(instance_name, GRAPH_UPDATE_STATE_CHANGE, 310 states); 311 312 sz = restarter_state_to_string(state, str_state, sizeof (str_state)); 313 assert(sz < sizeof (str_state)); 314 sz = restarter_state_to_string(next_state, str_next_state, 315 sizeof (str_next_state)); 316 assert(sz < sizeof (str_next_state)); 317 log_framework(LOG_DEBUG, "%s: state updates for %s (%s, %s)\n", fmri, 318 instance_name, str_state, str_next_state); 319 nvlist_free(attr_list); 320 return (0); 321 } 322 323 evchan_t * 324 restarter_protocol_init_delegate(char *fmri) 325 { 326 char *delegate_channel_name, *master_channel_name, *sid; 327 evchan_t *delegate_channel, *master_channel; 328 int r = 0; 329 330 /* master restarter -- nothing to do */ 331 if (strcmp(fmri, SCF_SERVICE_STARTD) == 0) { 332 uu_warn("Attempt to initialize restarter protocol delegate " 333 "with %s\n", fmri); 334 return (NULL); 335 } 336 337 log_framework(LOG_DEBUG, "%s: Intializing protocol for delegate\n", 338 fmri); 339 340 delegate_channel_name = master_channel_name = NULL; 341 if ((delegate_channel_name = _restarter_get_channel_name(fmri, 342 RESTARTER_CHANNEL_DELEGATE)) == NULL || 343 (master_channel_name = _restarter_get_channel_name(fmri, 344 RESTARTER_CHANNEL_MASTER)) == NULL || 345 (sid = strdup("svc.startd")) == NULL) { 346 if (delegate_channel_name) { 347 free(delegate_channel_name); 348 } 349 if (master_channel_name) { 350 free(master_channel_name); 351 } 352 uu_warn("Allocation of channel name failed"); 353 354 return (NULL); 355 } 356 357 if ((r = sysevent_evc_bind(delegate_channel_name, &delegate_channel, 358 EVCH_CREAT|EVCH_HOLD_PEND)) != 0) { 359 uu_warn("%s: sysevent_evc_bind failed: %s\n", 360 delegate_channel_name, strerror(errno)); 361 goto out; 362 } 363 364 if ((r = sysevent_evc_bind(master_channel_name, &master_channel, 365 EVCH_CREAT|EVCH_HOLD_PEND)) != 0) { 366 uu_warn("%s: sysevent_evc_bind failed: %s\n", 367 master_channel_name, strerror(errno)); 368 goto out; 369 } 370 371 log_framework(LOG_DEBUG, 372 "%s: Bound to channel %s (delegate), %s (master)\n", fmri, 373 delegate_channel_name, master_channel_name); 374 375 if ((r = sysevent_evc_subscribe(master_channel, sid, EC_ALL, 376 state_cb, fmri, EVCH_SUB_KEEP)) != 0) { 377 /* 378 * The following errors can be returned in this 379 * case : 380 * EINVAL : inappropriate flags or dump flag 381 * and the dump failed. 382 * EEXIST : svc.startd already has a channel 383 * named as the master channel name 384 * ENOMEM : too many subscribers to the channel 385 */ 386 uu_warn("Failed to subscribe to restarter %s, channel %s with " 387 "subscriber id %s : \n", fmri, master_channel_name, sid); 388 switch (r) { 389 case EEXIST: 390 uu_warn("Channel name already exists\n"); 391 break; 392 case ENOMEM: 393 uu_warn("Too many subscribers for the channel\n"); 394 break; 395 default: 396 uu_warn("%s\n", strerror(errno)); 397 } 398 } else { 399 log_framework(LOG_DEBUG, 400 "%s: Subscribed to channel %s with subscriber id %s\n", 401 fmri, master_channel_name, "svc.startd"); 402 } 403 404 405 out: 406 free(delegate_channel_name); 407 free(master_channel_name); 408 free(sid); 409 410 if (r == 0) 411 return (delegate_channel); 412 413 return (NULL); 414 } 415 416 void 417 restarter_protocol_send_event(const char *inst, evchan_t *chan, 418 restarter_event_type_t event) 419 { 420 nvlist_t *attr; 421 int ret; 422 423 /* 424 * If the service is managed by the master restarter, 425 * queue the event locally. 426 */ 427 if (chan == NULL) { 428 restarter_event_enqueue(inst, event); 429 MUTEX_LOCK(&ru->restarter_update_lock); 430 ru->restarter_update_wakeup = 1; 431 (void) pthread_cond_broadcast(&ru->restarter_update_cv); 432 MUTEX_UNLOCK(&ru->restarter_update_lock); 433 return; 434 } 435 436 /* 437 * Otherwise, send the event to the delegate. 438 */ 439 log_framework(LOG_DEBUG, "Sending %s to channel 0x%p for %s.\n", 440 event_names[event], chan, inst); 441 if (nvlist_alloc(&attr, NV_UNIQUE_NAME, 0) != 0 || 442 nvlist_add_uint32(attr, RESTARTER_NAME_TYPE, event) != 0 || 443 nvlist_add_string(attr, RESTARTER_NAME_INSTANCE, (char *)inst) != 0) 444 uu_die("Allocation failure\n"); 445 446 if ((ret = restarter_event_publish_retry(chan, "protocol", "restarter", 447 "com.sun", "svc.startd", attr, EVCH_NOSLEEP)) != 0) { 448 449 switch (ret) { 450 case ENOSPC: 451 log_framework(LOG_DEBUG, "Dropping %s event for %s. " 452 "Delegate may not be running.\n", 453 event_names[event], inst); 454 break; 455 default: 456 uu_die("%s: can't publish event: %s\n", inst, 457 strerror(errno)); 458 } 459 } 460 461 nvlist_free(attr); 462 463 if (event != RESTARTER_EVENT_TYPE_ADD_INSTANCE) { 464 /* 465 * Not relevant for graph loading. 466 */ 467 return; 468 } 469 470 /* 471 * For the purposes of loading state after interruption, this is 472 * sufficient, as svc.startd(1M) won't receive events on the contracts 473 * associated with each delegate. 474 */ 475 MUTEX_LOCK(&st->st_load_lock); 476 if (--st->st_load_instances == 0) 477 (void) pthread_cond_broadcast(&st->st_load_cv); 478 MUTEX_UNLOCK(&st->st_load_lock); 479 480 } 481