17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5e04145d0Seschrock * Common Development and Distribution License (the "License"). 6e04145d0Seschrock * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*f6e214c7SGavin Maltby * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate #include <sys/types.h> 267c478bd9Sstevel@tonic-gate #include <sys/errno.h> 277c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 287c478bd9Sstevel@tonic-gate #include <sys/debug.h> 297c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 307c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 317c478bd9Sstevel@tonic-gate #include <sys/vmem.h> 327c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 337c478bd9Sstevel@tonic-gate #include <sys/callb.h> 347c478bd9Sstevel@tonic-gate #include <sys/sysevent.h> 357c478bd9Sstevel@tonic-gate #include <sys/sysevent_impl.h> 367c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 377c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 387c478bd9Sstevel@tonic-gate #include <sys/disp.h> 397c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 407c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 41e04145d0Seschrock #include <sys/sdt.h> 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate /* for doors */ 447c478bd9Sstevel@tonic-gate #include <sys/pathname.h> 457c478bd9Sstevel@tonic-gate #include <sys/door.h> 467c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 477c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 487c478bd9Sstevel@tonic-gate #include <sys/fs/snode.h> 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate /* 517c478bd9Sstevel@tonic-gate * log_sysevent.c - Provides the interfaces for kernel event publication 527c478bd9Sstevel@tonic-gate * to the sysevent event daemon (syseventd). 537c478bd9Sstevel@tonic-gate */ 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate /* 567c478bd9Sstevel@tonic-gate * Debug stuff 577c478bd9Sstevel@tonic-gate */ 587c478bd9Sstevel@tonic-gate static int log_event_debug = 0; 597c478bd9Sstevel@tonic-gate #define LOG_DEBUG(args) if (log_event_debug) cmn_err args 607c478bd9Sstevel@tonic-gate #ifdef DEBUG 617c478bd9Sstevel@tonic-gate #define LOG_DEBUG1(args) if (log_event_debug > 1) cmn_err args 627c478bd9Sstevel@tonic-gate #else 637c478bd9Sstevel@tonic-gate #define LOG_DEBUG1(args) 647c478bd9Sstevel@tonic-gate #endif 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate /* 677c478bd9Sstevel@tonic-gate * Local static vars 687c478bd9Sstevel@tonic-gate */ 697c478bd9Sstevel@tonic-gate /* queue of event buffers sent to syseventd */ 707c478bd9Sstevel@tonic-gate static log_eventq_t *log_eventq_sent = NULL; 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate /* 737c478bd9Sstevel@tonic-gate * Count of event buffers in the queue 747c478bd9Sstevel@tonic-gate */ 757c478bd9Sstevel@tonic-gate int log_eventq_cnt = 0; 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate /* queue of event buffers awaiting delivery to syseventd */ 787c478bd9Sstevel@tonic-gate static log_eventq_t *log_eventq_head = NULL; 797c478bd9Sstevel@tonic-gate static log_eventq_t *log_eventq_tail = NULL; 807c478bd9Sstevel@tonic-gate static uint64_t kernel_event_id = 0; 817c478bd9Sstevel@tonic-gate static int encoding = NV_ENCODE_NATIVE; 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate /* log event delivery flag */ 847c478bd9Sstevel@tonic-gate #define LOGEVENT_DELIVERY_OK 0 /* OK to deliver event buffers */ 857c478bd9Sstevel@tonic-gate #define LOGEVENT_DELIVERY_CONT 1 /* Continue to deliver event buffers */ 867c478bd9Sstevel@tonic-gate #define LOGEVENT_DELIVERY_HOLD 2 /* Hold delivering of event buffers */ 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate /* 897c478bd9Sstevel@tonic-gate * Tunable maximum event buffer queue size. Size depends on how many events 907c478bd9Sstevel@tonic-gate * the queue must hold when syseventd is not available, for example during 917c478bd9Sstevel@tonic-gate * system startup. Experience showed that more than 2000 events could be posted 927c478bd9Sstevel@tonic-gate * due to correctable memory errors. 937c478bd9Sstevel@tonic-gate */ 947c478bd9Sstevel@tonic-gate int logevent_max_q_sz = 5000; 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate static int log_event_delivery = LOGEVENT_DELIVERY_HOLD; 987c478bd9Sstevel@tonic-gate static char *logevent_door_upcall_filename = NULL; 997c478bd9Sstevel@tonic-gate static int logevent_door_upcall_filename_size; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate static door_handle_t event_door = NULL; /* Door for upcalls */ 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate /* 1047c478bd9Sstevel@tonic-gate * async thread-related variables 1057c478bd9Sstevel@tonic-gate * 1067c478bd9Sstevel@tonic-gate * eventq_head_mutex - synchronizes access to the kernel event queue 1077c478bd9Sstevel@tonic-gate * 1087c478bd9Sstevel@tonic-gate * eventq_sent_mutex - synchronizes access to the queue of event sents to 1097c478bd9Sstevel@tonic-gate * userlevel 1107c478bd9Sstevel@tonic-gate * 1117c478bd9Sstevel@tonic-gate * log_event_cv - condition variable signaled when an event has arrived or 1127c478bd9Sstevel@tonic-gate * userlevel ready to process event buffers 1137c478bd9Sstevel@tonic-gate * 1147c478bd9Sstevel@tonic-gate * async_thread - asynchronous event delivery thread to userlevel daemon. 1157c478bd9Sstevel@tonic-gate * 1167c478bd9Sstevel@tonic-gate * sysevent_upcall_status - status of the door upcall link 1177c478bd9Sstevel@tonic-gate */ 1187c478bd9Sstevel@tonic-gate static kmutex_t eventq_head_mutex; 1197c478bd9Sstevel@tonic-gate static kmutex_t eventq_sent_mutex; 1207c478bd9Sstevel@tonic-gate static kcondvar_t log_event_cv; 1217c478bd9Sstevel@tonic-gate static kthread_id_t async_thread = NULL; 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate static kmutex_t event_qfull_mutex; 1247c478bd9Sstevel@tonic-gate static kcondvar_t event_qfull_cv; 1257c478bd9Sstevel@tonic-gate static int event_qfull_blocked = 0; 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate static int sysevent_upcall_status = -1; 1287c478bd9Sstevel@tonic-gate static kmutex_t registered_channel_mutex; 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate /* 1317c478bd9Sstevel@tonic-gate * Indicates the syseventd daemon has begun taking events 1327c478bd9Sstevel@tonic-gate */ 1337c478bd9Sstevel@tonic-gate int sysevent_daemon_init = 0; 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate /* 1367c478bd9Sstevel@tonic-gate * Back-off delay when door_ki_upcall returns EAGAIN. Typically 1377c478bd9Sstevel@tonic-gate * caused by the server process doing a forkall(). Since all threads 1387c478bd9Sstevel@tonic-gate * but the thread actually doing the forkall() need to be quiesced, 1397c478bd9Sstevel@tonic-gate * the fork may take some time. The min/max pause are in units 1407c478bd9Sstevel@tonic-gate * of clock ticks. 1417c478bd9Sstevel@tonic-gate */ 1427c478bd9Sstevel@tonic-gate #define LOG_EVENT_MIN_PAUSE 8 1437c478bd9Sstevel@tonic-gate #define LOG_EVENT_MAX_PAUSE 128 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate static kmutex_t event_pause_mutex; 1467c478bd9Sstevel@tonic-gate static kcondvar_t event_pause_cv; 1477c478bd9Sstevel@tonic-gate static int event_pause_state = 0; 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate /* 1507c478bd9Sstevel@tonic-gate * log_event_upcall_lookup - Establish door connection with user event 1517c478bd9Sstevel@tonic-gate * daemon (syseventd) 1527c478bd9Sstevel@tonic-gate */ 1537c478bd9Sstevel@tonic-gate static int 1547c478bd9Sstevel@tonic-gate log_event_upcall_lookup() 1557c478bd9Sstevel@tonic-gate { 1567c478bd9Sstevel@tonic-gate int error; 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate if (event_door) { /* Release our previous hold (if any) */ 1597c478bd9Sstevel@tonic-gate door_ki_rele(event_door); 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate event_door = NULL; 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate /* 1657c478bd9Sstevel@tonic-gate * Locate the door used for upcalls 1667c478bd9Sstevel@tonic-gate */ 1677c478bd9Sstevel@tonic-gate if ((error = 1687c478bd9Sstevel@tonic-gate door_ki_open(logevent_door_upcall_filename, &event_door)) != 0) { 1697c478bd9Sstevel@tonic-gate return (error); 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate return (0); 1737c478bd9Sstevel@tonic-gate } 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1777c478bd9Sstevel@tonic-gate static void 1787c478bd9Sstevel@tonic-gate log_event_busy_timeout(void *arg) 1797c478bd9Sstevel@tonic-gate { 1807c478bd9Sstevel@tonic-gate mutex_enter(&event_pause_mutex); 1817c478bd9Sstevel@tonic-gate event_pause_state = 0; 1827c478bd9Sstevel@tonic-gate cv_signal(&event_pause_cv); 1837c478bd9Sstevel@tonic-gate mutex_exit(&event_pause_mutex); 1847c478bd9Sstevel@tonic-gate } 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate static void 1877c478bd9Sstevel@tonic-gate log_event_pause(int nticks) 1887c478bd9Sstevel@tonic-gate { 1897c478bd9Sstevel@tonic-gate timeout_id_t id; 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate /* 1927c478bd9Sstevel@tonic-gate * Only one use of log_event_pause at a time 1937c478bd9Sstevel@tonic-gate */ 1947c478bd9Sstevel@tonic-gate ASSERT(event_pause_state == 0); 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate event_pause_state = 1; 1977c478bd9Sstevel@tonic-gate id = timeout(log_event_busy_timeout, NULL, nticks); 1987c478bd9Sstevel@tonic-gate if (id != 0) { 1997c478bd9Sstevel@tonic-gate mutex_enter(&event_pause_mutex); 2007c478bd9Sstevel@tonic-gate while (event_pause_state) 2017c478bd9Sstevel@tonic-gate cv_wait(&event_pause_cv, &event_pause_mutex); 2027c478bd9Sstevel@tonic-gate mutex_exit(&event_pause_mutex); 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate event_pause_state = 0; 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate /* 2097c478bd9Sstevel@tonic-gate * log_event_upcall - Perform the upcall to syseventd for event buffer delivery. 2107c478bd9Sstevel@tonic-gate * Check for rebinding errors 2117c478bd9Sstevel@tonic-gate * This buffer is reused to by the syseventd door_return 2127c478bd9Sstevel@tonic-gate * to hold the result code 2137c478bd9Sstevel@tonic-gate */ 2147c478bd9Sstevel@tonic-gate static int 2157c478bd9Sstevel@tonic-gate log_event_upcall(log_event_upcall_arg_t *arg) 2167c478bd9Sstevel@tonic-gate { 2177c478bd9Sstevel@tonic-gate int error; 2187c478bd9Sstevel@tonic-gate size_t size; 2197c478bd9Sstevel@tonic-gate sysevent_t *ev; 2207c478bd9Sstevel@tonic-gate door_arg_t darg, save_arg; 2217c478bd9Sstevel@tonic-gate int retry; 2227c478bd9Sstevel@tonic-gate int neagain = 0; 2237c478bd9Sstevel@tonic-gate int neintr = 0; 2247c478bd9Sstevel@tonic-gate int nticks = LOG_EVENT_MIN_PAUSE; 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate /* Initialize door args */ 2277c478bd9Sstevel@tonic-gate ev = (sysevent_t *)&arg->buf; 2287c478bd9Sstevel@tonic-gate size = sizeof (log_event_upcall_arg_t) + SE_PAYLOAD_SZ(ev); 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate darg.rbuf = (char *)arg; 2317c478bd9Sstevel@tonic-gate darg.data_ptr = (char *)arg; 2327c478bd9Sstevel@tonic-gate darg.rsize = size; 2337c478bd9Sstevel@tonic-gate darg.data_size = size; 2347c478bd9Sstevel@tonic-gate darg.desc_ptr = NULL; 2357c478bd9Sstevel@tonic-gate darg.desc_num = 0; 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate if ((event_door == NULL) && 2387c478bd9Sstevel@tonic-gate ((error = log_event_upcall_lookup()) != 0)) { 2397c478bd9Sstevel@tonic-gate LOG_DEBUG((CE_CONT, 2407c478bd9Sstevel@tonic-gate "log_event_upcall: event_door error (%d)\n", error)); 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate return (error); 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate LOG_DEBUG1((CE_CONT, "log_event_upcall: 0x%llx\n", 2467c478bd9Sstevel@tonic-gate (longlong_t)SE_SEQ((sysevent_t *)&arg->buf))); 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate save_arg = darg; 2497c478bd9Sstevel@tonic-gate for (retry = 0; ; retry++) { 250323a81d9Sjwadams if ((error = door_ki_upcall_limited(event_door, &darg, NULL, 251323a81d9Sjwadams SIZE_MAX, 0)) == 0) { 2527c478bd9Sstevel@tonic-gate break; 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate switch (error) { 2557c478bd9Sstevel@tonic-gate case EINTR: 2567c478bd9Sstevel@tonic-gate neintr++; 2577c478bd9Sstevel@tonic-gate log_event_pause(2); 2587c478bd9Sstevel@tonic-gate darg = save_arg; 2597c478bd9Sstevel@tonic-gate break; 2607c478bd9Sstevel@tonic-gate case EAGAIN: 2617c478bd9Sstevel@tonic-gate /* cannot deliver upcall - process may be forking */ 2627c478bd9Sstevel@tonic-gate neagain++; 2637c478bd9Sstevel@tonic-gate log_event_pause(nticks); 2647c478bd9Sstevel@tonic-gate nticks <<= 1; 2657c478bd9Sstevel@tonic-gate if (nticks > LOG_EVENT_MAX_PAUSE) 2667c478bd9Sstevel@tonic-gate nticks = LOG_EVENT_MAX_PAUSE; 2677c478bd9Sstevel@tonic-gate darg = save_arg; 2687c478bd9Sstevel@tonic-gate break; 2697c478bd9Sstevel@tonic-gate case EBADF: 2707c478bd9Sstevel@tonic-gate LOG_DEBUG((CE_CONT, "log_event_upcall: rebinding\n")); 2717c478bd9Sstevel@tonic-gate /* Server may have died. Try rebinding */ 2727c478bd9Sstevel@tonic-gate if ((error = log_event_upcall_lookup()) != 0) { 2737c478bd9Sstevel@tonic-gate LOG_DEBUG((CE_CONT, 2747c478bd9Sstevel@tonic-gate "log_event_upcall: lookup error %d\n", 2757c478bd9Sstevel@tonic-gate error)); 2767c478bd9Sstevel@tonic-gate return (EBADF); 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate if (retry > 4) { 2797c478bd9Sstevel@tonic-gate LOG_DEBUG((CE_CONT, 280*f6e214c7SGavin Maltby "log_event_upcall: ebadf\n")); 2817c478bd9Sstevel@tonic-gate return (EBADF); 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate LOG_DEBUG((CE_CONT, "log_event_upcall: " 284*f6e214c7SGavin Maltby "retrying upcall after lookup\n")); 2857c478bd9Sstevel@tonic-gate darg = save_arg; 2867c478bd9Sstevel@tonic-gate break; 2877c478bd9Sstevel@tonic-gate default: 2887c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 2897c478bd9Sstevel@tonic-gate "log_event_upcall: door_ki_upcall error %d\n", 2907c478bd9Sstevel@tonic-gate error); 2917c478bd9Sstevel@tonic-gate return (error); 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate if (neagain > 0 || neintr > 0) { 2967c478bd9Sstevel@tonic-gate LOG_DEBUG((CE_CONT, "upcall: eagain=%d eintr=%d nticks=%d\n", 297*f6e214c7SGavin Maltby neagain, neintr, nticks)); 2987c478bd9Sstevel@tonic-gate } 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate LOG_DEBUG1((CE_CONT, "log_event_upcall:\n\t" 301*f6e214c7SGavin Maltby "error=%d rptr1=%p rptr2=%p dptr2=%p ret1=%x ret2=%x\n", 302*f6e214c7SGavin Maltby error, (void *)arg, (void *)darg.rbuf, 303*f6e214c7SGavin Maltby (void *)darg.data_ptr, 304*f6e214c7SGavin Maltby *((int *)(darg.rbuf)), *((int *)(darg.data_ptr)))); 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate if (!error) { 3077c478bd9Sstevel@tonic-gate /* 3087c478bd9Sstevel@tonic-gate * upcall was successfully executed. Check return code. 3097c478bd9Sstevel@tonic-gate */ 3107c478bd9Sstevel@tonic-gate error = *((int *)(darg.rbuf)); 3117c478bd9Sstevel@tonic-gate } 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate return (error); 3147c478bd9Sstevel@tonic-gate } 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate /* 3177c478bd9Sstevel@tonic-gate * log_event_deliver - event delivery thread 3187c478bd9Sstevel@tonic-gate * Deliver all events on the event queue to syseventd. 3197c478bd9Sstevel@tonic-gate * If the daemon can not process events, stop event 3207c478bd9Sstevel@tonic-gate * delivery and wait for an indication from the 3217c478bd9Sstevel@tonic-gate * daemon to resume delivery. 3227c478bd9Sstevel@tonic-gate * 3237c478bd9Sstevel@tonic-gate * Once all event buffers have been delivered, wait 3247c478bd9Sstevel@tonic-gate * until there are more to deliver. 3257c478bd9Sstevel@tonic-gate */ 3267c478bd9Sstevel@tonic-gate static void 3277c478bd9Sstevel@tonic-gate log_event_deliver() 3287c478bd9Sstevel@tonic-gate { 3297c478bd9Sstevel@tonic-gate log_eventq_t *q; 3307c478bd9Sstevel@tonic-gate int upcall_err; 3317c478bd9Sstevel@tonic-gate callb_cpr_t cprinfo; 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate CALLB_CPR_INIT(&cprinfo, &eventq_head_mutex, callb_generic_cpr, 334*f6e214c7SGavin Maltby "logevent"); 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate /* 3377c478bd9Sstevel@tonic-gate * eventq_head_mutex is exited (released) when there are no more 3387c478bd9Sstevel@tonic-gate * events to process from the eventq in cv_wait(). 3397c478bd9Sstevel@tonic-gate */ 3407c478bd9Sstevel@tonic-gate mutex_enter(&eventq_head_mutex); 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate for (;;) { 3437c478bd9Sstevel@tonic-gate LOG_DEBUG1((CE_CONT, "log_event_deliver: head = %p\n", 3447c478bd9Sstevel@tonic-gate (void *)log_eventq_head)); 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate upcall_err = 0; 3477c478bd9Sstevel@tonic-gate q = log_eventq_head; 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate while (q) { 3507c478bd9Sstevel@tonic-gate log_eventq_t *next; 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate /* 3537c478bd9Sstevel@tonic-gate * Release event queue lock during upcall to 3547c478bd9Sstevel@tonic-gate * syseventd 3557c478bd9Sstevel@tonic-gate */ 3567c478bd9Sstevel@tonic-gate if (log_event_delivery == LOGEVENT_DELIVERY_HOLD) { 3577c478bd9Sstevel@tonic-gate upcall_err = EAGAIN; 3587c478bd9Sstevel@tonic-gate break; 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate mutex_exit(&eventq_head_mutex); 3627c478bd9Sstevel@tonic-gate if ((upcall_err = log_event_upcall(&q->arg)) != 0) { 3637c478bd9Sstevel@tonic-gate mutex_enter(&eventq_head_mutex); 3647c478bd9Sstevel@tonic-gate break; 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate /* 3687c478bd9Sstevel@tonic-gate * We may be able to add entries to 3697c478bd9Sstevel@tonic-gate * the queue now. 3707c478bd9Sstevel@tonic-gate */ 3717c478bd9Sstevel@tonic-gate if (event_qfull_blocked > 0 && 3727c478bd9Sstevel@tonic-gate log_eventq_cnt < logevent_max_q_sz) { 3737c478bd9Sstevel@tonic-gate mutex_enter(&event_qfull_mutex); 3747c478bd9Sstevel@tonic-gate if (event_qfull_blocked > 0) { 3757c478bd9Sstevel@tonic-gate cv_signal(&event_qfull_cv); 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate mutex_exit(&event_qfull_mutex); 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate mutex_enter(&eventq_head_mutex); 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate /* 3837c478bd9Sstevel@tonic-gate * Daemon restart can cause entries to be moved from 3847c478bd9Sstevel@tonic-gate * the sent queue and put back on the event queue. 3857c478bd9Sstevel@tonic-gate * If this has occurred, replay event queue 3867c478bd9Sstevel@tonic-gate * processing from the new queue head. 3877c478bd9Sstevel@tonic-gate */ 3887c478bd9Sstevel@tonic-gate if (q != log_eventq_head) { 3897c478bd9Sstevel@tonic-gate q = log_eventq_head; 3907c478bd9Sstevel@tonic-gate LOG_DEBUG((CE_CONT, "log_event_deliver: " 3917c478bd9Sstevel@tonic-gate "door upcall/daemon restart race\n")); 3927c478bd9Sstevel@tonic-gate } else { 3937c478bd9Sstevel@tonic-gate /* 3947c478bd9Sstevel@tonic-gate * Move the event to the sent queue when a 3957c478bd9Sstevel@tonic-gate * successful delivery has been made. 3967c478bd9Sstevel@tonic-gate */ 3977c478bd9Sstevel@tonic-gate mutex_enter(&eventq_sent_mutex); 3987c478bd9Sstevel@tonic-gate next = q->next; 3997c478bd9Sstevel@tonic-gate q->next = log_eventq_sent; 4007c478bd9Sstevel@tonic-gate log_eventq_sent = q; 4017c478bd9Sstevel@tonic-gate q = next; 4027c478bd9Sstevel@tonic-gate log_eventq_head = q; 4037c478bd9Sstevel@tonic-gate log_eventq_cnt--; 4047c478bd9Sstevel@tonic-gate if (q == NULL) { 4057c478bd9Sstevel@tonic-gate ASSERT(log_eventq_cnt == 0); 4067c478bd9Sstevel@tonic-gate log_eventq_tail = NULL; 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate mutex_exit(&eventq_sent_mutex); 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate } 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate switch (upcall_err) { 4137c478bd9Sstevel@tonic-gate case 0: 4147c478bd9Sstevel@tonic-gate /* 4157c478bd9Sstevel@tonic-gate * Success. The queue is empty. 4167c478bd9Sstevel@tonic-gate */ 4177c478bd9Sstevel@tonic-gate sysevent_upcall_status = 0; 4187c478bd9Sstevel@tonic-gate break; 4197c478bd9Sstevel@tonic-gate case EAGAIN: 4207c478bd9Sstevel@tonic-gate /* 4217c478bd9Sstevel@tonic-gate * Delivery is on hold (but functional). 4227c478bd9Sstevel@tonic-gate */ 4237c478bd9Sstevel@tonic-gate sysevent_upcall_status = 0; 4247c478bd9Sstevel@tonic-gate /* 4257c478bd9Sstevel@tonic-gate * If the user has already signaled for delivery 4267c478bd9Sstevel@tonic-gate * resumption, continue. Otherwise, we wait until 4277c478bd9Sstevel@tonic-gate * we are signaled to continue. 4287c478bd9Sstevel@tonic-gate */ 4297c478bd9Sstevel@tonic-gate if (log_event_delivery == LOGEVENT_DELIVERY_CONT) { 4307c478bd9Sstevel@tonic-gate log_event_delivery = LOGEVENT_DELIVERY_OK; 4317c478bd9Sstevel@tonic-gate continue; 4327c478bd9Sstevel@tonic-gate } else { 4337c478bd9Sstevel@tonic-gate log_event_delivery = LOGEVENT_DELIVERY_HOLD; 4347c478bd9Sstevel@tonic-gate } 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate LOG_DEBUG1((CE_CONT, "log_event_deliver: EAGAIN\n")); 4377c478bd9Sstevel@tonic-gate break; 4387c478bd9Sstevel@tonic-gate default: 4397c478bd9Sstevel@tonic-gate LOG_DEBUG((CE_CONT, "log_event_deliver: " 440*f6e214c7SGavin Maltby "upcall err %d\n", upcall_err)); 4417c478bd9Sstevel@tonic-gate sysevent_upcall_status = upcall_err; 4427c478bd9Sstevel@tonic-gate /* 4437c478bd9Sstevel@tonic-gate * Signal everyone waiting that transport is down 4447c478bd9Sstevel@tonic-gate */ 4457c478bd9Sstevel@tonic-gate if (event_qfull_blocked > 0) { 4467c478bd9Sstevel@tonic-gate mutex_enter(&event_qfull_mutex); 4477c478bd9Sstevel@tonic-gate if (event_qfull_blocked > 0) { 4487c478bd9Sstevel@tonic-gate cv_broadcast(&event_qfull_cv); 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate mutex_exit(&event_qfull_mutex); 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate break; 4537c478bd9Sstevel@tonic-gate } 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cprinfo); 4567c478bd9Sstevel@tonic-gate cv_wait(&log_event_cv, &eventq_head_mutex); 4577c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_END(&cprinfo, &eventq_head_mutex); 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4607c478bd9Sstevel@tonic-gate } 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate /* 4637c478bd9Sstevel@tonic-gate * log_event_init - Allocate and initialize log_event data structures. 4647c478bd9Sstevel@tonic-gate */ 4657c478bd9Sstevel@tonic-gate void 4667c478bd9Sstevel@tonic-gate log_event_init() 4677c478bd9Sstevel@tonic-gate { 4687c478bd9Sstevel@tonic-gate mutex_init(&eventq_head_mutex, NULL, MUTEX_DEFAULT, NULL); 4697c478bd9Sstevel@tonic-gate mutex_init(&eventq_sent_mutex, NULL, MUTEX_DEFAULT, NULL); 4707c478bd9Sstevel@tonic-gate cv_init(&log_event_cv, NULL, CV_DEFAULT, NULL); 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate mutex_init(&event_qfull_mutex, NULL, MUTEX_DEFAULT, NULL); 4737c478bd9Sstevel@tonic-gate cv_init(&event_qfull_cv, NULL, CV_DEFAULT, NULL); 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate mutex_init(&event_pause_mutex, NULL, MUTEX_DEFAULT, NULL); 4767c478bd9Sstevel@tonic-gate cv_init(&event_pause_cv, NULL, CV_DEFAULT, NULL); 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate mutex_init(®istered_channel_mutex, NULL, MUTEX_DEFAULT, NULL); 4797c478bd9Sstevel@tonic-gate sysevent_evc_init(); 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate /* 4837c478bd9Sstevel@tonic-gate * The following routines are used by kernel event publishers to 4847c478bd9Sstevel@tonic-gate * allocate, append and free event buffers 4857c478bd9Sstevel@tonic-gate */ 4867c478bd9Sstevel@tonic-gate /* 4877c478bd9Sstevel@tonic-gate * sysevent_alloc - Allocate new eventq struct. This element contains 4887c478bd9Sstevel@tonic-gate * an event buffer that will be used in a subsequent 4897c478bd9Sstevel@tonic-gate * call to log_sysevent. 4907c478bd9Sstevel@tonic-gate */ 4917c478bd9Sstevel@tonic-gate sysevent_t * 4927c478bd9Sstevel@tonic-gate sysevent_alloc(char *class, char *subclass, char *pub, int flag) 4937c478bd9Sstevel@tonic-gate { 4947c478bd9Sstevel@tonic-gate int payload_sz; 4957c478bd9Sstevel@tonic-gate int class_sz, subclass_sz, pub_sz; 4967c478bd9Sstevel@tonic-gate int aligned_class_sz, aligned_subclass_sz, aligned_pub_sz; 4977c478bd9Sstevel@tonic-gate sysevent_t *ev; 4987c478bd9Sstevel@tonic-gate log_eventq_t *q; 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate ASSERT(class != NULL); 5017c478bd9Sstevel@tonic-gate ASSERT(subclass != NULL); 5027c478bd9Sstevel@tonic-gate ASSERT(pub != NULL); 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate /* 5057c478bd9Sstevel@tonic-gate * Calculate and reserve space for the class, subclass and 5067c478bd9Sstevel@tonic-gate * publisher strings in the event buffer 5077c478bd9Sstevel@tonic-gate */ 5087c478bd9Sstevel@tonic-gate class_sz = strlen(class) + 1; 5097c478bd9Sstevel@tonic-gate subclass_sz = strlen(subclass) + 1; 5107c478bd9Sstevel@tonic-gate pub_sz = strlen(pub) + 1; 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate ASSERT((class_sz <= MAX_CLASS_LEN) && (subclass_sz 5137c478bd9Sstevel@tonic-gate <= MAX_SUBCLASS_LEN) && (pub_sz <= MAX_PUB_LEN)); 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate /* String sizes must be 64-bit aligned in the event buffer */ 5167c478bd9Sstevel@tonic-gate aligned_class_sz = SE_ALIGN(class_sz); 5177c478bd9Sstevel@tonic-gate aligned_subclass_sz = SE_ALIGN(subclass_sz); 5187c478bd9Sstevel@tonic-gate aligned_pub_sz = SE_ALIGN(pub_sz); 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate payload_sz = (aligned_class_sz - sizeof (uint64_t)) + 521*f6e214c7SGavin Maltby (aligned_subclass_sz - sizeof (uint64_t)) + 522*f6e214c7SGavin Maltby (aligned_pub_sz - sizeof (uint64_t)) - sizeof (uint64_t); 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate /* 5257c478bd9Sstevel@tonic-gate * Allocate event buffer plus additional sysevent queue 5267c478bd9Sstevel@tonic-gate * and payload overhead. 5277c478bd9Sstevel@tonic-gate */ 5287c478bd9Sstevel@tonic-gate q = kmem_zalloc(sizeof (log_eventq_t) + payload_sz, flag); 5297c478bd9Sstevel@tonic-gate if (q == NULL) { 5307c478bd9Sstevel@tonic-gate return (NULL); 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate /* Initialize the event buffer data */ 5347c478bd9Sstevel@tonic-gate ev = (sysevent_t *)&q->arg.buf; 5357c478bd9Sstevel@tonic-gate SE_VERSION(ev) = SYS_EVENT_VERSION; 5367c478bd9Sstevel@tonic-gate bcopy(class, SE_CLASS_NAME(ev), class_sz); 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate SE_SUBCLASS_OFF(ev) = SE_ALIGN(offsetof(sysevent_impl_t, se_class_name)) 5397c478bd9Sstevel@tonic-gate + aligned_class_sz; 5407c478bd9Sstevel@tonic-gate bcopy(subclass, SE_SUBCLASS_NAME(ev), subclass_sz); 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate SE_PUB_OFF(ev) = SE_SUBCLASS_OFF(ev) + aligned_subclass_sz; 5437c478bd9Sstevel@tonic-gate bcopy(pub, SE_PUB_NAME(ev), pub_sz); 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate SE_ATTR_PTR(ev) = UINT64_C(0); 5467c478bd9Sstevel@tonic-gate SE_PAYLOAD_SZ(ev) = payload_sz; 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate return (ev); 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate /* 5527c478bd9Sstevel@tonic-gate * sysevent_free - Free event buffer and any attribute data. 5537c478bd9Sstevel@tonic-gate */ 5547c478bd9Sstevel@tonic-gate void 5557c478bd9Sstevel@tonic-gate sysevent_free(sysevent_t *ev) 5567c478bd9Sstevel@tonic-gate { 5577c478bd9Sstevel@tonic-gate log_eventq_t *q; 5587c478bd9Sstevel@tonic-gate nvlist_t *nvl; 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate ASSERT(ev != NULL); 5617c478bd9Sstevel@tonic-gate q = (log_eventq_t *)((caddr_t)ev - offsetof(log_eventq_t, arg.buf)); 5627c478bd9Sstevel@tonic-gate nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev); 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate if (nvl != NULL) { 5657c478bd9Sstevel@tonic-gate size_t size = 0; 5667c478bd9Sstevel@tonic-gate (void) nvlist_size(nvl, &size, encoding); 5677c478bd9Sstevel@tonic-gate SE_PAYLOAD_SZ(ev) -= size; 5687c478bd9Sstevel@tonic-gate nvlist_free(nvl); 5697c478bd9Sstevel@tonic-gate } 5707c478bd9Sstevel@tonic-gate kmem_free(q, sizeof (log_eventq_t) + SE_PAYLOAD_SZ(ev)); 5717c478bd9Sstevel@tonic-gate } 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate /* 5747c478bd9Sstevel@tonic-gate * free_packed_event - Free packed event buffer 5757c478bd9Sstevel@tonic-gate */ 5767c478bd9Sstevel@tonic-gate static void 5777c478bd9Sstevel@tonic-gate free_packed_event(sysevent_t *ev) 5787c478bd9Sstevel@tonic-gate { 5797c478bd9Sstevel@tonic-gate log_eventq_t *q; 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate ASSERT(ev != NULL); 5827c478bd9Sstevel@tonic-gate q = (log_eventq_t *)((caddr_t)ev - offsetof(log_eventq_t, arg.buf)); 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate kmem_free(q, sizeof (log_eventq_t) + SE_PAYLOAD_SZ(ev)); 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate /* 5887c478bd9Sstevel@tonic-gate * sysevent_add_attr - Add new attribute element to an event attribute list 5897c478bd9Sstevel@tonic-gate * If attribute list is NULL, start a new list. 5907c478bd9Sstevel@tonic-gate */ 5917c478bd9Sstevel@tonic-gate int 5927c478bd9Sstevel@tonic-gate sysevent_add_attr(sysevent_attr_list_t **ev_attr_list, char *name, 5937c478bd9Sstevel@tonic-gate sysevent_value_t *se_value, int flag) 5947c478bd9Sstevel@tonic-gate { 5957c478bd9Sstevel@tonic-gate int error; 5967c478bd9Sstevel@tonic-gate nvlist_t **nvlp = (nvlist_t **)ev_attr_list; 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate if (nvlp == NULL || se_value == NULL) { 5997c478bd9Sstevel@tonic-gate return (SE_EINVAL); 6007c478bd9Sstevel@tonic-gate } 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate /* 6037c478bd9Sstevel@tonic-gate * attr_sz is composed of the value data size + the name data size + 6047c478bd9Sstevel@tonic-gate * any header data. 64-bit aligned. 6057c478bd9Sstevel@tonic-gate */ 6067c478bd9Sstevel@tonic-gate if (strlen(name) >= MAX_ATTR_NAME) { 6077c478bd9Sstevel@tonic-gate return (SE_EINVAL); 6087c478bd9Sstevel@tonic-gate } 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate /* 6117c478bd9Sstevel@tonic-gate * Allocate nvlist 6127c478bd9Sstevel@tonic-gate */ 6137c478bd9Sstevel@tonic-gate if ((*nvlp == NULL) && 6147c478bd9Sstevel@tonic-gate (nvlist_alloc(nvlp, NV_UNIQUE_NAME_TYPE, flag) != 0)) 6157c478bd9Sstevel@tonic-gate return (SE_ENOMEM); 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate /* add the attribute */ 6187c478bd9Sstevel@tonic-gate switch (se_value->value_type) { 6197c478bd9Sstevel@tonic-gate case SE_DATA_TYPE_BYTE: 6207c478bd9Sstevel@tonic-gate error = nvlist_add_byte(*ev_attr_list, name, 6217c478bd9Sstevel@tonic-gate se_value->value.sv_byte); 6227c478bd9Sstevel@tonic-gate break; 6237c478bd9Sstevel@tonic-gate case SE_DATA_TYPE_INT16: 6247c478bd9Sstevel@tonic-gate error = nvlist_add_int16(*ev_attr_list, name, 6257c478bd9Sstevel@tonic-gate se_value->value.sv_int16); 6267c478bd9Sstevel@tonic-gate break; 6277c478bd9Sstevel@tonic-gate case SE_DATA_TYPE_UINT16: 6287c478bd9Sstevel@tonic-gate error = nvlist_add_uint16(*ev_attr_list, name, 6297c478bd9Sstevel@tonic-gate se_value->value.sv_uint16); 6307c478bd9Sstevel@tonic-gate break; 6317c478bd9Sstevel@tonic-gate case SE_DATA_TYPE_INT32: 6327c478bd9Sstevel@tonic-gate error = nvlist_add_int32(*ev_attr_list, name, 6337c478bd9Sstevel@tonic-gate se_value->value.sv_int32); 6347c478bd9Sstevel@tonic-gate break; 6357c478bd9Sstevel@tonic-gate case SE_DATA_TYPE_UINT32: 6367c478bd9Sstevel@tonic-gate error = nvlist_add_uint32(*ev_attr_list, name, 6377c478bd9Sstevel@tonic-gate se_value->value.sv_uint32); 6387c478bd9Sstevel@tonic-gate break; 6397c478bd9Sstevel@tonic-gate case SE_DATA_TYPE_INT64: 6407c478bd9Sstevel@tonic-gate error = nvlist_add_int64(*ev_attr_list, name, 6417c478bd9Sstevel@tonic-gate se_value->value.sv_int64); 6427c478bd9Sstevel@tonic-gate break; 6437c478bd9Sstevel@tonic-gate case SE_DATA_TYPE_UINT64: 6447c478bd9Sstevel@tonic-gate error = nvlist_add_uint64(*ev_attr_list, name, 6457c478bd9Sstevel@tonic-gate se_value->value.sv_uint64); 6467c478bd9Sstevel@tonic-gate break; 6477c478bd9Sstevel@tonic-gate case SE_DATA_TYPE_STRING: 6487c478bd9Sstevel@tonic-gate if (strlen((char *)se_value->value.sv_string) >= MAX_STRING_SZ) 6497c478bd9Sstevel@tonic-gate return (SE_EINVAL); 6507c478bd9Sstevel@tonic-gate error = nvlist_add_string(*ev_attr_list, name, 6517c478bd9Sstevel@tonic-gate se_value->value.sv_string); 6527c478bd9Sstevel@tonic-gate break; 6537c478bd9Sstevel@tonic-gate case SE_DATA_TYPE_BYTES: 6547c478bd9Sstevel@tonic-gate if (se_value->value.sv_bytes.size > MAX_BYTE_ARRAY) 6557c478bd9Sstevel@tonic-gate return (SE_EINVAL); 6567c478bd9Sstevel@tonic-gate error = nvlist_add_byte_array(*ev_attr_list, name, 6577c478bd9Sstevel@tonic-gate se_value->value.sv_bytes.data, 6587c478bd9Sstevel@tonic-gate se_value->value.sv_bytes.size); 6597c478bd9Sstevel@tonic-gate break; 6607c478bd9Sstevel@tonic-gate case SE_DATA_TYPE_TIME: 6617c478bd9Sstevel@tonic-gate error = nvlist_add_hrtime(*ev_attr_list, name, 6627c478bd9Sstevel@tonic-gate se_value->value.sv_time); 6637c478bd9Sstevel@tonic-gate break; 6647c478bd9Sstevel@tonic-gate default: 6657c478bd9Sstevel@tonic-gate return (SE_EINVAL); 6667c478bd9Sstevel@tonic-gate } 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate return (error ? SE_ENOMEM : 0); 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate /* 6727c478bd9Sstevel@tonic-gate * sysevent_free_attr - Free an attribute list not associated with an 6737c478bd9Sstevel@tonic-gate * event buffer. 6747c478bd9Sstevel@tonic-gate */ 6757c478bd9Sstevel@tonic-gate void 6767c478bd9Sstevel@tonic-gate sysevent_free_attr(sysevent_attr_list_t *ev_attr_list) 6777c478bd9Sstevel@tonic-gate { 6787c478bd9Sstevel@tonic-gate nvlist_free((nvlist_t *)ev_attr_list); 6797c478bd9Sstevel@tonic-gate } 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate /* 6827c478bd9Sstevel@tonic-gate * sysevent_attach_attributes - Attach an attribute list to an event buffer. 6837c478bd9Sstevel@tonic-gate * 6847c478bd9Sstevel@tonic-gate * This data will be re-packed into contiguous memory when the event 6857c478bd9Sstevel@tonic-gate * buffer is posted to log_sysevent. 6867c478bd9Sstevel@tonic-gate */ 6877c478bd9Sstevel@tonic-gate int 6887c478bd9Sstevel@tonic-gate sysevent_attach_attributes(sysevent_t *ev, sysevent_attr_list_t *ev_attr_list) 6897c478bd9Sstevel@tonic-gate { 6907c478bd9Sstevel@tonic-gate size_t size = 0; 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate if (SE_ATTR_PTR(ev) != UINT64_C(0)) { 6937c478bd9Sstevel@tonic-gate return (SE_EINVAL); 6947c478bd9Sstevel@tonic-gate } 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate SE_ATTR_PTR(ev) = (uintptr_t)ev_attr_list; 6977c478bd9Sstevel@tonic-gate (void) nvlist_size((nvlist_t *)ev_attr_list, &size, encoding); 6987c478bd9Sstevel@tonic-gate SE_PAYLOAD_SZ(ev) += size; 6997c478bd9Sstevel@tonic-gate SE_FLAG(ev) = 0; 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate return (0); 7027c478bd9Sstevel@tonic-gate } 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate /* 7057c478bd9Sstevel@tonic-gate * sysevent_detach_attributes - Detach but don't free attribute list from the 7067c478bd9Sstevel@tonic-gate * event buffer. 7077c478bd9Sstevel@tonic-gate */ 7087c478bd9Sstevel@tonic-gate void 7097c478bd9Sstevel@tonic-gate sysevent_detach_attributes(sysevent_t *ev) 7107c478bd9Sstevel@tonic-gate { 7117c478bd9Sstevel@tonic-gate size_t size = 0; 7127c478bd9Sstevel@tonic-gate nvlist_t *nvl; 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate if ((nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev)) == NULL) { 7157c478bd9Sstevel@tonic-gate return; 7167c478bd9Sstevel@tonic-gate } 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate SE_ATTR_PTR(ev) = UINT64_C(0); 7197c478bd9Sstevel@tonic-gate (void) nvlist_size(nvl, &size, encoding); 7207c478bd9Sstevel@tonic-gate SE_PAYLOAD_SZ(ev) -= size; 7217c478bd9Sstevel@tonic-gate ASSERT(SE_PAYLOAD_SZ(ev) >= 0); 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate /* 7257c478bd9Sstevel@tonic-gate * sysevent_attr_name - Get name of attribute 7267c478bd9Sstevel@tonic-gate */ 7277c478bd9Sstevel@tonic-gate char * 7287c478bd9Sstevel@tonic-gate sysevent_attr_name(sysevent_attr_t *attr) 7297c478bd9Sstevel@tonic-gate { 7307c478bd9Sstevel@tonic-gate if (attr == NULL) { 7317c478bd9Sstevel@tonic-gate return (NULL); 7327c478bd9Sstevel@tonic-gate } 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate return (nvpair_name(attr)); 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate /* 7387c478bd9Sstevel@tonic-gate * sysevent_attr_type - Get type of attribute 7397c478bd9Sstevel@tonic-gate */ 7407c478bd9Sstevel@tonic-gate int 7417c478bd9Sstevel@tonic-gate sysevent_attr_type(sysevent_attr_t *attr) 7427c478bd9Sstevel@tonic-gate { 7437c478bd9Sstevel@tonic-gate /* 7447c478bd9Sstevel@tonic-gate * The SE_DATA_TYPE_* are typedef'ed to be the 7457c478bd9Sstevel@tonic-gate * same value as DATA_TYPE_* 7467c478bd9Sstevel@tonic-gate */ 7477c478bd9Sstevel@tonic-gate return (nvpair_type((nvpair_t *)attr)); 7487c478bd9Sstevel@tonic-gate } 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate /* 7517c478bd9Sstevel@tonic-gate * Repack event buffer into contiguous memory 7527c478bd9Sstevel@tonic-gate */ 7537c478bd9Sstevel@tonic-gate static sysevent_t * 7547c478bd9Sstevel@tonic-gate se_repack(sysevent_t *ev, int flag) 7557c478bd9Sstevel@tonic-gate { 7567c478bd9Sstevel@tonic-gate size_t copy_len; 7577c478bd9Sstevel@tonic-gate caddr_t attr; 7587c478bd9Sstevel@tonic-gate size_t size; 7597c478bd9Sstevel@tonic-gate uint64_t attr_offset; 7607c478bd9Sstevel@tonic-gate sysevent_t *copy; 7617c478bd9Sstevel@tonic-gate log_eventq_t *qcopy; 7627c478bd9Sstevel@tonic-gate sysevent_attr_list_t *nvl; 7637c478bd9Sstevel@tonic-gate 7647c478bd9Sstevel@tonic-gate copy_len = sizeof (log_eventq_t) + SE_PAYLOAD_SZ(ev); 7657c478bd9Sstevel@tonic-gate qcopy = kmem_zalloc(copy_len, flag); 7667c478bd9Sstevel@tonic-gate if (qcopy == NULL) { 7677c478bd9Sstevel@tonic-gate return (NULL); 7687c478bd9Sstevel@tonic-gate } 7697c478bd9Sstevel@tonic-gate copy = (sysevent_t *)&qcopy->arg.buf; 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate /* 7727c478bd9Sstevel@tonic-gate * Copy event header, class, subclass and publisher names 7737c478bd9Sstevel@tonic-gate * Set the attribute offset (in number of bytes) to contiguous 7747c478bd9Sstevel@tonic-gate * memory after the header. 7757c478bd9Sstevel@tonic-gate */ 7767c478bd9Sstevel@tonic-gate 7777c478bd9Sstevel@tonic-gate attr_offset = SE_ATTR_OFF(ev); 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate ASSERT((caddr_t)copy + attr_offset <= (caddr_t)copy + copy_len); 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate bcopy(ev, copy, attr_offset); 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate /* Check if attribute list exists */ 7847c478bd9Sstevel@tonic-gate if ((nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev)) == NULL) { 7857c478bd9Sstevel@tonic-gate return (copy); 7867c478bd9Sstevel@tonic-gate } 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate /* 7897c478bd9Sstevel@tonic-gate * Copy attribute data to contiguous memory 7907c478bd9Sstevel@tonic-gate */ 7917c478bd9Sstevel@tonic-gate attr = (char *)copy + attr_offset; 7927c478bd9Sstevel@tonic-gate (void) nvlist_size(nvl, &size, encoding); 7937c478bd9Sstevel@tonic-gate if (nvlist_pack(nvl, &attr, &size, encoding, flag) != 0) { 7947c478bd9Sstevel@tonic-gate kmem_free(qcopy, copy_len); 7957c478bd9Sstevel@tonic-gate return (NULL); 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate SE_ATTR_PTR(copy) = UINT64_C(0); 7987c478bd9Sstevel@tonic-gate SE_FLAG(copy) = SE_PACKED_BUF; 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gate return (copy); 8017c478bd9Sstevel@tonic-gate } 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate /* 8047c478bd9Sstevel@tonic-gate * The sysevent registration provides a persistent and reliable database 8057c478bd9Sstevel@tonic-gate * for channel information for sysevent channel publishers and 8067c478bd9Sstevel@tonic-gate * subscribers. 8077c478bd9Sstevel@tonic-gate * 8087c478bd9Sstevel@tonic-gate * A channel is created and maintained by the kernel upon the first 8097c478bd9Sstevel@tonic-gate * SE_OPEN_REGISTRATION operation to log_sysevent_register(). Channel 8107c478bd9Sstevel@tonic-gate * event subscription information is updated as publishers or subscribers 8117c478bd9Sstevel@tonic-gate * perform subsequent operations (SE_BIND_REGISTRATION, SE_REGISTER, 8127c478bd9Sstevel@tonic-gate * SE_UNREGISTER and SE_UNBIND_REGISTRATION). 8137c478bd9Sstevel@tonic-gate * 8147c478bd9Sstevel@tonic-gate * For consistency, id's are assigned for every publisher or subscriber 8157c478bd9Sstevel@tonic-gate * bound to a particular channel. The id's are used to constrain resources 8167c478bd9Sstevel@tonic-gate * and perform subscription lookup. 8177c478bd9Sstevel@tonic-gate * 8187c478bd9Sstevel@tonic-gate * Associated with each channel is a hashed list of the current subscriptions 8197c478bd9Sstevel@tonic-gate * based upon event class and subclasses. A subscription contains a class name, 8207c478bd9Sstevel@tonic-gate * list of possible subclasses and an array of subscriber ids. Subscriptions 8217c478bd9Sstevel@tonic-gate * are updated for every SE_REGISTER or SE_UNREGISTER operation. 8227c478bd9Sstevel@tonic-gate * 8237c478bd9Sstevel@tonic-gate * Channels are closed once the last subscriber or publisher performs a 8247c478bd9Sstevel@tonic-gate * SE_CLOSE_REGISTRATION operation. All resources associated with the named 8257c478bd9Sstevel@tonic-gate * channel are freed upon last close. 8267c478bd9Sstevel@tonic-gate * 8277c478bd9Sstevel@tonic-gate * Locking: 8287c478bd9Sstevel@tonic-gate * Every operation to log_sysevent() is protected by a single lock, 8297c478bd9Sstevel@tonic-gate * registered_channel_mutex. It is expected that the granularity of 8307c478bd9Sstevel@tonic-gate * a single lock is sufficient given the frequency that updates will 8317c478bd9Sstevel@tonic-gate * occur. 8327c478bd9Sstevel@tonic-gate * 8337c478bd9Sstevel@tonic-gate * If this locking strategy proves to be too contentious, a per-hash 8347c478bd9Sstevel@tonic-gate * or per-channel locking strategy may be implemented. 8357c478bd9Sstevel@tonic-gate */ 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate #define CHANN_HASH(channel_name) (hash_func(channel_name) \ 8397c478bd9Sstevel@tonic-gate % CHAN_HASH_SZ) 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate sysevent_channel_descriptor_t *registered_channels[CHAN_HASH_SZ]; 8427c478bd9Sstevel@tonic-gate static int channel_cnt; 8437c478bd9Sstevel@tonic-gate static void remove_all_class(sysevent_channel_descriptor_t *chan, 8447c478bd9Sstevel@tonic-gate uint32_t sub_id); 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate static uint32_t 8477c478bd9Sstevel@tonic-gate hash_func(const char *s) 8487c478bd9Sstevel@tonic-gate { 8497c478bd9Sstevel@tonic-gate uint32_t result = 0; 8507c478bd9Sstevel@tonic-gate uint_t g; 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate while (*s != '\0') { 8537c478bd9Sstevel@tonic-gate result <<= 4; 8547c478bd9Sstevel@tonic-gate result += (uint32_t)*s++; 8557c478bd9Sstevel@tonic-gate g = result & 0xf0000000; 8567c478bd9Sstevel@tonic-gate if (g != 0) { 8577c478bd9Sstevel@tonic-gate result ^= g >> 24; 8587c478bd9Sstevel@tonic-gate result ^= g; 8597c478bd9Sstevel@tonic-gate } 8607c478bd9Sstevel@tonic-gate } 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate return (result); 8637c478bd9Sstevel@tonic-gate } 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate static sysevent_channel_descriptor_t * 8667c478bd9Sstevel@tonic-gate get_channel(char *channel_name) 8677c478bd9Sstevel@tonic-gate { 8687c478bd9Sstevel@tonic-gate int hash_index; 8697c478bd9Sstevel@tonic-gate sysevent_channel_descriptor_t *chan_list; 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate if (channel_name == NULL) 8727c478bd9Sstevel@tonic-gate return (NULL); 8737c478bd9Sstevel@tonic-gate 8747c478bd9Sstevel@tonic-gate /* Find channel descriptor */ 8757c478bd9Sstevel@tonic-gate hash_index = CHANN_HASH(channel_name); 8767c478bd9Sstevel@tonic-gate chan_list = registered_channels[hash_index]; 8777c478bd9Sstevel@tonic-gate while (chan_list != NULL) { 8787c478bd9Sstevel@tonic-gate if (strcmp(chan_list->scd_channel_name, channel_name) == 0) { 8797c478bd9Sstevel@tonic-gate break; 8807c478bd9Sstevel@tonic-gate } else { 8817c478bd9Sstevel@tonic-gate chan_list = chan_list->scd_next; 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate } 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate return (chan_list); 8867c478bd9Sstevel@tonic-gate } 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate static class_lst_t * 8897c478bd9Sstevel@tonic-gate create_channel_registration(sysevent_channel_descriptor_t *chan, 8907c478bd9Sstevel@tonic-gate char *event_class, int index) 8917c478bd9Sstevel@tonic-gate { 8927c478bd9Sstevel@tonic-gate size_t class_len; 8937c478bd9Sstevel@tonic-gate class_lst_t *c_list; 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate class_len = strlen(event_class) + 1; 8967c478bd9Sstevel@tonic-gate c_list = kmem_zalloc(sizeof (class_lst_t), KM_SLEEP); 8977c478bd9Sstevel@tonic-gate c_list->cl_name = kmem_zalloc(class_len, KM_SLEEP); 8987c478bd9Sstevel@tonic-gate bcopy(event_class, c_list->cl_name, class_len); 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate c_list->cl_subclass_list = 9017c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (subclass_lst_t), KM_SLEEP); 9027c478bd9Sstevel@tonic-gate c_list->cl_subclass_list->sl_name = 9037c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (EC_SUB_ALL), KM_SLEEP); 9047c478bd9Sstevel@tonic-gate bcopy(EC_SUB_ALL, c_list->cl_subclass_list->sl_name, 9057c478bd9Sstevel@tonic-gate sizeof (EC_SUB_ALL)); 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate c_list->cl_next = chan->scd_class_list_tbl[index]; 9087c478bd9Sstevel@tonic-gate chan->scd_class_list_tbl[index] = c_list; 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate return (c_list); 9117c478bd9Sstevel@tonic-gate } 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate static void 9147c478bd9Sstevel@tonic-gate free_channel_registration(sysevent_channel_descriptor_t *chan) 9157c478bd9Sstevel@tonic-gate { 9167c478bd9Sstevel@tonic-gate int i; 9177c478bd9Sstevel@tonic-gate class_lst_t *clist, *next_clist; 9187c478bd9Sstevel@tonic-gate subclass_lst_t *sclist, *next_sc; 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate for (i = 0; i <= CLASS_HASH_SZ; ++i) { 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate clist = chan->scd_class_list_tbl[i]; 9237c478bd9Sstevel@tonic-gate while (clist != NULL) { 9247c478bd9Sstevel@tonic-gate sclist = clist->cl_subclass_list; 9257c478bd9Sstevel@tonic-gate while (sclist != NULL) { 9267c478bd9Sstevel@tonic-gate kmem_free(sclist->sl_name, 9277c478bd9Sstevel@tonic-gate strlen(sclist->sl_name) + 1); 9287c478bd9Sstevel@tonic-gate next_sc = sclist->sl_next; 9297c478bd9Sstevel@tonic-gate kmem_free(sclist, sizeof (subclass_lst_t)); 9307c478bd9Sstevel@tonic-gate sclist = next_sc; 9317c478bd9Sstevel@tonic-gate } 9327c478bd9Sstevel@tonic-gate kmem_free(clist->cl_name, 9337c478bd9Sstevel@tonic-gate strlen(clist->cl_name) + 1); 9347c478bd9Sstevel@tonic-gate next_clist = clist->cl_next; 9357c478bd9Sstevel@tonic-gate kmem_free(clist, sizeof (class_lst_t)); 9367c478bd9Sstevel@tonic-gate clist = next_clist; 9377c478bd9Sstevel@tonic-gate } 9387c478bd9Sstevel@tonic-gate } 9397c478bd9Sstevel@tonic-gate chan->scd_class_list_tbl[0] = NULL; 9407c478bd9Sstevel@tonic-gate } 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate static int 9437c478bd9Sstevel@tonic-gate open_channel(char *channel_name) 9447c478bd9Sstevel@tonic-gate { 9457c478bd9Sstevel@tonic-gate int hash_index; 9467c478bd9Sstevel@tonic-gate sysevent_channel_descriptor_t *chan, *chan_list; 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate if (channel_cnt > MAX_CHAN) { 9507c478bd9Sstevel@tonic-gate return (-1); 9517c478bd9Sstevel@tonic-gate } 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate /* Find channel descriptor */ 9547c478bd9Sstevel@tonic-gate hash_index = CHANN_HASH(channel_name); 9557c478bd9Sstevel@tonic-gate chan_list = registered_channels[hash_index]; 9567c478bd9Sstevel@tonic-gate while (chan_list != NULL) { 9577c478bd9Sstevel@tonic-gate if (strcmp(chan_list->scd_channel_name, channel_name) == 0) { 9587c478bd9Sstevel@tonic-gate chan_list->scd_ref_cnt++; 9597c478bd9Sstevel@tonic-gate kmem_free(channel_name, strlen(channel_name) + 1); 9607c478bd9Sstevel@tonic-gate return (0); 9617c478bd9Sstevel@tonic-gate } else { 9627c478bd9Sstevel@tonic-gate chan_list = chan_list->scd_next; 9637c478bd9Sstevel@tonic-gate } 9647c478bd9Sstevel@tonic-gate } 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate /* New channel descriptor */ 9687c478bd9Sstevel@tonic-gate chan = kmem_zalloc(sizeof (sysevent_channel_descriptor_t), KM_SLEEP); 9697c478bd9Sstevel@tonic-gate chan->scd_channel_name = channel_name; 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate /* 9727c478bd9Sstevel@tonic-gate * Create subscriber ids in the range [1, MAX_SUBSCRIBERS). 9737c478bd9Sstevel@tonic-gate * Subscriber id 0 is never allocated, but is used as a reserved id 9747c478bd9Sstevel@tonic-gate * by libsysevent 9757c478bd9Sstevel@tonic-gate */ 9767c478bd9Sstevel@tonic-gate if ((chan->scd_subscriber_cache = vmem_create(channel_name, (void *)1, 9777c478bd9Sstevel@tonic-gate MAX_SUBSCRIBERS + 1, 1, NULL, NULL, NULL, 0, 9787c478bd9Sstevel@tonic-gate VM_NOSLEEP | VMC_IDENTIFIER)) == NULL) { 9797c478bd9Sstevel@tonic-gate kmem_free(chan, sizeof (sysevent_channel_descriptor_t)); 9807c478bd9Sstevel@tonic-gate return (-1); 9817c478bd9Sstevel@tonic-gate } 9827c478bd9Sstevel@tonic-gate if ((chan->scd_publisher_cache = vmem_create(channel_name, (void *)1, 9837c478bd9Sstevel@tonic-gate MAX_PUBLISHERS + 1, 1, NULL, NULL, NULL, 0, 9847c478bd9Sstevel@tonic-gate VM_NOSLEEP | VMC_IDENTIFIER)) == NULL) { 9857c478bd9Sstevel@tonic-gate vmem_destroy(chan->scd_subscriber_cache); 9867c478bd9Sstevel@tonic-gate kmem_free(chan, sizeof (sysevent_channel_descriptor_t)); 9877c478bd9Sstevel@tonic-gate return (-1); 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate chan->scd_ref_cnt = 1; 9917c478bd9Sstevel@tonic-gate 9927c478bd9Sstevel@tonic-gate (void) create_channel_registration(chan, EC_ALL, 0); 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate if (registered_channels[hash_index] != NULL) 9957c478bd9Sstevel@tonic-gate chan->scd_next = registered_channels[hash_index]; 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate registered_channels[hash_index] = chan; 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate ++channel_cnt; 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate return (0); 10027c478bd9Sstevel@tonic-gate } 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate static void 10057c478bd9Sstevel@tonic-gate close_channel(char *channel_name) 10067c478bd9Sstevel@tonic-gate { 10077c478bd9Sstevel@tonic-gate int hash_index; 10087c478bd9Sstevel@tonic-gate sysevent_channel_descriptor_t *chan, *prev_chan; 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate /* Find channel descriptor */ 10117c478bd9Sstevel@tonic-gate hash_index = CHANN_HASH(channel_name); 10127c478bd9Sstevel@tonic-gate prev_chan = chan = registered_channels[hash_index]; 10137c478bd9Sstevel@tonic-gate 10147c478bd9Sstevel@tonic-gate while (chan != NULL) { 10157c478bd9Sstevel@tonic-gate if (strcmp(chan->scd_channel_name, channel_name) == 0) { 10167c478bd9Sstevel@tonic-gate break; 10177c478bd9Sstevel@tonic-gate } else { 10187c478bd9Sstevel@tonic-gate prev_chan = chan; 10197c478bd9Sstevel@tonic-gate chan = chan->scd_next; 10207c478bd9Sstevel@tonic-gate } 10217c478bd9Sstevel@tonic-gate } 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate if (chan == NULL) 10247c478bd9Sstevel@tonic-gate return; 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate chan->scd_ref_cnt--; 10277c478bd9Sstevel@tonic-gate if (chan->scd_ref_cnt > 0) 10287c478bd9Sstevel@tonic-gate return; 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate free_channel_registration(chan); 10317c478bd9Sstevel@tonic-gate vmem_destroy(chan->scd_subscriber_cache); 10327c478bd9Sstevel@tonic-gate vmem_destroy(chan->scd_publisher_cache); 10337c478bd9Sstevel@tonic-gate kmem_free(chan->scd_channel_name, 10347c478bd9Sstevel@tonic-gate strlen(chan->scd_channel_name) + 1); 10357c478bd9Sstevel@tonic-gate if (registered_channels[hash_index] == chan) 10367c478bd9Sstevel@tonic-gate registered_channels[hash_index] = chan->scd_next; 10377c478bd9Sstevel@tonic-gate else 10387c478bd9Sstevel@tonic-gate prev_chan->scd_next = chan->scd_next; 10397c478bd9Sstevel@tonic-gate kmem_free(chan, sizeof (sysevent_channel_descriptor_t)); 10407c478bd9Sstevel@tonic-gate --channel_cnt; 10417c478bd9Sstevel@tonic-gate } 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate static id_t 10447c478bd9Sstevel@tonic-gate bind_common(sysevent_channel_descriptor_t *chan, int type) 10457c478bd9Sstevel@tonic-gate { 10467c478bd9Sstevel@tonic-gate id_t id; 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate if (type == SUBSCRIBER) { 10497c478bd9Sstevel@tonic-gate id = (id_t)(uintptr_t)vmem_alloc(chan->scd_subscriber_cache, 1, 10507c478bd9Sstevel@tonic-gate VM_NOSLEEP | VM_NEXTFIT); 10517c478bd9Sstevel@tonic-gate if (id <= 0 || id > MAX_SUBSCRIBERS) 10527c478bd9Sstevel@tonic-gate return (0); 10537c478bd9Sstevel@tonic-gate chan->scd_subscriber_ids[id] = 1; 10547c478bd9Sstevel@tonic-gate } else { 10557c478bd9Sstevel@tonic-gate id = (id_t)(uintptr_t)vmem_alloc(chan->scd_publisher_cache, 1, 10567c478bd9Sstevel@tonic-gate VM_NOSLEEP | VM_NEXTFIT); 10577c478bd9Sstevel@tonic-gate if (id <= 0 || id > MAX_PUBLISHERS) 10587c478bd9Sstevel@tonic-gate return (0); 10597c478bd9Sstevel@tonic-gate chan->scd_publisher_ids[id] = 1; 10607c478bd9Sstevel@tonic-gate } 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate return (id); 10637c478bd9Sstevel@tonic-gate } 10647c478bd9Sstevel@tonic-gate 10657c478bd9Sstevel@tonic-gate static int 10667c478bd9Sstevel@tonic-gate unbind_common(sysevent_channel_descriptor_t *chan, int type, id_t id) 10677c478bd9Sstevel@tonic-gate { 10687c478bd9Sstevel@tonic-gate if (type == SUBSCRIBER) { 10697c478bd9Sstevel@tonic-gate if (id <= 0 || id > MAX_SUBSCRIBERS) 10707c478bd9Sstevel@tonic-gate return (0); 10717c478bd9Sstevel@tonic-gate if (chan->scd_subscriber_ids[id] == 0) 10727c478bd9Sstevel@tonic-gate return (0); 10737c478bd9Sstevel@tonic-gate (void) remove_all_class(chan, id); 10747c478bd9Sstevel@tonic-gate chan->scd_subscriber_ids[id] = 0; 10757c478bd9Sstevel@tonic-gate vmem_free(chan->scd_subscriber_cache, (void *)(uintptr_t)id, 1); 10767c478bd9Sstevel@tonic-gate } else { 10777c478bd9Sstevel@tonic-gate if (id <= 0 || id > MAX_PUBLISHERS) 10787c478bd9Sstevel@tonic-gate return (0); 10797c478bd9Sstevel@tonic-gate if (chan->scd_publisher_ids[id] == 0) 10807c478bd9Sstevel@tonic-gate return (0); 10817c478bd9Sstevel@tonic-gate chan->scd_publisher_ids[id] = 0; 10827c478bd9Sstevel@tonic-gate vmem_free(chan->scd_publisher_cache, (void *)(uintptr_t)id, 1); 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate return (1); 10867c478bd9Sstevel@tonic-gate } 10877c478bd9Sstevel@tonic-gate 10887c478bd9Sstevel@tonic-gate static void 10897c478bd9Sstevel@tonic-gate release_id(sysevent_channel_descriptor_t *chan, int type, id_t id) 10907c478bd9Sstevel@tonic-gate { 10917c478bd9Sstevel@tonic-gate if (unbind_common(chan, type, id)) 10927c478bd9Sstevel@tonic-gate close_channel(chan->scd_channel_name); 10937c478bd9Sstevel@tonic-gate } 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate static subclass_lst_t * 10967c478bd9Sstevel@tonic-gate find_subclass(class_lst_t *c_list, char *subclass) 10977c478bd9Sstevel@tonic-gate { 10987c478bd9Sstevel@tonic-gate subclass_lst_t *sc_list; 10997c478bd9Sstevel@tonic-gate 11007c478bd9Sstevel@tonic-gate if (c_list == NULL) 11017c478bd9Sstevel@tonic-gate return (NULL); 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate sc_list = c_list->cl_subclass_list; 11047c478bd9Sstevel@tonic-gate 11057c478bd9Sstevel@tonic-gate while (sc_list != NULL) { 11067c478bd9Sstevel@tonic-gate if (strcmp(sc_list->sl_name, subclass) == 0) { 11077c478bd9Sstevel@tonic-gate return (sc_list); 11087c478bd9Sstevel@tonic-gate } 11097c478bd9Sstevel@tonic-gate sc_list = sc_list->sl_next; 11107c478bd9Sstevel@tonic-gate } 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate return (NULL); 11137c478bd9Sstevel@tonic-gate } 11147c478bd9Sstevel@tonic-gate 11157c478bd9Sstevel@tonic-gate static void 11167c478bd9Sstevel@tonic-gate insert_subclass(class_lst_t *c_list, char **subclass_names, 11177c478bd9Sstevel@tonic-gate int subclass_num, uint32_t sub_id) 11187c478bd9Sstevel@tonic-gate { 11197c478bd9Sstevel@tonic-gate int i, subclass_sz; 11207c478bd9Sstevel@tonic-gate subclass_lst_t *sc_list; 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate for (i = 0; i < subclass_num; ++i) { 11237c478bd9Sstevel@tonic-gate if ((sc_list = find_subclass(c_list, subclass_names[i])) 11247c478bd9Sstevel@tonic-gate != NULL) { 11257c478bd9Sstevel@tonic-gate sc_list->sl_num[sub_id] = 1; 11267c478bd9Sstevel@tonic-gate } else { 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate sc_list = kmem_zalloc(sizeof (subclass_lst_t), 11297c478bd9Sstevel@tonic-gate KM_SLEEP); 11307c478bd9Sstevel@tonic-gate subclass_sz = strlen(subclass_names[i]) + 1; 11317c478bd9Sstevel@tonic-gate sc_list->sl_name = kmem_zalloc(subclass_sz, KM_SLEEP); 11327c478bd9Sstevel@tonic-gate bcopy(subclass_names[i], sc_list->sl_name, 11337c478bd9Sstevel@tonic-gate subclass_sz); 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate sc_list->sl_num[sub_id] = 1; 11367c478bd9Sstevel@tonic-gate 11377c478bd9Sstevel@tonic-gate sc_list->sl_next = c_list->cl_subclass_list; 11387c478bd9Sstevel@tonic-gate c_list->cl_subclass_list = sc_list; 11397c478bd9Sstevel@tonic-gate } 11407c478bd9Sstevel@tonic-gate } 11417c478bd9Sstevel@tonic-gate } 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate static class_lst_t * 11447c478bd9Sstevel@tonic-gate find_class(sysevent_channel_descriptor_t *chan, char *class_name) 11457c478bd9Sstevel@tonic-gate { 11467c478bd9Sstevel@tonic-gate class_lst_t *c_list; 11477c478bd9Sstevel@tonic-gate 11487c478bd9Sstevel@tonic-gate c_list = chan->scd_class_list_tbl[CLASS_HASH(class_name)]; 11497c478bd9Sstevel@tonic-gate while (c_list != NULL) { 11507c478bd9Sstevel@tonic-gate if (strcmp(class_name, c_list->cl_name) == 0) 11517c478bd9Sstevel@tonic-gate break; 11527c478bd9Sstevel@tonic-gate c_list = c_list->cl_next; 11537c478bd9Sstevel@tonic-gate } 11547c478bd9Sstevel@tonic-gate 11557c478bd9Sstevel@tonic-gate return (c_list); 11567c478bd9Sstevel@tonic-gate } 11577c478bd9Sstevel@tonic-gate 11587c478bd9Sstevel@tonic-gate static void 11597c478bd9Sstevel@tonic-gate remove_all_class(sysevent_channel_descriptor_t *chan, uint32_t sub_id) 11607c478bd9Sstevel@tonic-gate { 11617c478bd9Sstevel@tonic-gate int i; 11627c478bd9Sstevel@tonic-gate class_lst_t *c_list; 11637c478bd9Sstevel@tonic-gate subclass_lst_t *sc_list; 11647c478bd9Sstevel@tonic-gate 11657c478bd9Sstevel@tonic-gate for (i = 0; i <= CLASS_HASH_SZ; ++i) { 11667c478bd9Sstevel@tonic-gate 11677c478bd9Sstevel@tonic-gate c_list = chan->scd_class_list_tbl[i]; 11687c478bd9Sstevel@tonic-gate while (c_list != NULL) { 11697c478bd9Sstevel@tonic-gate sc_list = c_list->cl_subclass_list; 11707c478bd9Sstevel@tonic-gate while (sc_list != NULL) { 11717c478bd9Sstevel@tonic-gate sc_list->sl_num[sub_id] = 0; 11727c478bd9Sstevel@tonic-gate sc_list = sc_list->sl_next; 11737c478bd9Sstevel@tonic-gate } 11747c478bd9Sstevel@tonic-gate c_list = c_list->cl_next; 11757c478bd9Sstevel@tonic-gate } 11767c478bd9Sstevel@tonic-gate } 11777c478bd9Sstevel@tonic-gate } 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate static void 11807c478bd9Sstevel@tonic-gate remove_class(sysevent_channel_descriptor_t *chan, uint32_t sub_id, 11817c478bd9Sstevel@tonic-gate char *class_name) 11827c478bd9Sstevel@tonic-gate { 11837c478bd9Sstevel@tonic-gate class_lst_t *c_list; 11847c478bd9Sstevel@tonic-gate subclass_lst_t *sc_list; 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate if (strcmp(class_name, EC_ALL) == 0) { 11877c478bd9Sstevel@tonic-gate remove_all_class(chan, sub_id); 11887c478bd9Sstevel@tonic-gate return; 11897c478bd9Sstevel@tonic-gate } 11907c478bd9Sstevel@tonic-gate 11917c478bd9Sstevel@tonic-gate if ((c_list = find_class(chan, class_name)) == NULL) { 11927c478bd9Sstevel@tonic-gate return; 11937c478bd9Sstevel@tonic-gate } 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate sc_list = c_list->cl_subclass_list; 11967c478bd9Sstevel@tonic-gate while (sc_list != NULL) { 11977c478bd9Sstevel@tonic-gate sc_list->sl_num[sub_id] = 0; 11987c478bd9Sstevel@tonic-gate sc_list = sc_list->sl_next; 11997c478bd9Sstevel@tonic-gate } 12007c478bd9Sstevel@tonic-gate } 12017c478bd9Sstevel@tonic-gate 12027c478bd9Sstevel@tonic-gate static int 12037c478bd9Sstevel@tonic-gate insert_class(sysevent_channel_descriptor_t *chan, char *event_class, 12047c478bd9Sstevel@tonic-gate char **event_subclass_lst, int subclass_num, uint32_t sub_id) 12057c478bd9Sstevel@tonic-gate { 12067c478bd9Sstevel@tonic-gate class_lst_t *c_list; 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate if (strcmp(event_class, EC_ALL) == 0) { 12097c478bd9Sstevel@tonic-gate insert_subclass(chan->scd_class_list_tbl[0], 12107c478bd9Sstevel@tonic-gate event_subclass_lst, 1, sub_id); 12117c478bd9Sstevel@tonic-gate return (0); 12127c478bd9Sstevel@tonic-gate } 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate if (strlen(event_class) + 1 > MAX_CLASS_LEN) 12157c478bd9Sstevel@tonic-gate return (-1); 12167c478bd9Sstevel@tonic-gate 12177c478bd9Sstevel@tonic-gate /* New class, add to the registration cache */ 12187c478bd9Sstevel@tonic-gate if ((c_list = find_class(chan, event_class)) == NULL) { 12197c478bd9Sstevel@tonic-gate c_list = create_channel_registration(chan, event_class, 12207c478bd9Sstevel@tonic-gate CLASS_HASH(event_class)); 12217c478bd9Sstevel@tonic-gate } 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate /* Update the subclass list */ 12247c478bd9Sstevel@tonic-gate insert_subclass(c_list, event_subclass_lst, subclass_num, sub_id); 12257c478bd9Sstevel@tonic-gate 12267c478bd9Sstevel@tonic-gate return (0); 12277c478bd9Sstevel@tonic-gate } 12287c478bd9Sstevel@tonic-gate 12297c478bd9Sstevel@tonic-gate static int 12307c478bd9Sstevel@tonic-gate add_registration(sysevent_channel_descriptor_t *chan, uint32_t sub_id, 12317c478bd9Sstevel@tonic-gate char *nvlbuf, size_t nvlsize) 12327c478bd9Sstevel@tonic-gate { 12337c478bd9Sstevel@tonic-gate uint_t num_elem; 12347c478bd9Sstevel@tonic-gate char *event_class; 12357c478bd9Sstevel@tonic-gate char **event_list; 12367c478bd9Sstevel@tonic-gate nvlist_t *nvl; 12377c478bd9Sstevel@tonic-gate nvpair_t *nvpair = NULL; 12387c478bd9Sstevel@tonic-gate 12397c478bd9Sstevel@tonic-gate if (nvlist_unpack(nvlbuf, nvlsize, &nvl, KM_SLEEP) != 0) 12407c478bd9Sstevel@tonic-gate return (-1); 12417c478bd9Sstevel@tonic-gate 12427c478bd9Sstevel@tonic-gate if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) == NULL) { 12437c478bd9Sstevel@tonic-gate nvlist_free(nvl); 12447c478bd9Sstevel@tonic-gate return (-1); 12457c478bd9Sstevel@tonic-gate } 12467c478bd9Sstevel@tonic-gate 12477c478bd9Sstevel@tonic-gate if ((event_class = nvpair_name(nvpair)) == NULL) { 12487c478bd9Sstevel@tonic-gate nvlist_free(nvl); 12497c478bd9Sstevel@tonic-gate return (-1); 12507c478bd9Sstevel@tonic-gate } 12517c478bd9Sstevel@tonic-gate if (nvpair_value_string_array(nvpair, &event_list, 12527c478bd9Sstevel@tonic-gate &num_elem) != 0) { 12537c478bd9Sstevel@tonic-gate nvlist_free(nvl); 12547c478bd9Sstevel@tonic-gate return (-1); 12557c478bd9Sstevel@tonic-gate } 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate if (insert_class(chan, event_class, event_list, num_elem, sub_id) < 0) { 12587c478bd9Sstevel@tonic-gate nvlist_free(nvl); 12597c478bd9Sstevel@tonic-gate return (-1); 12607c478bd9Sstevel@tonic-gate } 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate nvlist_free(nvl); 12637c478bd9Sstevel@tonic-gate 12647c478bd9Sstevel@tonic-gate return (0); 12657c478bd9Sstevel@tonic-gate } 12667c478bd9Sstevel@tonic-gate 12677c478bd9Sstevel@tonic-gate /* 12687c478bd9Sstevel@tonic-gate * get_registration - Return the requested class hash chain 12697c478bd9Sstevel@tonic-gate */ 12707c478bd9Sstevel@tonic-gate static int 12717c478bd9Sstevel@tonic-gate get_registration(sysevent_channel_descriptor_t *chan, char *databuf, 12727c478bd9Sstevel@tonic-gate uint32_t *bufsz, uint32_t class_index) 12737c478bd9Sstevel@tonic-gate { 12747c478bd9Sstevel@tonic-gate int num_classes = 0; 12757c478bd9Sstevel@tonic-gate char *nvlbuf = NULL; 12767c478bd9Sstevel@tonic-gate size_t nvlsize; 12777c478bd9Sstevel@tonic-gate nvlist_t *nvl; 12787c478bd9Sstevel@tonic-gate class_lst_t *clist; 12797c478bd9Sstevel@tonic-gate subclass_lst_t *sc_list; 12807c478bd9Sstevel@tonic-gate 12817c478bd9Sstevel@tonic-gate if (class_index < 0 || class_index > CLASS_HASH_SZ) 12827c478bd9Sstevel@tonic-gate return (EINVAL); 12837c478bd9Sstevel@tonic-gate 12847c478bd9Sstevel@tonic-gate if ((clist = chan->scd_class_list_tbl[class_index]) == NULL) { 12857c478bd9Sstevel@tonic-gate return (ENOENT); 12867c478bd9Sstevel@tonic-gate } 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate if (nvlist_alloc(&nvl, 0, 0) != 0) { 12897c478bd9Sstevel@tonic-gate return (EFAULT); 12907c478bd9Sstevel@tonic-gate } 12917c478bd9Sstevel@tonic-gate 12927c478bd9Sstevel@tonic-gate while (clist != NULL) { 12937c478bd9Sstevel@tonic-gate if (nvlist_add_string(nvl, CLASS_NAME, clist->cl_name) 12947c478bd9Sstevel@tonic-gate != 0) { 12957c478bd9Sstevel@tonic-gate nvlist_free(nvl); 12967c478bd9Sstevel@tonic-gate return (EFAULT); 12977c478bd9Sstevel@tonic-gate } 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate sc_list = clist->cl_subclass_list; 13007c478bd9Sstevel@tonic-gate while (sc_list != NULL) { 13017c478bd9Sstevel@tonic-gate if (nvlist_add_byte_array(nvl, sc_list->sl_name, 13027c478bd9Sstevel@tonic-gate sc_list->sl_num, MAX_SUBSCRIBERS) != 0) { 13037c478bd9Sstevel@tonic-gate nvlist_free(nvl); 13047c478bd9Sstevel@tonic-gate return (EFAULT); 13057c478bd9Sstevel@tonic-gate } 13067c478bd9Sstevel@tonic-gate sc_list = sc_list->sl_next; 13077c478bd9Sstevel@tonic-gate } 13087c478bd9Sstevel@tonic-gate num_classes++; 13097c478bd9Sstevel@tonic-gate clist = clist->cl_next; 13107c478bd9Sstevel@tonic-gate } 13117c478bd9Sstevel@tonic-gate 13127c478bd9Sstevel@tonic-gate if (num_classes == 0) { 13137c478bd9Sstevel@tonic-gate nvlist_free(nvl); 13147c478bd9Sstevel@tonic-gate return (ENOENT); 13157c478bd9Sstevel@tonic-gate } 13167c478bd9Sstevel@tonic-gate 13177c478bd9Sstevel@tonic-gate if (nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE, 13187c478bd9Sstevel@tonic-gate KM_SLEEP) 13197c478bd9Sstevel@tonic-gate != 0) { 13207c478bd9Sstevel@tonic-gate nvlist_free(nvl); 13217c478bd9Sstevel@tonic-gate return (EFAULT); 13227c478bd9Sstevel@tonic-gate } 13237c478bd9Sstevel@tonic-gate 13247c478bd9Sstevel@tonic-gate nvlist_free(nvl); 13257c478bd9Sstevel@tonic-gate 13267c478bd9Sstevel@tonic-gate if (nvlsize > *bufsz) { 13277c478bd9Sstevel@tonic-gate kmem_free(nvlbuf, nvlsize); 13287c478bd9Sstevel@tonic-gate *bufsz = nvlsize; 13297c478bd9Sstevel@tonic-gate return (EAGAIN); 13307c478bd9Sstevel@tonic-gate } 13317c478bd9Sstevel@tonic-gate 13327c478bd9Sstevel@tonic-gate bcopy(nvlbuf, databuf, nvlsize); 13337c478bd9Sstevel@tonic-gate kmem_free(nvlbuf, nvlsize); 13347c478bd9Sstevel@tonic-gate 13357c478bd9Sstevel@tonic-gate return (0); 13367c478bd9Sstevel@tonic-gate } 13377c478bd9Sstevel@tonic-gate 13387c478bd9Sstevel@tonic-gate /* 13397c478bd9Sstevel@tonic-gate * log_sysevent_register - Register event subscriber for a particular 13407c478bd9Sstevel@tonic-gate * event channel. 13417c478bd9Sstevel@tonic-gate */ 13427c478bd9Sstevel@tonic-gate int 13437c478bd9Sstevel@tonic-gate log_sysevent_register(char *channel_name, char *udatabuf, se_pubsub_t *udata) 13447c478bd9Sstevel@tonic-gate { 13457c478bd9Sstevel@tonic-gate int error = 0; 13467c478bd9Sstevel@tonic-gate char *kchannel, *databuf = NULL; 13477c478bd9Sstevel@tonic-gate size_t bufsz; 13487c478bd9Sstevel@tonic-gate se_pubsub_t kdata; 13497c478bd9Sstevel@tonic-gate sysevent_channel_descriptor_t *chan; 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate if (copyin(udata, &kdata, sizeof (se_pubsub_t)) == -1) { 13527c478bd9Sstevel@tonic-gate return (EFAULT); 13537c478bd9Sstevel@tonic-gate } 13547c478bd9Sstevel@tonic-gate if (kdata.ps_channel_name_len == 0) { 13557c478bd9Sstevel@tonic-gate return (EINVAL); 13567c478bd9Sstevel@tonic-gate } 13577c478bd9Sstevel@tonic-gate kchannel = kmem_alloc(kdata.ps_channel_name_len, KM_SLEEP); 13587c478bd9Sstevel@tonic-gate if (copyin(channel_name, kchannel, kdata.ps_channel_name_len) == -1) { 13597c478bd9Sstevel@tonic-gate kmem_free(kchannel, kdata.ps_channel_name_len); 13607c478bd9Sstevel@tonic-gate return (EFAULT); 13617c478bd9Sstevel@tonic-gate } 13627c478bd9Sstevel@tonic-gate bufsz = kdata.ps_buflen; 13637c478bd9Sstevel@tonic-gate if (bufsz > 0) { 13647c478bd9Sstevel@tonic-gate databuf = kmem_alloc(bufsz, KM_SLEEP); 13657c478bd9Sstevel@tonic-gate if (copyin(udatabuf, databuf, bufsz) == -1) { 13667c478bd9Sstevel@tonic-gate kmem_free(kchannel, kdata.ps_channel_name_len); 13677c478bd9Sstevel@tonic-gate kmem_free(databuf, bufsz); 13687c478bd9Sstevel@tonic-gate return (EFAULT); 13697c478bd9Sstevel@tonic-gate } 13707c478bd9Sstevel@tonic-gate } 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate mutex_enter(®istered_channel_mutex); 13737c478bd9Sstevel@tonic-gate if (kdata.ps_op != SE_OPEN_REGISTRATION && 13747c478bd9Sstevel@tonic-gate kdata.ps_op != SE_CLOSE_REGISTRATION) { 13757c478bd9Sstevel@tonic-gate chan = get_channel(kchannel); 13767c478bd9Sstevel@tonic-gate if (chan == NULL) { 13777c478bd9Sstevel@tonic-gate mutex_exit(®istered_channel_mutex); 13787c478bd9Sstevel@tonic-gate kmem_free(kchannel, kdata.ps_channel_name_len); 13797c478bd9Sstevel@tonic-gate if (bufsz > 0) 13807c478bd9Sstevel@tonic-gate kmem_free(databuf, bufsz); 13817c478bd9Sstevel@tonic-gate return (ENOENT); 13827c478bd9Sstevel@tonic-gate } 13837c478bd9Sstevel@tonic-gate } 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate switch (kdata.ps_op) { 13867c478bd9Sstevel@tonic-gate case SE_OPEN_REGISTRATION: 13877c478bd9Sstevel@tonic-gate if (open_channel(kchannel) != 0) { 13887c478bd9Sstevel@tonic-gate error = ENOMEM; 13897c478bd9Sstevel@tonic-gate if (bufsz > 0) 13907c478bd9Sstevel@tonic-gate kmem_free(databuf, bufsz); 13917c478bd9Sstevel@tonic-gate kmem_free(kchannel, kdata.ps_channel_name_len); 13927c478bd9Sstevel@tonic-gate } 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate mutex_exit(®istered_channel_mutex); 13957c478bd9Sstevel@tonic-gate return (error); 13967c478bd9Sstevel@tonic-gate case SE_CLOSE_REGISTRATION: 13977c478bd9Sstevel@tonic-gate close_channel(kchannel); 13987c478bd9Sstevel@tonic-gate break; 13997c478bd9Sstevel@tonic-gate case SE_BIND_REGISTRATION: 14007c478bd9Sstevel@tonic-gate if ((kdata.ps_id = bind_common(chan, kdata.ps_type)) <= 0) 14017c478bd9Sstevel@tonic-gate error = EBUSY; 14027c478bd9Sstevel@tonic-gate break; 14037c478bd9Sstevel@tonic-gate case SE_UNBIND_REGISTRATION: 14047c478bd9Sstevel@tonic-gate (void) unbind_common(chan, kdata.ps_type, (id_t)kdata.ps_id); 14057c478bd9Sstevel@tonic-gate break; 14067c478bd9Sstevel@tonic-gate case SE_REGISTER: 14077c478bd9Sstevel@tonic-gate if (bufsz == 0) { 14087c478bd9Sstevel@tonic-gate error = EINVAL; 14097c478bd9Sstevel@tonic-gate break; 14107c478bd9Sstevel@tonic-gate } 14117c478bd9Sstevel@tonic-gate if (add_registration(chan, kdata.ps_id, databuf, bufsz) == -1) 14127c478bd9Sstevel@tonic-gate error = EINVAL; 14137c478bd9Sstevel@tonic-gate break; 14147c478bd9Sstevel@tonic-gate case SE_UNREGISTER: 14157c478bd9Sstevel@tonic-gate if (bufsz == 0) { 14167c478bd9Sstevel@tonic-gate error = EINVAL; 14177c478bd9Sstevel@tonic-gate break; 14187c478bd9Sstevel@tonic-gate } 14197c478bd9Sstevel@tonic-gate remove_class(chan, kdata.ps_id, databuf); 14207c478bd9Sstevel@tonic-gate break; 14217c478bd9Sstevel@tonic-gate case SE_CLEANUP: 14227c478bd9Sstevel@tonic-gate /* Cleanup the indicated subscriber or publisher */ 14237c478bd9Sstevel@tonic-gate release_id(chan, kdata.ps_type, kdata.ps_id); 14247c478bd9Sstevel@tonic-gate break; 14257c478bd9Sstevel@tonic-gate case SE_GET_REGISTRATION: 14267c478bd9Sstevel@tonic-gate error = get_registration(chan, databuf, 14277c478bd9Sstevel@tonic-gate &kdata.ps_buflen, kdata.ps_id); 14287c478bd9Sstevel@tonic-gate break; 14297c478bd9Sstevel@tonic-gate default: 14307c478bd9Sstevel@tonic-gate error = ENOTSUP; 14317c478bd9Sstevel@tonic-gate } 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate mutex_exit(®istered_channel_mutex); 14347c478bd9Sstevel@tonic-gate 14357c478bd9Sstevel@tonic-gate kmem_free(kchannel, kdata.ps_channel_name_len); 14367c478bd9Sstevel@tonic-gate 14377c478bd9Sstevel@tonic-gate if (bufsz > 0) { 14387c478bd9Sstevel@tonic-gate if (copyout(databuf, udatabuf, bufsz) == -1) 14397c478bd9Sstevel@tonic-gate error = EFAULT; 14407c478bd9Sstevel@tonic-gate kmem_free(databuf, bufsz); 14417c478bd9Sstevel@tonic-gate } 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate if (copyout(&kdata, udata, sizeof (se_pubsub_t)) == -1) 14447c478bd9Sstevel@tonic-gate return (EFAULT); 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate return (error); 14477c478bd9Sstevel@tonic-gate } 14487c478bd9Sstevel@tonic-gate 14497c478bd9Sstevel@tonic-gate /* 14507c478bd9Sstevel@tonic-gate * log_sysevent_copyout_data - Copyout event data to userland. 14517c478bd9Sstevel@tonic-gate * This is called from modctl(MODEVENTS, MODEVENTS_GETDATA) 14527c478bd9Sstevel@tonic-gate * The buffer size is always sufficient. 14537c478bd9Sstevel@tonic-gate */ 14547c478bd9Sstevel@tonic-gate int 14557c478bd9Sstevel@tonic-gate log_sysevent_copyout_data(sysevent_id_t *eid, size_t ubuflen, caddr_t ubuf) 14567c478bd9Sstevel@tonic-gate { 14577c478bd9Sstevel@tonic-gate int error = ENOENT; 14587c478bd9Sstevel@tonic-gate log_eventq_t *q; 14597c478bd9Sstevel@tonic-gate sysevent_t *ev; 14607c478bd9Sstevel@tonic-gate sysevent_id_t eid_copy; 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate /* 14637c478bd9Sstevel@tonic-gate * Copy eid 14647c478bd9Sstevel@tonic-gate */ 14657c478bd9Sstevel@tonic-gate if (copyin(eid, &eid_copy, sizeof (sysevent_id_t)) == -1) { 14667c478bd9Sstevel@tonic-gate return (EFAULT); 14677c478bd9Sstevel@tonic-gate } 14687c478bd9Sstevel@tonic-gate 14697c478bd9Sstevel@tonic-gate mutex_enter(&eventq_sent_mutex); 14707c478bd9Sstevel@tonic-gate q = log_eventq_sent; 14717c478bd9Sstevel@tonic-gate 14727c478bd9Sstevel@tonic-gate /* 14737c478bd9Sstevel@tonic-gate * Search for event buffer on the sent queue with matching 14747c478bd9Sstevel@tonic-gate * event identifier 14757c478bd9Sstevel@tonic-gate */ 14767c478bd9Sstevel@tonic-gate while (q) { 14777c478bd9Sstevel@tonic-gate ev = (sysevent_t *)&q->arg.buf; 14787c478bd9Sstevel@tonic-gate 14797c478bd9Sstevel@tonic-gate if (SE_TIME(ev) != eid_copy.eid_ts || 14807c478bd9Sstevel@tonic-gate SE_SEQ(ev) != eid_copy.eid_seq) { 14817c478bd9Sstevel@tonic-gate q = q->next; 14827c478bd9Sstevel@tonic-gate continue; 14837c478bd9Sstevel@tonic-gate } 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate if (ubuflen < SE_SIZE(ev)) { 14867c478bd9Sstevel@tonic-gate error = EFAULT; 14877c478bd9Sstevel@tonic-gate break; 14887c478bd9Sstevel@tonic-gate } 14897c478bd9Sstevel@tonic-gate if (copyout(ev, ubuf, SE_SIZE(ev)) != 0) { 14907c478bd9Sstevel@tonic-gate error = EFAULT; 14917c478bd9Sstevel@tonic-gate LOG_DEBUG((CE_NOTE, "Unable to retrieve system event " 14927c478bd9Sstevel@tonic-gate "0x%" PRIx64 " from queue: EFAULT\n", 14937c478bd9Sstevel@tonic-gate eid->eid_seq)); 14947c478bd9Sstevel@tonic-gate } else { 14957c478bd9Sstevel@tonic-gate error = 0; 14967c478bd9Sstevel@tonic-gate } 14977c478bd9Sstevel@tonic-gate break; 14987c478bd9Sstevel@tonic-gate } 14997c478bd9Sstevel@tonic-gate 15007c478bd9Sstevel@tonic-gate mutex_exit(&eventq_sent_mutex); 15017c478bd9Sstevel@tonic-gate 15027c478bd9Sstevel@tonic-gate return (error); 15037c478bd9Sstevel@tonic-gate } 15047c478bd9Sstevel@tonic-gate 15057c478bd9Sstevel@tonic-gate /* 15067c478bd9Sstevel@tonic-gate * log_sysevent_free_data - Free kernel copy of the event buffer identified 15077c478bd9Sstevel@tonic-gate * by eid (must have already been sent). Called from 15087c478bd9Sstevel@tonic-gate * modctl(MODEVENTS, MODEVENTS_FREEDATA). 15097c478bd9Sstevel@tonic-gate */ 15107c478bd9Sstevel@tonic-gate int 15117c478bd9Sstevel@tonic-gate log_sysevent_free_data(sysevent_id_t *eid) 15127c478bd9Sstevel@tonic-gate { 15137c478bd9Sstevel@tonic-gate int error = ENOENT; 15147c478bd9Sstevel@tonic-gate sysevent_t *ev; 15157c478bd9Sstevel@tonic-gate log_eventq_t *q, *prev = NULL; 15167c478bd9Sstevel@tonic-gate sysevent_id_t eid_copy; 15177c478bd9Sstevel@tonic-gate 15187c478bd9Sstevel@tonic-gate /* 15197c478bd9Sstevel@tonic-gate * Copy eid 15207c478bd9Sstevel@tonic-gate */ 15217c478bd9Sstevel@tonic-gate if (copyin(eid, &eid_copy, sizeof (sysevent_id_t)) == -1) { 15227c478bd9Sstevel@tonic-gate return (EFAULT); 15237c478bd9Sstevel@tonic-gate } 15247c478bd9Sstevel@tonic-gate 15257c478bd9Sstevel@tonic-gate mutex_enter(&eventq_sent_mutex); 15267c478bd9Sstevel@tonic-gate q = log_eventq_sent; 15277c478bd9Sstevel@tonic-gate 15287c478bd9Sstevel@tonic-gate /* 15297c478bd9Sstevel@tonic-gate * Look for the event to be freed on the sent queue. Due to delayed 15307c478bd9Sstevel@tonic-gate * processing of the event, it may not be on the sent queue yet. 15317c478bd9Sstevel@tonic-gate * It is up to the user to retry the free operation to ensure that the 15327c478bd9Sstevel@tonic-gate * event is properly freed. 15337c478bd9Sstevel@tonic-gate */ 15347c478bd9Sstevel@tonic-gate while (q) { 15357c478bd9Sstevel@tonic-gate ev = (sysevent_t *)&q->arg.buf; 15367c478bd9Sstevel@tonic-gate 15377c478bd9Sstevel@tonic-gate if (SE_TIME(ev) != eid_copy.eid_ts || 15387c478bd9Sstevel@tonic-gate SE_SEQ(ev) != eid_copy.eid_seq) { 15397c478bd9Sstevel@tonic-gate prev = q; 15407c478bd9Sstevel@tonic-gate q = q->next; 15417c478bd9Sstevel@tonic-gate continue; 15427c478bd9Sstevel@tonic-gate } 15437c478bd9Sstevel@tonic-gate /* 15447c478bd9Sstevel@tonic-gate * Take it out of log_eventq_sent and free it 15457c478bd9Sstevel@tonic-gate */ 15467c478bd9Sstevel@tonic-gate if (prev) { 15477c478bd9Sstevel@tonic-gate prev->next = q->next; 15487c478bd9Sstevel@tonic-gate } else { 15497c478bd9Sstevel@tonic-gate log_eventq_sent = q->next; 15507c478bd9Sstevel@tonic-gate } 15517c478bd9Sstevel@tonic-gate free_packed_event(ev); 15527c478bd9Sstevel@tonic-gate error = 0; 15537c478bd9Sstevel@tonic-gate break; 15547c478bd9Sstevel@tonic-gate } 15557c478bd9Sstevel@tonic-gate 15567c478bd9Sstevel@tonic-gate mutex_exit(&eventq_sent_mutex); 15577c478bd9Sstevel@tonic-gate 15587c478bd9Sstevel@tonic-gate return (error); 15597c478bd9Sstevel@tonic-gate } 15607c478bd9Sstevel@tonic-gate 15617c478bd9Sstevel@tonic-gate /* 15627c478bd9Sstevel@tonic-gate * log_sysevent_flushq - Begin or resume event buffer delivery. If neccessary, 15637c478bd9Sstevel@tonic-gate * create log_event_deliver thread or wake it up 15647c478bd9Sstevel@tonic-gate */ 15657c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 15667c478bd9Sstevel@tonic-gate void 15677c478bd9Sstevel@tonic-gate log_sysevent_flushq(int cmd, uint_t flag) 15687c478bd9Sstevel@tonic-gate { 15697c478bd9Sstevel@tonic-gate mutex_enter(&eventq_head_mutex); 15707c478bd9Sstevel@tonic-gate 15717c478bd9Sstevel@tonic-gate /* 15727c478bd9Sstevel@tonic-gate * Start the event delivery thread 15737c478bd9Sstevel@tonic-gate * Mark the upcall status as active since we should 15747c478bd9Sstevel@tonic-gate * now be able to begin emptying the queue normally. 15757c478bd9Sstevel@tonic-gate */ 15767c478bd9Sstevel@tonic-gate if (!async_thread) { 15777c478bd9Sstevel@tonic-gate sysevent_upcall_status = 0; 15787c478bd9Sstevel@tonic-gate sysevent_daemon_init = 1; 15797c478bd9Sstevel@tonic-gate setup_ddi_poststartup(); 15807c478bd9Sstevel@tonic-gate async_thread = thread_create(NULL, 0, log_event_deliver, 15817c478bd9Sstevel@tonic-gate NULL, 0, &p0, TS_RUN, minclsyspri); 15827c478bd9Sstevel@tonic-gate } 15837c478bd9Sstevel@tonic-gate 15847c478bd9Sstevel@tonic-gate log_event_delivery = LOGEVENT_DELIVERY_CONT; 15857c478bd9Sstevel@tonic-gate cv_signal(&log_event_cv); 15867c478bd9Sstevel@tonic-gate mutex_exit(&eventq_head_mutex); 15877c478bd9Sstevel@tonic-gate } 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate /* 15907c478bd9Sstevel@tonic-gate * log_sysevent_filename - Called by syseventd via 15917c478bd9Sstevel@tonic-gate * modctl(MODEVENTS, MODEVENTS_SET_DOOR_UPCALL_FILENAME) 15927c478bd9Sstevel@tonic-gate * to subsequently bind the event_door. 15937c478bd9Sstevel@tonic-gate * 15947c478bd9Sstevel@tonic-gate * This routine is called everytime syseventd (re)starts 15957c478bd9Sstevel@tonic-gate * and must therefore replay any events buffers that have 15967c478bd9Sstevel@tonic-gate * been sent but not freed. 15977c478bd9Sstevel@tonic-gate * 15987c478bd9Sstevel@tonic-gate * Event buffer delivery begins after a call to 15997c478bd9Sstevel@tonic-gate * log_sysevent_flushq(). 16007c478bd9Sstevel@tonic-gate */ 16017c478bd9Sstevel@tonic-gate int 16027c478bd9Sstevel@tonic-gate log_sysevent_filename(char *file) 16037c478bd9Sstevel@tonic-gate { 16047c478bd9Sstevel@tonic-gate /* 16057c478bd9Sstevel@tonic-gate * Called serially by syseventd init code, no need to protect door 16067c478bd9Sstevel@tonic-gate * data. 16077c478bd9Sstevel@tonic-gate */ 16087c478bd9Sstevel@tonic-gate /* Unbind old event door */ 16097c478bd9Sstevel@tonic-gate if (logevent_door_upcall_filename) { 16107c478bd9Sstevel@tonic-gate kmem_free(logevent_door_upcall_filename, 1611*f6e214c7SGavin Maltby logevent_door_upcall_filename_size); 16127c478bd9Sstevel@tonic-gate if (event_door) { 16137c478bd9Sstevel@tonic-gate door_ki_rele(event_door); 16147c478bd9Sstevel@tonic-gate event_door = NULL; 16157c478bd9Sstevel@tonic-gate } 16167c478bd9Sstevel@tonic-gate } 16177c478bd9Sstevel@tonic-gate logevent_door_upcall_filename_size = strlen(file) + 1; 16187c478bd9Sstevel@tonic-gate logevent_door_upcall_filename = kmem_alloc( 1619*f6e214c7SGavin Maltby logevent_door_upcall_filename_size, KM_SLEEP); 16207c478bd9Sstevel@tonic-gate (void) strcpy(logevent_door_upcall_filename, file); 16217c478bd9Sstevel@tonic-gate 16227c478bd9Sstevel@tonic-gate /* 16237c478bd9Sstevel@tonic-gate * We are called when syseventd restarts. Move all sent, but 16247c478bd9Sstevel@tonic-gate * not committed events from log_eventq_sent to log_eventq_head. 16257c478bd9Sstevel@tonic-gate * Do it in proper order to maintain increasing event id. 16267c478bd9Sstevel@tonic-gate */ 16277c478bd9Sstevel@tonic-gate mutex_enter(&eventq_head_mutex); 16287c478bd9Sstevel@tonic-gate 16297c478bd9Sstevel@tonic-gate mutex_enter(&eventq_sent_mutex); 16307c478bd9Sstevel@tonic-gate while (log_eventq_sent) { 16317c478bd9Sstevel@tonic-gate log_eventq_t *tmp = log_eventq_sent->next; 16327c478bd9Sstevel@tonic-gate log_eventq_sent->next = log_eventq_head; 16337c478bd9Sstevel@tonic-gate if (log_eventq_head == NULL) { 16347c478bd9Sstevel@tonic-gate ASSERT(log_eventq_cnt == 0); 16357c478bd9Sstevel@tonic-gate log_eventq_tail = log_eventq_sent; 16367c478bd9Sstevel@tonic-gate log_eventq_tail->next = NULL; 16377c478bd9Sstevel@tonic-gate } else if (log_eventq_head == log_eventq_tail) { 16387c478bd9Sstevel@tonic-gate ASSERT(log_eventq_cnt == 1); 16397c478bd9Sstevel@tonic-gate ASSERT(log_eventq_head->next == NULL); 16407c478bd9Sstevel@tonic-gate ASSERT(log_eventq_tail->next == NULL); 16417c478bd9Sstevel@tonic-gate } 16427c478bd9Sstevel@tonic-gate log_eventq_head = log_eventq_sent; 16437c478bd9Sstevel@tonic-gate log_eventq_sent = tmp; 16447c478bd9Sstevel@tonic-gate log_eventq_cnt++; 16457c478bd9Sstevel@tonic-gate } 16467c478bd9Sstevel@tonic-gate mutex_exit(&eventq_sent_mutex); 16477c478bd9Sstevel@tonic-gate mutex_exit(&eventq_head_mutex); 16487c478bd9Sstevel@tonic-gate 16497c478bd9Sstevel@tonic-gate return (0); 16507c478bd9Sstevel@tonic-gate } 16517c478bd9Sstevel@tonic-gate 16527c478bd9Sstevel@tonic-gate /* 16537c478bd9Sstevel@tonic-gate * queue_sysevent - queue an event buffer 16547c478bd9Sstevel@tonic-gate */ 16557c478bd9Sstevel@tonic-gate static int 16567c478bd9Sstevel@tonic-gate queue_sysevent(sysevent_t *ev, sysevent_id_t *eid, int flag) 16577c478bd9Sstevel@tonic-gate { 16587c478bd9Sstevel@tonic-gate log_eventq_t *q; 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate ASSERT(flag == SE_SLEEP || flag == SE_NOSLEEP); 16617c478bd9Sstevel@tonic-gate 1662e04145d0Seschrock DTRACE_SYSEVENT2(post, evch_bind_t *, NULL, sysevent_impl_t *, ev); 1663e04145d0Seschrock 16647c478bd9Sstevel@tonic-gate restart: 16657c478bd9Sstevel@tonic-gate 16667c478bd9Sstevel@tonic-gate /* Max Q size exceeded */ 16677c478bd9Sstevel@tonic-gate mutex_enter(&event_qfull_mutex); 16687c478bd9Sstevel@tonic-gate if (sysevent_daemon_init && log_eventq_cnt >= logevent_max_q_sz) { 16697c478bd9Sstevel@tonic-gate /* 16707c478bd9Sstevel@tonic-gate * If queue full and transport down, return no transport 16717c478bd9Sstevel@tonic-gate */ 16727c478bd9Sstevel@tonic-gate if (sysevent_upcall_status != 0) { 16737c478bd9Sstevel@tonic-gate mutex_exit(&event_qfull_mutex); 16747c478bd9Sstevel@tonic-gate free_packed_event(ev); 16757c478bd9Sstevel@tonic-gate eid->eid_seq = UINT64_C(0); 16767c478bd9Sstevel@tonic-gate eid->eid_ts = INT64_C(0); 16777c478bd9Sstevel@tonic-gate return (SE_NO_TRANSPORT); 16787c478bd9Sstevel@tonic-gate } 16797c478bd9Sstevel@tonic-gate if (flag == SE_NOSLEEP) { 16807c478bd9Sstevel@tonic-gate mutex_exit(&event_qfull_mutex); 16817c478bd9Sstevel@tonic-gate free_packed_event(ev); 16827c478bd9Sstevel@tonic-gate eid->eid_seq = UINT64_C(0); 16837c478bd9Sstevel@tonic-gate eid->eid_ts = INT64_C(0); 16847c478bd9Sstevel@tonic-gate return (SE_EQSIZE); 16857c478bd9Sstevel@tonic-gate } 16867c478bd9Sstevel@tonic-gate event_qfull_blocked++; 16877c478bd9Sstevel@tonic-gate cv_wait(&event_qfull_cv, &event_qfull_mutex); 16887c478bd9Sstevel@tonic-gate event_qfull_blocked--; 16897c478bd9Sstevel@tonic-gate mutex_exit(&event_qfull_mutex); 16907c478bd9Sstevel@tonic-gate goto restart; 16917c478bd9Sstevel@tonic-gate } 16927c478bd9Sstevel@tonic-gate mutex_exit(&event_qfull_mutex); 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate mutex_enter(&eventq_head_mutex); 16957c478bd9Sstevel@tonic-gate 16967c478bd9Sstevel@tonic-gate /* Time stamp and assign ID */ 16977c478bd9Sstevel@tonic-gate SE_SEQ(ev) = eid->eid_seq = atomic_add_64_nv(&kernel_event_id, 1698*f6e214c7SGavin Maltby (uint64_t)1); 16997c478bd9Sstevel@tonic-gate SE_TIME(ev) = eid->eid_ts = gethrtime(); 17007c478bd9Sstevel@tonic-gate 17017c478bd9Sstevel@tonic-gate LOG_DEBUG1((CE_CONT, "log_sysevent: class=%d type=%d id=0x%llx\n", 17027c478bd9Sstevel@tonic-gate SE_CLASS(ev), SE_SUBCLASS(ev), (longlong_t)SE_SEQ(ev))); 17037c478bd9Sstevel@tonic-gate 17047c478bd9Sstevel@tonic-gate /* 17057c478bd9Sstevel@tonic-gate * Put event on eventq 17067c478bd9Sstevel@tonic-gate */ 17077c478bd9Sstevel@tonic-gate q = (log_eventq_t *)((caddr_t)ev - offsetof(log_eventq_t, arg.buf)); 17087c478bd9Sstevel@tonic-gate q->next = NULL; 17097c478bd9Sstevel@tonic-gate if (log_eventq_head == NULL) { 17107c478bd9Sstevel@tonic-gate ASSERT(log_eventq_cnt == 0); 17117c478bd9Sstevel@tonic-gate log_eventq_head = q; 17127c478bd9Sstevel@tonic-gate log_eventq_tail = q; 17137c478bd9Sstevel@tonic-gate } else { 17147c478bd9Sstevel@tonic-gate if (log_eventq_head == log_eventq_tail) { 17157c478bd9Sstevel@tonic-gate ASSERT(log_eventq_cnt == 1); 17167c478bd9Sstevel@tonic-gate ASSERT(log_eventq_head->next == NULL); 17177c478bd9Sstevel@tonic-gate ASSERT(log_eventq_tail->next == NULL); 17187c478bd9Sstevel@tonic-gate } 17197c478bd9Sstevel@tonic-gate log_eventq_tail->next = q; 17207c478bd9Sstevel@tonic-gate log_eventq_tail = q; 17217c478bd9Sstevel@tonic-gate } 17227c478bd9Sstevel@tonic-gate log_eventq_cnt++; 17237c478bd9Sstevel@tonic-gate 17247c478bd9Sstevel@tonic-gate /* Signal event delivery thread */ 17257c478bd9Sstevel@tonic-gate if (log_eventq_cnt == 1) { 17267c478bd9Sstevel@tonic-gate cv_signal(&log_event_cv); 17277c478bd9Sstevel@tonic-gate } 17287c478bd9Sstevel@tonic-gate mutex_exit(&eventq_head_mutex); 17297c478bd9Sstevel@tonic-gate 17307c478bd9Sstevel@tonic-gate return (0); 17317c478bd9Sstevel@tonic-gate } 17327c478bd9Sstevel@tonic-gate 17337c478bd9Sstevel@tonic-gate /* 17347c478bd9Sstevel@tonic-gate * log_sysevent - kernel system event logger. 17357c478bd9Sstevel@tonic-gate * 17367c478bd9Sstevel@tonic-gate * Returns SE_ENOMEM if buf allocation failed or SE_EQSIZE if the 17377c478bd9Sstevel@tonic-gate * maximum event queue size will be exceeded 17387c478bd9Sstevel@tonic-gate * Returns 0 for successfully queued event buffer 17397c478bd9Sstevel@tonic-gate */ 17407c478bd9Sstevel@tonic-gate int 17417c478bd9Sstevel@tonic-gate log_sysevent(sysevent_t *ev, int flag, sysevent_id_t *eid) 17427c478bd9Sstevel@tonic-gate { 17437c478bd9Sstevel@tonic-gate sysevent_t *ev_copy; 17447c478bd9Sstevel@tonic-gate int rval; 17457c478bd9Sstevel@tonic-gate 17467c478bd9Sstevel@tonic-gate ASSERT(flag == SE_SLEEP || flag == SE_NOSLEEP); 17477c478bd9Sstevel@tonic-gate ASSERT(!(flag == SE_SLEEP && servicing_interrupt())); 17487c478bd9Sstevel@tonic-gate 17497c478bd9Sstevel@tonic-gate ev_copy = se_repack(ev, flag); 17507c478bd9Sstevel@tonic-gate if (ev_copy == NULL) { 17517c478bd9Sstevel@tonic-gate ASSERT(flag == SE_NOSLEEP); 17527c478bd9Sstevel@tonic-gate return (SE_ENOMEM); 17537c478bd9Sstevel@tonic-gate } 17547c478bd9Sstevel@tonic-gate rval = queue_sysevent(ev_copy, eid, flag); 17557c478bd9Sstevel@tonic-gate ASSERT(rval == 0 || rval == SE_ENOMEM || rval == SE_EQSIZE || 1756*f6e214c7SGavin Maltby rval == SE_NO_TRANSPORT); 17577c478bd9Sstevel@tonic-gate ASSERT(!(flag == SE_SLEEP && (rval == SE_EQSIZE || rval == SE_ENOMEM))); 17587c478bd9Sstevel@tonic-gate return (rval); 17597c478bd9Sstevel@tonic-gate } 17607c478bd9Sstevel@tonic-gate 17617c478bd9Sstevel@tonic-gate /* 17627c478bd9Sstevel@tonic-gate * log_usr_sysevent - user system event logger 17637c478bd9Sstevel@tonic-gate * Private to devfsadm and accessible only via 17647c478bd9Sstevel@tonic-gate * modctl(MODEVENTS, MODEVENTS_POST_EVENT) 17657c478bd9Sstevel@tonic-gate */ 17667c478bd9Sstevel@tonic-gate int 17677c478bd9Sstevel@tonic-gate log_usr_sysevent(sysevent_t *ev, int ev_size, sysevent_id_t *eid) 17687c478bd9Sstevel@tonic-gate { 17697c478bd9Sstevel@tonic-gate int ret, copy_sz; 17707c478bd9Sstevel@tonic-gate sysevent_t *ev_copy; 17717c478bd9Sstevel@tonic-gate sysevent_id_t new_eid; 17727c478bd9Sstevel@tonic-gate log_eventq_t *qcopy; 17737c478bd9Sstevel@tonic-gate 17747c478bd9Sstevel@tonic-gate copy_sz = ev_size + offsetof(log_eventq_t, arg) + 1775*f6e214c7SGavin Maltby offsetof(log_event_upcall_arg_t, buf); 17767c478bd9Sstevel@tonic-gate qcopy = kmem_zalloc(copy_sz, KM_SLEEP); 17777c478bd9Sstevel@tonic-gate ev_copy = (sysevent_t *)&qcopy->arg.buf; 17787c478bd9Sstevel@tonic-gate 17797c478bd9Sstevel@tonic-gate /* 17807c478bd9Sstevel@tonic-gate * Copy event 17817c478bd9Sstevel@tonic-gate */ 17827c478bd9Sstevel@tonic-gate if (copyin(ev, ev_copy, ev_size) == -1) { 17837c478bd9Sstevel@tonic-gate kmem_free(qcopy, copy_sz); 17847c478bd9Sstevel@tonic-gate return (EFAULT); 17857c478bd9Sstevel@tonic-gate } 17867c478bd9Sstevel@tonic-gate 17877c478bd9Sstevel@tonic-gate if ((ret = queue_sysevent(ev_copy, &new_eid, SE_NOSLEEP)) != 0) { 17887c478bd9Sstevel@tonic-gate if (ret == SE_ENOMEM || ret == SE_EQSIZE) 17897c478bd9Sstevel@tonic-gate return (EAGAIN); 17907c478bd9Sstevel@tonic-gate else 17917c478bd9Sstevel@tonic-gate return (EIO); 17927c478bd9Sstevel@tonic-gate } 17937c478bd9Sstevel@tonic-gate 17947c478bd9Sstevel@tonic-gate if (copyout(&new_eid, eid, sizeof (sysevent_id_t)) == -1) { 17957c478bd9Sstevel@tonic-gate return (EFAULT); 17967c478bd9Sstevel@tonic-gate } 17977c478bd9Sstevel@tonic-gate 17987c478bd9Sstevel@tonic-gate return (0); 17997c478bd9Sstevel@tonic-gate } 18007c478bd9Sstevel@tonic-gate 18017c478bd9Sstevel@tonic-gate 18027c478bd9Sstevel@tonic-gate 18037c478bd9Sstevel@tonic-gate int 18047c478bd9Sstevel@tonic-gate ddi_log_sysevent( 18057c478bd9Sstevel@tonic-gate dev_info_t *dip, 18067c478bd9Sstevel@tonic-gate char *vendor, 18077c478bd9Sstevel@tonic-gate char *class, 18087c478bd9Sstevel@tonic-gate char *subclass, 18097c478bd9Sstevel@tonic-gate nvlist_t *attr_list, 18107c478bd9Sstevel@tonic-gate sysevent_id_t *eidp, 18117c478bd9Sstevel@tonic-gate int sleep_flag) 18127c478bd9Sstevel@tonic-gate { 18137c478bd9Sstevel@tonic-gate sysevent_attr_list_t *list = (sysevent_attr_list_t *)attr_list; 18147c478bd9Sstevel@tonic-gate char pubstr[32]; 18157c478bd9Sstevel@tonic-gate sysevent_t *event; 18167c478bd9Sstevel@tonic-gate sysevent_id_t eid; 18177c478bd9Sstevel@tonic-gate const char *drvname; 18187c478bd9Sstevel@tonic-gate char *publisher; 18197c478bd9Sstevel@tonic-gate int se_flag; 18207c478bd9Sstevel@tonic-gate int rval; 18217c478bd9Sstevel@tonic-gate int n; 18227c478bd9Sstevel@tonic-gate 18237c478bd9Sstevel@tonic-gate if (sleep_flag == DDI_SLEEP && servicing_interrupt()) { 18247c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "!ddi_log_syevent: driver %s%d - cannot queue " 1825*f6e214c7SGavin Maltby "event from interrupt context with sleep semantics\n", 1826*f6e214c7SGavin Maltby ddi_driver_name(dip), ddi_get_instance(dip)); 18277c478bd9Sstevel@tonic-gate return (DDI_ECONTEXT); 18287c478bd9Sstevel@tonic-gate } 18297c478bd9Sstevel@tonic-gate 18307c478bd9Sstevel@tonic-gate drvname = ddi_driver_name(dip); 18317c478bd9Sstevel@tonic-gate n = strlen(vendor) + strlen(drvname) + 7; 18327c478bd9Sstevel@tonic-gate if (n < sizeof (pubstr)) { 18337c478bd9Sstevel@tonic-gate publisher = pubstr; 18347c478bd9Sstevel@tonic-gate } else { 18357c478bd9Sstevel@tonic-gate publisher = kmem_alloc(n, 1836*f6e214c7SGavin Maltby (sleep_flag == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP); 18377c478bd9Sstevel@tonic-gate if (publisher == NULL) { 18387c478bd9Sstevel@tonic-gate return (DDI_ENOMEM); 18397c478bd9Sstevel@tonic-gate } 18407c478bd9Sstevel@tonic-gate } 18417c478bd9Sstevel@tonic-gate (void) strcpy(publisher, vendor); 18427c478bd9Sstevel@tonic-gate (void) strcat(publisher, ":kern:"); 18437c478bd9Sstevel@tonic-gate (void) strcat(publisher, drvname); 18447c478bd9Sstevel@tonic-gate 18457c478bd9Sstevel@tonic-gate se_flag = (sleep_flag == DDI_SLEEP) ? SE_SLEEP : SE_NOSLEEP; 18467c478bd9Sstevel@tonic-gate event = sysevent_alloc(class, subclass, publisher, se_flag); 18477c478bd9Sstevel@tonic-gate 18487c478bd9Sstevel@tonic-gate if (publisher != pubstr) { 18497c478bd9Sstevel@tonic-gate kmem_free(publisher, n); 18507c478bd9Sstevel@tonic-gate } 18517c478bd9Sstevel@tonic-gate 18527c478bd9Sstevel@tonic-gate if (event == NULL) { 18537c478bd9Sstevel@tonic-gate return (DDI_ENOMEM); 18547c478bd9Sstevel@tonic-gate } 18557c478bd9Sstevel@tonic-gate 18567c478bd9Sstevel@tonic-gate if (list) { 18577c478bd9Sstevel@tonic-gate (void) sysevent_attach_attributes(event, list); 18587c478bd9Sstevel@tonic-gate } 18597c478bd9Sstevel@tonic-gate 18607c478bd9Sstevel@tonic-gate rval = log_sysevent(event, se_flag, &eid); 18617c478bd9Sstevel@tonic-gate if (list) { 18627c478bd9Sstevel@tonic-gate sysevent_detach_attributes(event); 18637c478bd9Sstevel@tonic-gate } 18647c478bd9Sstevel@tonic-gate sysevent_free(event); 18657c478bd9Sstevel@tonic-gate if (rval == 0) { 18667c478bd9Sstevel@tonic-gate if (eidp) { 18677c478bd9Sstevel@tonic-gate eidp->eid_seq = eid.eid_seq; 18687c478bd9Sstevel@tonic-gate eidp->eid_ts = eid.eid_ts; 18697c478bd9Sstevel@tonic-gate } 18707c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 18717c478bd9Sstevel@tonic-gate } 18727c478bd9Sstevel@tonic-gate if (rval == SE_NO_TRANSPORT) 18737c478bd9Sstevel@tonic-gate return (DDI_ETRANSPORT); 18747c478bd9Sstevel@tonic-gate 18757c478bd9Sstevel@tonic-gate ASSERT(rval == SE_ENOMEM || rval == SE_EQSIZE); 18767c478bd9Sstevel@tonic-gate return ((rval == SE_ENOMEM) ? DDI_ENOMEM : DDI_EBUSY); 18777c478bd9Sstevel@tonic-gate } 18787c478bd9Sstevel@tonic-gate 18797c478bd9Sstevel@tonic-gate uint64_t 1880*f6e214c7SGavin Maltby log_sysevent_new_id(void) 18817c478bd9Sstevel@tonic-gate { 18827c478bd9Sstevel@tonic-gate return (atomic_add_64_nv(&kernel_event_id, (uint64_t)1)); 18837c478bd9Sstevel@tonic-gate } 1884