xref: /illumos-gate/usr/src/uts/common/os/evchannels.c (revision c6f039c73ee9eb7e4acb232afaca51cdf9d30ff3)
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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 /*
26  * Copyright (c) 2018, Joyent, Inc.
27  */
28 
29 /*
30  * This file contains the source of the general purpose event channel extension
31  * to the sysevent framework. This implementation is made up mainly of four
32  * layers of functionality: the event queues (evch_evq_*()), the handling of
33  * channels (evch_ch*()), the kernel interface (sysevent_evc_*()) and the
34  * interface for the sysevent pseudo driver (evch_usr*()).
35  * Libsysevent.so uses the pseudo driver sysevent's ioctl to access the event
36  * channel extensions. The driver in turn uses the evch_usr*() functions below.
37  *
38  * The interfaces for user land and kernel are declared in sys/sysevent.h
39  * Internal data structures for event channels are defined in
40  * sys/sysevent_impl.h.
41  *
42  * The basic data structure for an event channel is of type evch_chan_t.
43  * All channels are maintained by a list named evch_list. The list head
44  * is of type evch_dlist_t.
45  */
46 
47 #include <sys/types.h>
48 #include <sys/errno.h>
49 #include <sys/stropts.h>
50 #include <sys/debug.h>
51 #include <sys/ddi.h>
52 #include <sys/vmem.h>
53 #include <sys/cmn_err.h>
54 #include <sys/callb.h>
55 #include <sys/sysevent.h>
56 #include <sys/sysevent_impl.h>
57 #include <sys/sysmacros.h>
58 #include <sys/disp.h>
59 #include <sys/atomic.h>
60 #include <sys/door.h>
61 #include <sys/zone.h>
62 #include <sys/sdt.h>
63 
64 /* Back-off delay for door_ki_upcall */
65 #define	EVCH_MIN_PAUSE	8
66 #define	EVCH_MAX_PAUSE	128
67 
68 #define	GEVENT(ev)	((evch_gevent_t *)((char *)ev - \
69 			    offsetof(evch_gevent_t, ge_payload)))
70 
71 #define	EVCH_EVQ_EVCOUNT(x)	((&(x)->eq_eventq)->sq_count)
72 #define	EVCH_EVQ_HIGHWM(x)	((&(x)->eq_eventq)->sq_highwm)
73 
74 #define	CH_HOLD_PEND		1
75 #define	CH_HOLD_PEND_INDEF	2
76 
77 struct evch_globals {
78 	evch_dlist_t evch_list;
79 	kmutex_t evch_list_lock;
80 };
81 
82 /* Variables used by event channel routines */
83 static int		evq_initcomplete = 0;
84 static zone_key_t	evch_zone_key;
85 static uint32_t		evch_channels_max;
86 static uint32_t		evch_bindings_max = EVCH_MAX_BINDS_PER_CHANNEL;
87 static uint32_t		evch_events_max;
88 
89 static void evch_evq_unsub(evch_eventq_t *, evch_evqsub_t *);
90 static void evch_evq_destroy(evch_eventq_t *);
91 
92 /*
93  * List handling. These functions handle a doubly linked list. The list has
94  * to be protected by the calling functions. evch_dlist_t is the list head.
95  * Every node of the list has to put a evch_dlelem_t data type in its data
96  * structure as its first element.
97  *
98  * evch_dl_init		- Initialize list head
99  * evch_dl_fini		- Terminate list handling
100  * evch_dl_is_init	- Returns one if list is initialized
101  * evch_dl_add		- Add element to end of list
102  * evch_dl_del		- Remove given element from list
103  * evch_dl_search	- Lookup element in list
104  * evch_dl_getnum	- Get number of elements in list
105  * evch_dl_next		- Get next elements of list
106  */
107 
108 static void
evch_dl_init(evch_dlist_t * hp)109 evch_dl_init(evch_dlist_t *hp)
110 {
111 	hp->dh_head.dl_prev = hp->dh_head.dl_next = &hp->dh_head;
112 	hp->dh_count = 0;
113 }
114 
115 /*
116  * Assumes that list is empty.
117  */
118 static void
evch_dl_fini(evch_dlist_t * hp)119 evch_dl_fini(evch_dlist_t *hp)
120 {
121 	hp->dh_head.dl_prev = hp->dh_head.dl_next = NULL;
122 }
123 
124 static int
evch_dl_is_init(evch_dlist_t * hp)125 evch_dl_is_init(evch_dlist_t *hp)
126 {
127 	return (hp->dh_head.dl_next != NULL ? 1 : 0);
128 }
129 
130 /*
131  * Add an element at the end of the list.
132  */
133 static void
evch_dl_add(evch_dlist_t * hp,evch_dlelem_t * el)134 evch_dl_add(evch_dlist_t *hp, evch_dlelem_t *el)
135 {
136 	evch_dlelem_t	*x = hp->dh_head.dl_prev;
137 	evch_dlelem_t	*y = &hp->dh_head;
138 
139 	x->dl_next = el;
140 	y->dl_prev = el;
141 	el->dl_next = y;
142 	el->dl_prev = x;
143 	hp->dh_count++;
144 }
145 
146 /*
147  * Remove arbitrary element out of dlist.
148  */
149 static void
evch_dl_del(evch_dlist_t * hp,evch_dlelem_t * p)150 evch_dl_del(evch_dlist_t *hp, evch_dlelem_t *p)
151 {
152 	ASSERT(hp->dh_count > 0 && p != &hp->dh_head);
153 	p->dl_prev->dl_next = p->dl_next;
154 	p->dl_next->dl_prev = p->dl_prev;
155 	p->dl_prev = NULL;
156 	p->dl_next = NULL;
157 	hp->dh_count--;
158 }
159 
160 /*
161  * Search an element in a list. Caller provides comparison callback function.
162  */
163 static evch_dlelem_t *
evch_dl_search(evch_dlist_t * hp,int (* cmp)(evch_dlelem_t *,char *),char * s)164 evch_dl_search(evch_dlist_t *hp, int (*cmp)(evch_dlelem_t *, char *), char *s)
165 {
166 	evch_dlelem_t *p;
167 
168 	for (p = hp->dh_head.dl_next; p != &hp->dh_head; p = p->dl_next) {
169 		if (cmp(p, s) == 0) {
170 			return (p);
171 		}
172 	}
173 	return (NULL);
174 }
175 
176 /*
177  * Return number of elements in the list.
178  */
179 static int
evch_dl_getnum(evch_dlist_t * hp)180 evch_dl_getnum(evch_dlist_t *hp)
181 {
182 	return (hp->dh_count);
183 }
184 
185 /*
186  * Find next element of a evch_dlist_t list. Find first element if el == NULL.
187  * Returns NULL if end of list is reached.
188  */
189 static void *
evch_dl_next(evch_dlist_t * hp,void * el)190 evch_dl_next(evch_dlist_t *hp, void *el)
191 {
192 	evch_dlelem_t *ep = (evch_dlelem_t *)el;
193 
194 	if (hp->dh_count == 0) {
195 		return (NULL);
196 	}
197 	if (ep == NULL) {
198 		return (hp->dh_head.dl_next);
199 	}
200 	if ((ep = ep->dl_next) == (evch_dlelem_t *)hp) {
201 		return (NULL);
202 	}
203 	return ((void *)ep);
204 }
205 
206 /*
207  * Queue handling routines. Mutexes have to be entered previously.
208  *
209  * evch_q_init	- Initialize queue head
210  * evch_q_in	- Put element into queue
211  * evch_q_out	- Get element out of queue
212  * evch_q_next	- Iterate over the elements of a queue
213  */
214 static void
evch_q_init(evch_squeue_t * q)215 evch_q_init(evch_squeue_t *q)
216 {
217 	q->sq_head = NULL;
218 	q->sq_tail = (evch_qelem_t *)q;
219 	q->sq_count = 0;
220 	q->sq_highwm = 0;
221 }
222 
223 /*
224  * Put element into the queue q
225  */
226 static void
evch_q_in(evch_squeue_t * q,evch_qelem_t * el)227 evch_q_in(evch_squeue_t *q, evch_qelem_t *el)
228 {
229 	q->sq_tail->q_next = el;
230 	el->q_next = NULL;
231 	q->sq_tail = el;
232 	q->sq_count++;
233 	if (q->sq_count > q->sq_highwm) {
234 		q->sq_highwm = q->sq_count;
235 	}
236 }
237 
238 /*
239  * Returns NULL if queue is empty.
240  */
241 static evch_qelem_t *
evch_q_out(evch_squeue_t * q)242 evch_q_out(evch_squeue_t *q)
243 {
244 	evch_qelem_t *el;
245 
246 	if ((el = q->sq_head) != NULL) {
247 		q->sq_head = el->q_next;
248 		q->sq_count--;
249 		if (q->sq_head == NULL) {
250 			q->sq_tail = (evch_qelem_t *)q;
251 		}
252 	}
253 	return (el);
254 }
255 
256 /*
257  * Returns element after *el or first if el == NULL. NULL is returned
258  * if queue is empty or *el points to the last element in the queue.
259  */
260 static evch_qelem_t *
evch_q_next(evch_squeue_t * q,evch_qelem_t * el)261 evch_q_next(evch_squeue_t *q, evch_qelem_t *el)
262 {
263 	if (el == NULL)
264 		return (q->sq_head);
265 	return (el->q_next);
266 }
267 
268 /*
269  * Event queue handling functions. An event queue is the basic building block
270  * of an event channel. One event queue makes up the publisher-side event queue.
271  * Further event queues build the per-subscriber queues of an event channel.
272  * Each queue is associated an event delivery thread.
273  * These functions support a two-step initialization. First step, when kernel
274  * memory is ready and second when threads are ready.
275  * Events consist of an administrating evch_gevent_t structure with the event
276  * data appended as variable length payload.
277  * The internal interface functions for the event queue handling are:
278  *
279  * evch_evq_create	- create an event queue
280  * evch_evq_thrcreate	- create thread for an event queue.
281  * evch_evq_destroy	- delete an event queue
282  * evch_evq_sub		- Subscribe to event delivery from an event queue
283  * evch_evq_unsub	- Unsubscribe
284  * evch_evq_pub		- Post an event into an event queue
285  * evch_evq_stop	- Put delivery thread on hold
286  * evch_evq_continue	- Resume event delivery thread
287  * evch_evq_status	- Return status of delivery thread, running or on hold
288  * evch_evq_evzalloc	- Allocate an event structure
289  * evch_evq_evfree	- Free an event structure
290  * evch_evq_evadd_dest	- Add a destructor function to an event structure
291  * evch_evq_evnext	- Iterate over events non-destructive
292  */
293 
294 /*ARGSUSED*/
295 static void *
evch_zoneinit(zoneid_t zoneid)296 evch_zoneinit(zoneid_t zoneid)
297 {
298 	struct evch_globals *eg;
299 
300 	eg = kmem_zalloc(sizeof (*eg), KM_SLEEP);
301 	evch_dl_init(&eg->evch_list);
302 	return (eg);
303 }
304 
305 /*ARGSUSED*/
306 static void
evch_zonefree(zoneid_t zoneid,void * arg)307 evch_zonefree(zoneid_t zoneid, void *arg)
308 {
309 	struct evch_globals *eg = arg;
310 	evch_chan_t *chp;
311 	evch_subd_t *sdp;
312 
313 	mutex_enter(&eg->evch_list_lock);
314 
315 	/*
316 	 * Keep picking the head element off the list until there are no
317 	 * more.
318 	 */
319 	while ((chp = evch_dl_next(&eg->evch_list, NULL)) != NULL) {
320 
321 		/*
322 		 * Since all processes are gone, all bindings should be gone,
323 		 * and only channels with SUB_KEEP subscribers should remain.
324 		 */
325 		mutex_enter(&chp->ch_mutex);
326 		ASSERT(chp->ch_bindings == 0);
327 		ASSERT(evch_dl_getnum(&chp->ch_subscr) != 0 ||
328 		    chp->ch_holdpend == CH_HOLD_PEND_INDEF);
329 
330 		/* Forcibly unsubscribe each remaining subscription */
331 		while ((sdp = evch_dl_next(&chp->ch_subscr, NULL)) != NULL) {
332 			/*
333 			 * We should only be tearing down persistent
334 			 * subscribers at this point, since all processes
335 			 * from this zone are gone.
336 			 */
337 			ASSERT(sdp->sd_active == 0);
338 			ASSERT((sdp->sd_persist & EVCH_SUB_KEEP) != 0);
339 			/*
340 			 * Disconnect subscriber queue from main event queue.
341 			 */
342 			evch_evq_unsub(chp->ch_queue, sdp->sd_msub);
343 
344 			/* Destruct per subscriber queue */
345 			evch_evq_unsub(sdp->sd_queue, sdp->sd_ssub);
346 			evch_evq_destroy(sdp->sd_queue);
347 			/*
348 			 * Eliminate the subscriber data from channel list.
349 			 */
350 			evch_dl_del(&chp->ch_subscr, &sdp->sd_link);
351 			kmem_free(sdp->sd_classname, sdp->sd_clnsize);
352 			kmem_free(sdp->sd_ident, strlen(sdp->sd_ident) + 1);
353 			kmem_free(sdp, sizeof (evch_subd_t));
354 		}
355 
356 		/* Channel must now have no subscribers */
357 		ASSERT(evch_dl_getnum(&chp->ch_subscr) == 0);
358 
359 		/* Just like unbind */
360 		mutex_exit(&chp->ch_mutex);
361 		evch_dl_del(&eg->evch_list, &chp->ch_link);
362 		evch_evq_destroy(chp->ch_queue);
363 		mutex_destroy(&chp->ch_mutex);
364 		mutex_destroy(&chp->ch_pubmx);
365 		cv_destroy(&chp->ch_pubcv);
366 		kmem_free(chp->ch_name, chp->ch_namelen);
367 		kmem_free(chp, sizeof (evch_chan_t));
368 	}
369 
370 	mutex_exit(&eg->evch_list_lock);
371 	/* all channels should now be gone */
372 	ASSERT(evch_dl_getnum(&eg->evch_list) == 0);
373 	kmem_free(eg, sizeof (*eg));
374 }
375 
376 /*
377  * Frees evch_gevent_t structure including the payload, if the reference count
378  * drops to or below zero. Below zero happens when the event is freed
379  * without beeing queued into a queue.
380  */
381 static void
evch_gevent_free(evch_gevent_t * evp)382 evch_gevent_free(evch_gevent_t *evp)
383 {
384 	int32_t refcnt;
385 
386 	refcnt = (int32_t)atomic_dec_32_nv(&evp->ge_refcount);
387 	if (refcnt <= 0) {
388 		if (evp->ge_destruct != NULL) {
389 			evp->ge_destruct((void *)&(evp->ge_payload),
390 			    evp->ge_dstcookie);
391 		}
392 		kmem_free(evp, evp->ge_size);
393 	}
394 }
395 
396 /*
397  * Deliver is called for every subscription to the current event
398  * It calls the registered filter function and then the registered delivery
399  * callback routine. Returns 0 on success. The callback routine returns
400  * EVQ_AGAIN or EVQ_SLEEP in case the event could not be delivered.
401  */
402 static int
evch_deliver(evch_evqsub_t * sp,evch_gevent_t * ep)403 evch_deliver(evch_evqsub_t *sp, evch_gevent_t *ep)
404 {
405 	void		*uep = &ep->ge_payload;
406 	int		res = EVQ_DELIVER;
407 
408 	if (sp->su_filter != NULL) {
409 		res = sp->su_filter(uep, sp->su_fcookie);
410 	}
411 	if (res == EVQ_DELIVER) {
412 		return (sp->su_callb(uep, sp->su_cbcookie));
413 	}
414 	return (0);
415 }
416 
417 /*
418  * Holds event delivery in case of eq_holdmode set or in case the
419  * event queue is empty. Mutex must be held when called.
420  * Wakes up a thread waiting for the delivery thread reaching the hold mode.
421  */
422 static void
evch_delivery_hold(evch_eventq_t * eqp,callb_cpr_t * cpip)423 evch_delivery_hold(evch_eventq_t *eqp, callb_cpr_t *cpip)
424 {
425 	if (eqp->eq_tabortflag == 0) {
426 		do {
427 			if (eqp->eq_holdmode) {
428 				cv_signal(&eqp->eq_onholdcv);
429 			}
430 			CALLB_CPR_SAFE_BEGIN(cpip);
431 			cv_wait(&eqp->eq_thrsleepcv, &eqp->eq_queuemx);
432 			CALLB_CPR_SAFE_END(cpip, &eqp->eq_queuemx);
433 		} while (eqp->eq_holdmode);
434 	}
435 }
436 
437 /*
438  * Event delivery thread. Enumerates all subscribers and calls evch_deliver()
439  * for each one.
440  */
441 static void
evch_delivery_thr(evch_eventq_t * eqp)442 evch_delivery_thr(evch_eventq_t *eqp)
443 {
444 	evch_qelem_t	*qep;
445 	callb_cpr_t	cprinfo;
446 	int		res;
447 	evch_evqsub_t	*sub;
448 	int		deltime;
449 	int		repeatcount;
450 	char		thnam[32];
451 
452 	(void) snprintf(thnam, sizeof (thnam), "sysevent_chan-%d",
453 	    (int)eqp->eq_thrid);
454 	CALLB_CPR_INIT(&cprinfo, &eqp->eq_queuemx, callb_generic_cpr, thnam);
455 	mutex_enter(&eqp->eq_queuemx);
456 	while (eqp->eq_tabortflag == 0) {
457 		while (eqp->eq_holdmode == 0 && eqp->eq_tabortflag == 0 &&
458 		    (qep = evch_q_out(&eqp->eq_eventq)) != NULL) {
459 
460 			/* Filter and deliver event to all subscribers */
461 			deltime = EVCH_MIN_PAUSE;
462 			repeatcount = EVCH_MAX_TRY_DELIVERY;
463 			eqp->eq_curevent = qep->q_objref;
464 			sub = evch_dl_next(&eqp->eq_subscr, NULL);
465 			while (sub != NULL) {
466 				eqp->eq_dactive = 1;
467 				mutex_exit(&eqp->eq_queuemx);
468 				res = evch_deliver(sub, qep->q_objref);
469 				mutex_enter(&eqp->eq_queuemx);
470 				eqp->eq_dactive = 0;
471 				cv_signal(&eqp->eq_dactivecv);
472 				switch (res) {
473 				case EVQ_SLEEP:
474 					/*
475 					 * Wait for subscriber to return.
476 					 */
477 					eqp->eq_holdmode = 1;
478 					evch_delivery_hold(eqp, &cprinfo);
479 					if (eqp->eq_tabortflag) {
480 						break;
481 					}
482 					continue;
483 				case EVQ_AGAIN:
484 					CALLB_CPR_SAFE_BEGIN(&cprinfo);
485 					mutex_exit(&eqp->eq_queuemx);
486 					delay(deltime);
487 					deltime =
488 					    deltime > EVCH_MAX_PAUSE ?
489 					    deltime : deltime << 1;
490 					mutex_enter(&eqp->eq_queuemx);
491 					CALLB_CPR_SAFE_END(&cprinfo,
492 					    &eqp->eq_queuemx);
493 					if (repeatcount-- > 0) {
494 						continue;
495 					}
496 					break;
497 				}
498 				if (eqp->eq_tabortflag) {
499 					break;
500 				}
501 				sub = evch_dl_next(&eqp->eq_subscr, sub);
502 				repeatcount = EVCH_MAX_TRY_DELIVERY;
503 			}
504 			eqp->eq_curevent = NULL;
505 
506 			/* Free event data and queue element */
507 			evch_gevent_free((evch_gevent_t *)qep->q_objref);
508 			kmem_free(qep, qep->q_objsize);
509 		}
510 
511 		/* Wait for next event or end of hold mode if set */
512 		evch_delivery_hold(eqp, &cprinfo);
513 	}
514 	CALLB_CPR_EXIT(&cprinfo);	/* Does mutex_exit of eqp->eq_queuemx */
515 	thread_exit();
516 }
517 
518 /*
519  * Create the event delivery thread for an existing event queue.
520  */
521 static void
evch_evq_thrcreate(evch_eventq_t * eqp)522 evch_evq_thrcreate(evch_eventq_t *eqp)
523 {
524 	kthread_t *thp;
525 
526 	thp = thread_create(NULL, 0, evch_delivery_thr, (char *)eqp, 0, &p0,
527 	    TS_RUN, minclsyspri);
528 	eqp->eq_thrid = thp->t_did;
529 }
530 
531 /*
532  * Create event queue.
533  */
534 static evch_eventq_t *
evch_evq_create()535 evch_evq_create()
536 {
537 	evch_eventq_t *p;
538 
539 	/* Allocate and initialize event queue descriptor */
540 	p = kmem_zalloc(sizeof (evch_eventq_t), KM_SLEEP);
541 	mutex_init(&p->eq_queuemx, NULL, MUTEX_DEFAULT, NULL);
542 	cv_init(&p->eq_thrsleepcv, NULL, CV_DEFAULT, NULL);
543 	evch_q_init(&p->eq_eventq);
544 	evch_dl_init(&p->eq_subscr);
545 	cv_init(&p->eq_dactivecv, NULL, CV_DEFAULT, NULL);
546 	cv_init(&p->eq_onholdcv, NULL, CV_DEFAULT, NULL);
547 
548 	/* Create delivery thread */
549 	if (evq_initcomplete) {
550 		evch_evq_thrcreate(p);
551 	}
552 	return (p);
553 }
554 
555 /*
556  * Destroy an event queue. All subscribers have to be unsubscribed prior to
557  * this call.
558  */
559 static void
evch_evq_destroy(evch_eventq_t * eqp)560 evch_evq_destroy(evch_eventq_t *eqp)
561 {
562 	evch_qelem_t *qep;
563 
564 	ASSERT(evch_dl_getnum(&eqp->eq_subscr) == 0);
565 	/* Kill delivery thread */
566 	if (eqp->eq_thrid != 0) {
567 		mutex_enter(&eqp->eq_queuemx);
568 		eqp->eq_tabortflag = 1;
569 		eqp->eq_holdmode = 0;
570 		cv_signal(&eqp->eq_thrsleepcv);
571 		mutex_exit(&eqp->eq_queuemx);
572 		thread_join(eqp->eq_thrid);
573 	}
574 
575 	/* Get rid of stale events in the event queue */
576 	while ((qep = (evch_qelem_t *)evch_q_out(&eqp->eq_eventq)) != NULL) {
577 		evch_gevent_free((evch_gevent_t *)qep->q_objref);
578 		kmem_free(qep, qep->q_objsize);
579 	}
580 
581 	/* Wrap up event queue structure */
582 	cv_destroy(&eqp->eq_onholdcv);
583 	cv_destroy(&eqp->eq_dactivecv);
584 	cv_destroy(&eqp->eq_thrsleepcv);
585 	evch_dl_fini(&eqp->eq_subscr);
586 	mutex_destroy(&eqp->eq_queuemx);
587 
588 	/* Free descriptor structure */
589 	kmem_free(eqp, sizeof (evch_eventq_t));
590 }
591 
592 /*
593  * Subscribe to an event queue. Every subscriber provides a filter callback
594  * routine and an event delivery callback routine.
595  */
596 static evch_evqsub_t *
evch_evq_sub(evch_eventq_t * eqp,filter_f filter,void * fcookie,deliver_f callb,void * cbcookie)597 evch_evq_sub(evch_eventq_t *eqp, filter_f filter, void *fcookie,
598     deliver_f callb, void *cbcookie)
599 {
600 	evch_evqsub_t *sp = kmem_zalloc(sizeof (evch_evqsub_t), KM_SLEEP);
601 
602 	/* Initialize subscriber structure */
603 	sp->su_filter = filter;
604 	sp->su_fcookie = fcookie;
605 	sp->su_callb = callb;
606 	sp->su_cbcookie = cbcookie;
607 
608 	/* Add subscription to queue */
609 	mutex_enter(&eqp->eq_queuemx);
610 	evch_dl_add(&eqp->eq_subscr, &sp->su_link);
611 	mutex_exit(&eqp->eq_queuemx);
612 	return (sp);
613 }
614 
615 /*
616  * Unsubscribe from an event queue.
617  */
618 static void
evch_evq_unsub(evch_eventq_t * eqp,evch_evqsub_t * sp)619 evch_evq_unsub(evch_eventq_t *eqp, evch_evqsub_t *sp)
620 {
621 	mutex_enter(&eqp->eq_queuemx);
622 
623 	/* Wait if delivery is just in progress */
624 	if (eqp->eq_dactive) {
625 		cv_wait(&eqp->eq_dactivecv, &eqp->eq_queuemx);
626 	}
627 	evch_dl_del(&eqp->eq_subscr, &sp->su_link);
628 	mutex_exit(&eqp->eq_queuemx);
629 	kmem_free(sp, sizeof (evch_evqsub_t));
630 }
631 
632 /*
633  * Publish an event. Returns 0 on success and -1 if memory alloc failed.
634  */
635 static int
evch_evq_pub(evch_eventq_t * eqp,void * ev,int flags)636 evch_evq_pub(evch_eventq_t *eqp, void *ev, int flags)
637 {
638 	size_t size;
639 	evch_qelem_t	*qep;
640 	evch_gevent_t	*evp = GEVENT(ev);
641 
642 	size = sizeof (evch_qelem_t);
643 	if (flags & EVCH_TRYHARD) {
644 		qep = kmem_alloc_tryhard(size, &size, KM_NOSLEEP);
645 	} else {
646 		qep = kmem_alloc(size, flags & EVCH_NOSLEEP ?
647 		    KM_NOSLEEP : KM_SLEEP);
648 	}
649 	if (qep == NULL) {
650 		return (-1);
651 	}
652 	qep->q_objref = (void *)evp;
653 	qep->q_objsize = size;
654 	atomic_inc_32(&evp->ge_refcount);
655 	mutex_enter(&eqp->eq_queuemx);
656 	evch_q_in(&eqp->eq_eventq, qep);
657 
658 	/* Wakeup delivery thread */
659 	cv_signal(&eqp->eq_thrsleepcv);
660 	mutex_exit(&eqp->eq_queuemx);
661 	return (0);
662 }
663 
664 /*
665  * Enter hold mode of an event queue. Event delivery thread stops event
666  * handling after delivery of current event (if any).
667  */
668 static void
evch_evq_stop(evch_eventq_t * eqp)669 evch_evq_stop(evch_eventq_t *eqp)
670 {
671 	mutex_enter(&eqp->eq_queuemx);
672 	eqp->eq_holdmode = 1;
673 	if (evq_initcomplete) {
674 		cv_signal(&eqp->eq_thrsleepcv);
675 		cv_wait(&eqp->eq_onholdcv, &eqp->eq_queuemx);
676 	}
677 	mutex_exit(&eqp->eq_queuemx);
678 }
679 
680 /*
681  * Continue event delivery.
682  */
683 static void
evch_evq_continue(evch_eventq_t * eqp)684 evch_evq_continue(evch_eventq_t *eqp)
685 {
686 	mutex_enter(&eqp->eq_queuemx);
687 	eqp->eq_holdmode = 0;
688 	cv_signal(&eqp->eq_thrsleepcv);
689 	mutex_exit(&eqp->eq_queuemx);
690 }
691 
692 /*
693  * Returns status of delivery thread. 0 if running and 1 if on hold.
694  */
695 static int
evch_evq_status(evch_eventq_t * eqp)696 evch_evq_status(evch_eventq_t *eqp)
697 {
698 	return (eqp->eq_holdmode);
699 }
700 
701 /*
702  * Add a destructor function to an event structure.
703  */
704 static void
evch_evq_evadd_dest(void * ev,destr_f destructor,void * cookie)705 evch_evq_evadd_dest(void *ev, destr_f destructor, void *cookie)
706 {
707 	evch_gevent_t *evp = GEVENT(ev);
708 
709 	evp->ge_destruct = destructor;
710 	evp->ge_dstcookie = cookie;
711 }
712 
713 /*
714  * Allocate evch_gevent_t structure. Return address of payload offset of
715  * evch_gevent_t.  If EVCH_TRYHARD allocation is requested, we use
716  * kmem_alloc_tryhard to alloc memory of at least paylsize bytes.
717  *
718  * If either memory allocation is unsuccessful, we return NULL.
719  */
720 static void *
evch_evq_evzalloc(size_t paylsize,int flag)721 evch_evq_evzalloc(size_t paylsize, int flag)
722 {
723 	evch_gevent_t	*evp;
724 	size_t		rsize, evsize, ge_size;
725 
726 	rsize = offsetof(evch_gevent_t, ge_payload) + paylsize;
727 	if (flag & EVCH_TRYHARD) {
728 		evp = kmem_alloc_tryhard(rsize, &evsize, KM_NOSLEEP);
729 		ge_size = evsize;
730 	} else {
731 		evp = kmem_alloc(rsize, flag & EVCH_NOSLEEP ? KM_NOSLEEP :
732 		    KM_SLEEP);
733 		ge_size = rsize;
734 	}
735 
736 	if (evp) {
737 		bzero(evp, rsize);
738 		evp->ge_size = ge_size;
739 		return (&evp->ge_payload);
740 	}
741 	return (evp);
742 }
743 
744 /*
745  * Free event structure. Argument ev is address of payload offset.
746  */
747 static void
evch_evq_evfree(void * ev)748 evch_evq_evfree(void *ev)
749 {
750 	evch_gevent_free(GEVENT(ev));
751 }
752 
753 /*
754  * Iterate over all events in the event queue. Begin with an event
755  * which is currently being delivered. No mutexes are grabbed and no
756  * resources allocated so that this function can be called in panic
757  * context too. This function has to be called with ev == NULL initially.
758  * Actually argument ev is only a flag. Internally the member eq_nextev
759  * is used to determine the next event. But ev allows for the convenient
760  * use like
761  *	ev = NULL;
762  *	while ((ev = evch_evq_evnext(evp, ev)) != NULL) ...
763  */
764 static void *
evch_evq_evnext(evch_eventq_t * evq,void * ev)765 evch_evq_evnext(evch_eventq_t *evq, void *ev)
766 {
767 	if (ev == NULL) {
768 		evq->eq_nextev = NULL;
769 		if (evq->eq_curevent != NULL)
770 			return (&evq->eq_curevent->ge_payload);
771 	}
772 	evq->eq_nextev = evch_q_next(&evq->eq_eventq, evq->eq_nextev);
773 	if (evq->eq_nextev == NULL)
774 		return (NULL);
775 	return (&((evch_gevent_t *)evq->eq_nextev->q_objref)->ge_payload);
776 }
777 
778 /*
779  * Channel handling functions. First some support functions. Functions belonging
780  * to the channel handling interface start with evch_ch. The following functions
781  * make up the channel handling internal interfaces:
782  *
783  * evch_chinit		- Initialize channel handling
784  * evch_chinitthr	- Second step init: initialize threads
785  * evch_chbind		- Bind to a channel
786  * evch_chunbind	- Unbind from a channel
787  * evch_chsubscribe	- Subscribe to a sysevent class
788  * evch_chunsubscribe	- Unsubscribe
789  * evch_chpublish	- Publish an event
790  * evch_chgetnames	- Get names of all channels
791  * evch_chgetchdata	- Get data of a channel
792  * evch_chrdevent_init  - Init event q traversal
793  * evch_chgetnextev	- Read out events queued for a subscriber
794  * evch_chrdevent_fini  - Finish event q traversal
795  */
796 
797 /*
798  * Compare channel name. Used for evch_dl_search to find a channel with the
799  * name s.
800  */
801 static int
evch_namecmp(evch_dlelem_t * ep,char * s)802 evch_namecmp(evch_dlelem_t *ep, char *s)
803 {
804 	return (strcmp(((evch_chan_t *)ep)->ch_name, s));
805 }
806 
807 /*
808  * Simple wildcarded match test of event class string 'class' to
809  * wildcarded subscription string 'pat'.  Recursive only if
810  * 'pat' includes a wildcard, otherwise essentially just strcmp.
811  */
812 static int
evch_clsmatch(char * class,const char * pat)813 evch_clsmatch(char *class, const char *pat)
814 {
815 	char c;
816 
817 	do {
818 		if ((c = *pat++) == '\0')
819 			return (*class == '\0');
820 
821 		if (c == '*') {
822 			while (*pat == '*')
823 				pat++; /* consecutive *'s can be collapsed */
824 
825 			if (*pat == '\0')
826 				return (1);
827 
828 			while (*class != '\0') {
829 				if (evch_clsmatch(class++, pat) != 0)
830 					return (1);
831 			}
832 
833 			return (0);
834 		}
835 	} while (c == *class++);
836 
837 	return (0);
838 }
839 
840 /*
841  * Sysevent filter callback routine. Enables event delivery only if it matches
842  * the event class pattern string given by parameter cookie.
843  */
844 static int
evch_class_filter(void * ev,void * cookie)845 evch_class_filter(void *ev, void *cookie)
846 {
847 	const char *pat = (const char *)cookie;
848 
849 	if (pat == NULL || evch_clsmatch(SE_CLASS_NAME(ev), pat))
850 		return (EVQ_DELIVER);
851 
852 	return (EVQ_IGNORE);
853 }
854 
855 /*
856  * Callback routine to propagate the event into a per subscriber queue.
857  */
858 static int
evch_subq_deliver(void * evp,void * cookie)859 evch_subq_deliver(void *evp, void *cookie)
860 {
861 	evch_subd_t *p = (evch_subd_t *)cookie;
862 
863 	(void) evch_evq_pub(p->sd_queue, evp, EVCH_SLEEP);
864 	return (EVQ_CONT);
865 }
866 
867 /*
868  * Call kernel callback routine for sysevent kernel delivery.
869  */
870 static int
evch_kern_deliver(void * evp,void * cookie)871 evch_kern_deliver(void *evp, void *cookie)
872 {
873 	sysevent_impl_t	*ev = (sysevent_impl_t *)evp;
874 	evch_subd_t	*sdp = (evch_subd_t *)cookie;
875 
876 	return (sdp->sd_callback(ev, sdp->sd_cbcookie));
877 }
878 
879 /*
880  * Door upcall for user land sysevent delivery.
881  */
882 static int
evch_door_deliver(void * evp,void * cookie)883 evch_door_deliver(void *evp, void *cookie)
884 {
885 	int		error;
886 	size_t		size;
887 	sysevent_impl_t	*ev = (sysevent_impl_t *)evp;
888 	door_arg_t	darg;
889 	evch_subd_t	*sdp = (evch_subd_t *)cookie;
890 	int		nticks = EVCH_MIN_PAUSE;
891 	uint32_t	retval;
892 	int		retry = 20;
893 
894 	/* Initialize door args */
895 	size = sizeof (sysevent_impl_t) + SE_PAYLOAD_SZ(ev);
896 
897 	darg.rbuf = (char *)&retval;
898 	darg.rsize = sizeof (retval);
899 	darg.data_ptr = (char *)ev;
900 	darg.data_size = size;
901 	darg.desc_ptr = NULL;
902 	darg.desc_num = 0;
903 
904 	for (;;) {
905 		if ((error = door_ki_upcall_limited(sdp->sd_door, &darg,
906 		    NULL, SIZE_MAX, 0)) == 0) {
907 			break;
908 		}
909 		switch (error) {
910 		case EAGAIN:
911 			/* Cannot deliver event - process may be forking */
912 			delay(nticks);
913 			nticks <<= 1;
914 			if (nticks > EVCH_MAX_PAUSE) {
915 				nticks = EVCH_MAX_PAUSE;
916 			}
917 			if (retry-- <= 0) {
918 				cmn_err(CE_CONT, "event delivery thread: "
919 				    "door_ki_upcall error EAGAIN\n");
920 				return (EVQ_CONT);
921 			}
922 			break;
923 		case EINTR:
924 		case EBADF:
925 			/* Process died */
926 			return (EVQ_SLEEP);
927 		default:
928 			cmn_err(CE_CONT,
929 			    "event delivery thread: door_ki_upcall error %d\n",
930 			    error);
931 			return (EVQ_CONT);
932 		}
933 	}
934 	if (retval == EAGAIN) {
935 		return (EVQ_AGAIN);
936 	}
937 	return (EVQ_CONT);
938 }
939 
940 /*
941  * Callback routine for evch_dl_search() to compare subscriber id's. Used by
942  * evch_subscribe() and evch_chrdevent_init().
943  */
944 static int
evch_subidcmp(evch_dlelem_t * ep,char * s)945 evch_subidcmp(evch_dlelem_t *ep, char *s)
946 {
947 	return (strcmp(((evch_subd_t *)ep)->sd_ident, s));
948 }
949 
950 /*
951  * Callback routine for evch_dl_search() to find a subscriber with EVCH_SUB_DUMP
952  * set (indicated by sub->sd_dump != 0). Used by evch_chrdevent_init() and
953  * evch_subscribe(). Needs to returns 0 if subscriber with sd_dump set is
954  * found.
955  */
956 /*ARGSUSED1*/
957 static int
evch_dumpflgcmp(evch_dlelem_t * ep,char * s)958 evch_dumpflgcmp(evch_dlelem_t *ep, char *s)
959 {
960 	return (((evch_subd_t *)ep)->sd_dump ? 0 : 1);
961 }
962 
963 /*
964  * Event destructor function. Used to maintain the number of events per channel.
965  */
966 /*ARGSUSED*/
967 static void
evch_destr_event(void * ev,void * ch)968 evch_destr_event(void *ev, void *ch)
969 {
970 	evch_chan_t *chp = (evch_chan_t *)ch;
971 
972 	mutex_enter(&chp->ch_pubmx);
973 	chp->ch_nevents--;
974 	cv_signal(&chp->ch_pubcv);
975 	mutex_exit(&chp->ch_pubmx);
976 }
977 
978 /*
979  * Integer square root according to Newton's iteration.
980  */
981 static uint32_t
evch_isqrt(uint64_t n)982 evch_isqrt(uint64_t n)
983 {
984 	uint64_t	x = n >> 1;
985 	uint64_t	xn = x - 1;
986 	static uint32_t	lowval[] = { 0, 1, 1, 2 };
987 
988 	if (n < 4) {
989 		return (lowval[n]);
990 	}
991 	while (xn < x) {
992 		x = xn;
993 		xn = (x + n / x) / 2;
994 	}
995 	return ((uint32_t)xn);
996 }
997 
998 /*
999  * First step sysevent channel initialization. Called when kernel memory
1000  * allocator is initialized.
1001  */
1002 static void
evch_chinit()1003 evch_chinit()
1004 {
1005 	size_t k;
1006 
1007 	/*
1008 	 * Calculate limits: max no of channels and max no of events per
1009 	 * channel. The smallest machine with 128 MByte will allow for
1010 	 * >= 8 channels and an upper limit of 2048 events per channel.
1011 	 * The event limit is the number of channels times 256 (hence
1012 	 * the shift factor of 8). These number where selected arbitrarily.
1013 	 */
1014 	k = kmem_maxavail() >> 20;
1015 	evch_channels_max = min(evch_isqrt(k), EVCH_MAX_CHANNELS);
1016 	evch_events_max = evch_channels_max << 8;
1017 
1018 	/*
1019 	 * Will trigger creation of the global zone's evch state.
1020 	 */
1021 	zone_key_create(&evch_zone_key, evch_zoneinit, NULL, evch_zonefree);
1022 }
1023 
1024 /*
1025  * Second step sysevent channel initialization. Called when threads are ready.
1026  */
1027 static void
evch_chinitthr()1028 evch_chinitthr()
1029 {
1030 	struct evch_globals *eg;
1031 	evch_chan_t	*chp;
1032 	evch_subd_t	*sdp;
1033 
1034 	/*
1035 	 * We're early enough in boot that we know that only the global
1036 	 * zone exists; we only need to initialize its threads.
1037 	 */
1038 	eg = zone_getspecific(evch_zone_key, global_zone);
1039 	ASSERT(eg != NULL);
1040 
1041 	for (chp = evch_dl_next(&eg->evch_list, NULL); chp != NULL;
1042 	    chp = evch_dl_next(&eg->evch_list, chp)) {
1043 		for (sdp = evch_dl_next(&chp->ch_subscr, NULL); sdp;
1044 		    sdp = evch_dl_next(&chp->ch_subscr, sdp)) {
1045 			evch_evq_thrcreate(sdp->sd_queue);
1046 		}
1047 		evch_evq_thrcreate(chp->ch_queue);
1048 	}
1049 	evq_initcomplete = 1;
1050 }
1051 
1052 /*
1053  * Sysevent channel bind. Create channel and allocate binding structure.
1054  */
1055 static int
evch_chbind(const char * chnam,evch_bind_t ** scpp,uint32_t flags)1056 evch_chbind(const char *chnam, evch_bind_t **scpp, uint32_t flags)
1057 {
1058 	struct evch_globals *eg;
1059 	evch_bind_t	*bp;
1060 	evch_chan_t	*p;
1061 	char		*chn;
1062 	size_t		namlen;
1063 	int		rv;
1064 
1065 	eg = zone_getspecific(evch_zone_key, curproc->p_zone);
1066 	ASSERT(eg != NULL);
1067 
1068 	/* Create channel if it does not exist */
1069 	ASSERT(evch_dl_is_init(&eg->evch_list));
1070 	if ((namlen = strlen(chnam) + 1) > MAX_CHNAME_LEN) {
1071 		return (EINVAL);
1072 	}
1073 	mutex_enter(&eg->evch_list_lock);
1074 	if ((p = (evch_chan_t *)evch_dl_search(&eg->evch_list, evch_namecmp,
1075 	    (char *)chnam)) == NULL) {
1076 		if (flags & EVCH_CREAT) {
1077 			if (evch_dl_getnum(&eg->evch_list) >=
1078 			    evch_channels_max) {
1079 				mutex_exit(&eg->evch_list_lock);
1080 				return (ENOMEM);
1081 			}
1082 			chn = kmem_alloc(namlen, KM_SLEEP);
1083 			bcopy(chnam, chn, namlen);
1084 
1085 			/* Allocate and initialize channel descriptor */
1086 			p = kmem_zalloc(sizeof (evch_chan_t), KM_SLEEP);
1087 			p->ch_name = chn;
1088 			p->ch_namelen = namlen;
1089 			mutex_init(&p->ch_mutex, NULL, MUTEX_DEFAULT, NULL);
1090 			p->ch_queue = evch_evq_create();
1091 			evch_dl_init(&p->ch_subscr);
1092 			if (evq_initcomplete) {
1093 				p->ch_uid = crgetuid(curthread->t_cred);
1094 				p->ch_gid = crgetgid(curthread->t_cred);
1095 			}
1096 			cv_init(&p->ch_pubcv, NULL, CV_DEFAULT, NULL);
1097 			mutex_init(&p->ch_pubmx, NULL, MUTEX_DEFAULT, NULL);
1098 			p->ch_maxev = min(EVCH_DEFAULT_EVENTS, evch_events_max);
1099 			p->ch_maxsubscr = EVCH_MAX_SUBSCRIPTIONS;
1100 			p->ch_maxbinds = evch_bindings_max;
1101 			p->ch_ctime = gethrestime_sec();
1102 
1103 			if (flags & (EVCH_HOLD_PEND | EVCH_HOLD_PEND_INDEF)) {
1104 				if (flags & EVCH_HOLD_PEND_INDEF)
1105 					p->ch_holdpend = CH_HOLD_PEND_INDEF;
1106 				else
1107 					p->ch_holdpend = CH_HOLD_PEND;
1108 
1109 				evch_evq_stop(p->ch_queue);
1110 			}
1111 
1112 			/* Put new descriptor into channel list */
1113 			evch_dl_add(&eg->evch_list, (evch_dlelem_t *)p);
1114 		} else {
1115 			mutex_exit(&eg->evch_list_lock);
1116 			return (ENOENT);
1117 		}
1118 	}
1119 
1120 	/* Check for max binds and create binding */
1121 	mutex_enter(&p->ch_mutex);
1122 	if (p->ch_bindings >= p->ch_maxbinds) {
1123 		rv = ENOMEM;
1124 		/*
1125 		 * No need to destroy the channel because this call did not
1126 		 * create it. Other bindings will be present if ch_maxbinds
1127 		 * is exceeded.
1128 		 */
1129 		goto errorexit;
1130 	}
1131 	bp = kmem_alloc(sizeof (evch_bind_t), KM_SLEEP);
1132 	bp->bd_channel = p;
1133 	bp->bd_sublst = NULL;
1134 	p->ch_bindings++;
1135 	rv = 0;
1136 	*scpp = bp;
1137 errorexit:
1138 	mutex_exit(&p->ch_mutex);
1139 	mutex_exit(&eg->evch_list_lock);
1140 	return (rv);
1141 }
1142 
1143 /*
1144  * Unbind: Free bind structure. Remove channel if last binding was freed.
1145  */
1146 static void
evch_chunbind(evch_bind_t * bp)1147 evch_chunbind(evch_bind_t *bp)
1148 {
1149 	struct evch_globals *eg;
1150 	evch_chan_t *chp = bp->bd_channel;
1151 
1152 	eg = zone_getspecific(evch_zone_key, curproc->p_zone);
1153 	ASSERT(eg != NULL);
1154 
1155 	mutex_enter(&eg->evch_list_lock);
1156 	mutex_enter(&chp->ch_mutex);
1157 	ASSERT(chp->ch_bindings > 0);
1158 	chp->ch_bindings--;
1159 	kmem_free(bp, sizeof (evch_bind_t));
1160 	if (chp->ch_bindings == 0 && evch_dl_getnum(&chp->ch_subscr) == 0 &&
1161 	    (chp->ch_nevents == 0 || chp->ch_holdpend != CH_HOLD_PEND_INDEF)) {
1162 		/*
1163 		 * No more bindings and no persistent subscriber(s).  If there
1164 		 * are no events in the channel then destroy the channel;
1165 		 * otherwise destroy the channel only if we're not holding
1166 		 * pending events indefinitely.
1167 		 */
1168 		mutex_exit(&chp->ch_mutex);
1169 		evch_dl_del(&eg->evch_list, &chp->ch_link);
1170 		evch_evq_destroy(chp->ch_queue);
1171 		nvlist_free(chp->ch_propnvl);
1172 		mutex_destroy(&chp->ch_mutex);
1173 		mutex_destroy(&chp->ch_pubmx);
1174 		cv_destroy(&chp->ch_pubcv);
1175 		kmem_free(chp->ch_name, chp->ch_namelen);
1176 		kmem_free(chp, sizeof (evch_chan_t));
1177 	} else
1178 		mutex_exit(&chp->ch_mutex);
1179 	mutex_exit(&eg->evch_list_lock);
1180 }
1181 
1182 static int
wildcard_count(const char * class)1183 wildcard_count(const char *class)
1184 {
1185 	int count = 0;
1186 	char c;
1187 
1188 	if (class == NULL)
1189 		return (0);
1190 
1191 	while ((c = *class++) != '\0') {
1192 		if (c == '*')
1193 			count++;
1194 	}
1195 
1196 	return (count);
1197 }
1198 
1199 /*
1200  * Subscribe to a channel. dtype is either EVCH_DELKERN for kernel callbacks
1201  * or EVCH_DELDOOR for door upcall delivery to user land. Depending on dtype
1202  * dinfo gives the call back routine address or the door handle.
1203  */
1204 static int
evch_chsubscribe(evch_bind_t * bp,int dtype,const char * sid,const char * class,void * dinfo,void * cookie,int flags,pid_t pid)1205 evch_chsubscribe(evch_bind_t *bp, int dtype, const char *sid, const char *class,
1206     void *dinfo, void *cookie, int flags, pid_t pid)
1207 {
1208 	evch_chan_t	*chp = bp->bd_channel;
1209 	evch_eventq_t	*eqp = chp->ch_queue;
1210 	evch_subd_t	*sdp;
1211 	evch_subd_t	*esp;
1212 	int		(*delivfkt)();
1213 	char		*clb = NULL;
1214 	int		clblen = 0;
1215 	char		*subid;
1216 	int		subidblen;
1217 
1218 	/*
1219 	 * Check if only known flags are set.
1220 	 */
1221 	if (flags & ~(EVCH_SUB_KEEP | EVCH_SUB_DUMP))
1222 		return (EINVAL);
1223 
1224 	/*
1225 	 * Enforce a limit on the number of wildcards allowed in the class
1226 	 * subscription string (limits recursion in pattern matching).
1227 	 */
1228 	if (wildcard_count(class) > EVCH_WILDCARD_MAX)
1229 		return (EINVAL);
1230 
1231 	/*
1232 	 * Check if we have already a subscription with that name and if we
1233 	 * have to reconnect the subscriber to a persistent subscription.
1234 	 */
1235 	mutex_enter(&chp->ch_mutex);
1236 	if ((esp = (evch_subd_t *)evch_dl_search(&chp->ch_subscr,
1237 	    evch_subidcmp, (char *)sid)) != NULL) {
1238 		int error = 0;
1239 		if ((flags & EVCH_SUB_KEEP) && (esp->sd_active == 0)) {
1240 			/*
1241 			 * Subscription with the name on hold, reconnect to
1242 			 * existing queue.
1243 			 */
1244 			ASSERT(dtype == EVCH_DELDOOR);
1245 			esp->sd_subnxt = bp->bd_sublst;
1246 			bp->bd_sublst = esp;
1247 			esp->sd_pid = pid;
1248 			esp->sd_door = (door_handle_t)dinfo;
1249 			esp->sd_active++;
1250 			evch_evq_continue(esp->sd_queue);
1251 		} else {
1252 			/* Subscriber with given name already exists */
1253 			error = EEXIST;
1254 		}
1255 		mutex_exit(&chp->ch_mutex);
1256 		return (error);
1257 	}
1258 
1259 	if (evch_dl_getnum(&chp->ch_subscr) >= chp->ch_maxsubscr) {
1260 		mutex_exit(&chp->ch_mutex);
1261 		return (ENOMEM);
1262 	}
1263 
1264 	if (flags & EVCH_SUB_DUMP && evch_dl_search(&chp->ch_subscr,
1265 	    evch_dumpflgcmp, NULL) != NULL) {
1266 		/*
1267 		 * Subscription with EVCH_SUB_DUMP flagged already exists.
1268 		 * Only one subscription with EVCH_SUB_DUMP possible. Return
1269 		 * error.
1270 		 */
1271 		mutex_exit(&chp->ch_mutex);
1272 		return (EINVAL);
1273 	}
1274 
1275 	if (class != NULL) {
1276 		clblen = strlen(class) + 1;
1277 		clb = kmem_alloc(clblen, KM_SLEEP);
1278 		bcopy(class, clb, clblen);
1279 	}
1280 
1281 	subidblen = strlen(sid) + 1;
1282 	subid = kmem_alloc(subidblen, KM_SLEEP);
1283 	bcopy(sid, subid, subidblen);
1284 
1285 	/* Create per subscriber queue */
1286 	sdp = kmem_zalloc(sizeof (evch_subd_t), KM_SLEEP);
1287 	sdp->sd_queue = evch_evq_create();
1288 
1289 	/* Subscribe to subscriber queue */
1290 	sdp->sd_persist = flags & EVCH_SUB_KEEP ? 1 : 0;
1291 	sdp->sd_dump = flags & EVCH_SUB_DUMP ? 1 : 0;
1292 	sdp->sd_type = dtype;
1293 	sdp->sd_cbcookie = cookie;
1294 	sdp->sd_ident = subid;
1295 	if (dtype == EVCH_DELKERN) {
1296 		sdp->sd_callback = (kerndlv_f)dinfo;
1297 		delivfkt = evch_kern_deliver;
1298 	} else {
1299 		sdp->sd_door = (door_handle_t)dinfo;
1300 		delivfkt = evch_door_deliver;
1301 	}
1302 	sdp->sd_ssub =
1303 	    evch_evq_sub(sdp->sd_queue, NULL, NULL, delivfkt, (void *)sdp);
1304 
1305 	/* Connect per subscriber queue to main event queue */
1306 	sdp->sd_msub = evch_evq_sub(eqp, evch_class_filter, clb,
1307 	    evch_subq_deliver, (void *)sdp);
1308 	sdp->sd_classname = clb;
1309 	sdp->sd_clnsize = clblen;
1310 	sdp->sd_pid = pid;
1311 	sdp->sd_active++;
1312 
1313 	/* Add subscription to binding */
1314 	sdp->sd_subnxt = bp->bd_sublst;
1315 	bp->bd_sublst = sdp;
1316 
1317 	/* Add subscription to channel */
1318 	evch_dl_add(&chp->ch_subscr, &sdp->sd_link);
1319 	if (chp->ch_holdpend && evch_dl_getnum(&chp->ch_subscr) == 1) {
1320 
1321 		/* Let main event queue run in case of HOLDPEND */
1322 		evch_evq_continue(eqp);
1323 	}
1324 	mutex_exit(&chp->ch_mutex);
1325 
1326 	return (0);
1327 }
1328 
1329 /*
1330  * If flag == EVCH_SUB_KEEP only non-persistent subscriptions are deleted.
1331  * When sid == NULL all subscriptions except the ones with EVCH_SUB_KEEP set
1332  * are removed.
1333  */
1334 static void
evch_chunsubscribe(evch_bind_t * bp,const char * sid,uint32_t flags)1335 evch_chunsubscribe(evch_bind_t *bp, const char *sid, uint32_t flags)
1336 {
1337 	evch_subd_t	*sdp;
1338 	evch_subd_t	*next;
1339 	evch_subd_t	*prev;
1340 	evch_chan_t	*chp = bp->bd_channel;
1341 
1342 	mutex_enter(&chp->ch_mutex);
1343 	if (chp->ch_holdpend) {
1344 		evch_evq_stop(chp->ch_queue);	/* Hold main event queue */
1345 	}
1346 	prev = NULL;
1347 	for (sdp = bp->bd_sublst; sdp; sdp = next) {
1348 		if (sid == NULL || strcmp(sid, sdp->sd_ident) == 0) {
1349 			if (flags == 0 || sdp->sd_persist == 0) {
1350 				/*
1351 				 * Disconnect subscriber queue from main event
1352 				 * queue.
1353 				 */
1354 				evch_evq_unsub(chp->ch_queue, sdp->sd_msub);
1355 
1356 				/* Destruct per subscriber queue */
1357 				evch_evq_unsub(sdp->sd_queue, sdp->sd_ssub);
1358 				evch_evq_destroy(sdp->sd_queue);
1359 				/*
1360 				 * Eliminate the subscriber data from channel
1361 				 * list.
1362 				 */
1363 				evch_dl_del(&chp->ch_subscr, &sdp->sd_link);
1364 				kmem_free(sdp->sd_classname, sdp->sd_clnsize);
1365 				if (sdp->sd_type == EVCH_DELDOOR) {
1366 					door_ki_rele(sdp->sd_door);
1367 				}
1368 				next = sdp->sd_subnxt;
1369 				if (prev) {
1370 					prev->sd_subnxt = next;
1371 				} else {
1372 					bp->bd_sublst = next;
1373 				}
1374 				kmem_free(sdp->sd_ident,
1375 				    strlen(sdp->sd_ident) + 1);
1376 				kmem_free(sdp, sizeof (evch_subd_t));
1377 			} else {
1378 				/*
1379 				 * EVCH_SUB_KEEP case
1380 				 */
1381 				evch_evq_stop(sdp->sd_queue);
1382 				if (sdp->sd_type == EVCH_DELDOOR) {
1383 					door_ki_rele(sdp->sd_door);
1384 				}
1385 				sdp->sd_active--;
1386 				ASSERT(sdp->sd_active == 0);
1387 				next = sdp->sd_subnxt;
1388 				prev = sdp;
1389 			}
1390 			if (sid != NULL) {
1391 				break;
1392 			}
1393 		} else {
1394 			next = sdp->sd_subnxt;
1395 			prev = sdp;
1396 		}
1397 	}
1398 	if (!(chp->ch_holdpend && evch_dl_getnum(&chp->ch_subscr) == 0)) {
1399 		/*
1400 		 * Continue dispatch thread except if no subscribers are present
1401 		 * in HOLDPEND mode.
1402 		 */
1403 		evch_evq_continue(chp->ch_queue);
1404 	}
1405 	mutex_exit(&chp->ch_mutex);
1406 }
1407 
1408 /*
1409  * Publish an event. Returns zero on success and an error code else.
1410  */
1411 static int
evch_chpublish(evch_bind_t * bp,sysevent_impl_t * ev,int flags)1412 evch_chpublish(evch_bind_t *bp, sysevent_impl_t *ev, int flags)
1413 {
1414 	evch_chan_t *chp = bp->bd_channel;
1415 
1416 	DTRACE_SYSEVENT2(post, evch_bind_t *, bp, sysevent_impl_t *, ev);
1417 
1418 	mutex_enter(&chp->ch_pubmx);
1419 	if (chp->ch_nevents >= chp->ch_maxev) {
1420 		if (!(flags & EVCH_QWAIT)) {
1421 			evch_evq_evfree(ev);
1422 			mutex_exit(&chp->ch_pubmx);
1423 			return (EAGAIN);
1424 		} else {
1425 			while (chp->ch_nevents >= chp->ch_maxev) {
1426 				if (cv_wait_sig(&chp->ch_pubcv,
1427 				    &chp->ch_pubmx) == 0) {
1428 
1429 					/* Got Signal, return EINTR */
1430 					evch_evq_evfree(ev);
1431 					mutex_exit(&chp->ch_pubmx);
1432 					return (EINTR);
1433 				}
1434 			}
1435 		}
1436 	}
1437 	chp->ch_nevents++;
1438 	mutex_exit(&chp->ch_pubmx);
1439 	SE_TIME(ev) = gethrtime();
1440 	SE_SEQ(ev) = log_sysevent_new_id();
1441 	/*
1442 	 * Add the destructor function to the event structure, now that the
1443 	 * event is accounted for. The only task of the descructor is to
1444 	 * decrement the channel event count. The evq_*() routines (including
1445 	 * the event delivery thread) do not have knowledge of the channel
1446 	 * data. So the anonymous destructor handles the channel data for it.
1447 	 */
1448 	evch_evq_evadd_dest(ev, evch_destr_event, (void *)chp);
1449 	return (evch_evq_pub(chp->ch_queue, ev, flags) == 0 ? 0 : EAGAIN);
1450 }
1451 
1452 /*
1453  * Fills a buffer consecutive with the names of all available channels.
1454  * Returns the length of all name strings or -1 if buffer size was unsufficient.
1455  */
1456 static int
evch_chgetnames(char * buf,size_t size)1457 evch_chgetnames(char *buf, size_t size)
1458 {
1459 	struct evch_globals *eg;
1460 	int		len = 0;
1461 	char		*addr = buf;
1462 	int		max = size;
1463 	evch_chan_t	*chp;
1464 
1465 	eg = zone_getspecific(evch_zone_key, curproc->p_zone);
1466 	ASSERT(eg != NULL);
1467 
1468 	mutex_enter(&eg->evch_list_lock);
1469 	for (chp = evch_dl_next(&eg->evch_list, NULL); chp != NULL;
1470 	    chp = evch_dl_next(&eg->evch_list, chp)) {
1471 		len += chp->ch_namelen;
1472 		if (len >= max) {
1473 			mutex_exit(&eg->evch_list_lock);
1474 			return (-1);
1475 		}
1476 		bcopy(chp->ch_name, addr, chp->ch_namelen);
1477 		addr += chp->ch_namelen;
1478 	}
1479 	mutex_exit(&eg->evch_list_lock);
1480 	addr[0] = 0;
1481 	return (len + 1);
1482 }
1483 
1484 /*
1485  * Fills the data of one channel and all subscribers of that channel into
1486  * a buffer. Returns -1 if the channel name is invalid and 0 on buffer overflow.
1487  */
1488 static int
evch_chgetchdata(char * chname,void * buf,size_t size)1489 evch_chgetchdata(char *chname, void *buf, size_t size)
1490 {
1491 	struct evch_globals *eg;
1492 	char		*cpaddr;
1493 	int		bufmax;
1494 	int		buflen;
1495 	evch_chan_t	*chp;
1496 	sev_chinfo_t	*p = (sev_chinfo_t *)buf;
1497 	int		chdlen;
1498 	evch_subd_t	*sdp;
1499 	sev_subinfo_t	*subp;
1500 	int		idlen;
1501 	int		len;
1502 
1503 	eg = zone_getspecific(evch_zone_key, curproc->p_zone);
1504 	ASSERT(eg != NULL);
1505 
1506 	mutex_enter(&eg->evch_list_lock);
1507 	chp = (evch_chan_t *)evch_dl_search(&eg->evch_list, evch_namecmp,
1508 	    chname);
1509 	if (chp == NULL) {
1510 		mutex_exit(&eg->evch_list_lock);
1511 		return (-1);
1512 	}
1513 	chdlen = offsetof(sev_chinfo_t, cd_subinfo);
1514 	if (size < chdlen) {
1515 		mutex_exit(&eg->evch_list_lock);
1516 		return (0);
1517 	}
1518 	p->cd_version = 0;
1519 	p->cd_suboffs = chdlen;
1520 	p->cd_uid = chp->ch_uid;
1521 	p->cd_gid = chp->ch_gid;
1522 	p->cd_perms = 0;
1523 	p->cd_ctime = chp->ch_ctime;
1524 	p->cd_maxev = chp->ch_maxev;
1525 	p->cd_evhwm = EVCH_EVQ_HIGHWM(chp->ch_queue);
1526 	p->cd_nevents = EVCH_EVQ_EVCOUNT(chp->ch_queue);
1527 	p->cd_maxsub = chp->ch_maxsubscr;
1528 	p->cd_nsub = evch_dl_getnum(&chp->ch_subscr);
1529 	p->cd_maxbinds = chp->ch_maxbinds;
1530 	p->cd_nbinds = chp->ch_bindings;
1531 	p->cd_holdpend = chp->ch_holdpend;
1532 	p->cd_limev = evch_events_max;
1533 	cpaddr = (char *)p + chdlen;
1534 	bufmax = size - chdlen;
1535 	buflen = 0;
1536 
1537 	for (sdp = evch_dl_next(&chp->ch_subscr, NULL); sdp != NULL;
1538 	    sdp = evch_dl_next(&chp->ch_subscr, sdp)) {
1539 		idlen = strlen(sdp->sd_ident) + 1;
1540 		len = SE_ALIGN(offsetof(sev_subinfo_t, sb_strings) + idlen +
1541 		    sdp->sd_clnsize);
1542 		buflen += len;
1543 		if (buflen >= bufmax) {
1544 			mutex_exit(&eg->evch_list_lock);
1545 			return (0);
1546 		}
1547 		subp = (sev_subinfo_t *)cpaddr;
1548 		subp->sb_nextoff = len;
1549 		subp->sb_stroff = offsetof(sev_subinfo_t, sb_strings);
1550 		if (sdp->sd_classname) {
1551 			bcopy(sdp->sd_classname, subp->sb_strings + idlen,
1552 			    sdp->sd_clnsize);
1553 			subp->sb_clnamoff = idlen;
1554 		} else {
1555 			subp->sb_clnamoff = idlen - 1;
1556 		}
1557 		subp->sb_pid = sdp->sd_pid;
1558 		subp->sb_nevents = EVCH_EVQ_EVCOUNT(sdp->sd_queue);
1559 		subp->sb_evhwm = EVCH_EVQ_HIGHWM(sdp->sd_queue);
1560 		subp->sb_persist = sdp->sd_persist;
1561 		subp->sb_status = evch_evq_status(sdp->sd_queue);
1562 		subp->sb_active = sdp->sd_active;
1563 		subp->sb_dump = sdp->sd_dump;
1564 		bcopy(sdp->sd_ident, subp->sb_strings, idlen);
1565 		cpaddr += len;
1566 	}
1567 	mutex_exit(&eg->evch_list_lock);
1568 	return (chdlen + buflen);
1569 }
1570 
1571 static void
evch_chsetpropnvl(evch_bind_t * bp,nvlist_t * nvl)1572 evch_chsetpropnvl(evch_bind_t *bp, nvlist_t *nvl)
1573 {
1574 	evch_chan_t *chp = bp->bd_channel;
1575 
1576 	mutex_enter(&chp->ch_mutex);
1577 
1578 	nvlist_free(chp->ch_propnvl);
1579 
1580 	chp->ch_propnvl = nvl;
1581 	chp->ch_propnvlgen++;
1582 
1583 	mutex_exit(&chp->ch_mutex);
1584 }
1585 
1586 static int
evch_chgetpropnvl(evch_bind_t * bp,nvlist_t ** nvlp,int64_t * genp)1587 evch_chgetpropnvl(evch_bind_t *bp, nvlist_t **nvlp, int64_t *genp)
1588 {
1589 	evch_chan_t *chp = bp->bd_channel;
1590 	int rc = 0;
1591 
1592 	mutex_enter(&chp->ch_mutex);
1593 
1594 	if (chp->ch_propnvl != NULL)
1595 		rc = (nvlist_dup(chp->ch_propnvl, nvlp, 0) == 0) ? 0 : ENOMEM;
1596 	else
1597 		*nvlp = NULL;	/* rc still 0 */
1598 
1599 	if (genp)
1600 		*genp = chp->ch_propnvlgen;
1601 
1602 	mutex_exit(&chp->ch_mutex);
1603 
1604 	if (rc != 0)
1605 		*nvlp = NULL;
1606 
1607 	return (rc);
1608 
1609 }
1610 
1611 /*
1612  * Init iteration of all events of a channel. This function creates a new
1613  * event queue and puts all events from the channel into that queue.
1614  * Subsequent calls to evch_chgetnextev will deliver the events from that
1615  * queue. Only one thread per channel is allowed to read through the events.
1616  * Returns 0 on success and 1 if there is already someone reading the
1617  * events.
1618  * If argument subid == NULL, we look for a subscriber which has
1619  * flag EVCH_SUB_DUMP set.
1620  */
1621 /*
1622  * Static variables that are used to traverse events of a channel in panic case.
1623  */
1624 static evch_chan_t	*evch_chan;
1625 static evch_eventq_t	*evch_subq;
1626 static sysevent_impl_t	*evch_curev;
1627 
1628 static evchanq_t *
evch_chrdevent_init(evch_chan_t * chp,char * subid)1629 evch_chrdevent_init(evch_chan_t *chp, char *subid)
1630 {
1631 	evch_subd_t	*sdp;
1632 	void		*ev;
1633 	int		pmqstat;	/* Prev status of main queue */
1634 	int		psqstat;	/* Prev status of subscriber queue */
1635 	evchanq_t	*snp;		/* Pointer to q with snapshot of ev */
1636 	compare_f	compfunc;
1637 
1638 	compfunc = subid == NULL ? evch_dumpflgcmp : evch_subidcmp;
1639 	if (panicstr != NULL) {
1640 		evch_chan = chp;
1641 		evch_subq = NULL;
1642 		evch_curev = NULL;
1643 		if ((sdp = (evch_subd_t *)evch_dl_search(&chp->ch_subscr,
1644 		    compfunc, subid)) != NULL) {
1645 			evch_subq = sdp->sd_queue;
1646 		}
1647 		return (NULL);
1648 	}
1649 	mutex_enter(&chp->ch_mutex);
1650 	sdp = (evch_subd_t *)evch_dl_search(&chp->ch_subscr, compfunc, subid);
1651 	/*
1652 	 * Stop main event queue and subscriber queue if not already
1653 	 * in stop mode.
1654 	 */
1655 	pmqstat = evch_evq_status(chp->ch_queue);
1656 	if (pmqstat == 0)
1657 		evch_evq_stop(chp->ch_queue);
1658 
1659 	psqstat = 0;
1660 	if (sdp != NULL) {
1661 		psqstat = evch_evq_status(sdp->sd_queue);
1662 		if (psqstat == 0)
1663 			evch_evq_stop(sdp->sd_queue);
1664 	}
1665 	/*
1666 	 * Create event queue to make a snapshot of all events in the
1667 	 * channel.
1668 	 */
1669 	snp = kmem_alloc(sizeof (evchanq_t), KM_SLEEP);
1670 	snp->sn_queue = evch_evq_create();
1671 	evch_evq_stop(snp->sn_queue);
1672 	/*
1673 	 * Make a snapshot of the subscriber queue and the main event queue.
1674 	 */
1675 	if (sdp != NULL) {
1676 		ev = NULL;
1677 		while ((ev = evch_evq_evnext(sdp->sd_queue, ev)) != NULL) {
1678 			(void) evch_evq_pub(snp->sn_queue, ev, EVCH_SLEEP);
1679 		}
1680 	}
1681 	ev = NULL;
1682 	while ((ev = evch_evq_evnext(chp->ch_queue, ev)) != NULL) {
1683 		(void) evch_evq_pub(snp->sn_queue, ev, EVCH_SLEEP);
1684 	}
1685 	snp->sn_nxtev = NULL;
1686 	/*
1687 	 * Restart main and subscriber queue if previously stopped
1688 	 */
1689 	if (sdp != NULL && psqstat == 0)
1690 		evch_evq_continue(sdp->sd_queue);
1691 	if (pmqstat == 0)
1692 		evch_evq_continue(chp->ch_queue);
1693 	mutex_exit(&chp->ch_mutex);
1694 	return (snp);
1695 }
1696 
1697 /*
1698  * Free all resources of the event queue snapshot. In case of panic
1699  * context snp must be NULL and no resources need to be free'ed.
1700  */
1701 static void
evch_chrdevent_fini(evchanq_t * snp)1702 evch_chrdevent_fini(evchanq_t *snp)
1703 {
1704 	if (snp != NULL) {
1705 		evch_evq_destroy(snp->sn_queue);
1706 		kmem_free(snp, sizeof (evchanq_t));
1707 	}
1708 }
1709 
1710 /*
1711  * Get address of next event from an event channel.
1712  * This function might be called in a panic context. In that case
1713  * no resources will be allocated and no locks grabbed.
1714  * In normal operation context a snapshot of the event queues of the
1715  * specified event channel will be taken.
1716  */
1717 static sysevent_impl_t *
evch_chgetnextev(evchanq_t * snp)1718 evch_chgetnextev(evchanq_t *snp)
1719 {
1720 	if (panicstr != NULL) {
1721 		if (evch_chan == NULL)
1722 			return (NULL);
1723 		if (evch_subq != NULL) {
1724 			/*
1725 			 * We have a subscriber queue. Traverse this queue
1726 			 * first.
1727 			 */
1728 			if ((evch_curev = (sysevent_impl_t *)
1729 			    evch_evq_evnext(evch_subq, evch_curev)) != NULL) {
1730 				return (evch_curev);
1731 			} else {
1732 				/*
1733 				 * All subscriber events traversed. evch_subq
1734 				 * == NULL indicates to take the main event
1735 				 * queue now.
1736 				 */
1737 				evch_subq = NULL;
1738 			}
1739 		}
1740 		/*
1741 		 * Traverse the main event queue.
1742 		 */
1743 		if ((evch_curev = (sysevent_impl_t *)
1744 		    evch_evq_evnext(evch_chan->ch_queue, evch_curev)) ==
1745 		    NULL) {
1746 			evch_chan = NULL;
1747 		}
1748 		return (evch_curev);
1749 	}
1750 	ASSERT(snp != NULL);
1751 	snp->sn_nxtev = (sysevent_impl_t *)evch_evq_evnext(snp->sn_queue,
1752 	    snp->sn_nxtev);
1753 	return (snp->sn_nxtev);
1754 }
1755 
1756 /*
1757  * The functions below build up the interface for the kernel to bind/unbind,
1758  * subscribe/unsubscribe and publish to event channels. It consists of the
1759  * following functions:
1760  *
1761  * sysevent_evc_bind	    - Bind to a channel. Create a channel if required
1762  * sysevent_evc_unbind	    - Unbind from a channel. Destroy ch. if last unbind
1763  * sysevent_evc_subscribe   - Subscribe to events from a channel
1764  * sysevent_evc_unsubscribe - Unsubscribe from an event class
1765  * sysevent_evc_publish	    - Publish an event to an event channel
1766  * sysevent_evc_control	    - Various control operation on event channel
1767  * sysevent_evc_setpropnvl  - Set channel property nvlist
1768  * sysevent_evc_getpropnvl  - Get channel property nvlist
1769  *
1770  * The function below are for evaluating a sysevent:
1771  *
1772  * sysevent_get_class_name  - Get pointer to event class string
1773  * sysevent_get_subclass_name - Get pointer to event subclass string
1774  * sysevent_get_seq	    - Get unique event sequence number
1775  * sysevent_get_time	    - Get hrestime of event publish
1776  * sysevent_get_size	    - Get size of event structure
1777  * sysevent_get_pub	    - Get publisher string
1778  * sysevent_get_attr_list   - Get copy of attribute list
1779  *
1780  * The following interfaces represent stability level project privat
1781  * and allow to save the events of an event channel even in a panic case.
1782  *
1783  * sysevent_evc_walk_init   - Take a snapshot of the events in a channel
1784  * sysevent_evc_walk_step   - Read next event from snapshot
1785  * sysevent_evc_walk_fini   - Free resources from event channel snapshot
1786  * sysevent_evc_event_attr  - Get event payload address and size
1787  */
1788 /*
1789  * allocate sysevent structure with optional space for attributes
1790  */
1791 static sysevent_impl_t *
sysevent_evc_alloc(const char * class,const char * subclass,const char * pub,size_t pub_sz,size_t atsz,uint32_t flag)1792 sysevent_evc_alloc(const char *class, const char *subclass, const char *pub,
1793     size_t pub_sz, size_t atsz, uint32_t flag)
1794 {
1795 	int		payload_sz;
1796 	int		class_sz, subclass_sz;
1797 	int 		aligned_class_sz, aligned_subclass_sz, aligned_pub_sz;
1798 	sysevent_impl_t	*ev;
1799 
1800 	/*
1801 	 * Calculate and reserve space for the class, subclass and
1802 	 * publisher strings in the event buffer
1803 	 */
1804 	class_sz = strlen(class) + 1;
1805 	subclass_sz = strlen(subclass) + 1;
1806 
1807 	ASSERT((class_sz <= MAX_CLASS_LEN) && (subclass_sz <=
1808 	    MAX_SUBCLASS_LEN) && (pub_sz <= MAX_PUB_LEN));
1809 
1810 	/* String sizes must be 64-bit aligned in the event buffer */
1811 	aligned_class_sz = SE_ALIGN(class_sz);
1812 	aligned_subclass_sz = SE_ALIGN(subclass_sz);
1813 	aligned_pub_sz = SE_ALIGN(pub_sz);
1814 
1815 	/*
1816 	 * Calculate payload size. Consider the space needed for alignment
1817 	 * and subtract the size of the uint64_t placeholder variables of
1818 	 * sysevent_impl_t.
1819 	 */
1820 	payload_sz = (aligned_class_sz - sizeof (uint64_t)) +
1821 	    (aligned_subclass_sz - sizeof (uint64_t)) +
1822 	    (aligned_pub_sz - sizeof (uint64_t)) - sizeof (uint64_t) +
1823 	    atsz;
1824 
1825 	/*
1826 	 * Allocate event buffer plus additional payload overhead
1827 	 */
1828 	if ((ev = evch_evq_evzalloc(sizeof (sysevent_impl_t) +
1829 	    payload_sz, flag)) == NULL) {
1830 		return (NULL);
1831 	}
1832 
1833 	/* Initialize the event buffer data */
1834 	SE_VERSION(ev) = SYS_EVENT_VERSION;
1835 	bcopy(class, SE_CLASS_NAME(ev), class_sz);
1836 
1837 	SE_SUBCLASS_OFF(ev) = SE_ALIGN(offsetof(sysevent_impl_t,
1838 	    se_class_name)) + aligned_class_sz;
1839 	bcopy(subclass, SE_SUBCLASS_NAME(ev), subclass_sz);
1840 
1841 	SE_PUB_OFF(ev) = SE_SUBCLASS_OFF(ev) + aligned_subclass_sz;
1842 	bcopy(pub, SE_PUB_NAME(ev), pub_sz);
1843 
1844 	SE_ATTR_PTR(ev) = (uint64_t)0;
1845 	SE_PAYLOAD_SZ(ev) = payload_sz;
1846 
1847 	return (ev);
1848 }
1849 
1850 /*
1851  * Initialize event channel handling queues.
1852  */
1853 void
sysevent_evc_init()1854 sysevent_evc_init()
1855 {
1856 	evch_chinit();
1857 }
1858 
1859 /*
1860  * Second initialization step: create threads, if event channels are already
1861  * created
1862  */
1863 void
sysevent_evc_thrinit()1864 sysevent_evc_thrinit()
1865 {
1866 	evch_chinitthr();
1867 }
1868 
1869 int
sysevent_evc_bind(const char * ch_name,evchan_t ** scpp,uint32_t flags)1870 sysevent_evc_bind(const char *ch_name, evchan_t **scpp, uint32_t flags)
1871 {
1872 	ASSERT(ch_name != NULL && scpp != NULL);
1873 	ASSERT((flags & ~EVCH_B_FLAGS) == 0);
1874 	return (evch_chbind(ch_name, (evch_bind_t **)scpp, flags));
1875 }
1876 
1877 int
sysevent_evc_unbind(evchan_t * scp)1878 sysevent_evc_unbind(evchan_t *scp)
1879 {
1880 	evch_bind_t *bp = (evch_bind_t *)scp;
1881 
1882 	ASSERT(scp != NULL);
1883 	evch_chunsubscribe(bp, NULL, 0);
1884 	evch_chunbind(bp);
1885 
1886 	return (0);
1887 }
1888 
1889 int
sysevent_evc_subscribe(evchan_t * scp,const char * sid,const char * class,int (* callb)(sysevent_t * ev,void * cookie),void * cookie,uint32_t flags)1890 sysevent_evc_subscribe(evchan_t *scp, const char *sid, const char *class,
1891     int (*callb)(sysevent_t *ev, void *cookie),
1892     void *cookie, uint32_t flags)
1893 {
1894 	ASSERT(scp != NULL && sid != NULL && class != NULL && callb != NULL);
1895 	ASSERT(flags == 0);
1896 	if (strlen(sid) > MAX_SUBID_LEN) {
1897 		return (EINVAL);
1898 	}
1899 	if (strcmp(class, EC_ALL) == 0) {
1900 		class = NULL;
1901 	}
1902 	return (evch_chsubscribe((evch_bind_t *)scp, EVCH_DELKERN, sid, class,
1903 	    (void *)callb, cookie, 0, 0));
1904 }
1905 
1906 int
sysevent_evc_unsubscribe(evchan_t * scp,const char * sid)1907 sysevent_evc_unsubscribe(evchan_t *scp, const char *sid)
1908 {
1909 	ASSERT(scp != NULL && sid != NULL);
1910 	if (strcmp(sid, EVCH_ALLSUB) == 0) {
1911 		sid = NULL;
1912 	}
1913 	evch_chunsubscribe((evch_bind_t *)scp, sid, 0);
1914 
1915 	return (0);
1916 }
1917 
1918 /*
1919  * Publish kernel event. Returns 0 on success, error code else.
1920  * Optional attribute data is packed into the event structure.
1921  */
1922 int
sysevent_evc_publish(evchan_t * scp,const char * class,const char * subclass,const char * vendor,const char * pubs,nvlist_t * attr,uint32_t flags)1923 sysevent_evc_publish(evchan_t *scp, const char *class, const char *subclass,
1924     const char *vendor, const char *pubs, nvlist_t *attr, uint32_t flags)
1925 {
1926 	sysevent_impl_t	*evp;
1927 	char		pub[MAX_PUB_LEN];
1928 	int		pub_sz;		/* includes terminating 0 */
1929 	int		km_flags;
1930 	size_t		asz = 0;
1931 	uint64_t	attr_offset;
1932 	caddr_t		patt;
1933 	int		err;
1934 
1935 	ASSERT(scp != NULL && class != NULL && subclass != NULL &&
1936 	    vendor != NULL && pubs != NULL);
1937 
1938 	ASSERT((flags & ~(EVCH_SLEEP | EVCH_NOSLEEP | EVCH_TRYHARD |
1939 	    EVCH_QWAIT)) == 0);
1940 
1941 	km_flags = flags & (EVCH_SLEEP | EVCH_NOSLEEP | EVCH_TRYHARD);
1942 	ASSERT(km_flags == EVCH_SLEEP || km_flags == EVCH_NOSLEEP ||
1943 	    km_flags == EVCH_TRYHARD);
1944 
1945 	pub_sz = snprintf(pub, MAX_PUB_LEN, "%s:kern:%s", vendor, pubs) + 1;
1946 	if (pub_sz > MAX_PUB_LEN)
1947 		return (EINVAL);
1948 
1949 	if (attr != NULL) {
1950 		if ((err = nvlist_size(attr, &asz, NV_ENCODE_NATIVE)) != 0) {
1951 			return (err);
1952 		}
1953 	}
1954 	evp = sysevent_evc_alloc(class, subclass, pub, pub_sz, asz, km_flags);
1955 	if (evp == NULL) {
1956 		return (ENOMEM);
1957 	}
1958 	if (attr != NULL) {
1959 		/*
1960 		 * Pack attributes into event buffer. Event buffer already
1961 		 * has enough room for the packed nvlist.
1962 		 */
1963 		attr_offset = SE_ATTR_OFF(evp);
1964 		patt = (caddr_t)evp + attr_offset;
1965 
1966 		err = nvlist_pack(attr, &patt, &asz, NV_ENCODE_NATIVE,
1967 		    km_flags & EVCH_SLEEP ? KM_SLEEP : KM_NOSLEEP);
1968 
1969 		ASSERT(err != ENOMEM);
1970 
1971 		if (err != 0) {
1972 			return (EINVAL);
1973 		}
1974 
1975 		evp->seh_attr_off = attr_offset;
1976 		SE_FLAG(evp) = SE_PACKED_BUF;
1977 	}
1978 	return (evch_chpublish((evch_bind_t *)scp, evp, flags));
1979 }
1980 
1981 int
sysevent_evc_control(evchan_t * scp,int cmd,...)1982 sysevent_evc_control(evchan_t *scp, int cmd, ...)
1983 {
1984 	va_list		ap;
1985 	evch_chan_t	*chp;
1986 	uint32_t	*chlenp;
1987 	uint32_t	chlen;
1988 	uint32_t	ochlen;
1989 	int		rc = 0;
1990 
1991 	if (scp == NULL) {
1992 		return (EINVAL);
1993 	}
1994 
1995 	chp = ((evch_bind_t *)scp)->bd_channel;
1996 
1997 	va_start(ap, cmd);
1998 	mutex_enter(&chp->ch_mutex);
1999 	switch (cmd) {
2000 	case EVCH_GET_CHAN_LEN:
2001 		chlenp = va_arg(ap, uint32_t *);
2002 		*chlenp = chp->ch_maxev;
2003 		break;
2004 	case EVCH_SET_CHAN_LEN:
2005 		chlen = va_arg(ap, uint32_t);
2006 		ochlen = chp->ch_maxev;
2007 		chp->ch_maxev = min(chlen, evch_events_max);
2008 		if (ochlen < chp->ch_maxev) {
2009 			cv_signal(&chp->ch_pubcv);
2010 		}
2011 		break;
2012 	case EVCH_GET_CHAN_LEN_MAX:
2013 		*va_arg(ap, uint32_t *) = evch_events_max;
2014 		break;
2015 	default:
2016 		rc = EINVAL;
2017 	}
2018 
2019 	mutex_exit(&chp->ch_mutex);
2020 	va_end(ap);
2021 	return (rc);
2022 }
2023 
2024 int
sysevent_evc_setpropnvl(evchan_t * scp,nvlist_t * nvl)2025 sysevent_evc_setpropnvl(evchan_t *scp, nvlist_t *nvl)
2026 {
2027 	nvlist_t *nvlcp = nvl;
2028 
2029 	if (nvl != NULL && nvlist_dup(nvl, &nvlcp, 0) != 0)
2030 		return (ENOMEM);
2031 
2032 	evch_chsetpropnvl((evch_bind_t *)scp, nvlcp);
2033 
2034 	return (0);
2035 }
2036 
2037 int
sysevent_evc_getpropnvl(evchan_t * scp,nvlist_t ** nvlp)2038 sysevent_evc_getpropnvl(evchan_t *scp, nvlist_t **nvlp)
2039 {
2040 	return (evch_chgetpropnvl((evch_bind_t *)scp, nvlp, NULL));
2041 }
2042 
2043 /*
2044  * Project private interface to take a snapshot of all events of the
2045  * specified event channel. Argument subscr may be a subscriber id, the empty
2046  * string "", or NULL. The empty string indicates that no subscriber is
2047  * selected, for example if a previous subscriber died. sysevent_evc_walk_next()
2048  * will deliver events from the main event queue in this case. If subscr is
2049  * NULL, the subscriber with the EVCH_SUB_DUMP flag set (subd->sd_dump != 0)
2050  * will be selected.
2051  *
2052  * In panic case this function returns NULL. This is legal. The NULL has
2053  * to be delivered to sysevent_evc_walk_step() and sysevent_evc_walk_fini().
2054  */
2055 evchanq_t *
sysevent_evc_walk_init(evchan_t * scp,char * subscr)2056 sysevent_evc_walk_init(evchan_t *scp, char *subscr)
2057 {
2058 	if (panicstr != NULL && scp == NULL)
2059 		return (NULL);
2060 	ASSERT(scp != NULL);
2061 	return (evch_chrdevent_init(((evch_bind_t *)scp)->bd_channel, subscr));
2062 }
2063 
2064 /*
2065  * Project private interface to read events from a previously taken
2066  * snapshot (with sysevent_evc_walk_init). In case of panic events
2067  * are retrieved directly from the channel data structures. No resources
2068  * are allocated and no mutexes are grabbed in panic context.
2069  */
2070 sysevent_t *
sysevent_evc_walk_step(evchanq_t * evcq)2071 sysevent_evc_walk_step(evchanq_t *evcq)
2072 {
2073 	return ((sysevent_t *)evch_chgetnextev(evcq));
2074 }
2075 
2076 /*
2077  * Project private interface to free a previously taken snapshot.
2078  */
2079 void
sysevent_evc_walk_fini(evchanq_t * evcq)2080 sysevent_evc_walk_fini(evchanq_t *evcq)
2081 {
2082 	evch_chrdevent_fini(evcq);
2083 }
2084 
2085 /*
2086  * Get address and size of an event payload. Returns NULL when no
2087  * payload present.
2088  */
2089 char *
sysevent_evc_event_attr(sysevent_t * ev,size_t * plsize)2090 sysevent_evc_event_attr(sysevent_t *ev, size_t *plsize)
2091 {
2092 	char	*attrp;
2093 	size_t	aoff;
2094 	size_t	asz;
2095 
2096 	aoff = SE_ATTR_OFF(ev);
2097 	attrp = (char *)ev + aoff;
2098 	asz = *plsize = SE_SIZE(ev) - aoff;
2099 	return (asz ? attrp : NULL);
2100 }
2101 
2102 /*
2103  * sysevent_get_class_name - Get class name string
2104  */
2105 char *
sysevent_get_class_name(sysevent_t * ev)2106 sysevent_get_class_name(sysevent_t *ev)
2107 {
2108 	return (SE_CLASS_NAME(ev));
2109 }
2110 
2111 /*
2112  * sysevent_get_subclass_name - Get subclass name string
2113  */
2114 char *
sysevent_get_subclass_name(sysevent_t * ev)2115 sysevent_get_subclass_name(sysevent_t *ev)
2116 {
2117 	return (SE_SUBCLASS_NAME(ev));
2118 }
2119 
2120 /*
2121  * sysevent_get_seq - Get event sequence id
2122  */
2123 uint64_t
sysevent_get_seq(sysevent_t * ev)2124 sysevent_get_seq(sysevent_t *ev)
2125 {
2126 	return (SE_SEQ(ev));
2127 }
2128 
2129 /*
2130  * sysevent_get_time - Get event timestamp
2131  */
2132 void
sysevent_get_time(sysevent_t * ev,hrtime_t * etime)2133 sysevent_get_time(sysevent_t *ev, hrtime_t *etime)
2134 {
2135 	*etime = SE_TIME(ev);
2136 }
2137 
2138 /*
2139  * sysevent_get_size - Get event buffer size
2140  */
2141 size_t
sysevent_get_size(sysevent_t * ev)2142 sysevent_get_size(sysevent_t *ev)
2143 {
2144 	return ((size_t)SE_SIZE(ev));
2145 }
2146 
2147 /*
2148  * sysevent_get_pub - Get publisher name string
2149  */
2150 char *
sysevent_get_pub(sysevent_t * ev)2151 sysevent_get_pub(sysevent_t *ev)
2152 {
2153 	return (SE_PUB_NAME(ev));
2154 }
2155 
2156 /*
2157  * sysevent_get_attr_list - stores address of a copy of the attribute list
2158  * associated with the given sysevent buffer. The list must be freed by the
2159  * caller.
2160  */
2161 int
sysevent_get_attr_list(sysevent_t * ev,nvlist_t ** nvlist)2162 sysevent_get_attr_list(sysevent_t *ev, nvlist_t **nvlist)
2163 {
2164 	int		error;
2165 	caddr_t		attr;
2166 	size_t		attr_len;
2167 	uint64_t	attr_offset;
2168 
2169 	*nvlist = NULL;
2170 	if (SE_FLAG(ev) != SE_PACKED_BUF) {
2171 		return (EINVAL);
2172 	}
2173 	attr_offset = SE_ATTR_OFF(ev);
2174 	if (SE_SIZE(ev) == attr_offset) {
2175 		return (EINVAL);
2176 	}
2177 
2178 	/* unpack nvlist */
2179 	attr = (caddr_t)ev + attr_offset;
2180 	attr_len = SE_SIZE(ev) - attr_offset;
2181 	if ((error = nvlist_unpack(attr, attr_len, nvlist, 0)) != 0) {
2182 		error = error != ENOMEM ? EINVAL : error;
2183 		return (error);
2184 	}
2185 	return (0);
2186 }
2187 
2188 /*
2189  * Functions called by the sysevent driver for general purpose event channels
2190  *
2191  * evch_usrchanopen	- Create/Bind to an event channel
2192  * evch_usrchanclose	- Unbind/Destroy event channel
2193  * evch_usrallocev	- Allocate event data structure
2194  * evch_usrfreeev	- Free event data structure
2195  * evch_usrpostevent	- Publish event
2196  * evch_usrsubscribe	- Subscribe (register callback function)
2197  * evch_usrunsubscribe	- Unsubscribe
2198  * evch_usrcontrol_set	- Set channel properties
2199  * evch_usrcontrol_get	- Get channel properties
2200  * evch_usrgetchnames	- Get list of channel names
2201  * evch_usrgetchdata	- Get data of an event channel
2202  * evch_usrsetpropnvl	- Set channel properties nvlist
2203  * evch_usrgetpropnvl	- Get channel properties nvlist
2204  */
2205 evchan_t *
evch_usrchanopen(const char * name,uint32_t flags,int * err)2206 evch_usrchanopen(const char *name, uint32_t flags, int *err)
2207 {
2208 	evch_bind_t *bp = NULL;
2209 
2210 	*err = evch_chbind(name, &bp, flags);
2211 	return ((evchan_t *)bp);
2212 }
2213 
2214 /*
2215  * Unbind from the channel.
2216  */
2217 void
evch_usrchanclose(evchan_t * cbp)2218 evch_usrchanclose(evchan_t *cbp)
2219 {
2220 	evch_chunbind((evch_bind_t *)cbp);
2221 }
2222 
2223 /*
2224  * Allocates log_evch_eventq_t structure but returns the pointer of the embedded
2225  * sysevent_impl_t structure as the opaque sysevent_t * data type
2226  */
2227 sysevent_impl_t *
evch_usrallocev(size_t evsize,uint32_t flags)2228 evch_usrallocev(size_t evsize, uint32_t flags)
2229 {
2230 	return ((sysevent_impl_t *)evch_evq_evzalloc(evsize, flags));
2231 }
2232 
2233 /*
2234  * Free evch_eventq_t structure
2235  */
2236 void
evch_usrfreeev(sysevent_impl_t * ev)2237 evch_usrfreeev(sysevent_impl_t *ev)
2238 {
2239 	evch_evq_evfree((void *)ev);
2240 }
2241 
2242 /*
2243  * Posts an event to the given channel. The event structure has to be
2244  * allocated by evch_usrallocev(). Returns zero on success and an error
2245  * code else. Attributes have to be packed and included in the event structure.
2246  *
2247  */
2248 int
evch_usrpostevent(evchan_t * bp,sysevent_impl_t * ev,uint32_t flags)2249 evch_usrpostevent(evchan_t *bp, sysevent_impl_t *ev, uint32_t flags)
2250 {
2251 	return (evch_chpublish((evch_bind_t *)bp, ev, flags));
2252 }
2253 
2254 /*
2255  * Subscribe function for user land subscriptions
2256  */
2257 int
evch_usrsubscribe(evchan_t * bp,const char * sid,const char * class,int d,uint32_t flags)2258 evch_usrsubscribe(evchan_t *bp, const char *sid, const char *class,
2259     int d, uint32_t flags)
2260 {
2261 	door_handle_t	dh = door_ki_lookup(d);
2262 	int		rv;
2263 
2264 	if (dh == NULL) {
2265 		return (EINVAL);
2266 	}
2267 	if ((rv = evch_chsubscribe((evch_bind_t *)bp, EVCH_DELDOOR, sid, class,
2268 	    (void *)dh, NULL, flags, curproc->p_pid)) != 0) {
2269 		door_ki_rele(dh);
2270 	}
2271 	return (rv);
2272 }
2273 
2274 /*
2275  * Flag can be EVCH_SUB_KEEP or 0. EVCH_SUB_KEEP preserves persistent
2276  * subscribers
2277  */
2278 void
evch_usrunsubscribe(evchan_t * bp,const char * subid,uint32_t flags)2279 evch_usrunsubscribe(evchan_t *bp, const char *subid, uint32_t flags)
2280 {
2281 	evch_chunsubscribe((evch_bind_t *)bp, subid, flags);
2282 }
2283 
2284 /*ARGSUSED*/
2285 int
evch_usrcontrol_set(evchan_t * bp,int cmd,uint32_t value)2286 evch_usrcontrol_set(evchan_t *bp, int cmd, uint32_t value)
2287 {
2288 	evch_chan_t	*chp = ((evch_bind_t *)bp)->bd_channel;
2289 	uid_t		uid = crgetuid(curthread->t_cred);
2290 	int		rc = 0;
2291 
2292 	mutex_enter(&chp->ch_mutex);
2293 	switch (cmd) {
2294 	case EVCH_SET_CHAN_LEN:
2295 		if (uid && uid != chp->ch_uid) {
2296 			rc = EACCES;
2297 			break;
2298 		}
2299 		chp->ch_maxev = min(value, evch_events_max);
2300 		break;
2301 	default:
2302 		rc = EINVAL;
2303 	}
2304 	mutex_exit(&chp->ch_mutex);
2305 	return (rc);
2306 }
2307 
2308 /*ARGSUSED*/
2309 int
evch_usrcontrol_get(evchan_t * bp,int cmd,uint32_t * value)2310 evch_usrcontrol_get(evchan_t *bp, int cmd, uint32_t *value)
2311 {
2312 	evch_chan_t	*chp = ((evch_bind_t *)bp)->bd_channel;
2313 	int		rc = 0;
2314 
2315 	mutex_enter(&chp->ch_mutex);
2316 	switch (cmd) {
2317 	case EVCH_GET_CHAN_LEN:
2318 		*value = chp->ch_maxev;
2319 		break;
2320 	case EVCH_GET_CHAN_LEN_MAX:
2321 		*value = evch_events_max;
2322 		break;
2323 	default:
2324 		rc = EINVAL;
2325 	}
2326 	mutex_exit(&chp->ch_mutex);
2327 	return (rc);
2328 }
2329 
2330 int
evch_usrgetchnames(char * buf,size_t size)2331 evch_usrgetchnames(char *buf, size_t size)
2332 {
2333 	return (evch_chgetnames(buf, size));
2334 }
2335 
2336 int
evch_usrgetchdata(char * chname,void * buf,size_t size)2337 evch_usrgetchdata(char *chname, void *buf, size_t size)
2338 {
2339 	return (evch_chgetchdata(chname, buf, size));
2340 }
2341 
2342 void
evch_usrsetpropnvl(evchan_t * bp,nvlist_t * nvl)2343 evch_usrsetpropnvl(evchan_t *bp, nvlist_t *nvl)
2344 {
2345 	evch_chsetpropnvl((evch_bind_t *)bp, nvl);
2346 }
2347 
2348 int
evch_usrgetpropnvl(evchan_t * bp,nvlist_t ** nvlp,int64_t * genp)2349 evch_usrgetpropnvl(evchan_t *bp, nvlist_t **nvlp, int64_t *genp)
2350 {
2351 	return (evch_chgetpropnvl((evch_bind_t *)bp, nvlp, genp));
2352 }
2353