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 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 237c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 26*5cffb260SRob Johnston /* 27*5cffb260SRob Johnston * Copyright 2019 Joyent, Inc. 28*5cffb260SRob Johnston */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <stdio.h> 317c478bd9Sstevel@tonic-gate #include <stdlib.h> 327c478bd9Sstevel@tonic-gate #include <stropts.h> 337c478bd9Sstevel@tonic-gate #include <synch.h> 347c478bd9Sstevel@tonic-gate #include <thread.h> 357c478bd9Sstevel@tonic-gate #include <libsysevent.h> 367c478bd9Sstevel@tonic-gate #include <sys/sysevent/eventdefs.h> 377c478bd9Sstevel@tonic-gate #include <sys/sysevent/dev.h> 387c478bd9Sstevel@tonic-gate #include <errno.h> 397c478bd9Sstevel@tonic-gate #include <libgen.h> 407c478bd9Sstevel@tonic-gate #include <unistd.h> 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #include "libdiskmgt.h" 437c478bd9Sstevel@tonic-gate #include "disks_private.h" 447c478bd9Sstevel@tonic-gate 45*5cffb260SRob Johnston #pragma fini(libdiskmgt_fini) 46*5cffb260SRob Johnston 477c478bd9Sstevel@tonic-gate struct event_list { 487c478bd9Sstevel@tonic-gate struct event_list *next; 497c478bd9Sstevel@tonic-gate nvlist_t *event; 507c478bd9Sstevel@tonic-gate }; 517c478bd9Sstevel@tonic-gate 52*5cffb260SRob Johnston static mutex_t shp_lock = ERRORCHECKMUTEX; 53*5cffb260SRob Johnston static sysevent_handle_t *shp = NULL; 54*5cffb260SRob Johnston 557c478bd9Sstevel@tonic-gate static struct event_list *events = NULL; 567c478bd9Sstevel@tonic-gate static int event_error = 0; 577c478bd9Sstevel@tonic-gate static int event_break = 0; 587c478bd9Sstevel@tonic-gate static mutex_t queue_lock; 597c478bd9Sstevel@tonic-gate static sema_t semaphore; 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate /* 627c478bd9Sstevel@tonic-gate * When we add a controller we get an add event for each drive on the 637c478bd9Sstevel@tonic-gate * controller. We don't want to walk the devtree for each drive since 647c478bd9Sstevel@tonic-gate * we will get the same information each time. So, the solution is to 657c478bd9Sstevel@tonic-gate * wait for a few seconds for all of the add events to come in and then 667c478bd9Sstevel@tonic-gate * do a single walk. If an add event comes in after we start the walk, we 677c478bd9Sstevel@tonic-gate * need to do another walk since we might have missed that drive. 687c478bd9Sstevel@tonic-gate * 697c478bd9Sstevel@tonic-gate * State: 0 - no walker; 1 - walker waiting; 2 - walker running 707c478bd9Sstevel@tonic-gate * 0 -> 1; wait a few seconds 717c478bd9Sstevel@tonic-gate * 1 -> 2; walking the devtree 727c478bd9Sstevel@tonic-gate * 2 -> either 0 or 1 (see below) 737c478bd9Sstevel@tonic-gate * While running (state 2), if event comes in, go back to waiting (state 1) 747c478bd9Sstevel@tonic-gate * after the walk otherwise go back to none (state 0). 757c478bd9Sstevel@tonic-gate * 767c478bd9Sstevel@tonic-gate * walker_lock protects walker_state & events_pending 777c478bd9Sstevel@tonic-gate */ 787c478bd9Sstevel@tonic-gate #define WALK_NONE 0 797c478bd9Sstevel@tonic-gate #define WALK_WAITING 1 807c478bd9Sstevel@tonic-gate #define WALK_RUNNING 2 817c478bd9Sstevel@tonic-gate #define WALK_WAIT_TIME 60 /* wait 60 seconds */ 827c478bd9Sstevel@tonic-gate 83*5cffb260SRob Johnston static mutex_t walker_lock = ERRORCHECKMUTEX; 84*5cffb260SRob Johnston static cond_t walker_cv = DEFAULTCV; 857c478bd9Sstevel@tonic-gate static int walker_state = WALK_NONE; 86*5cffb260SRob Johnston 877c478bd9Sstevel@tonic-gate static int events_pending = 0; 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate static int sendevents = 0; 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate static void add_event_to_queue(nvlist_t *event); 927c478bd9Sstevel@tonic-gate static void cb_watch_events(); 937c478bd9Sstevel@tonic-gate static void event_handler(sysevent_t *ev); 947c478bd9Sstevel@tonic-gate static void print_nvlist(char *prefix, nvlist_t *list); 957c478bd9Sstevel@tonic-gate static void walk_devtree(); 967c478bd9Sstevel@tonic-gate static void walker(void *arg); 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate static void(*callback)(nvlist_t *, int) = NULL; 997c478bd9Sstevel@tonic-gate 100*5cffb260SRob Johnston static boolean_t shutting_down = B_FALSE; 101*5cffb260SRob Johnston 102*5cffb260SRob Johnston static void 103*5cffb260SRob Johnston libdiskmgt_fini(void) 104*5cffb260SRob Johnston { 105*5cffb260SRob Johnston mutex_enter(&shp_lock); 106*5cffb260SRob Johnston if (shp != NULL) { 107*5cffb260SRob Johnston sysevent_unsubscribe_event(shp, EC_ALL); 108*5cffb260SRob Johnston sysevent_unbind_handle(shp); 109*5cffb260SRob Johnston shp = NULL; 110*5cffb260SRob Johnston } 111*5cffb260SRob Johnston /* 112*5cffb260SRob Johnston * At this point a new invocation of walker() can't occur. However, 113*5cffb260SRob Johnston * if one was already running then we need to wait for it to finish 114*5cffb260SRob Johnston * because if we allow ourselves to be unloaded out from underneath 115*5cffb260SRob Johnston * it, then bad things will happen. 116*5cffb260SRob Johnston */ 117*5cffb260SRob Johnston mutex_enter(&walker_lock); 118*5cffb260SRob Johnston shutting_down = B_TRUE; 119*5cffb260SRob Johnston while (walker_state != WALK_NONE) 120*5cffb260SRob Johnston (void) cond_wait(&walker_cv, &walker_lock); 121*5cffb260SRob Johnston 122*5cffb260SRob Johnston mutex_exit(&walker_lock); 123*5cffb260SRob Johnston } 124*5cffb260SRob Johnston 1257c478bd9Sstevel@tonic-gate nvlist_t * 1267c478bd9Sstevel@tonic-gate dm_get_event(int *errp) 1277c478bd9Sstevel@tonic-gate { 1287c478bd9Sstevel@tonic-gate nvlist_t *event = NULL; 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate *errp = 0; 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate /* wait until there is an event in the queue */ 1337c478bd9Sstevel@tonic-gate /*CONSTCOND*/ 1347c478bd9Sstevel@tonic-gate while (1) { 1357c478bd9Sstevel@tonic-gate (void) sema_wait(&semaphore); 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate if (event_break) { 1387c478bd9Sstevel@tonic-gate event_break = 0; 1397c478bd9Sstevel@tonic-gate *errp = EINTR; 1407c478bd9Sstevel@tonic-gate break; 1417c478bd9Sstevel@tonic-gate } 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate (void) mutex_lock(&queue_lock); 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate /* first see if we ran out of memory since the last call */ 1467c478bd9Sstevel@tonic-gate if (event_error != 0) { 1477c478bd9Sstevel@tonic-gate *errp = event_error; 1487c478bd9Sstevel@tonic-gate event_error = 0; 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate } else if (events != NULL) { 1517c478bd9Sstevel@tonic-gate struct event_list *tmpp; 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate event = events->event; 1547c478bd9Sstevel@tonic-gate tmpp = events->next; 1557c478bd9Sstevel@tonic-gate free(events); 1567c478bd9Sstevel@tonic-gate events = tmpp; 1577c478bd9Sstevel@tonic-gate } 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate (void) mutex_unlock(&queue_lock); 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate if (*errp != 0 || event != NULL) { 1627c478bd9Sstevel@tonic-gate break; 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate } 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate return (event); 1677c478bd9Sstevel@tonic-gate } 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate void 1707c478bd9Sstevel@tonic-gate dm_init_event_queue(void (*cb)(nvlist_t *, int), int *errp) 1717c478bd9Sstevel@tonic-gate { 1727c478bd9Sstevel@tonic-gate if (sendevents == 1) { 1737c478bd9Sstevel@tonic-gate /* we were already initialized, see what changes to make */ 1747c478bd9Sstevel@tonic-gate *errp = 0; 1757c478bd9Sstevel@tonic-gate if (cb != callback) { 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate callback = cb; 1787c478bd9Sstevel@tonic-gate if (cb == NULL) { 1797c478bd9Sstevel@tonic-gate /* clearing the cb so shutdown the internal cb thread */ 1807c478bd9Sstevel@tonic-gate event_break = 1; 1817c478bd9Sstevel@tonic-gate (void) sema_post(&semaphore); 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate } else { 1847c478bd9Sstevel@tonic-gate /* installing a cb; we didn't have one before */ 1857c478bd9Sstevel@tonic-gate thread_t watch_thread; 1867c478bd9Sstevel@tonic-gate 187bd401f05SToomas Soome *errp = thr_create(NULL, 0, 1887c478bd9Sstevel@tonic-gate (void *(*)(void *))cb_watch_events, NULL, THR_DAEMON, 1897c478bd9Sstevel@tonic-gate &watch_thread); 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate } else { 1947c478bd9Sstevel@tonic-gate /* first time to initialize */ 1957c478bd9Sstevel@tonic-gate sendevents = 1; 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate *errp = sema_init(&semaphore, 0, USYNC_THREAD, NULL); 1987c478bd9Sstevel@tonic-gate if (*errp != 0) { 1997c478bd9Sstevel@tonic-gate return; 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate if (cb != NULL) { 2037c478bd9Sstevel@tonic-gate thread_t watch_thread; 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate callback = cb; 2067c478bd9Sstevel@tonic-gate 207bd401f05SToomas Soome *errp = thr_create(NULL, 0, 2087c478bd9Sstevel@tonic-gate (void *(*)(void *))cb_watch_events, NULL, THR_DAEMON, 2097c478bd9Sstevel@tonic-gate &watch_thread); 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate } 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate void 2157c478bd9Sstevel@tonic-gate events_new_event(char *name, int dtype, char *etype) 2167c478bd9Sstevel@tonic-gate { 2177c478bd9Sstevel@tonic-gate nvlist_t *event = NULL; 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate if (!sendevents) { 2207c478bd9Sstevel@tonic-gate return; 2217c478bd9Sstevel@tonic-gate } 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate if (nvlist_alloc(&event, NVATTRS, 0) != 0) { 2247c478bd9Sstevel@tonic-gate event = NULL; 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate } else { 2277c478bd9Sstevel@tonic-gate int error = 0; 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate if (name != NULL && 2307c478bd9Sstevel@tonic-gate nvlist_add_string(event, DM_EV_NAME, name) != 0) { 2317c478bd9Sstevel@tonic-gate error = ENOMEM; 2327c478bd9Sstevel@tonic-gate } 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate if (dtype != -1 && 2357c478bd9Sstevel@tonic-gate nvlist_add_uint32(event, DM_EV_DTYPE, dtype) != 0) { 2367c478bd9Sstevel@tonic-gate error = ENOMEM; 2377c478bd9Sstevel@tonic-gate } 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate if (nvlist_add_string(event, DM_EV_TYPE, etype) != 0) { 2407c478bd9Sstevel@tonic-gate error = ENOMEM; 2417c478bd9Sstevel@tonic-gate } 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate if (error != 0) { 2447c478bd9Sstevel@tonic-gate nvlist_free(event); 2457c478bd9Sstevel@tonic-gate event = NULL; 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate add_event_to_queue(event); 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate void 2537c478bd9Sstevel@tonic-gate events_new_slice_event(char *dev, char *type) 2547c478bd9Sstevel@tonic-gate { 2557c478bd9Sstevel@tonic-gate events_new_event(basename(dev), DM_SLICE, type); 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate int 2597c478bd9Sstevel@tonic-gate events_start_event_watcher() 2607c478bd9Sstevel@tonic-gate { 2617c478bd9Sstevel@tonic-gate const char *subclass_list[1]; 262*5cffb260SRob Johnston int ret = -1; 263*5cffb260SRob Johnston 264*5cffb260SRob Johnston mutex_enter(&shp_lock); 265*5cffb260SRob Johnston if (shp != NULL) { 266*5cffb260SRob Johnston ret = 0; 267*5cffb260SRob Johnston goto out; 268*5cffb260SRob Johnston } 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate /* Bind event handler and create subscriber handle */ 2717c478bd9Sstevel@tonic-gate shp = sysevent_bind_handle(event_handler); 2727c478bd9Sstevel@tonic-gate if (shp == NULL) { 273*5cffb260SRob Johnston if (dm_debug) { 274*5cffb260SRob Johnston (void) fprintf(stderr, "ERROR: sysevent bind failed: " 275*5cffb260SRob Johnston "%d\n", errno); 276*5cffb260SRob Johnston } 277*5cffb260SRob Johnston goto out; 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate subclass_list[0] = ESC_DISK; 281*5cffb260SRob Johnston if (sysevent_subscribe_event(shp, EC_DEV_ADD, subclass_list, 1) != 0 || 282*5cffb260SRob Johnston sysevent_subscribe_event(shp, EC_DEV_REMOVE, subclass_list, 1) != 283*5cffb260SRob Johnston 0) { 284*5cffb260SRob Johnston 285*5cffb260SRob Johnston sysevent_unsubscribe_event(shp, EC_ALL); 286*5cffb260SRob Johnston sysevent_unbind_handle(shp); 287*5cffb260SRob Johnston shp = NULL; 2887c478bd9Sstevel@tonic-gate 289*5cffb260SRob Johnston if (dm_debug) { 290*5cffb260SRob Johnston (void) fprintf(stderr, "ERROR: sysevent subscribe " 291*5cffb260SRob Johnston "failed: %d\n", errno); 292*5cffb260SRob Johnston } 293*5cffb260SRob Johnston goto out; 294*5cffb260SRob Johnston } 295*5cffb260SRob Johnston ret = 0; 296*5cffb260SRob Johnston out: 297*5cffb260SRob Johnston mutex_exit(&shp_lock); 298*5cffb260SRob Johnston return (ret); 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate static void 3027c478bd9Sstevel@tonic-gate add_event_to_queue(nvlist_t *event) 3037c478bd9Sstevel@tonic-gate { 3047c478bd9Sstevel@tonic-gate (void) mutex_lock(&queue_lock); 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate if (event == NULL) { 3077c478bd9Sstevel@tonic-gate event_error = ENOMEM; 3087c478bd9Sstevel@tonic-gate (void) mutex_unlock(&queue_lock); 3097c478bd9Sstevel@tonic-gate return; 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate if (events == NULL) { 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate events = (struct event_list *)malloc(sizeof (struct event_list)); 3157c478bd9Sstevel@tonic-gate if (events == NULL) { 3167c478bd9Sstevel@tonic-gate event_error = ENOMEM; 3177c478bd9Sstevel@tonic-gate nvlist_free(event); 3187c478bd9Sstevel@tonic-gate } else { 3197c478bd9Sstevel@tonic-gate events->next = NULL; 3207c478bd9Sstevel@tonic-gate events->event = event; 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate } else { 3247c478bd9Sstevel@tonic-gate /* already have events in the queue */ 3257c478bd9Sstevel@tonic-gate struct event_list *ep; 3267c478bd9Sstevel@tonic-gate struct event_list *new_event; 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate /* find the last element in the list */ 3297c478bd9Sstevel@tonic-gate for (ep = events; ep->next != NULL; ep = ep->next); 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate new_event = (struct event_list *)malloc(sizeof (struct event_list)); 3327c478bd9Sstevel@tonic-gate if (new_event == NULL) { 3337c478bd9Sstevel@tonic-gate event_error = ENOMEM; 3347c478bd9Sstevel@tonic-gate nvlist_free(event); 3357c478bd9Sstevel@tonic-gate } else { 3367c478bd9Sstevel@tonic-gate new_event->next = NULL; 3377c478bd9Sstevel@tonic-gate new_event->event = event; 3387c478bd9Sstevel@tonic-gate ep->next = new_event; 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate (void) mutex_unlock(&queue_lock); 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate (void) sema_post(&semaphore); 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate static void 3487c478bd9Sstevel@tonic-gate cb_watch_events() 3497c478bd9Sstevel@tonic-gate { 3507c478bd9Sstevel@tonic-gate nvlist_t *event; 3517c478bd9Sstevel@tonic-gate int error; 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate /*CONSTCOND*/ 3547c478bd9Sstevel@tonic-gate while (1) { 3557c478bd9Sstevel@tonic-gate event = dm_get_event(&error); 3567c478bd9Sstevel@tonic-gate if (callback == NULL) { 3577c478bd9Sstevel@tonic-gate /* end the thread */ 3587c478bd9Sstevel@tonic-gate return; 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate callback(event, error); 3617c478bd9Sstevel@tonic-gate } 3627c478bd9Sstevel@tonic-gate } 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate static void 3657c478bd9Sstevel@tonic-gate event_handler(sysevent_t *ev) 3667c478bd9Sstevel@tonic-gate { 3677c478bd9Sstevel@tonic-gate char *class_name; 3687c478bd9Sstevel@tonic-gate char *pub; 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate class_name = sysevent_get_class_name(ev); 3717c478bd9Sstevel@tonic-gate if (dm_debug) { 3727c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "****EVENT: %s %s ", class_name, 3737c478bd9Sstevel@tonic-gate sysevent_get_subclass_name(ev)); 3747c478bd9Sstevel@tonic-gate if ((pub = sysevent_get_pub_name(ev)) != NULL) { 3757c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s\n", pub); 3767c478bd9Sstevel@tonic-gate free(pub); 3777c478bd9Sstevel@tonic-gate } else { 3787c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate if (libdiskmgt_str_eq(class_name, EC_DEV_ADD)) { 3837c478bd9Sstevel@tonic-gate /* batch up the adds into a single devtree walk */ 3847c478bd9Sstevel@tonic-gate walk_devtree(); 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate } else if (libdiskmgt_str_eq(class_name, EC_DEV_REMOVE)) { 3877c478bd9Sstevel@tonic-gate nvlist_t *nvlist = NULL; 3887c478bd9Sstevel@tonic-gate char *dev_name = NULL; 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate (void) sysevent_get_attr_list(ev, &nvlist); 3917c478bd9Sstevel@tonic-gate if (nvlist != NULL) { 3927c478bd9Sstevel@tonic-gate (void) nvlist_lookup_string(nvlist, DEV_NAME, &dev_name); 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate if (dm_debug) { 3957c478bd9Sstevel@tonic-gate print_nvlist("**** ", nvlist); 3967c478bd9Sstevel@tonic-gate } 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate if (dev_name != NULL) { 4007c478bd9Sstevel@tonic-gate cache_update(DM_EV_DISK_DELETE, dev_name); 4017c478bd9Sstevel@tonic-gate } 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate if (nvlist != NULL) { 4047c478bd9Sstevel@tonic-gate nvlist_free(nvlist); 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate } 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate /* 4107c478bd9Sstevel@tonic-gate * This is a debugging function only. 4117c478bd9Sstevel@tonic-gate */ 4127c478bd9Sstevel@tonic-gate static void 4137c478bd9Sstevel@tonic-gate print_nvlist(char *prefix, nvlist_t *list) 4147c478bd9Sstevel@tonic-gate { 4157c478bd9Sstevel@tonic-gate nvpair_t *nvp; 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate nvp = nvlist_next_nvpair(list, NULL); 4187c478bd9Sstevel@tonic-gate while (nvp != NULL) { 4197c478bd9Sstevel@tonic-gate char *attrname; 4207c478bd9Sstevel@tonic-gate char *str; 4217c478bd9Sstevel@tonic-gate uint32_t ui32; 4227c478bd9Sstevel@tonic-gate uint64_t ui64; 4237c478bd9Sstevel@tonic-gate char **str_array; 4247c478bd9Sstevel@tonic-gate uint_t cnt; 4257c478bd9Sstevel@tonic-gate int i; 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate attrname = nvpair_name(nvp); 4287c478bd9Sstevel@tonic-gate switch (nvpair_type(nvp)) { 4297c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING: 4307c478bd9Sstevel@tonic-gate (void) nvpair_value_string(nvp, &str); 4317c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s%s: %s\n", prefix, attrname, str); 4327c478bd9Sstevel@tonic-gate break; 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: 4357c478bd9Sstevel@tonic-gate (void) nvpair_value_string_array(nvp, &str_array, &cnt); 4367c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s%s:\n", prefix, attrname); 4377c478bd9Sstevel@tonic-gate for (i = 0; i < cnt; i++) { 4387c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s %s\n", prefix, str_array[i]); 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate break; 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32: 4437c478bd9Sstevel@tonic-gate (void) nvpair_value_uint32(nvp, &ui32); 4447c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s%s: %u\n", prefix, attrname, ui32); 4457c478bd9Sstevel@tonic-gate break; 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64: 4487c478bd9Sstevel@tonic-gate (void) nvpair_value_uint64(nvp, &ui64); 4497c478bd9Sstevel@tonic-gate #ifdef _LP64 4507c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s%s: %lu\n", prefix, attrname, ui64); 4517c478bd9Sstevel@tonic-gate #else 4527c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s%s: %llu\n", prefix, attrname, ui64); 4537c478bd9Sstevel@tonic-gate #endif 4547c478bd9Sstevel@tonic-gate break; 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN: 4587c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s%s: true\n", prefix, attrname); 4597c478bd9Sstevel@tonic-gate break; 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate default: 4627c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s%s: UNSUPPORTED TYPE\n", prefix, 4637c478bd9Sstevel@tonic-gate attrname); 4647c478bd9Sstevel@tonic-gate break; 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate nvp = nvlist_next_nvpair(list, nvp); 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate } 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate /* 4727c478bd9Sstevel@tonic-gate * Batch up the adds into a single devtree walk. We can get a bunch of 4737c478bd9Sstevel@tonic-gate * adds when we add a controller since we will get an add event for each 4747c478bd9Sstevel@tonic-gate * drive. 4757c478bd9Sstevel@tonic-gate */ 4767c478bd9Sstevel@tonic-gate static void 4777c478bd9Sstevel@tonic-gate walk_devtree() 4787c478bd9Sstevel@tonic-gate { 4797c478bd9Sstevel@tonic-gate thread_t walk_thread; 4807c478bd9Sstevel@tonic-gate 481*5cffb260SRob Johnston mutex_enter(&walker_lock); 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate switch (walker_state) { 4847c478bd9Sstevel@tonic-gate case WALK_NONE: 485bd401f05SToomas Soome if (thr_create(NULL, 0, (void *(*)(void *))walker, NULL, 4867c478bd9Sstevel@tonic-gate THR_DAEMON, &walk_thread) == 0) { 4877c478bd9Sstevel@tonic-gate walker_state = WALK_WAITING; 4887c478bd9Sstevel@tonic-gate } 4897c478bd9Sstevel@tonic-gate break; 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate case WALK_WAITING: 4927c478bd9Sstevel@tonic-gate /* absorb the event and do nothing */ 4937c478bd9Sstevel@tonic-gate break; 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate case WALK_RUNNING: 4967c478bd9Sstevel@tonic-gate events_pending = 1; 4977c478bd9Sstevel@tonic-gate break; 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate 500*5cffb260SRob Johnston mutex_exit(&walker_lock); 5017c478bd9Sstevel@tonic-gate } 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5047c478bd9Sstevel@tonic-gate static void 5057c478bd9Sstevel@tonic-gate walker(void *arg) 5067c478bd9Sstevel@tonic-gate { 5077c478bd9Sstevel@tonic-gate int walk_again = 0; 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate do { 510*5cffb260SRob Johnston /* start by waiting for a few seconds to absorb extra events */ 5117c478bd9Sstevel@tonic-gate (void) sleep(WALK_WAIT_TIME); 5127c478bd9Sstevel@tonic-gate 513*5cffb260SRob Johnston mutex_enter(&walker_lock); 514*5cffb260SRob Johnston if (shutting_down) { 515*5cffb260SRob Johnston walker_state = WALK_NONE; 516*5cffb260SRob Johnston (void) cond_broadcast(&walker_cv); 517*5cffb260SRob Johnston mutex_exit(&walker_lock); 518*5cffb260SRob Johnston return; 519*5cffb260SRob Johnston } 5207c478bd9Sstevel@tonic-gate walker_state = WALK_RUNNING; 521*5cffb260SRob Johnston mutex_exit(&walker_lock); 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate cache_update(DM_EV_DISK_ADD, NULL); 5247c478bd9Sstevel@tonic-gate 525*5cffb260SRob Johnston mutex_enter(&walker_lock); 526*5cffb260SRob Johnston if (shutting_down) { 527*5cffb260SRob Johnston walker_state = WALK_NONE; 528*5cffb260SRob Johnston (void) cond_broadcast(&walker_cv); 529*5cffb260SRob Johnston mutex_exit(&walker_lock); 530*5cffb260SRob Johnston return; 531*5cffb260SRob Johnston } 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate if (events_pending) { 5347c478bd9Sstevel@tonic-gate events_pending = 0; 5357c478bd9Sstevel@tonic-gate walker_state = WALK_WAITING; 5367c478bd9Sstevel@tonic-gate walk_again = 1; 5377c478bd9Sstevel@tonic-gate } else { 5387c478bd9Sstevel@tonic-gate walker_state = WALK_NONE; 5397c478bd9Sstevel@tonic-gate walk_again = 0; 5407c478bd9Sstevel@tonic-gate } 5417c478bd9Sstevel@tonic-gate 542*5cffb260SRob Johnston mutex_exit(&walker_lock); 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate } while (walk_again); 5457c478bd9Sstevel@tonic-gate } 546