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