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