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) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
24 */
25
26 #include <sys/types.h>
27 #include <sys/errno.h>
28 #include <sys/stropts.h>
29 #include <sys/debug.h>
30 #include <sys/ddi.h>
31 #include <sys/sunddi.h>
32 #include <sys/vmem.h>
33 #include <sys/cmn_err.h>
34 #include <sys/callb.h>
35 #include <sys/sysevent.h>
36 #include <sys/sysevent_impl.h>
37 #include <sys/modctl.h>
38 #include <sys/sysmacros.h>
39 #include <sys/disp.h>
40 #include <sys/autoconf.h>
41 #include <sys/atomic.h>
42 #include <sys/sdt.h>
43
44 /* for doors */
45 #include <sys/pathname.h>
46 #include <sys/door.h>
47 #include <sys/kmem.h>
48 #include <sys/cpuvar.h>
49 #include <sys/fs/snode.h>
50
51 /*
52 * log_sysevent.c - Provides the interfaces for kernel event publication
53 * to the sysevent event daemon (syseventd).
54 */
55
56 /*
57 * Debug stuff
58 */
59 static int log_event_debug = 0;
60 #define LOG_DEBUG(args) if (log_event_debug) cmn_err args
61 #ifdef DEBUG
62 #define LOG_DEBUG1(args) if (log_event_debug > 1) cmn_err args
63 #else
64 #define LOG_DEBUG1(args)
65 #endif
66
67 /*
68 * Local static vars
69 */
70 /* queue of event buffers sent to syseventd */
71 static log_eventq_t *log_eventq_sent = NULL;
72
73 /*
74 * Count of event buffers in the queue
75 */
76 int log_eventq_cnt = 0;
77
78 /* queue of event buffers awaiting delivery to syseventd */
79 static log_eventq_t *log_eventq_head = NULL;
80 static log_eventq_t *log_eventq_tail = NULL;
81 static uint64_t kernel_event_id = 0;
82 static int encoding = NV_ENCODE_NATIVE;
83
84 /* log event delivery flag */
85 #define LOGEVENT_DELIVERY_OK 0 /* OK to deliver event buffers */
86 #define LOGEVENT_DELIVERY_CONT 1 /* Continue to deliver event buffers */
87 #define LOGEVENT_DELIVERY_HOLD 2 /* Hold delivering of event buffers */
88
89 /*
90 * Tunable maximum event buffer queue size. Size depends on how many events
91 * the queue must hold when syseventd is not available, for example during
92 * system startup. Experience showed that more than 2000 events could be posted
93 * due to correctable memory errors.
94 */
95 int logevent_max_q_sz = 5000;
96
97
98 static int log_event_delivery = LOGEVENT_DELIVERY_HOLD;
99 static char logevent_door_upcall_filename[MAXPATHLEN];
100
101 static door_handle_t event_door = NULL; /* Door for upcalls */
102 static kmutex_t event_door_mutex; /* To protect event_door */
103
104 /*
105 * async thread-related variables
106 *
107 * eventq_head_mutex - synchronizes access to the kernel event queue
108 *
109 * eventq_sent_mutex - synchronizes access to the queue of event sents to
110 * userlevel
111 *
112 * log_event_cv - condition variable signaled when an event has arrived or
113 * userlevel ready to process event buffers
114 *
115 * async_thread - asynchronous event delivery thread to userlevel daemon.
116 *
117 * sysevent_upcall_status - status of the door upcall link
118 */
119 static kmutex_t eventq_head_mutex;
120 static kmutex_t eventq_sent_mutex;
121 static kcondvar_t log_event_cv;
122 static kthread_id_t async_thread = NULL;
123
124 static kmutex_t event_qfull_mutex;
125 static kcondvar_t event_qfull_cv;
126 static int event_qfull_blocked = 0;
127
128 static int sysevent_upcall_status = -1;
129 static kmutex_t registered_channel_mutex;
130
131 /*
132 * Indicates the syseventd daemon has begun taking events
133 */
134 int sysevent_daemon_init = 0;
135
136 /*
137 * Back-off delay when door_ki_upcall returns EAGAIN. Typically
138 * caused by the server process doing a forkall(). Since all threads
139 * but the thread actually doing the forkall() need to be quiesced,
140 * the fork may take some time. The min/max pause are in units
141 * of clock ticks.
142 */
143 #define LOG_EVENT_MIN_PAUSE 8
144 #define LOG_EVENT_MAX_PAUSE 128
145
146 static kmutex_t event_pause_mutex;
147 static kcondvar_t event_pause_cv;
148 static int event_pause_state = 0;
149
150 /*ARGSUSED*/
151 static void
log_event_busy_timeout(void * arg)152 log_event_busy_timeout(void *arg)
153 {
154 mutex_enter(&event_pause_mutex);
155 event_pause_state = 0;
156 cv_signal(&event_pause_cv);
157 mutex_exit(&event_pause_mutex);
158 }
159
160 static void
log_event_pause(int nticks)161 log_event_pause(int nticks)
162 {
163 timeout_id_t id;
164
165 /*
166 * Only one use of log_event_pause at a time
167 */
168 ASSERT(event_pause_state == 0);
169
170 event_pause_state = 1;
171 id = timeout(log_event_busy_timeout, NULL, nticks);
172 if (id != 0) {
173 mutex_enter(&event_pause_mutex);
174 while (event_pause_state)
175 cv_wait(&event_pause_cv, &event_pause_mutex);
176 mutex_exit(&event_pause_mutex);
177 }
178 event_pause_state = 0;
179 }
180
181
182 /*
183 * log_event_upcall - Perform the upcall to syseventd for event buffer delivery.
184 * Check for rebinding errors
185 * This buffer is reused to by the syseventd door_return
186 * to hold the result code
187 */
188 static int
log_event_upcall(log_event_upcall_arg_t * arg)189 log_event_upcall(log_event_upcall_arg_t *arg)
190 {
191 int error;
192 size_t size;
193 sysevent_t *ev;
194 door_arg_t darg, save_arg;
195 int retry;
196 int neagain = 0;
197 int neintr = 0;
198 int nticks = LOG_EVENT_MIN_PAUSE;
199
200 /* Initialize door args */
201 ev = (sysevent_t *)&arg->buf;
202 size = sizeof (log_event_upcall_arg_t) + SE_PAYLOAD_SZ(ev);
203
204 darg.rbuf = (char *)arg;
205 darg.data_ptr = (char *)arg;
206 darg.rsize = size;
207 darg.data_size = size;
208 darg.desc_ptr = NULL;
209 darg.desc_num = 0;
210
211 LOG_DEBUG1((CE_CONT, "log_event_upcall: 0x%llx\n",
212 (longlong_t)SE_SEQ((sysevent_t *)&arg->buf)));
213
214 save_arg = darg;
215 for (retry = 0; ; retry++) {
216
217 mutex_enter(&event_door_mutex);
218 if (event_door == NULL) {
219 mutex_exit(&event_door_mutex);
220
221 return (EBADF);
222 }
223
224 if ((error = door_ki_upcall_limited(event_door, &darg, NULL,
225 SIZE_MAX, 0)) == 0) {
226 mutex_exit(&event_door_mutex);
227 break;
228 }
229
230 /*
231 * EBADF is handled outside the switch below because we need to
232 * hold event_door_mutex a bit longer
233 */
234 if (error == EBADF) {
235 /* Server died */
236 door_ki_rele(event_door);
237 event_door = NULL;
238
239 mutex_exit(&event_door_mutex);
240 return (error);
241 }
242
243 mutex_exit(&event_door_mutex);
244
245 /*
246 * The EBADF case is already handled above with event_door_mutex
247 * held
248 */
249 switch (error) {
250 case EINTR:
251 neintr++;
252 log_event_pause(2);
253 darg = save_arg;
254 break;
255 case EAGAIN:
256 /* cannot deliver upcall - process may be forking */
257 neagain++;
258 log_event_pause(nticks);
259 nticks <<= 1;
260 if (nticks > LOG_EVENT_MAX_PAUSE)
261 nticks = LOG_EVENT_MAX_PAUSE;
262 darg = save_arg;
263 break;
264 default:
265 cmn_err(CE_CONT,
266 "log_event_upcall: door_ki_upcall error %d\n",
267 error);
268 return (error);
269 }
270 }
271
272 if (neagain > 0 || neintr > 0) {
273 LOG_DEBUG((CE_CONT, "upcall: eagain=%d eintr=%d nticks=%d\n",
274 neagain, neintr, nticks));
275 }
276
277 LOG_DEBUG1((CE_CONT, "log_event_upcall:\n\t"
278 "error=%d rptr1=%p rptr2=%p dptr2=%p ret1=%x ret2=%x\n",
279 error, (void *)arg, (void *)darg.rbuf,
280 (void *)darg.data_ptr,
281 *((int *)(darg.rbuf)), *((int *)(darg.data_ptr))));
282
283 if (!error) {
284 /*
285 * upcall was successfully executed. Check return code.
286 */
287 error = *((int *)(darg.rbuf));
288 }
289
290 return (error);
291 }
292
293 /*
294 * log_event_deliver - event delivery thread
295 * Deliver all events on the event queue to syseventd.
296 * If the daemon can not process events, stop event
297 * delivery and wait for an indication from the
298 * daemon to resume delivery.
299 *
300 * Once all event buffers have been delivered, wait
301 * until there are more to deliver.
302 */
303 static void
log_event_deliver()304 log_event_deliver()
305 {
306 log_eventq_t *q;
307 int upcall_err;
308 callb_cpr_t cprinfo;
309
310 CALLB_CPR_INIT(&cprinfo, &eventq_head_mutex, callb_generic_cpr,
311 "logevent");
312
313 /*
314 * eventq_head_mutex is exited (released) when there are no more
315 * events to process from the eventq in cv_wait().
316 */
317 mutex_enter(&eventq_head_mutex);
318
319 for (;;) {
320 LOG_DEBUG1((CE_CONT, "log_event_deliver: head = %p\n",
321 (void *)log_eventq_head));
322
323 upcall_err = 0;
324 q = log_eventq_head;
325
326 while (q) {
327 if (log_event_delivery == LOGEVENT_DELIVERY_HOLD) {
328 upcall_err = EAGAIN;
329 break;
330 }
331
332 log_event_delivery = LOGEVENT_DELIVERY_OK;
333
334 /*
335 * Release event queue lock during upcall to
336 * syseventd
337 */
338 mutex_exit(&eventq_head_mutex);
339 if ((upcall_err = log_event_upcall(&q->arg)) != 0) {
340 mutex_enter(&eventq_head_mutex);
341 break;
342 }
343
344 /*
345 * We may be able to add entries to
346 * the queue now.
347 */
348 if (event_qfull_blocked > 0 &&
349 log_eventq_cnt < logevent_max_q_sz) {
350 mutex_enter(&event_qfull_mutex);
351 if (event_qfull_blocked > 0) {
352 cv_signal(&event_qfull_cv);
353 }
354 mutex_exit(&event_qfull_mutex);
355 }
356
357 mutex_enter(&eventq_head_mutex);
358
359 /*
360 * Daemon restart can cause entries to be moved from
361 * the sent queue and put back on the event queue.
362 * If this has occurred, replay event queue
363 * processing from the new queue head.
364 */
365 if (q != log_eventq_head) {
366 q = log_eventq_head;
367 LOG_DEBUG((CE_CONT, "log_event_deliver: "
368 "door upcall/daemon restart race\n"));
369 } else {
370 log_eventq_t *next;
371
372 /*
373 * Move the event to the sent queue when a
374 * successful delivery has been made.
375 */
376 mutex_enter(&eventq_sent_mutex);
377 next = q->next;
378 q->next = log_eventq_sent;
379 log_eventq_sent = q;
380 q = next;
381 log_eventq_head = q;
382 log_eventq_cnt--;
383 if (q == NULL) {
384 ASSERT(log_eventq_cnt == 0);
385 log_eventq_tail = NULL;
386 }
387 mutex_exit(&eventq_sent_mutex);
388 }
389 }
390
391 switch (upcall_err) {
392 case 0:
393 /*
394 * Success. The queue is empty.
395 */
396 sysevent_upcall_status = 0;
397 break;
398 case EAGAIN:
399 /*
400 * Delivery is on hold (but functional).
401 */
402 sysevent_upcall_status = 0;
403 /*
404 * If the user has already signaled for delivery
405 * resumption, continue. Otherwise, we wait until
406 * we are signaled to continue.
407 */
408 if (log_event_delivery == LOGEVENT_DELIVERY_CONT)
409 continue;
410 log_event_delivery = LOGEVENT_DELIVERY_HOLD;
411
412 LOG_DEBUG1((CE_CONT, "log_event_deliver: EAGAIN\n"));
413 break;
414 default:
415 LOG_DEBUG((CE_CONT, "log_event_deliver: "
416 "upcall err %d\n", upcall_err));
417 sysevent_upcall_status = upcall_err;
418 /*
419 * Signal everyone waiting that transport is down
420 */
421 if (event_qfull_blocked > 0) {
422 mutex_enter(&event_qfull_mutex);
423 if (event_qfull_blocked > 0) {
424 cv_broadcast(&event_qfull_cv);
425 }
426 mutex_exit(&event_qfull_mutex);
427 }
428 break;
429 }
430
431 CALLB_CPR_SAFE_BEGIN(&cprinfo);
432 cv_wait(&log_event_cv, &eventq_head_mutex);
433 CALLB_CPR_SAFE_END(&cprinfo, &eventq_head_mutex);
434 }
435 /* NOTREACHED */
436 }
437
438 /*
439 * log_event_init - Allocate and initialize log_event data structures.
440 */
441 void
log_event_init()442 log_event_init()
443 {
444 mutex_init(&event_door_mutex, NULL, MUTEX_DEFAULT, NULL);
445
446 mutex_init(&eventq_head_mutex, NULL, MUTEX_DEFAULT, NULL);
447 mutex_init(&eventq_sent_mutex, NULL, MUTEX_DEFAULT, NULL);
448 cv_init(&log_event_cv, NULL, CV_DEFAULT, NULL);
449
450 mutex_init(&event_qfull_mutex, NULL, MUTEX_DEFAULT, NULL);
451 cv_init(&event_qfull_cv, NULL, CV_DEFAULT, NULL);
452
453 mutex_init(&event_pause_mutex, NULL, MUTEX_DEFAULT, NULL);
454 cv_init(&event_pause_cv, NULL, CV_DEFAULT, NULL);
455
456 mutex_init(®istered_channel_mutex, NULL, MUTEX_DEFAULT, NULL);
457 sysevent_evc_init();
458 }
459
460 /*
461 * The following routines are used by kernel event publishers to
462 * allocate, append and free event buffers
463 */
464 /*
465 * sysevent_alloc - Allocate new eventq struct. This element contains
466 * an event buffer that will be used in a subsequent
467 * call to log_sysevent.
468 */
469 sysevent_t *
sysevent_alloc(char * class,char * subclass,char * pub,int flag)470 sysevent_alloc(char *class, char *subclass, char *pub, int flag)
471 {
472 int payload_sz;
473 int class_sz, subclass_sz, pub_sz;
474 int aligned_class_sz, aligned_subclass_sz, aligned_pub_sz;
475 sysevent_t *ev;
476 log_eventq_t *q;
477
478 ASSERT(class != NULL);
479 ASSERT(subclass != NULL);
480 ASSERT(pub != NULL);
481
482 /*
483 * Calculate and reserve space for the class, subclass and
484 * publisher strings in the event buffer
485 */
486 class_sz = strlen(class) + 1;
487 subclass_sz = strlen(subclass) + 1;
488 pub_sz = strlen(pub) + 1;
489
490 ASSERT((class_sz <= MAX_CLASS_LEN) && (subclass_sz
491 <= MAX_SUBCLASS_LEN) && (pub_sz <= MAX_PUB_LEN));
492
493 /* String sizes must be 64-bit aligned in the event buffer */
494 aligned_class_sz = SE_ALIGN(class_sz);
495 aligned_subclass_sz = SE_ALIGN(subclass_sz);
496 aligned_pub_sz = SE_ALIGN(pub_sz);
497
498 payload_sz = (aligned_class_sz - sizeof (uint64_t)) +
499 (aligned_subclass_sz - sizeof (uint64_t)) +
500 (aligned_pub_sz - sizeof (uint64_t)) - sizeof (uint64_t);
501
502 /*
503 * Allocate event buffer plus additional sysevent queue
504 * and payload overhead.
505 */
506 q = kmem_zalloc(sizeof (log_eventq_t) + payload_sz, flag);
507 if (q == NULL) {
508 return (NULL);
509 }
510
511 /* Initialize the event buffer data */
512 ev = (sysevent_t *)&q->arg.buf;
513 SE_VERSION(ev) = SYS_EVENT_VERSION;
514 bcopy(class, SE_CLASS_NAME(ev), class_sz);
515
516 SE_SUBCLASS_OFF(ev) = SE_ALIGN(offsetof(sysevent_impl_t, se_class_name))
517 + aligned_class_sz;
518 bcopy(subclass, SE_SUBCLASS_NAME(ev), subclass_sz);
519
520 SE_PUB_OFF(ev) = SE_SUBCLASS_OFF(ev) + aligned_subclass_sz;
521 bcopy(pub, SE_PUB_NAME(ev), pub_sz);
522
523 SE_ATTR_PTR(ev) = UINT64_C(0);
524 SE_PAYLOAD_SZ(ev) = payload_sz;
525
526 return (ev);
527 }
528
529 /*
530 * sysevent_free - Free event buffer and any attribute data.
531 */
532 void
sysevent_free(sysevent_t * ev)533 sysevent_free(sysevent_t *ev)
534 {
535 log_eventq_t *q;
536 nvlist_t *nvl;
537
538 ASSERT(ev != NULL);
539 q = (log_eventq_t *)((caddr_t)ev - offsetof(log_eventq_t, arg.buf));
540 nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev);
541
542 if (nvl != NULL) {
543 size_t size = 0;
544 (void) nvlist_size(nvl, &size, encoding);
545 SE_PAYLOAD_SZ(ev) -= size;
546 nvlist_free(nvl);
547 }
548 kmem_free(q, sizeof (log_eventq_t) + SE_PAYLOAD_SZ(ev));
549 }
550
551 /*
552 * free_packed_event - Free packed event buffer
553 */
554 static void
free_packed_event(sysevent_t * ev)555 free_packed_event(sysevent_t *ev)
556 {
557 log_eventq_t *q;
558
559 ASSERT(ev != NULL);
560 q = (log_eventq_t *)((caddr_t)ev - offsetof(log_eventq_t, arg.buf));
561
562 kmem_free(q, sizeof (log_eventq_t) + SE_PAYLOAD_SZ(ev));
563 }
564
565 /*
566 * sysevent_add_attr - Add new attribute element to an event attribute list
567 * If attribute list is NULL, start a new list.
568 */
569 int
sysevent_add_attr(sysevent_attr_list_t ** ev_attr_list,char * name,sysevent_value_t * se_value,int flag)570 sysevent_add_attr(sysevent_attr_list_t **ev_attr_list, char *name,
571 sysevent_value_t *se_value, int flag)
572 {
573 int error;
574 nvlist_t **nvlp = (nvlist_t **)ev_attr_list;
575
576 if (nvlp == NULL || se_value == NULL) {
577 return (SE_EINVAL);
578 }
579
580 /*
581 * attr_sz is composed of the value data size + the name data size +
582 * any header data. 64-bit aligned.
583 */
584 if (strlen(name) >= MAX_ATTR_NAME) {
585 return (SE_EINVAL);
586 }
587
588 /*
589 * Allocate nvlist
590 */
591 if ((*nvlp == NULL) &&
592 (nvlist_alloc(nvlp, NV_UNIQUE_NAME_TYPE, flag) != 0))
593 return (SE_ENOMEM);
594
595 /* add the attribute */
596 switch (se_value->value_type) {
597 case SE_DATA_TYPE_BYTE:
598 error = nvlist_add_byte(*ev_attr_list, name,
599 se_value->value.sv_byte);
600 break;
601 case SE_DATA_TYPE_INT16:
602 error = nvlist_add_int16(*ev_attr_list, name,
603 se_value->value.sv_int16);
604 break;
605 case SE_DATA_TYPE_UINT16:
606 error = nvlist_add_uint16(*ev_attr_list, name,
607 se_value->value.sv_uint16);
608 break;
609 case SE_DATA_TYPE_INT32:
610 error = nvlist_add_int32(*ev_attr_list, name,
611 se_value->value.sv_int32);
612 break;
613 case SE_DATA_TYPE_UINT32:
614 error = nvlist_add_uint32(*ev_attr_list, name,
615 se_value->value.sv_uint32);
616 break;
617 case SE_DATA_TYPE_INT64:
618 error = nvlist_add_int64(*ev_attr_list, name,
619 se_value->value.sv_int64);
620 break;
621 case SE_DATA_TYPE_UINT64:
622 error = nvlist_add_uint64(*ev_attr_list, name,
623 se_value->value.sv_uint64);
624 break;
625 case SE_DATA_TYPE_STRING:
626 if (strlen((char *)se_value->value.sv_string) >= MAX_STRING_SZ)
627 return (SE_EINVAL);
628 error = nvlist_add_string(*ev_attr_list, name,
629 se_value->value.sv_string);
630 break;
631 case SE_DATA_TYPE_BYTES:
632 if (se_value->value.sv_bytes.size > MAX_BYTE_ARRAY)
633 return (SE_EINVAL);
634 error = nvlist_add_byte_array(*ev_attr_list, name,
635 se_value->value.sv_bytes.data,
636 se_value->value.sv_bytes.size);
637 break;
638 case SE_DATA_TYPE_TIME:
639 error = nvlist_add_hrtime(*ev_attr_list, name,
640 se_value->value.sv_time);
641 break;
642 default:
643 return (SE_EINVAL);
644 }
645
646 return (error ? SE_ENOMEM : 0);
647 }
648
649 /*
650 * sysevent_free_attr - Free an attribute list not associated with an
651 * event buffer.
652 */
653 void
sysevent_free_attr(sysevent_attr_list_t * ev_attr_list)654 sysevent_free_attr(sysevent_attr_list_t *ev_attr_list)
655 {
656 nvlist_free((nvlist_t *)ev_attr_list);
657 }
658
659 /*
660 * sysevent_attach_attributes - Attach an attribute list to an event buffer.
661 *
662 * This data will be re-packed into contiguous memory when the event
663 * buffer is posted to log_sysevent.
664 */
665 int
sysevent_attach_attributes(sysevent_t * ev,sysevent_attr_list_t * ev_attr_list)666 sysevent_attach_attributes(sysevent_t *ev, sysevent_attr_list_t *ev_attr_list)
667 {
668 size_t size = 0;
669
670 if (SE_ATTR_PTR(ev) != UINT64_C(0)) {
671 return (SE_EINVAL);
672 }
673
674 SE_ATTR_PTR(ev) = (uintptr_t)ev_attr_list;
675 (void) nvlist_size((nvlist_t *)ev_attr_list, &size, encoding);
676 SE_PAYLOAD_SZ(ev) += size;
677 SE_FLAG(ev) = 0;
678
679 return (0);
680 }
681
682 /*
683 * sysevent_detach_attributes - Detach but don't free attribute list from the
684 * event buffer.
685 */
686 void
sysevent_detach_attributes(sysevent_t * ev)687 sysevent_detach_attributes(sysevent_t *ev)
688 {
689 size_t size = 0;
690 nvlist_t *nvl;
691
692 if ((nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev)) == NULL) {
693 return;
694 }
695
696 SE_ATTR_PTR(ev) = UINT64_C(0);
697 (void) nvlist_size(nvl, &size, encoding);
698 SE_PAYLOAD_SZ(ev) -= size;
699 ASSERT(SE_PAYLOAD_SZ(ev) >= 0);
700 }
701
702 /*
703 * sysevent_attr_name - Get name of attribute
704 */
705 char *
sysevent_attr_name(sysevent_attr_t * attr)706 sysevent_attr_name(sysevent_attr_t *attr)
707 {
708 if (attr == NULL) {
709 return (NULL);
710 }
711
712 return (nvpair_name(attr));
713 }
714
715 /*
716 * sysevent_attr_type - Get type of attribute
717 */
718 int
sysevent_attr_type(sysevent_attr_t * attr)719 sysevent_attr_type(sysevent_attr_t *attr)
720 {
721 /*
722 * The SE_DATA_TYPE_* are typedef'ed to be the
723 * same value as DATA_TYPE_*
724 */
725 return (nvpair_type((nvpair_t *)attr));
726 }
727
728 /*
729 * Repack event buffer into contiguous memory
730 */
731 static sysevent_t *
se_repack(sysevent_t * ev,int flag)732 se_repack(sysevent_t *ev, int flag)
733 {
734 size_t copy_len;
735 caddr_t attr;
736 size_t size;
737 uint64_t attr_offset;
738 sysevent_t *copy;
739 log_eventq_t *qcopy;
740 sysevent_attr_list_t *nvl;
741
742 copy_len = sizeof (log_eventq_t) + SE_PAYLOAD_SZ(ev);
743 qcopy = kmem_zalloc(copy_len, flag);
744 if (qcopy == NULL) {
745 return (NULL);
746 }
747 copy = (sysevent_t *)&qcopy->arg.buf;
748
749 /*
750 * Copy event header, class, subclass and publisher names
751 * Set the attribute offset (in number of bytes) to contiguous
752 * memory after the header.
753 */
754
755 attr_offset = SE_ATTR_OFF(ev);
756
757 ASSERT((caddr_t)copy + attr_offset <= (caddr_t)copy + copy_len);
758
759 bcopy(ev, copy, attr_offset);
760
761 /* Check if attribute list exists */
762 if ((nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev)) == NULL) {
763 return (copy);
764 }
765
766 /*
767 * Copy attribute data to contiguous memory
768 */
769 attr = (char *)copy + attr_offset;
770 (void) nvlist_size(nvl, &size, encoding);
771 if (nvlist_pack(nvl, &attr, &size, encoding, flag) != 0) {
772 kmem_free(qcopy, copy_len);
773 return (NULL);
774 }
775 SE_ATTR_PTR(copy) = UINT64_C(0);
776 SE_FLAG(copy) = SE_PACKED_BUF;
777
778 return (copy);
779 }
780
781 /*
782 * The sysevent registration provides a persistent and reliable database
783 * for channel information for sysevent channel publishers and
784 * subscribers.
785 *
786 * A channel is created and maintained by the kernel upon the first
787 * SE_OPEN_REGISTRATION operation to log_sysevent_register(). Channel
788 * event subscription information is updated as publishers or subscribers
789 * perform subsequent operations (SE_BIND_REGISTRATION, SE_REGISTER,
790 * SE_UNREGISTER and SE_UNBIND_REGISTRATION).
791 *
792 * For consistency, id's are assigned for every publisher or subscriber
793 * bound to a particular channel. The id's are used to constrain resources
794 * and perform subscription lookup.
795 *
796 * Associated with each channel is a hashed list of the current subscriptions
797 * based upon event class and subclasses. A subscription contains a class name,
798 * list of possible subclasses and an array of subscriber ids. Subscriptions
799 * are updated for every SE_REGISTER or SE_UNREGISTER operation.
800 *
801 * Channels are closed once the last subscriber or publisher performs a
802 * SE_CLOSE_REGISTRATION operation. All resources associated with the named
803 * channel are freed upon last close.
804 *
805 * Locking:
806 * Every operation to log_sysevent() is protected by a single lock,
807 * registered_channel_mutex. It is expected that the granularity of
808 * a single lock is sufficient given the frequency that updates will
809 * occur.
810 *
811 * If this locking strategy proves to be too contentious, a per-hash
812 * or per-channel locking strategy may be implemented.
813 */
814
815
816 #define CHANN_HASH(channel_name) (hash_func(channel_name) \
817 % CHAN_HASH_SZ)
818
819 sysevent_channel_descriptor_t *registered_channels[CHAN_HASH_SZ];
820 static int channel_cnt;
821 static void remove_all_class(sysevent_channel_descriptor_t *chan,
822 uint32_t sub_id);
823
824 static uint32_t
hash_func(const char * s)825 hash_func(const char *s)
826 {
827 uint32_t result = 0;
828 uint_t g;
829
830 while (*s != '\0') {
831 result <<= 4;
832 result += (uint32_t)*s++;
833 g = result & 0xf0000000;
834 if (g != 0) {
835 result ^= g >> 24;
836 result ^= g;
837 }
838 }
839
840 return (result);
841 }
842
843 static sysevent_channel_descriptor_t *
get_channel(char * channel_name)844 get_channel(char *channel_name)
845 {
846 int hash_index;
847 sysevent_channel_descriptor_t *chan_list;
848
849 if (channel_name == NULL)
850 return (NULL);
851
852 /* Find channel descriptor */
853 hash_index = CHANN_HASH(channel_name);
854 chan_list = registered_channels[hash_index];
855 while (chan_list != NULL) {
856 if (strcmp(chan_list->scd_channel_name, channel_name) == 0) {
857 break;
858 } else {
859 chan_list = chan_list->scd_next;
860 }
861 }
862
863 return (chan_list);
864 }
865
866 static class_lst_t *
create_channel_registration(sysevent_channel_descriptor_t * chan,char * event_class,int index)867 create_channel_registration(sysevent_channel_descriptor_t *chan,
868 char *event_class, int index)
869 {
870 size_t class_len;
871 class_lst_t *c_list;
872
873 class_len = strlen(event_class) + 1;
874 c_list = kmem_zalloc(sizeof (class_lst_t), KM_SLEEP);
875 c_list->cl_name = kmem_zalloc(class_len, KM_SLEEP);
876 bcopy(event_class, c_list->cl_name, class_len);
877
878 c_list->cl_subclass_list =
879 kmem_zalloc(sizeof (subclass_lst_t), KM_SLEEP);
880 c_list->cl_subclass_list->sl_name =
881 kmem_zalloc(sizeof (EC_SUB_ALL), KM_SLEEP);
882 bcopy(EC_SUB_ALL, c_list->cl_subclass_list->sl_name,
883 sizeof (EC_SUB_ALL));
884
885 c_list->cl_next = chan->scd_class_list_tbl[index];
886 chan->scd_class_list_tbl[index] = c_list;
887
888 return (c_list);
889 }
890
891 static void
free_channel_registration(sysevent_channel_descriptor_t * chan)892 free_channel_registration(sysevent_channel_descriptor_t *chan)
893 {
894 int i;
895 class_lst_t *clist, *next_clist;
896 subclass_lst_t *sclist, *next_sc;
897
898 for (i = 0; i <= CLASS_HASH_SZ; ++i) {
899
900 clist = chan->scd_class_list_tbl[i];
901 while (clist != NULL) {
902 sclist = clist->cl_subclass_list;
903 while (sclist != NULL) {
904 kmem_free(sclist->sl_name,
905 strlen(sclist->sl_name) + 1);
906 next_sc = sclist->sl_next;
907 kmem_free(sclist, sizeof (subclass_lst_t));
908 sclist = next_sc;
909 }
910 kmem_free(clist->cl_name,
911 strlen(clist->cl_name) + 1);
912 next_clist = clist->cl_next;
913 kmem_free(clist, sizeof (class_lst_t));
914 clist = next_clist;
915 }
916 }
917 chan->scd_class_list_tbl[0] = NULL;
918 }
919
920 static int
open_channel(char * channel_name)921 open_channel(char *channel_name)
922 {
923 int hash_index;
924 sysevent_channel_descriptor_t *chan, *chan_list;
925
926
927 if (channel_cnt > MAX_CHAN) {
928 return (-1);
929 }
930
931 /* Find channel descriptor */
932 hash_index = CHANN_HASH(channel_name);
933 chan_list = registered_channels[hash_index];
934 while (chan_list != NULL) {
935 if (strcmp(chan_list->scd_channel_name, channel_name) == 0) {
936 chan_list->scd_ref_cnt++;
937 kmem_free(channel_name, strlen(channel_name) + 1);
938 return (0);
939 } else {
940 chan_list = chan_list->scd_next;
941 }
942 }
943
944
945 /* New channel descriptor */
946 chan = kmem_zalloc(sizeof (sysevent_channel_descriptor_t), KM_SLEEP);
947 chan->scd_channel_name = channel_name;
948
949 /*
950 * Create subscriber ids in the range [1, MAX_SUBSCRIBERS).
951 * Subscriber id 0 is never allocated, but is used as a reserved id
952 * by libsysevent
953 */
954 if ((chan->scd_subscriber_cache = vmem_create(channel_name, (void *)1,
955 MAX_SUBSCRIBERS + 1, 1, NULL, NULL, NULL, 0,
956 VM_NOSLEEP | VMC_IDENTIFIER)) == NULL) {
957 kmem_free(chan, sizeof (sysevent_channel_descriptor_t));
958 return (-1);
959 }
960 if ((chan->scd_publisher_cache = vmem_create(channel_name, (void *)1,
961 MAX_PUBLISHERS + 1, 1, NULL, NULL, NULL, 0,
962 VM_NOSLEEP | VMC_IDENTIFIER)) == NULL) {
963 vmem_destroy(chan->scd_subscriber_cache);
964 kmem_free(chan, sizeof (sysevent_channel_descriptor_t));
965 return (-1);
966 }
967
968 chan->scd_ref_cnt = 1;
969
970 (void) create_channel_registration(chan, EC_ALL, 0);
971
972 if (registered_channels[hash_index] != NULL)
973 chan->scd_next = registered_channels[hash_index];
974
975 registered_channels[hash_index] = chan;
976
977 ++channel_cnt;
978
979 return (0);
980 }
981
982 static void
close_channel(char * channel_name)983 close_channel(char *channel_name)
984 {
985 int hash_index;
986 sysevent_channel_descriptor_t *chan, *prev_chan;
987
988 /* Find channel descriptor */
989 hash_index = CHANN_HASH(channel_name);
990 prev_chan = chan = registered_channels[hash_index];
991
992 while (chan != NULL) {
993 if (strcmp(chan->scd_channel_name, channel_name) == 0) {
994 break;
995 } else {
996 prev_chan = chan;
997 chan = chan->scd_next;
998 }
999 }
1000
1001 if (chan == NULL)
1002 return;
1003
1004 chan->scd_ref_cnt--;
1005 if (chan->scd_ref_cnt > 0)
1006 return;
1007
1008 free_channel_registration(chan);
1009 vmem_destroy(chan->scd_subscriber_cache);
1010 vmem_destroy(chan->scd_publisher_cache);
1011 kmem_free(chan->scd_channel_name,
1012 strlen(chan->scd_channel_name) + 1);
1013 if (registered_channels[hash_index] == chan)
1014 registered_channels[hash_index] = chan->scd_next;
1015 else
1016 prev_chan->scd_next = chan->scd_next;
1017 kmem_free(chan, sizeof (sysevent_channel_descriptor_t));
1018 --channel_cnt;
1019 }
1020
1021 static id_t
bind_common(sysevent_channel_descriptor_t * chan,int type)1022 bind_common(sysevent_channel_descriptor_t *chan, int type)
1023 {
1024 id_t id;
1025
1026 if (type == SUBSCRIBER) {
1027 id = (id_t)(uintptr_t)vmem_alloc(chan->scd_subscriber_cache, 1,
1028 VM_NOSLEEP | VM_NEXTFIT);
1029 if (id <= 0 || id > MAX_SUBSCRIBERS)
1030 return (0);
1031 chan->scd_subscriber_ids[id] = 1;
1032 } else {
1033 id = (id_t)(uintptr_t)vmem_alloc(chan->scd_publisher_cache, 1,
1034 VM_NOSLEEP | VM_NEXTFIT);
1035 if (id <= 0 || id > MAX_PUBLISHERS)
1036 return (0);
1037 chan->scd_publisher_ids[id] = 1;
1038 }
1039
1040 return (id);
1041 }
1042
1043 static int
unbind_common(sysevent_channel_descriptor_t * chan,int type,id_t id)1044 unbind_common(sysevent_channel_descriptor_t *chan, int type, id_t id)
1045 {
1046 if (type == SUBSCRIBER) {
1047 if (id <= 0 || id > MAX_SUBSCRIBERS)
1048 return (0);
1049 if (chan->scd_subscriber_ids[id] == 0)
1050 return (0);
1051 (void) remove_all_class(chan, id);
1052 chan->scd_subscriber_ids[id] = 0;
1053 vmem_free(chan->scd_subscriber_cache, (void *)(uintptr_t)id, 1);
1054 } else {
1055 if (id <= 0 || id > MAX_PUBLISHERS)
1056 return (0);
1057 if (chan->scd_publisher_ids[id] == 0)
1058 return (0);
1059 chan->scd_publisher_ids[id] = 0;
1060 vmem_free(chan->scd_publisher_cache, (void *)(uintptr_t)id, 1);
1061 }
1062
1063 return (1);
1064 }
1065
1066 static void
release_id(sysevent_channel_descriptor_t * chan,int type,id_t id)1067 release_id(sysevent_channel_descriptor_t *chan, int type, id_t id)
1068 {
1069 if (unbind_common(chan, type, id))
1070 close_channel(chan->scd_channel_name);
1071 }
1072
1073 static subclass_lst_t *
find_subclass(class_lst_t * c_list,char * subclass)1074 find_subclass(class_lst_t *c_list, char *subclass)
1075 {
1076 subclass_lst_t *sc_list;
1077
1078 if (c_list == NULL)
1079 return (NULL);
1080
1081 sc_list = c_list->cl_subclass_list;
1082
1083 while (sc_list != NULL) {
1084 if (strcmp(sc_list->sl_name, subclass) == 0) {
1085 return (sc_list);
1086 }
1087 sc_list = sc_list->sl_next;
1088 }
1089
1090 return (NULL);
1091 }
1092
1093 static void
insert_subclass(class_lst_t * c_list,char ** subclass_names,int subclass_num,uint32_t sub_id)1094 insert_subclass(class_lst_t *c_list, char **subclass_names,
1095 int subclass_num, uint32_t sub_id)
1096 {
1097 int i, subclass_sz;
1098 subclass_lst_t *sc_list;
1099
1100 for (i = 0; i < subclass_num; ++i) {
1101 if ((sc_list = find_subclass(c_list, subclass_names[i]))
1102 != NULL) {
1103 sc_list->sl_num[sub_id] = 1;
1104 } else {
1105
1106 sc_list = kmem_zalloc(sizeof (subclass_lst_t),
1107 KM_SLEEP);
1108 subclass_sz = strlen(subclass_names[i]) + 1;
1109 sc_list->sl_name = kmem_zalloc(subclass_sz, KM_SLEEP);
1110 bcopy(subclass_names[i], sc_list->sl_name,
1111 subclass_sz);
1112
1113 sc_list->sl_num[sub_id] = 1;
1114
1115 sc_list->sl_next = c_list->cl_subclass_list;
1116 c_list->cl_subclass_list = sc_list;
1117 }
1118 }
1119 }
1120
1121 static class_lst_t *
find_class(sysevent_channel_descriptor_t * chan,char * class_name)1122 find_class(sysevent_channel_descriptor_t *chan, char *class_name)
1123 {
1124 class_lst_t *c_list;
1125
1126 c_list = chan->scd_class_list_tbl[CLASS_HASH(class_name)];
1127 while (c_list != NULL) {
1128 if (strcmp(class_name, c_list->cl_name) == 0)
1129 break;
1130 c_list = c_list->cl_next;
1131 }
1132
1133 return (c_list);
1134 }
1135
1136 static void
remove_all_class(sysevent_channel_descriptor_t * chan,uint32_t sub_id)1137 remove_all_class(sysevent_channel_descriptor_t *chan, uint32_t sub_id)
1138 {
1139 int i;
1140 class_lst_t *c_list;
1141 subclass_lst_t *sc_list;
1142
1143 for (i = 0; i <= CLASS_HASH_SZ; ++i) {
1144
1145 c_list = chan->scd_class_list_tbl[i];
1146 while (c_list != NULL) {
1147 sc_list = c_list->cl_subclass_list;
1148 while (sc_list != NULL) {
1149 sc_list->sl_num[sub_id] = 0;
1150 sc_list = sc_list->sl_next;
1151 }
1152 c_list = c_list->cl_next;
1153 }
1154 }
1155 }
1156
1157 static void
remove_class(sysevent_channel_descriptor_t * chan,uint32_t sub_id,char * class_name)1158 remove_class(sysevent_channel_descriptor_t *chan, uint32_t sub_id,
1159 char *class_name)
1160 {
1161 class_lst_t *c_list;
1162 subclass_lst_t *sc_list;
1163
1164 if (strcmp(class_name, EC_ALL) == 0) {
1165 remove_all_class(chan, sub_id);
1166 return;
1167 }
1168
1169 if ((c_list = find_class(chan, class_name)) == NULL) {
1170 return;
1171 }
1172
1173 sc_list = c_list->cl_subclass_list;
1174 while (sc_list != NULL) {
1175 sc_list->sl_num[sub_id] = 0;
1176 sc_list = sc_list->sl_next;
1177 }
1178 }
1179
1180 static int
insert_class(sysevent_channel_descriptor_t * chan,char * event_class,char ** event_subclass_lst,int subclass_num,uint32_t sub_id)1181 insert_class(sysevent_channel_descriptor_t *chan, char *event_class,
1182 char **event_subclass_lst, int subclass_num, uint32_t sub_id)
1183 {
1184 class_lst_t *c_list;
1185
1186 if (strcmp(event_class, EC_ALL) == 0) {
1187 insert_subclass(chan->scd_class_list_tbl[0],
1188 event_subclass_lst, 1, sub_id);
1189 return (0);
1190 }
1191
1192 if (strlen(event_class) + 1 > MAX_CLASS_LEN)
1193 return (-1);
1194
1195 /* New class, add to the registration cache */
1196 if ((c_list = find_class(chan, event_class)) == NULL) {
1197 c_list = create_channel_registration(chan, event_class,
1198 CLASS_HASH(event_class));
1199 }
1200
1201 /* Update the subclass list */
1202 insert_subclass(c_list, event_subclass_lst, subclass_num, sub_id);
1203
1204 return (0);
1205 }
1206
1207 static int
add_registration(sysevent_channel_descriptor_t * chan,uint32_t sub_id,char * nvlbuf,size_t nvlsize)1208 add_registration(sysevent_channel_descriptor_t *chan, uint32_t sub_id,
1209 char *nvlbuf, size_t nvlsize)
1210 {
1211 uint_t num_elem;
1212 char *event_class;
1213 char **event_list;
1214 nvlist_t *nvl;
1215 nvpair_t *nvpair = NULL;
1216
1217 if (nvlist_unpack(nvlbuf, nvlsize, &nvl, KM_SLEEP) != 0)
1218 return (-1);
1219
1220 if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) == NULL) {
1221 nvlist_free(nvl);
1222 return (-1);
1223 }
1224
1225 if ((event_class = nvpair_name(nvpair)) == NULL) {
1226 nvlist_free(nvl);
1227 return (-1);
1228 }
1229 if (nvpair_value_string_array(nvpair, &event_list,
1230 &num_elem) != 0) {
1231 nvlist_free(nvl);
1232 return (-1);
1233 }
1234
1235 if (insert_class(chan, event_class, event_list, num_elem, sub_id) < 0) {
1236 nvlist_free(nvl);
1237 return (-1);
1238 }
1239
1240 nvlist_free(nvl);
1241
1242 return (0);
1243 }
1244
1245 /*
1246 * get_registration - Return the requested class hash chain
1247 */
1248 static int
get_registration(sysevent_channel_descriptor_t * chan,char * databuf,uint32_t * bufsz,uint32_t class_index)1249 get_registration(sysevent_channel_descriptor_t *chan, char *databuf,
1250 uint32_t *bufsz, uint32_t class_index)
1251 {
1252 int num_classes = 0;
1253 char *nvlbuf = NULL;
1254 size_t nvlsize;
1255 nvlist_t *nvl;
1256 class_lst_t *clist;
1257 subclass_lst_t *sc_list;
1258
1259 if (class_index < 0 || class_index > CLASS_HASH_SZ)
1260 return (EINVAL);
1261
1262 if ((clist = chan->scd_class_list_tbl[class_index]) == NULL) {
1263 return (ENOENT);
1264 }
1265
1266 if (nvlist_alloc(&nvl, 0, 0) != 0) {
1267 return (EFAULT);
1268 }
1269
1270 while (clist != NULL) {
1271 if (nvlist_add_string(nvl, CLASS_NAME, clist->cl_name)
1272 != 0) {
1273 nvlist_free(nvl);
1274 return (EFAULT);
1275 }
1276
1277 sc_list = clist->cl_subclass_list;
1278 while (sc_list != NULL) {
1279 if (nvlist_add_byte_array(nvl, sc_list->sl_name,
1280 sc_list->sl_num, MAX_SUBSCRIBERS) != 0) {
1281 nvlist_free(nvl);
1282 return (EFAULT);
1283 }
1284 sc_list = sc_list->sl_next;
1285 }
1286 num_classes++;
1287 clist = clist->cl_next;
1288 }
1289
1290 if (num_classes == 0) {
1291 nvlist_free(nvl);
1292 return (ENOENT);
1293 }
1294
1295 if (nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE,
1296 KM_SLEEP)
1297 != 0) {
1298 nvlist_free(nvl);
1299 return (EFAULT);
1300 }
1301
1302 nvlist_free(nvl);
1303
1304 if (nvlsize > *bufsz) {
1305 kmem_free(nvlbuf, nvlsize);
1306 *bufsz = nvlsize;
1307 return (EAGAIN);
1308 }
1309
1310 bcopy(nvlbuf, databuf, nvlsize);
1311 kmem_free(nvlbuf, nvlsize);
1312
1313 return (0);
1314 }
1315
1316 /*
1317 * log_sysevent_register - Register event subscriber for a particular
1318 * event channel.
1319 */
1320 int
log_sysevent_register(char * channel_name,char * udatabuf,se_pubsub_t * udata)1321 log_sysevent_register(char *channel_name, char *udatabuf, se_pubsub_t *udata)
1322 {
1323 int error = 0;
1324 char *kchannel, *databuf = NULL;
1325 size_t bufsz;
1326 se_pubsub_t kdata;
1327 sysevent_channel_descriptor_t *chan;
1328
1329 if (copyin(udata, &kdata, sizeof (se_pubsub_t)) == -1) {
1330 return (EFAULT);
1331 }
1332 if (kdata.ps_channel_name_len == 0) {
1333 return (EINVAL);
1334 }
1335 kchannel = kmem_alloc(kdata.ps_channel_name_len, KM_SLEEP);
1336 if (copyin(channel_name, kchannel, kdata.ps_channel_name_len) == -1) {
1337 kmem_free(kchannel, kdata.ps_channel_name_len);
1338 return (EFAULT);
1339 }
1340 bufsz = kdata.ps_buflen;
1341 if (bufsz > 0) {
1342 databuf = kmem_alloc(bufsz, KM_SLEEP);
1343 if (copyin(udatabuf, databuf, bufsz) == -1) {
1344 kmem_free(kchannel, kdata.ps_channel_name_len);
1345 kmem_free(databuf, bufsz);
1346 return (EFAULT);
1347 }
1348 }
1349
1350 mutex_enter(®istered_channel_mutex);
1351 if (kdata.ps_op != SE_OPEN_REGISTRATION &&
1352 kdata.ps_op != SE_CLOSE_REGISTRATION) {
1353 chan = get_channel(kchannel);
1354 if (chan == NULL) {
1355 mutex_exit(®istered_channel_mutex);
1356 kmem_free(kchannel, kdata.ps_channel_name_len);
1357 if (bufsz > 0)
1358 kmem_free(databuf, bufsz);
1359 return (ENOENT);
1360 }
1361 }
1362
1363 switch (kdata.ps_op) {
1364 case SE_OPEN_REGISTRATION:
1365 if (open_channel(kchannel) != 0) {
1366 error = ENOMEM;
1367 if (bufsz > 0)
1368 kmem_free(databuf, bufsz);
1369 kmem_free(kchannel, kdata.ps_channel_name_len);
1370 }
1371
1372 mutex_exit(®istered_channel_mutex);
1373 return (error);
1374 case SE_CLOSE_REGISTRATION:
1375 close_channel(kchannel);
1376 break;
1377 case SE_BIND_REGISTRATION:
1378 if ((kdata.ps_id = bind_common(chan, kdata.ps_type)) <= 0)
1379 error = EBUSY;
1380 break;
1381 case SE_UNBIND_REGISTRATION:
1382 (void) unbind_common(chan, kdata.ps_type, (id_t)kdata.ps_id);
1383 break;
1384 case SE_REGISTER:
1385 if (bufsz == 0) {
1386 error = EINVAL;
1387 break;
1388 }
1389 if (add_registration(chan, kdata.ps_id, databuf, bufsz) == -1)
1390 error = EINVAL;
1391 break;
1392 case SE_UNREGISTER:
1393 if (bufsz == 0) {
1394 error = EINVAL;
1395 break;
1396 }
1397 remove_class(chan, kdata.ps_id, databuf);
1398 break;
1399 case SE_CLEANUP:
1400 /* Cleanup the indicated subscriber or publisher */
1401 release_id(chan, kdata.ps_type, kdata.ps_id);
1402 break;
1403 case SE_GET_REGISTRATION:
1404 error = get_registration(chan, databuf,
1405 &kdata.ps_buflen, kdata.ps_id);
1406 break;
1407 default:
1408 error = ENOTSUP;
1409 }
1410
1411 mutex_exit(®istered_channel_mutex);
1412
1413 kmem_free(kchannel, kdata.ps_channel_name_len);
1414
1415 if (bufsz > 0) {
1416 if (copyout(databuf, udatabuf, bufsz) == -1)
1417 error = EFAULT;
1418 kmem_free(databuf, bufsz);
1419 }
1420
1421 if (copyout(&kdata, udata, sizeof (se_pubsub_t)) == -1)
1422 return (EFAULT);
1423
1424 return (error);
1425 }
1426
1427 /*
1428 * log_sysevent_copyout_data - Copyout event data to userland.
1429 * This is called from modctl(MODEVENTS, MODEVENTS_GETDATA)
1430 * The buffer size is always sufficient.
1431 */
1432 int
log_sysevent_copyout_data(sysevent_id_t * eid,size_t ubuflen,caddr_t ubuf)1433 log_sysevent_copyout_data(sysevent_id_t *eid, size_t ubuflen, caddr_t ubuf)
1434 {
1435 int error = ENOENT;
1436 log_eventq_t *q;
1437 sysevent_t *ev;
1438 sysevent_id_t eid_copy;
1439
1440 /*
1441 * Copy eid
1442 */
1443 if (copyin(eid, &eid_copy, sizeof (sysevent_id_t)) == -1) {
1444 return (EFAULT);
1445 }
1446
1447 mutex_enter(&eventq_sent_mutex);
1448 q = log_eventq_sent;
1449
1450 /*
1451 * Search for event buffer on the sent queue with matching
1452 * event identifier
1453 */
1454 while (q) {
1455 ev = (sysevent_t *)&q->arg.buf;
1456
1457 if (SE_TIME(ev) != eid_copy.eid_ts ||
1458 SE_SEQ(ev) != eid_copy.eid_seq) {
1459 q = q->next;
1460 continue;
1461 }
1462
1463 if (ubuflen < SE_SIZE(ev)) {
1464 error = EFAULT;
1465 break;
1466 }
1467 if (copyout(ev, ubuf, SE_SIZE(ev)) != 0) {
1468 error = EFAULT;
1469 LOG_DEBUG((CE_NOTE, "Unable to retrieve system event "
1470 "0x%" PRIx64 " from queue: EFAULT\n",
1471 eid->eid_seq));
1472 } else {
1473 error = 0;
1474 }
1475 break;
1476 }
1477
1478 mutex_exit(&eventq_sent_mutex);
1479
1480 return (error);
1481 }
1482
1483 /*
1484 * log_sysevent_free_data - Free kernel copy of the event buffer identified
1485 * by eid (must have already been sent). Called from
1486 * modctl(MODEVENTS, MODEVENTS_FREEDATA).
1487 */
1488 int
log_sysevent_free_data(sysevent_id_t * eid)1489 log_sysevent_free_data(sysevent_id_t *eid)
1490 {
1491 int error = ENOENT;
1492 sysevent_t *ev;
1493 log_eventq_t *q, *prev = NULL;
1494 sysevent_id_t eid_copy;
1495
1496 /*
1497 * Copy eid
1498 */
1499 if (copyin(eid, &eid_copy, sizeof (sysevent_id_t)) == -1) {
1500 return (EFAULT);
1501 }
1502
1503 mutex_enter(&eventq_sent_mutex);
1504 q = log_eventq_sent;
1505
1506 /*
1507 * Look for the event to be freed on the sent queue. Due to delayed
1508 * processing of the event, it may not be on the sent queue yet.
1509 * It is up to the user to retry the free operation to ensure that the
1510 * event is properly freed.
1511 */
1512 while (q) {
1513 ev = (sysevent_t *)&q->arg.buf;
1514
1515 if (SE_TIME(ev) != eid_copy.eid_ts ||
1516 SE_SEQ(ev) != eid_copy.eid_seq) {
1517 prev = q;
1518 q = q->next;
1519 continue;
1520 }
1521 /*
1522 * Take it out of log_eventq_sent and free it
1523 */
1524 if (prev) {
1525 prev->next = q->next;
1526 } else {
1527 log_eventq_sent = q->next;
1528 }
1529 free_packed_event(ev);
1530 error = 0;
1531 break;
1532 }
1533
1534 mutex_exit(&eventq_sent_mutex);
1535
1536 return (error);
1537 }
1538
1539 /*
1540 * log_sysevent_flushq - Begin or resume event buffer delivery. If neccessary,
1541 * create log_event_deliver thread or wake it up
1542 */
1543 /*ARGSUSED*/
1544 void
log_sysevent_flushq(int cmd,uint_t flag)1545 log_sysevent_flushq(int cmd, uint_t flag)
1546 {
1547 mutex_enter(&eventq_head_mutex);
1548
1549 /*
1550 * Start the event delivery thread
1551 * Mark the upcall status as active since we should
1552 * now be able to begin emptying the queue normally.
1553 */
1554 if (!async_thread) {
1555 sysevent_upcall_status = 0;
1556 sysevent_daemon_init = 1;
1557 setup_ddi_poststartup();
1558 async_thread = thread_create(NULL, 0, log_event_deliver,
1559 NULL, 0, &p0, TS_RUN, minclsyspri);
1560 }
1561
1562 log_event_delivery = LOGEVENT_DELIVERY_CONT;
1563 cv_signal(&log_event_cv);
1564 mutex_exit(&eventq_head_mutex);
1565 }
1566
1567 /*
1568 * log_sysevent_filename - Called by syseventd via
1569 * modctl(MODEVENTS, MODEVENTS_SET_DOOR_UPCALL_FILENAME)
1570 * to subsequently bind the event_door.
1571 *
1572 * This routine is called everytime syseventd (re)starts
1573 * and must therefore replay any events buffers that have
1574 * been sent but not freed.
1575 *
1576 * Event buffer delivery begins after a call to
1577 * log_sysevent_flushq().
1578 */
1579 int
log_sysevent_filename(char * file)1580 log_sysevent_filename(char *file)
1581 {
1582 mutex_enter(&event_door_mutex);
1583
1584 (void) strlcpy(logevent_door_upcall_filename, file,
1585 sizeof (logevent_door_upcall_filename));
1586
1587 /* Unbind old event door */
1588 if (event_door != NULL)
1589 door_ki_rele(event_door);
1590 /* Establish door connection with user event daemon (syseventd) */
1591 if (door_ki_open(logevent_door_upcall_filename, &event_door) != 0)
1592 event_door = NULL;
1593
1594 mutex_exit(&event_door_mutex);
1595
1596 /*
1597 * We are called when syseventd restarts. Move all sent, but
1598 * not committed events from log_eventq_sent to log_eventq_head.
1599 * Do it in proper order to maintain increasing event id.
1600 */
1601 mutex_enter(&eventq_head_mutex);
1602
1603 mutex_enter(&eventq_sent_mutex);
1604 while (log_eventq_sent) {
1605 log_eventq_t *tmp = log_eventq_sent->next;
1606 log_eventq_sent->next = log_eventq_head;
1607 if (log_eventq_head == NULL) {
1608 ASSERT(log_eventq_cnt == 0);
1609 log_eventq_tail = log_eventq_sent;
1610 log_eventq_tail->next = NULL;
1611 } else if (log_eventq_head == log_eventq_tail) {
1612 ASSERT(log_eventq_cnt == 1);
1613 ASSERT(log_eventq_head->next == NULL);
1614 ASSERT(log_eventq_tail->next == NULL);
1615 }
1616 log_eventq_head = log_eventq_sent;
1617 log_eventq_sent = tmp;
1618 log_eventq_cnt++;
1619 }
1620 mutex_exit(&eventq_sent_mutex);
1621 mutex_exit(&eventq_head_mutex);
1622
1623 return (0);
1624 }
1625
1626 /*
1627 * queue_sysevent - queue an event buffer
1628 */
1629 static int
queue_sysevent(sysevent_t * ev,sysevent_id_t * eid,int flag)1630 queue_sysevent(sysevent_t *ev, sysevent_id_t *eid, int flag)
1631 {
1632 log_eventq_t *q;
1633
1634 ASSERT(flag == SE_SLEEP || flag == SE_NOSLEEP);
1635
1636 DTRACE_SYSEVENT2(post, evch_bind_t *, NULL, sysevent_impl_t *, ev);
1637
1638 restart:
1639
1640 /* Max Q size exceeded */
1641 mutex_enter(&event_qfull_mutex);
1642 if (sysevent_daemon_init && log_eventq_cnt >= logevent_max_q_sz) {
1643 /*
1644 * If queue full and transport down, return no transport
1645 */
1646 if (sysevent_upcall_status != 0) {
1647 mutex_exit(&event_qfull_mutex);
1648 free_packed_event(ev);
1649 eid->eid_seq = UINT64_C(0);
1650 eid->eid_ts = INT64_C(0);
1651 return (SE_NO_TRANSPORT);
1652 }
1653 if (flag == SE_NOSLEEP) {
1654 mutex_exit(&event_qfull_mutex);
1655 free_packed_event(ev);
1656 eid->eid_seq = UINT64_C(0);
1657 eid->eid_ts = INT64_C(0);
1658 return (SE_EQSIZE);
1659 }
1660 event_qfull_blocked++;
1661 cv_wait(&event_qfull_cv, &event_qfull_mutex);
1662 event_qfull_blocked--;
1663 mutex_exit(&event_qfull_mutex);
1664 goto restart;
1665 }
1666 mutex_exit(&event_qfull_mutex);
1667
1668 mutex_enter(&eventq_head_mutex);
1669
1670 /* Time stamp and assign ID */
1671 SE_SEQ(ev) = eid->eid_seq = atomic_add_64_nv(&kernel_event_id,
1672 (uint64_t)1);
1673 SE_TIME(ev) = eid->eid_ts = gethrtime();
1674
1675 LOG_DEBUG1((CE_CONT, "log_sysevent: class=%d type=%d id=0x%llx\n",
1676 SE_CLASS(ev), SE_SUBCLASS(ev), (longlong_t)SE_SEQ(ev)));
1677
1678 /*
1679 * Put event on eventq
1680 */
1681 q = (log_eventq_t *)((caddr_t)ev - offsetof(log_eventq_t, arg.buf));
1682 q->next = NULL;
1683 if (log_eventq_head == NULL) {
1684 ASSERT(log_eventq_cnt == 0);
1685 log_eventq_head = q;
1686 log_eventq_tail = q;
1687 } else {
1688 if (log_eventq_head == log_eventq_tail) {
1689 ASSERT(log_eventq_cnt == 1);
1690 ASSERT(log_eventq_head->next == NULL);
1691 ASSERT(log_eventq_tail->next == NULL);
1692 }
1693 log_eventq_tail->next = q;
1694 log_eventq_tail = q;
1695 }
1696 log_eventq_cnt++;
1697
1698 /* Signal event delivery thread */
1699 if (log_eventq_cnt == 1) {
1700 cv_signal(&log_event_cv);
1701 }
1702 mutex_exit(&eventq_head_mutex);
1703
1704 return (0);
1705 }
1706
1707 /*
1708 * log_sysevent - kernel system event logger.
1709 *
1710 * Returns SE_ENOMEM if buf allocation failed or SE_EQSIZE if the
1711 * maximum event queue size will be exceeded
1712 * Returns 0 for successfully queued event buffer
1713 */
1714 int
log_sysevent(sysevent_t * ev,int flag,sysevent_id_t * eid)1715 log_sysevent(sysevent_t *ev, int flag, sysevent_id_t *eid)
1716 {
1717 sysevent_t *ev_copy;
1718 int rval;
1719
1720 ASSERT(flag == SE_SLEEP || flag == SE_NOSLEEP);
1721 ASSERT(!(flag == SE_SLEEP && servicing_interrupt()));
1722
1723 ev_copy = se_repack(ev, flag);
1724 if (ev_copy == NULL) {
1725 ASSERT(flag == SE_NOSLEEP);
1726 return (SE_ENOMEM);
1727 }
1728 rval = queue_sysevent(ev_copy, eid, flag);
1729 ASSERT(rval == 0 || rval == SE_ENOMEM || rval == SE_EQSIZE ||
1730 rval == SE_NO_TRANSPORT);
1731 ASSERT(!(flag == SE_SLEEP && (rval == SE_EQSIZE || rval == SE_ENOMEM)));
1732 return (rval);
1733 }
1734
1735 /*
1736 * log_usr_sysevent - user system event logger
1737 * Private to devfsadm and accessible only via
1738 * modctl(MODEVENTS, MODEVENTS_POST_EVENT)
1739 */
1740 int
log_usr_sysevent(sysevent_t * ev,int ev_size,sysevent_id_t * eid)1741 log_usr_sysevent(sysevent_t *ev, int ev_size, sysevent_id_t *eid)
1742 {
1743 int ret, copy_sz;
1744 sysevent_t *ev_copy;
1745 sysevent_id_t new_eid;
1746 log_eventq_t *qcopy;
1747
1748 copy_sz = ev_size + offsetof(log_eventq_t, arg) +
1749 offsetof(log_event_upcall_arg_t, buf);
1750 qcopy = kmem_zalloc(copy_sz, KM_SLEEP);
1751 ev_copy = (sysevent_t *)&qcopy->arg.buf;
1752
1753 /*
1754 * Copy event
1755 */
1756 if (copyin(ev, ev_copy, ev_size) == -1) {
1757 kmem_free(qcopy, copy_sz);
1758 return (EFAULT);
1759 }
1760
1761 if ((ret = queue_sysevent(ev_copy, &new_eid, SE_NOSLEEP)) != 0) {
1762 if (ret == SE_ENOMEM || ret == SE_EQSIZE)
1763 return (EAGAIN);
1764 else
1765 return (EIO);
1766 }
1767
1768 if (copyout(&new_eid, eid, sizeof (sysevent_id_t)) == -1) {
1769 return (EFAULT);
1770 }
1771
1772 return (0);
1773 }
1774
1775
1776
1777 int
ddi_log_sysevent(dev_info_t * dip,char * vendor,char * class,char * subclass,nvlist_t * attr_list,sysevent_id_t * eidp,int sleep_flag)1778 ddi_log_sysevent(
1779 dev_info_t *dip,
1780 char *vendor,
1781 char *class,
1782 char *subclass,
1783 nvlist_t *attr_list,
1784 sysevent_id_t *eidp,
1785 int sleep_flag)
1786 {
1787 sysevent_attr_list_t *list = (sysevent_attr_list_t *)attr_list;
1788 char pubstr[32];
1789 sysevent_t *event;
1790 sysevent_id_t eid;
1791 const char *drvname;
1792 char *publisher;
1793 int se_flag;
1794 int rval;
1795 int n;
1796
1797 if (sleep_flag == DDI_SLEEP && servicing_interrupt()) {
1798 cmn_err(CE_NOTE, "!ddi_log_syevent: driver %s%d - cannot queue "
1799 "event from interrupt context with sleep semantics\n",
1800 ddi_driver_name(dip), ddi_get_instance(dip));
1801 return (DDI_ECONTEXT);
1802 }
1803
1804 drvname = ddi_driver_name(dip);
1805 n = strlen(vendor) + strlen(drvname) + 7;
1806 if (n < sizeof (pubstr)) {
1807 publisher = pubstr;
1808 } else {
1809 publisher = kmem_alloc(n,
1810 (sleep_flag == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
1811 if (publisher == NULL) {
1812 return (DDI_ENOMEM);
1813 }
1814 }
1815 (void) strcpy(publisher, vendor);
1816 (void) strcat(publisher, ":kern:");
1817 (void) strcat(publisher, drvname);
1818
1819 se_flag = (sleep_flag == DDI_SLEEP) ? SE_SLEEP : SE_NOSLEEP;
1820 event = sysevent_alloc(class, subclass, publisher, se_flag);
1821
1822 if (publisher != pubstr) {
1823 kmem_free(publisher, n);
1824 }
1825
1826 if (event == NULL) {
1827 return (DDI_ENOMEM);
1828 }
1829
1830 if (list) {
1831 (void) sysevent_attach_attributes(event, list);
1832 }
1833
1834 rval = log_sysevent(event, se_flag, &eid);
1835 if (list) {
1836 sysevent_detach_attributes(event);
1837 }
1838 sysevent_free(event);
1839 if (rval == 0) {
1840 if (eidp) {
1841 eidp->eid_seq = eid.eid_seq;
1842 eidp->eid_ts = eid.eid_ts;
1843 }
1844 return (DDI_SUCCESS);
1845 }
1846 if (rval == SE_NO_TRANSPORT)
1847 return (DDI_ETRANSPORT);
1848
1849 ASSERT(rval == SE_ENOMEM || rval == SE_EQSIZE);
1850 return ((rval == SE_ENOMEM) ? DDI_ENOMEM : DDI_EBUSY);
1851 }
1852
1853 uint64_t
log_sysevent_new_id(void)1854 log_sysevent_new_id(void)
1855 {
1856 return (atomic_add_64_nv(&kernel_event_id, (uint64_t)1));
1857 }
1858