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