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