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