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
73struct evch_globals {
74	evch_dlist_t evch_list;
75	kmutex_t evch_list_lock;
76};
77
78/* Variables used by event channel routines */
79static int		evq_initcomplete = 0;
80static zone_key_t	evch_zone_key;
81static uint32_t		evch_channels_max;
82static uint32_t		evch_bindings_max = EVCH_MAX_BINDS_PER_CHANNEL;
83static uint32_t		evch_events_max;
84
85static void evch_evq_unsub(evch_eventq_t *, evch_evqsub_t *);
86static 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
104static void
105evch_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 */
114static void
115evch_dl_fini(evch_dlist_t *hp)
116{
117	hp->dh_head.dl_prev = hp->dh_head.dl_next = NULL;
118}
119
120static int
121evch_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 */
129static void
130evch_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 */
145static void
146evch_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 */
159static evch_dlelem_t *
160evch_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 */
175static int
176evch_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 */
185static void *
186evch_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 */
210static void
211evch_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 */
222static void
223evch_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 */
237static evch_qelem_t *
238evch_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 */
256static evch_qelem_t *
257evch_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*/
291static void *
292evch_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*/
302static void
303evch_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 */
377static void
378evch_gevent_free(evch_gevent_t *evp)
379{
380	int32_t refcnt;
381
382	refcnt = (int32_t)atomic_add_32_nv(&evp->ge_refcount, -1);
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 */
398static int
399evch_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 */
418static void
419evch_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 */
437static void
438evch_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 */
517static void
518evch_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 */
530static evch_eventq_t *
531evch_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 */
555static void
556evch_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 */
592static evch_evqsub_t *
593evch_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 */
614static void
615evch_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 */
631static int
632evch_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_add_32(&evp->ge_refcount, 1);
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 */
664static void
665evch_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 */
679static void
680evch_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 */
691static int
692evch_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 */
700static void
701evch_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 */
716static void *
717evch_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 */
743static void
744evch_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 */
760static void *
761evch_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 */
797static int
798evch_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 */
808static int
809evch_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 */
840static int
841evch_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 */
854static int
855evch_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 */
866static int
867evch_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 */
878static int
879evch_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 */
940static int
941evch_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*/
953static int
954evch_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*/
963static void
964evch_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 */
977static uint32_t
978evch_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 */
998static void
999evch_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 */
1023static void
1024evch_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 */
1051static int
1052evch_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;
1133errorexit:
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 */
1142static void
1143evch_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
1179static int
1180wildcard_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 */
1201static int
1202evch_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 */
1331static void
1332evch_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 */
1408static int
1409evch_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 */
1453static int
1454evch_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 */
1485static int
1486evch_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
1568static void
1569evch_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
1584static int
1585evch_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 */
1622static evch_chan_t	*evch_chan;
1623static evch_eventq_t	*evch_subq;
1624static sysevent_impl_t	*evch_curev;
1625
1626static evchanq_t *
1627evch_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 */
1697static void
1698evch_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 */
1713static sysevent_impl_t *
1714evch_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 */
1787static sysevent_impl_t *
1788sysevent_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 */
1849void
1850sysevent_evc_init()
1851{
1852	evch_chinit();
1853}
1854
1855/*
1856 * Second initialization step: create threads, if event channels are already
1857 * created
1858 */
1859void
1860sysevent_evc_thrinit()
1861{
1862	evch_chinitthr();
1863}
1864
1865int
1866sysevent_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
1873int
1874sysevent_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
1885int
1886sysevent_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
1902int
1903sysevent_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 */
1918int
1919sysevent_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
1977int
1978sysevent_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
2018int
2019sysevent_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
2031int
2032sysevent_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 */
2049evchanq_t *
2050sysevent_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 */
2064sysevent_t *
2065sysevent_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 */
2073void
2074sysevent_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 */
2083char *
2084sysevent_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 */
2099char *
2100sysevent_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 */
2108char *
2109sysevent_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 */
2117uint64_t
2118sysevent_get_seq(sysevent_t *ev)
2119{
2120	return (SE_SEQ(ev));
2121}
2122
2123/*
2124 * sysevent_get_time - Get event timestamp
2125 */
2126void
2127sysevent_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 */
2135size_t
2136sysevent_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 */
2144char *
2145sysevent_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 */
2155int
2156sysevent_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 */
2199evchan_t *
2200evch_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 */
2211void
2212evch_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 */
2221sysevent_impl_t *
2222evch_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 */
2230void
2231evch_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 */
2242int
2243evch_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 */
2251int
2252evch_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 */
2272void
2273evch_usrunsubscribe(evchan_t *bp, const char *subid, uint32_t flags)
2274{
2275	evch_chunsubscribe((evch_bind_t *)bp, subid, flags);
2276}
2277
2278/*ARGSUSED*/
2279int
2280evch_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*/
2303int
2304evch_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
2324int
2325evch_usrgetchnames(char *buf, size_t size)
2326{
2327	return (evch_chgetnames(buf, size));
2328}
2329
2330int
2331evch_usrgetchdata(char *chname, void *buf, size_t size)
2332{
2333	return (evch_chgetchdata(chname, buf, size));
2334}
2335
2336void
2337evch_usrsetpropnvl(evchan_t *bp, nvlist_t *nvl)
2338{
2339	evch_chsetpropnvl((evch_bind_t *)bp, nvl);
2340}
2341
2342int
2343evch_usrgetpropnvl(evchan_t *bp, nvlist_t **nvlp, int64_t *genp)
2344{
2345	return (evch_chgetpropnvl((evch_bind_t *)bp, nvlp, genp));
2346}
2347