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