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