xref: /illumos-gate/usr/src/cmd/svc/startd/protocol.c (revision 13d8aaa19025bce854122482c986b488bbb781e8)
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