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 5*25e8c5aaSvikram * Common Development and Distribution License (the "License"). 6*25e8c5aaSvikram * 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 * 21*25e8c5aaSvikram * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 227c478bd9Sstevel@tonic-gate * Use is subject to license terms. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include "rcm_impl.h" 287c478bd9Sstevel@tonic-gate #include "rcm_module.h" 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate /* 317c478bd9Sstevel@tonic-gate * Short-circuits unloading of modules with no registrations, so that 327c478bd9Sstevel@tonic-gate * they are present during the next db_sync cycle. 337c478bd9Sstevel@tonic-gate */ 347c478bd9Sstevel@tonic-gate #define MOD_REFCNT_INIT 2 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate int need_cleanup; /* flag indicating if clean up is needed */ 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate static mutex_t mod_lock; /* protects module list */ 397c478bd9Sstevel@tonic-gate static module_t *module_head; /* linked list of modules */ 407c478bd9Sstevel@tonic-gate static rsrc_node_t *rsrc_root; /* root of all resources */ 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate /* 437c478bd9Sstevel@tonic-gate * Misc help routines 447c478bd9Sstevel@tonic-gate */ 457c478bd9Sstevel@tonic-gate static void rcmd_db_print(); 467c478bd9Sstevel@tonic-gate static void rcm_handle_free(rcm_handle_t *); 477c478bd9Sstevel@tonic-gate static rcm_handle_t *rcm_handle_alloc(module_t *); 487c478bd9Sstevel@tonic-gate static void rsrc_clients_free(client_t *); 497c478bd9Sstevel@tonic-gate static struct rcm_mod_ops *modops_from_v1(void *); 507c478bd9Sstevel@tonic-gate static int call_getinfo(struct rcm_mod_ops *, rcm_handle_t *, char *, id_t, 517c478bd9Sstevel@tonic-gate uint_t, char **, char **, nvlist_t *, rcm_info_t **); 527c478bd9Sstevel@tonic-gate static int node_action(rsrc_node_t *, void *); 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate extern void start_polling_thread(); 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate /* 577c478bd9Sstevel@tonic-gate * translate /dev name to a /devices path 587c478bd9Sstevel@tonic-gate * 597c478bd9Sstevel@tonic-gate * N.B. This routine can be enhanced to understand network names 607c478bd9Sstevel@tonic-gate * and friendly names in the future. 617c478bd9Sstevel@tonic-gate */ 627c478bd9Sstevel@tonic-gate char * 637c478bd9Sstevel@tonic-gate resolve_name(char *alias) 647c478bd9Sstevel@tonic-gate { 657c478bd9Sstevel@tonic-gate char *tmp; 667c478bd9Sstevel@tonic-gate const char *dev = "/dev/"; 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate if (strlen(alias) == 0) 697c478bd9Sstevel@tonic-gate return (NULL); 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate if (strncmp(alias, dev, strlen(dev)) == 0) { 727c478bd9Sstevel@tonic-gate /* 737c478bd9Sstevel@tonic-gate * Treat /dev/... as a symbolic link 747c478bd9Sstevel@tonic-gate */ 757c478bd9Sstevel@tonic-gate tmp = s_malloc(PATH_MAX); 767c478bd9Sstevel@tonic-gate if (realpath(alias, tmp) != NULL) { 777c478bd9Sstevel@tonic-gate return (tmp); 787c478bd9Sstevel@tonic-gate } else { 797c478bd9Sstevel@tonic-gate free(tmp); 807c478bd9Sstevel@tonic-gate } 817c478bd9Sstevel@tonic-gate /* Fail to resolve /dev/ name, use the name as is */ 827c478bd9Sstevel@tonic-gate } 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate return (s_strdup(alias)); 857c478bd9Sstevel@tonic-gate } 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate /* 887c478bd9Sstevel@tonic-gate * Figure out resource type based on "resolved" name 897c478bd9Sstevel@tonic-gate * 907c478bd9Sstevel@tonic-gate * N.B. This routine does not figure out file system mount points. 917c478bd9Sstevel@tonic-gate * This is determined at runtime when filesys module register 927c478bd9Sstevel@tonic-gate * with RCM_FILESYS flag. 937c478bd9Sstevel@tonic-gate */ 947c478bd9Sstevel@tonic-gate int 957c478bd9Sstevel@tonic-gate rsrc_get_type(const char *resolved_name) 967c478bd9Sstevel@tonic-gate { 977c478bd9Sstevel@tonic-gate if (resolved_name[0] != '/') 987c478bd9Sstevel@tonic-gate return (RSRC_TYPE_ABSTRACT); 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate if (strncmp("/devices/", resolved_name, 9) == 0) 1017c478bd9Sstevel@tonic-gate return (RSRC_TYPE_DEVICE); 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate return (RSRC_TYPE_NORMAL); 1047c478bd9Sstevel@tonic-gate } 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate /* 1077c478bd9Sstevel@tonic-gate * Module operations: 1087c478bd9Sstevel@tonic-gate * module_load, module_unload, module_info, module_attach, module_detach, 1097c478bd9Sstevel@tonic-gate * cli_module_hold, cli_module_rele 1107c478bd9Sstevel@tonic-gate */ 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate #ifdef ENABLE_MODULE_DETACH 1137c478bd9Sstevel@tonic-gate /* 1147c478bd9Sstevel@tonic-gate * call unregister() entry point to allow module to unregister for 1157c478bd9Sstevel@tonic-gate * resources without getting confused. 1167c478bd9Sstevel@tonic-gate */ 1177c478bd9Sstevel@tonic-gate static void 1187c478bd9Sstevel@tonic-gate module_detach(module_t *module) 1197c478bd9Sstevel@tonic-gate { 1207c478bd9Sstevel@tonic-gate struct rcm_mod_ops *ops = module->modops; 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, "module_detach(name=%s)\n", module->name); 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate ops->rcmop_unregister(module->rcmhandle); 1257c478bd9Sstevel@tonic-gate } 1267c478bd9Sstevel@tonic-gate #endif /* ENABLE_MODULE_DETACH */ 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate /* 1297c478bd9Sstevel@tonic-gate * call register() entry point to allow module to register for resources 1307c478bd9Sstevel@tonic-gate */ 1317c478bd9Sstevel@tonic-gate static void 1327c478bd9Sstevel@tonic-gate module_attach(module_t *module) 1337c478bd9Sstevel@tonic-gate { 1347c478bd9Sstevel@tonic-gate struct rcm_mod_ops *ops = module->modops; 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, "module_attach(name=%s)\n", module->name); 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate if (ops->rcmop_register(module->rcmhandle) != RCM_SUCCESS) { 1397c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING, 1407c478bd9Sstevel@tonic-gate gettext("module %s register() failed\n"), module->name); 1417c478bd9Sstevel@tonic-gate } 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate struct rcm_mod_ops * 1457c478bd9Sstevel@tonic-gate module_init(module_t *module) 1467c478bd9Sstevel@tonic-gate { 1477c478bd9Sstevel@tonic-gate if (module->dlhandle) 1487c478bd9Sstevel@tonic-gate /* rcm module */ 1497c478bd9Sstevel@tonic-gate return (module->init()); 1507c478bd9Sstevel@tonic-gate else 1517c478bd9Sstevel@tonic-gate /* rcm script */ 1527c478bd9Sstevel@tonic-gate return (script_init(module)); 1537c478bd9Sstevel@tonic-gate } 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate /* 1567c478bd9Sstevel@tonic-gate * call rmc_mod_info() entry of module 1577c478bd9Sstevel@tonic-gate */ 1587c478bd9Sstevel@tonic-gate static const char * 1597c478bd9Sstevel@tonic-gate module_info(module_t *module) 1607c478bd9Sstevel@tonic-gate { 1617c478bd9Sstevel@tonic-gate if (module->dlhandle) 1627c478bd9Sstevel@tonic-gate /* rcm module */ 1637c478bd9Sstevel@tonic-gate return (module->info()); 1647c478bd9Sstevel@tonic-gate else 1657c478bd9Sstevel@tonic-gate /* rcm script */ 1667c478bd9Sstevel@tonic-gate return (script_info(module)); 1677c478bd9Sstevel@tonic-gate } 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate int 1707c478bd9Sstevel@tonic-gate module_fini(module_t *module) 1717c478bd9Sstevel@tonic-gate { 1727c478bd9Sstevel@tonic-gate if (module->dlhandle) 1737c478bd9Sstevel@tonic-gate /* rcm module */ 1747c478bd9Sstevel@tonic-gate return (module->fini()); 1757c478bd9Sstevel@tonic-gate else 1767c478bd9Sstevel@tonic-gate /* rcm script */ 1777c478bd9Sstevel@tonic-gate return (script_fini(module)); 1787c478bd9Sstevel@tonic-gate } 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate /* 1817c478bd9Sstevel@tonic-gate * call rmc_mod_fini() entry of module, dlclose module, and free memory 1827c478bd9Sstevel@tonic-gate */ 1837c478bd9Sstevel@tonic-gate static void 1847c478bd9Sstevel@tonic-gate module_unload(module_t *module) 1857c478bd9Sstevel@tonic-gate { 1867c478bd9Sstevel@tonic-gate int version = module->modops->version; 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "module_unload(name=%s)\n", module->name); 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate (void) module_fini(module); 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate rcm_handle_free(module->rcmhandle); 1937c478bd9Sstevel@tonic-gate free(module->name); 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate switch (version) { 1967c478bd9Sstevel@tonic-gate case RCM_MOD_OPS_V1: 1977c478bd9Sstevel@tonic-gate /* 1987c478bd9Sstevel@tonic-gate * Free memory associated with converted ops vector 1997c478bd9Sstevel@tonic-gate */ 2007c478bd9Sstevel@tonic-gate free(module->modops); 2017c478bd9Sstevel@tonic-gate break; 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate case RCM_MOD_OPS_VERSION: 2047c478bd9Sstevel@tonic-gate default: 2057c478bd9Sstevel@tonic-gate break; 2067c478bd9Sstevel@tonic-gate } 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate if (module->dlhandle) 2097c478bd9Sstevel@tonic-gate rcm_module_close(module->dlhandle); 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate free(module); 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate /* 2157c478bd9Sstevel@tonic-gate * Locate the module, execute rcm_mod_init() and check ops vector version 2167c478bd9Sstevel@tonic-gate */ 2177c478bd9Sstevel@tonic-gate static module_t * 2187c478bd9Sstevel@tonic-gate module_load(char *modname) 2197c478bd9Sstevel@tonic-gate { 2207c478bd9Sstevel@tonic-gate module_t *module; 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "module_load(name=%s)\n", modname); 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate /* 2257c478bd9Sstevel@tonic-gate * dlopen the module 2267c478bd9Sstevel@tonic-gate */ 2277c478bd9Sstevel@tonic-gate module = s_calloc(1, sizeof (*module)); 2287c478bd9Sstevel@tonic-gate module->name = s_strdup(modname); 2297c478bd9Sstevel@tonic-gate module->modops = NULL; 2307c478bd9Sstevel@tonic-gate rcm_init_queue(&module->client_q); 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate if (rcm_is_script(modname) == 0) { 2337c478bd9Sstevel@tonic-gate /* rcm module */ 2347c478bd9Sstevel@tonic-gate module->dlhandle = rcm_module_open(modname); 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate if (module->dlhandle == NULL) { 2377c478bd9Sstevel@tonic-gate rcm_log_message(RCM_NOTICE, 2387c478bd9Sstevel@tonic-gate gettext("cannot open module %s\n"), modname); 2397c478bd9Sstevel@tonic-gate goto fail; 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate /* 2437c478bd9Sstevel@tonic-gate * dlsym rcm_mod_init/fini/info() entry points 2447c478bd9Sstevel@tonic-gate */ 2457c478bd9Sstevel@tonic-gate module->init = (struct rcm_mod_ops *(*)())dlsym( 2467c478bd9Sstevel@tonic-gate module->dlhandle, "rcm_mod_init"); 2477c478bd9Sstevel@tonic-gate module->fini = (int (*)())dlsym( 2487c478bd9Sstevel@tonic-gate module->dlhandle, "rcm_mod_fini"); 2497c478bd9Sstevel@tonic-gate module->info = (const char *(*)())dlsym(module->dlhandle, 2507c478bd9Sstevel@tonic-gate "rcm_mod_info"); 2517c478bd9Sstevel@tonic-gate if (module->init == NULL || module->fini == NULL || 2527c478bd9Sstevel@tonic-gate module->info == NULL) { 2537c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, 2547c478bd9Sstevel@tonic-gate gettext("missing entries in module %s\n"), modname); 2557c478bd9Sstevel@tonic-gate goto fail; 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate } else { 2597c478bd9Sstevel@tonic-gate /* rcm script */ 2607c478bd9Sstevel@tonic-gate module->dlhandle = NULL; 2617c478bd9Sstevel@tonic-gate module->init = (struct rcm_mod_ops *(*)()) NULL; 2627c478bd9Sstevel@tonic-gate module->fini = (int (*)()) NULL; 2637c478bd9Sstevel@tonic-gate module->info = (const char *(*)()) NULL; 2647c478bd9Sstevel@tonic-gate } 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate if ((module->modops = module_init(module)) == NULL) { 2677c478bd9Sstevel@tonic-gate if (module->dlhandle) 2687c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, 2697c478bd9Sstevel@tonic-gate gettext("cannot init module %s\n"), modname); 2707c478bd9Sstevel@tonic-gate goto fail; 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate /* 2747c478bd9Sstevel@tonic-gate * Check ops vector version 2757c478bd9Sstevel@tonic-gate */ 2767c478bd9Sstevel@tonic-gate switch (module->modops->version) { 2777c478bd9Sstevel@tonic-gate case RCM_MOD_OPS_V1: 2787c478bd9Sstevel@tonic-gate module->modops = modops_from_v1((void *)module->modops); 2797c478bd9Sstevel@tonic-gate break; 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate case RCM_MOD_OPS_VERSION: 2827c478bd9Sstevel@tonic-gate break; 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate default: 2857c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, 2867c478bd9Sstevel@tonic-gate gettext("module %s rejected: version %d not supported\n"), 2877c478bd9Sstevel@tonic-gate modname, module->modops->version); 2887c478bd9Sstevel@tonic-gate (void) module_fini(module); 2897c478bd9Sstevel@tonic-gate goto fail; 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate /* 2937c478bd9Sstevel@tonic-gate * Make sure all fields are set 2947c478bd9Sstevel@tonic-gate */ 2957c478bd9Sstevel@tonic-gate if ((module->modops->rcmop_register == NULL) || 2967c478bd9Sstevel@tonic-gate (module->modops->rcmop_unregister == NULL) || 2977c478bd9Sstevel@tonic-gate (module->modops->rcmop_get_info == NULL) || 2987c478bd9Sstevel@tonic-gate (module->modops->rcmop_request_suspend == NULL) || 2997c478bd9Sstevel@tonic-gate (module->modops->rcmop_notify_resume == NULL) || 3007c478bd9Sstevel@tonic-gate (module->modops->rcmop_request_offline == NULL) || 3017c478bd9Sstevel@tonic-gate (module->modops->rcmop_notify_online == NULL) || 3027c478bd9Sstevel@tonic-gate (module->modops->rcmop_notify_remove == NULL)) { 3037c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, 3047c478bd9Sstevel@tonic-gate gettext("module %s rejected: has NULL ops fields\n"), 3057c478bd9Sstevel@tonic-gate modname); 3067c478bd9Sstevel@tonic-gate (void) module_fini(module); 3077c478bd9Sstevel@tonic-gate goto fail; 3087c478bd9Sstevel@tonic-gate } 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate module->rcmhandle = rcm_handle_alloc(module); 3117c478bd9Sstevel@tonic-gate return (module); 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate fail: 3147c478bd9Sstevel@tonic-gate if (module->modops && module->modops->version == RCM_MOD_OPS_V1) 3157c478bd9Sstevel@tonic-gate free(module->modops); 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate if (module->dlhandle) 3187c478bd9Sstevel@tonic-gate rcm_module_close(module->dlhandle); 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate free(module->name); 3217c478bd9Sstevel@tonic-gate free(module); 3227c478bd9Sstevel@tonic-gate return (NULL); 3237c478bd9Sstevel@tonic-gate } 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate /* 3267c478bd9Sstevel@tonic-gate * add one to module hold count. load the module if not loaded 3277c478bd9Sstevel@tonic-gate */ 3287c478bd9Sstevel@tonic-gate static module_t * 3297c478bd9Sstevel@tonic-gate cli_module_hold(char *modname) 3307c478bd9Sstevel@tonic-gate { 3317c478bd9Sstevel@tonic-gate module_t *module; 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE3, "cli_module_hold(%s)\n", modname); 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate (void) mutex_lock(&mod_lock); 3367c478bd9Sstevel@tonic-gate module = module_head; 3377c478bd9Sstevel@tonic-gate while (module) { 3387c478bd9Sstevel@tonic-gate if (strcmp(module->name, modname) == 0) { 3397c478bd9Sstevel@tonic-gate break; 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate module = module->next; 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate if (module) { 3457c478bd9Sstevel@tonic-gate module->ref_count++; 3467c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mod_lock); 3477c478bd9Sstevel@tonic-gate return (module); 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate /* 3517c478bd9Sstevel@tonic-gate * Module not found, attempt to load it 3527c478bd9Sstevel@tonic-gate */ 3537c478bd9Sstevel@tonic-gate if ((module = module_load(modname)) == NULL) { 3547c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mod_lock); 3557c478bd9Sstevel@tonic-gate return (NULL); 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate /* 3597c478bd9Sstevel@tonic-gate * Hold module and link module into module list 3607c478bd9Sstevel@tonic-gate */ 3617c478bd9Sstevel@tonic-gate module->ref_count = MOD_REFCNT_INIT; 3627c478bd9Sstevel@tonic-gate module->next = module_head; 3637c478bd9Sstevel@tonic-gate module_head = module; 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mod_lock); 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate return (module); 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate /* 3717c478bd9Sstevel@tonic-gate * decrement module hold count. Unload it if no reference 3727c478bd9Sstevel@tonic-gate */ 3737c478bd9Sstevel@tonic-gate static void 3747c478bd9Sstevel@tonic-gate cli_module_rele(module_t *module) 3757c478bd9Sstevel@tonic-gate { 3767c478bd9Sstevel@tonic-gate module_t *curr = module_head, *prev = NULL; 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE3, "cli_module_rele(name=%s)\n", module->name); 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate (void) mutex_lock(&mod_lock); 3817c478bd9Sstevel@tonic-gate if (--(module->ref_count) != 0) { 3827c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mod_lock); 3837c478bd9Sstevel@tonic-gate return; 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, "unloading module %s\n", module->name); 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate /* 3897c478bd9Sstevel@tonic-gate * Unlink the module from list 3907c478bd9Sstevel@tonic-gate */ 3917c478bd9Sstevel@tonic-gate while (curr && (curr != module)) { 3927c478bd9Sstevel@tonic-gate prev = curr; 3937c478bd9Sstevel@tonic-gate curr = curr->next; 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate if (curr == NULL) { 3967c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, 3977c478bd9Sstevel@tonic-gate gettext("Unexpected error: module %s not found.\n"), 3987c478bd9Sstevel@tonic-gate module->name); 3997c478bd9Sstevel@tonic-gate } else if (prev == NULL) { 4007c478bd9Sstevel@tonic-gate module_head = curr->next; 4017c478bd9Sstevel@tonic-gate } else { 4027c478bd9Sstevel@tonic-gate prev->next = curr->next; 4037c478bd9Sstevel@tonic-gate } 4047c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mod_lock); 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate module_unload(module); 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate /* 4107c478bd9Sstevel@tonic-gate * Gather usage info be passed back to requester. Discard info if user does 4117c478bd9Sstevel@tonic-gate * not care (list == NULL). 4127c478bd9Sstevel@tonic-gate */ 4137c478bd9Sstevel@tonic-gate void 4147c478bd9Sstevel@tonic-gate add_busy_rsrc_to_list(char *alias, pid_t pid, int state, int seq_num, 4157c478bd9Sstevel@tonic-gate char *modname, const char *infostr, const char *errstr, 4167c478bd9Sstevel@tonic-gate nvlist_t *client_props, rcm_info_t **list) 4177c478bd9Sstevel@tonic-gate { 4187c478bd9Sstevel@tonic-gate rcm_info_t *info; 4197c478bd9Sstevel@tonic-gate rcm_info_t *tmp; 4207c478bd9Sstevel@tonic-gate char *buf = NULL; 4217c478bd9Sstevel@tonic-gate size_t buflen = 0; 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate if (list == NULL) { 4247c478bd9Sstevel@tonic-gate return; 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate info = s_calloc(1, sizeof (*info)); 4287c478bd9Sstevel@tonic-gate if (errno = nvlist_alloc(&(info->info), NV_UNIQUE_NAME, 0)) { 4297c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, "failed (nvlist_alloc=%s).\n", 4307c478bd9Sstevel@tonic-gate strerror(errno)); 4317c478bd9Sstevel@tonic-gate rcmd_exit(errno); 4327c478bd9Sstevel@tonic-gate } 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate /*LINTED*/ 4357c478bd9Sstevel@tonic-gate if ((errno = nvlist_add_string(info->info, RCM_RSRCNAME, alias)) || 4367c478bd9Sstevel@tonic-gate (errno = nvlist_add_int32(info->info, RCM_SEQ_NUM, seq_num)) || 4377c478bd9Sstevel@tonic-gate (errno = nvlist_add_int64(info->info, RCM_CLIENT_ID, pid)) || 4387c478bd9Sstevel@tonic-gate (errno = nvlist_add_int32(info->info, RCM_RSRCSTATE, state))) { 4397c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, "failed (nvlist_add=%s).\n", 4407c478bd9Sstevel@tonic-gate strerror(errno)); 4417c478bd9Sstevel@tonic-gate rcmd_exit(errno); 4427c478bd9Sstevel@tonic-gate } 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate /* 4457c478bd9Sstevel@tonic-gate * Daemon calls to add_busy_rsrc_to_list may pass in 4467c478bd9Sstevel@tonic-gate * error/info. Add these through librcm interfaces. 4477c478bd9Sstevel@tonic-gate */ 4487c478bd9Sstevel@tonic-gate if (errstr) { 4497c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE3, "adding error string: %s\n", 4507c478bd9Sstevel@tonic-gate errstr); 4517c478bd9Sstevel@tonic-gate if (errno = nvlist_add_string(info->info, RCM_CLIENT_ERROR, 4527c478bd9Sstevel@tonic-gate (char *)errstr)) { 4537c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, "failed (nvlist_add=%s).\n", 4547c478bd9Sstevel@tonic-gate strerror(errno)); 4557c478bd9Sstevel@tonic-gate rcmd_exit(errno); 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate if (infostr) { 4607c478bd9Sstevel@tonic-gate if (errno = nvlist_add_string(info->info, RCM_CLIENT_INFO, 4617c478bd9Sstevel@tonic-gate (char *)infostr)) { 4627c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, "failed (nvlist_add=%s).\n", 4637c478bd9Sstevel@tonic-gate strerror(errno)); 4647c478bd9Sstevel@tonic-gate rcmd_exit(errno); 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate if (modname) { 4697c478bd9Sstevel@tonic-gate if (errno = nvlist_add_string(info->info, RCM_CLIENT_MODNAME, 4707c478bd9Sstevel@tonic-gate modname)) { 4717c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, "failed (nvlist_add=%s).\n", 4727c478bd9Sstevel@tonic-gate strerror(errno)); 4737c478bd9Sstevel@tonic-gate rcmd_exit(errno); 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate if (client_props) { 4787c478bd9Sstevel@tonic-gate if (errno = nvlist_pack(client_props, &buf, &buflen, 4797c478bd9Sstevel@tonic-gate NV_ENCODE_NATIVE, 0)) { 4807c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, "failed (nvlist_pack=%s).\n", 4817c478bd9Sstevel@tonic-gate strerror(errno)); 4827c478bd9Sstevel@tonic-gate rcmd_exit(errno); 4837c478bd9Sstevel@tonic-gate } 4847c478bd9Sstevel@tonic-gate if (errno = nvlist_add_byte_array(info->info, 4857c478bd9Sstevel@tonic-gate RCM_CLIENT_PROPERTIES, (uchar_t *)buf, buflen)) { 4867c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, "failed (nvlist_add=%s).\n", 4877c478bd9Sstevel@tonic-gate strerror(errno)); 4887c478bd9Sstevel@tonic-gate rcmd_exit(errno); 4897c478bd9Sstevel@tonic-gate } 4907c478bd9Sstevel@tonic-gate (void) free(buf); 4917c478bd9Sstevel@tonic-gate } 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate /* link info at end of list */ 4957c478bd9Sstevel@tonic-gate if (*list) { 4967c478bd9Sstevel@tonic-gate tmp = *list; 4977c478bd9Sstevel@tonic-gate while (tmp->next) 4987c478bd9Sstevel@tonic-gate tmp = tmp->next; 4997c478bd9Sstevel@tonic-gate tmp->next = info; 5007c478bd9Sstevel@tonic-gate } else { 5017c478bd9Sstevel@tonic-gate *list = info; 5027c478bd9Sstevel@tonic-gate } 5037c478bd9Sstevel@tonic-gate } 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate /* 5067c478bd9Sstevel@tonic-gate * Resource client realted operations: 5077c478bd9Sstevel@tonic-gate * rsrc_client_alloc, rsrc_client_find, rsrc_client_add, 5087c478bd9Sstevel@tonic-gate * rsrc_client_remove, rsrc_client_action, rsrc_client_action_list 5097c478bd9Sstevel@tonic-gate */ 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate /* Allocate rsrc_client_t structure. Load module if necessary. */ 5127c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5137c478bd9Sstevel@tonic-gate static client_t * 5147c478bd9Sstevel@tonic-gate rsrc_client_alloc(char *alias, char *modname, pid_t pid, uint_t flag) 5157c478bd9Sstevel@tonic-gate { 5167c478bd9Sstevel@tonic-gate client_t *client; 5177c478bd9Sstevel@tonic-gate module_t *mod; 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate assert((alias != NULL) && (modname != NULL)); 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE4, "rsrc_client_alloc(%s, %s, %ld)\n", 5227c478bd9Sstevel@tonic-gate alias, modname, pid); 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate if ((mod = cli_module_hold(modname)) == NULL) { 5257c478bd9Sstevel@tonic-gate return (NULL); 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate client = s_calloc(1, sizeof (client_t)); 5297c478bd9Sstevel@tonic-gate client->module = mod; 5307c478bd9Sstevel@tonic-gate client->pid = pid; 5317c478bd9Sstevel@tonic-gate client->alias = s_strdup(alias); 5327c478bd9Sstevel@tonic-gate client->prv_flags = 0; 5337c478bd9Sstevel@tonic-gate client->state = RCM_STATE_ONLINE; 5347c478bd9Sstevel@tonic-gate client->flag = flag; 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate /* This queue is protected by rcm_req_lock */ 5377c478bd9Sstevel@tonic-gate rcm_enqueue_tail(&mod->client_q, &client->queue); 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate return (client); 5407c478bd9Sstevel@tonic-gate } 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate /* Find client in list matching modname and pid */ 5437c478bd9Sstevel@tonic-gate client_t * 5447c478bd9Sstevel@tonic-gate rsrc_client_find(char *modname, pid_t pid, client_t **list) 5457c478bd9Sstevel@tonic-gate { 5467c478bd9Sstevel@tonic-gate client_t *client = *list; 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE4, "rsrc_client_find(%s, %ld, %p)\n", 5497c478bd9Sstevel@tonic-gate modname, pid, (void *)list); 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate while (client) { 5527c478bd9Sstevel@tonic-gate if ((client->pid == pid) && 5537c478bd9Sstevel@tonic-gate strcmp(modname, client->module->name) == 0) { 5547c478bd9Sstevel@tonic-gate break; 5557c478bd9Sstevel@tonic-gate } 5567c478bd9Sstevel@tonic-gate client = client->next; 5577c478bd9Sstevel@tonic-gate } 5587c478bd9Sstevel@tonic-gate return (client); 5597c478bd9Sstevel@tonic-gate } 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate /* Add a client to client list */ 5627c478bd9Sstevel@tonic-gate static void 5637c478bd9Sstevel@tonic-gate rsrc_client_add(client_t *client, client_t **list) 5647c478bd9Sstevel@tonic-gate { 5657c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE4, "rsrc_client_add: %s, %s, %ld\n", 5667c478bd9Sstevel@tonic-gate client->alias, client->module->name, client->pid); 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate client->next = *list; 5697c478bd9Sstevel@tonic-gate *list = client; 5707c478bd9Sstevel@tonic-gate } 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate /* Remove client from list and destroy it */ 5737c478bd9Sstevel@tonic-gate static void 5747c478bd9Sstevel@tonic-gate rsrc_client_remove(client_t *client, client_t **list) 5757c478bd9Sstevel@tonic-gate { 5767c478bd9Sstevel@tonic-gate client_t *tmp, *prev = NULL; 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE4, "rsrc_client_remove: %s, %s, %ld\n", 5797c478bd9Sstevel@tonic-gate client->alias, client->module->name, client->pid); 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate tmp = *list; 5827c478bd9Sstevel@tonic-gate while (tmp) { 5837c478bd9Sstevel@tonic-gate if (client != tmp) { 5847c478bd9Sstevel@tonic-gate prev = tmp; 5857c478bd9Sstevel@tonic-gate tmp = tmp->next; 5867c478bd9Sstevel@tonic-gate continue; 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate if (prev) { 5897c478bd9Sstevel@tonic-gate prev->next = tmp->next; 5907c478bd9Sstevel@tonic-gate } else { 5917c478bd9Sstevel@tonic-gate *list = tmp->next; 5927c478bd9Sstevel@tonic-gate } 5937c478bd9Sstevel@tonic-gate tmp->next = NULL; 5947c478bd9Sstevel@tonic-gate rsrc_clients_free(tmp); 5957c478bd9Sstevel@tonic-gate return; 5967c478bd9Sstevel@tonic-gate } 5977c478bd9Sstevel@tonic-gate } 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate /* Free a list of clients. Called from cleanup thread only */ 6007c478bd9Sstevel@tonic-gate static void 6017c478bd9Sstevel@tonic-gate rsrc_clients_free(client_t *list) 6027c478bd9Sstevel@tonic-gate { 6037c478bd9Sstevel@tonic-gate client_t *client = list; 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate while (client) { 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate /* 6087c478bd9Sstevel@tonic-gate * Note that the rcm daemon is single threaded while 6097c478bd9Sstevel@tonic-gate * executing this routine. So there is no need to acquire 6107c478bd9Sstevel@tonic-gate * rcm_req_lock here while dequeuing. 6117c478bd9Sstevel@tonic-gate */ 6127c478bd9Sstevel@tonic-gate rcm_dequeue(&client->queue); 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate if (client->module) { 6157c478bd9Sstevel@tonic-gate cli_module_rele(client->module); 6167c478bd9Sstevel@tonic-gate } 6177c478bd9Sstevel@tonic-gate list = client->next; 6187c478bd9Sstevel@tonic-gate if (client->alias) { 6197c478bd9Sstevel@tonic-gate free(client->alias); 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate free(client); 6227c478bd9Sstevel@tonic-gate client = list; 6237c478bd9Sstevel@tonic-gate } 6247c478bd9Sstevel@tonic-gate } 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate /* 6277c478bd9Sstevel@tonic-gate * Invoke a callback into a single client 6287c478bd9Sstevel@tonic-gate * This is the core of rcm_mod_ops interface 6297c478bd9Sstevel@tonic-gate */ 6307c478bd9Sstevel@tonic-gate static int 6317c478bd9Sstevel@tonic-gate rsrc_client_action(client_t *client, int cmd, void *arg) 6327c478bd9Sstevel@tonic-gate { 6337c478bd9Sstevel@tonic-gate int rval = RCM_SUCCESS; 6347c478bd9Sstevel@tonic-gate char *dummy_error = NULL; 6357c478bd9Sstevel@tonic-gate char *error = NULL; 6367c478bd9Sstevel@tonic-gate char *info = NULL; 6377c478bd9Sstevel@tonic-gate rcm_handle_t *hdl; 6387c478bd9Sstevel@tonic-gate nvlist_t *client_props = NULL; 6397c478bd9Sstevel@tonic-gate rcm_info_t *depend_info = NULL; 6407c478bd9Sstevel@tonic-gate struct rcm_mod_ops *ops = client->module->modops; 6417c478bd9Sstevel@tonic-gate tree_walk_arg_t *targ = (tree_walk_arg_t *)arg; 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE4, 6447c478bd9Sstevel@tonic-gate "rsrc_client_action: %s, %s, cmd=%d, flag=0x%x\n", client->alias, 6457c478bd9Sstevel@tonic-gate client->module->name, cmd, targ->flag); 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate /* 6487c478bd9Sstevel@tonic-gate * Create a per-operation handle, increment seq_num by 1 so we will 6497c478bd9Sstevel@tonic-gate * know if a module uses this handle to callback into rcm_daemon. 6507c478bd9Sstevel@tonic-gate */ 6517c478bd9Sstevel@tonic-gate hdl = rcm_handle_alloc(client->module); 6527c478bd9Sstevel@tonic-gate hdl->seq_num = targ->seq_num + 1; 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate /* 6557c478bd9Sstevel@tonic-gate * Filter out operations for which the client didn't register. 6567c478bd9Sstevel@tonic-gate */ 6577c478bd9Sstevel@tonic-gate switch (cmd) { 6587c478bd9Sstevel@tonic-gate case CMD_SUSPEND: 6597c478bd9Sstevel@tonic-gate case CMD_RESUME: 6607c478bd9Sstevel@tonic-gate case CMD_OFFLINE: 6617c478bd9Sstevel@tonic-gate case CMD_ONLINE: 6627c478bd9Sstevel@tonic-gate case CMD_REMOVE: 6637c478bd9Sstevel@tonic-gate if ((client->flag & RCM_REGISTER_DR) == 0) { 6647c478bd9Sstevel@tonic-gate rcm_handle_free(hdl); 6657c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 6667c478bd9Sstevel@tonic-gate } 6677c478bd9Sstevel@tonic-gate break; 6687c478bd9Sstevel@tonic-gate case CMD_REQUEST_CHANGE: 6697c478bd9Sstevel@tonic-gate case CMD_NOTIFY_CHANGE: 6707c478bd9Sstevel@tonic-gate if ((client->flag & RCM_REGISTER_CAPACITY) == 0) { 6717c478bd9Sstevel@tonic-gate rcm_handle_free(hdl); 6727c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 6737c478bd9Sstevel@tonic-gate } 6747c478bd9Sstevel@tonic-gate break; 6757c478bd9Sstevel@tonic-gate case CMD_EVENT: 6767c478bd9Sstevel@tonic-gate if ((client->flag & RCM_REGISTER_EVENT) == 0) { 6777c478bd9Sstevel@tonic-gate rcm_handle_free(hdl); 6787c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 6797c478bd9Sstevel@tonic-gate } 6807c478bd9Sstevel@tonic-gate break; 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate /* 6847c478bd9Sstevel@tonic-gate * Create nvlist_t for any client-specific properties. 6857c478bd9Sstevel@tonic-gate */ 6867c478bd9Sstevel@tonic-gate if (errno = nvlist_alloc(&client_props, NV_UNIQUE_NAME, 0)) { 6877c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, 6887c478bd9Sstevel@tonic-gate "client action failed (nvlist_alloc=%s)\n", 6897c478bd9Sstevel@tonic-gate strerror(errno)); 6907c478bd9Sstevel@tonic-gate rcmd_exit(errno); 6917c478bd9Sstevel@tonic-gate } 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate /* 6947c478bd9Sstevel@tonic-gate * Process the operation via a callback to the client module. 6957c478bd9Sstevel@tonic-gate */ 6967c478bd9Sstevel@tonic-gate switch (cmd) { 6977c478bd9Sstevel@tonic-gate case CMD_GETINFO: 6987c478bd9Sstevel@tonic-gate rval = call_getinfo(ops, hdl, client->alias, client->pid, 6997c478bd9Sstevel@tonic-gate targ->flag, &info, &error, client_props, &depend_info); 7007c478bd9Sstevel@tonic-gate break; 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate case CMD_SUSPEND: 7037c478bd9Sstevel@tonic-gate if (((targ->flag & RCM_QUERY_CANCEL) == 0) && 7047c478bd9Sstevel@tonic-gate (client->state == RCM_STATE_SUSPEND)) { 7057c478bd9Sstevel@tonic-gate break; 7067c478bd9Sstevel@tonic-gate } 7077c478bd9Sstevel@tonic-gate 7087c478bd9Sstevel@tonic-gate if ((targ->flag & RCM_QUERY) == 0) { 7097c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "suspending %s\n", 7107c478bd9Sstevel@tonic-gate client->alias); 7117c478bd9Sstevel@tonic-gate } else if ((targ->flag & RCM_QUERY_CANCEL) == 0) { 7127c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "suspend query %s\n", 7137c478bd9Sstevel@tonic-gate client->alias); 7147c478bd9Sstevel@tonic-gate } else { 7157c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, 7167c478bd9Sstevel@tonic-gate "suspend query %s cancelled\n", client->alias); 7177c478bd9Sstevel@tonic-gate } 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate /* 7207c478bd9Sstevel@tonic-gate * Update the client's state before the operation. 7217c478bd9Sstevel@tonic-gate * If this is a cancelled query, then updating the state is 7227c478bd9Sstevel@tonic-gate * the only thing that needs to be done, so break afterwards. 7237c478bd9Sstevel@tonic-gate */ 7247c478bd9Sstevel@tonic-gate if ((targ->flag & RCM_QUERY) == 0) { 7257c478bd9Sstevel@tonic-gate client->state = RCM_STATE_SUSPENDING; 7267c478bd9Sstevel@tonic-gate } else if ((targ->flag & RCM_QUERY_CANCEL) == 0) { 7277c478bd9Sstevel@tonic-gate client->state = RCM_STATE_SUSPEND_QUERYING; 7287c478bd9Sstevel@tonic-gate } else { 7297c478bd9Sstevel@tonic-gate client->state = RCM_STATE_ONLINE; 7307c478bd9Sstevel@tonic-gate break; 7317c478bd9Sstevel@tonic-gate } 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate rval = ops->rcmop_request_suspend(hdl, client->alias, 7347c478bd9Sstevel@tonic-gate client->pid, targ->interval, targ->flag, &error, 7357c478bd9Sstevel@tonic-gate &depend_info); 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate /* Update the client's state after the operation. */ 7387c478bd9Sstevel@tonic-gate if ((targ->flag & RCM_QUERY) == 0) { 7397c478bd9Sstevel@tonic-gate if (rval == RCM_SUCCESS) { 7407c478bd9Sstevel@tonic-gate client->state = RCM_STATE_SUSPEND; 7417c478bd9Sstevel@tonic-gate } else { 7427c478bd9Sstevel@tonic-gate client->state = RCM_STATE_SUSPEND_FAIL; 7437c478bd9Sstevel@tonic-gate } 7447c478bd9Sstevel@tonic-gate } else { 7457c478bd9Sstevel@tonic-gate if (rval == RCM_SUCCESS) { 7467c478bd9Sstevel@tonic-gate client->state = RCM_STATE_SUSPEND_QUERY; 7477c478bd9Sstevel@tonic-gate } else { 7487c478bd9Sstevel@tonic-gate client->state = RCM_STATE_SUSPEND_QUERY_FAIL; 7497c478bd9Sstevel@tonic-gate } 7507c478bd9Sstevel@tonic-gate } 7517c478bd9Sstevel@tonic-gate break; 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate case CMD_RESUME: 7547c478bd9Sstevel@tonic-gate if (client->state == RCM_STATE_ONLINE) { 7557c478bd9Sstevel@tonic-gate break; 7567c478bd9Sstevel@tonic-gate } 7577c478bd9Sstevel@tonic-gate client->state = RCM_STATE_RESUMING; 7587c478bd9Sstevel@tonic-gate rval = ops->rcmop_notify_resume(hdl, client->alias, client->pid, 7597c478bd9Sstevel@tonic-gate targ->flag, &error, &depend_info); 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gate /* online state is unconditional */ 7627c478bd9Sstevel@tonic-gate client->state = RCM_STATE_ONLINE; 7637c478bd9Sstevel@tonic-gate break; 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate case CMD_OFFLINE: 7667c478bd9Sstevel@tonic-gate if (((targ->flag & RCM_QUERY_CANCEL) == 0) && 7677c478bd9Sstevel@tonic-gate (client->state == RCM_STATE_OFFLINE)) { 7687c478bd9Sstevel@tonic-gate break; 7697c478bd9Sstevel@tonic-gate } 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate if ((targ->flag & RCM_QUERY) == 0) { 7727c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "offlining %s\n", 7737c478bd9Sstevel@tonic-gate client->alias); 7747c478bd9Sstevel@tonic-gate } else if ((targ->flag & RCM_QUERY_CANCEL) == 0) { 7757c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "offline query %s\n", 7767c478bd9Sstevel@tonic-gate client->alias); 7777c478bd9Sstevel@tonic-gate } else { 7787c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, 7797c478bd9Sstevel@tonic-gate "offline query %s cancelled\n", client->alias); 7807c478bd9Sstevel@tonic-gate } 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate /* 7837c478bd9Sstevel@tonic-gate * Update the client's state before the operation. 7847c478bd9Sstevel@tonic-gate * If this is a cancelled query, then updating the state is 7857c478bd9Sstevel@tonic-gate * the only thing that needs to be done, so break afterwards. 7867c478bd9Sstevel@tonic-gate */ 7877c478bd9Sstevel@tonic-gate if ((targ->flag & RCM_QUERY) == 0) { 7887c478bd9Sstevel@tonic-gate client->state = RCM_STATE_OFFLINING; 7897c478bd9Sstevel@tonic-gate } else if ((targ->flag & RCM_QUERY_CANCEL) == 0) { 7907c478bd9Sstevel@tonic-gate client->state = RCM_STATE_OFFLINE_QUERYING; 7917c478bd9Sstevel@tonic-gate } else { 7927c478bd9Sstevel@tonic-gate client->state = RCM_STATE_ONLINE; 7937c478bd9Sstevel@tonic-gate break; 7947c478bd9Sstevel@tonic-gate } 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate rval = ops->rcmop_request_offline(hdl, client->alias, 7977c478bd9Sstevel@tonic-gate client->pid, targ->flag, &error, &depend_info); 7987c478bd9Sstevel@tonic-gate 799*25e8c5aaSvikram /* 800*25e8c5aaSvikram * If this is a retire operation and we managed to call 801*25e8c5aaSvikram * into at least one client, set retcode to RCM_SUCCESS to 802*25e8c5aaSvikram * indicate that retire has been subject to constraints 803*25e8c5aaSvikram * This retcode will be further modified by actual return 804*25e8c5aaSvikram * code. 805*25e8c5aaSvikram */ 806*25e8c5aaSvikram if ((targ->flag & RCM_RETIRE_REQUEST) && 807*25e8c5aaSvikram (targ->retcode == RCM_NO_CONSTRAINT)) { 808*25e8c5aaSvikram rcm_log_message(RCM_DEBUG, 809*25e8c5aaSvikram "at least 1 client, constraint applied: %s\n", 810*25e8c5aaSvikram client->alias); 811*25e8c5aaSvikram targ->retcode = RCM_SUCCESS; 812*25e8c5aaSvikram } 813*25e8c5aaSvikram 8147c478bd9Sstevel@tonic-gate /* Update the client's state after the operation. */ 8157c478bd9Sstevel@tonic-gate if ((targ->flag & RCM_QUERY) == 0) { 8167c478bd9Sstevel@tonic-gate if (rval == RCM_SUCCESS) { 8177c478bd9Sstevel@tonic-gate client->state = RCM_STATE_OFFLINE; 8187c478bd9Sstevel@tonic-gate } else { 8197c478bd9Sstevel@tonic-gate client->state = RCM_STATE_OFFLINE_FAIL; 8207c478bd9Sstevel@tonic-gate } 8217c478bd9Sstevel@tonic-gate } else { 8227c478bd9Sstevel@tonic-gate if (rval == RCM_SUCCESS) { 8237c478bd9Sstevel@tonic-gate client->state = RCM_STATE_OFFLINE_QUERY; 8247c478bd9Sstevel@tonic-gate } else { 8257c478bd9Sstevel@tonic-gate client->state = RCM_STATE_OFFLINE_QUERY_FAIL; 8267c478bd9Sstevel@tonic-gate } 8277c478bd9Sstevel@tonic-gate } 8287c478bd9Sstevel@tonic-gate break; 8297c478bd9Sstevel@tonic-gate 8307c478bd9Sstevel@tonic-gate case CMD_ONLINE: 8317c478bd9Sstevel@tonic-gate if (client->state == RCM_STATE_ONLINE) { 8327c478bd9Sstevel@tonic-gate break; 8337c478bd9Sstevel@tonic-gate } 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "onlining %s\n", client->alias); 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate client->state = RCM_STATE_ONLINING; 8387c478bd9Sstevel@tonic-gate rval = ops->rcmop_notify_online(hdl, client->alias, client->pid, 8397c478bd9Sstevel@tonic-gate targ->flag, &error, &depend_info); 8407c478bd9Sstevel@tonic-gate client->state = RCM_STATE_ONLINE; 8417c478bd9Sstevel@tonic-gate break; 8427c478bd9Sstevel@tonic-gate 8437c478bd9Sstevel@tonic-gate case CMD_REMOVE: 8447c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "removing %s\n", client->alias); 8457c478bd9Sstevel@tonic-gate client->state = RCM_STATE_REMOVING; 8467c478bd9Sstevel@tonic-gate rval = ops->rcmop_notify_remove(hdl, client->alias, client->pid, 8477c478bd9Sstevel@tonic-gate targ->flag, &error, &depend_info); 8487c478bd9Sstevel@tonic-gate client->state = RCM_STATE_REMOVE; 8497c478bd9Sstevel@tonic-gate break; 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate case CMD_REQUEST_CHANGE: 8527c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "requesting state change of %s\n", 8537c478bd9Sstevel@tonic-gate client->alias); 8547c478bd9Sstevel@tonic-gate if (ops->rcmop_request_capacity_change) 8557c478bd9Sstevel@tonic-gate rval = ops->rcmop_request_capacity_change(hdl, 8567c478bd9Sstevel@tonic-gate client->alias, client->pid, targ->flag, targ->nvl, 8577c478bd9Sstevel@tonic-gate &error, &depend_info); 8587c478bd9Sstevel@tonic-gate break; 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate case CMD_NOTIFY_CHANGE: 8617c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "requesting state change of %s\n", 8627c478bd9Sstevel@tonic-gate client->alias); 8637c478bd9Sstevel@tonic-gate if (ops->rcmop_notify_capacity_change) 8647c478bd9Sstevel@tonic-gate rval = ops->rcmop_notify_capacity_change(hdl, 8657c478bd9Sstevel@tonic-gate client->alias, client->pid, targ->flag, targ->nvl, 8667c478bd9Sstevel@tonic-gate &error, &depend_info); 8677c478bd9Sstevel@tonic-gate break; 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate case CMD_EVENT: 8707c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "delivering event to %s\n", 8717c478bd9Sstevel@tonic-gate client->alias); 8727c478bd9Sstevel@tonic-gate if (ops->rcmop_notify_event) 8737c478bd9Sstevel@tonic-gate rval = ops->rcmop_notify_event(hdl, client->alias, 8747c478bd9Sstevel@tonic-gate client->pid, targ->flag, &error, targ->nvl, 8757c478bd9Sstevel@tonic-gate &depend_info); 8767c478bd9Sstevel@tonic-gate break; 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate default: 8797c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, gettext("unknown command %d\n"), 8807c478bd9Sstevel@tonic-gate cmd); 8817c478bd9Sstevel@tonic-gate rval = RCM_FAILURE; 8827c478bd9Sstevel@tonic-gate break; 8837c478bd9Sstevel@tonic-gate } 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate /* reset error code to the most significant error */ 8867c478bd9Sstevel@tonic-gate if (rval != RCM_SUCCESS) 8877c478bd9Sstevel@tonic-gate targ->retcode = rval; 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate /* 8907c478bd9Sstevel@tonic-gate * XXX - The code below may produce duplicate rcm_info_t's on error? 8917c478bd9Sstevel@tonic-gate */ 8927c478bd9Sstevel@tonic-gate if ((cmd != CMD_GETINFO) && 8937c478bd9Sstevel@tonic-gate ((rval != RCM_SUCCESS) || 8947c478bd9Sstevel@tonic-gate (error != NULL) || 8957c478bd9Sstevel@tonic-gate (targ->flag & RCM_SCOPE))) { 8967c478bd9Sstevel@tonic-gate (void) call_getinfo(ops, hdl, client->alias, client->pid, 8977c478bd9Sstevel@tonic-gate targ->flag & (~(RCM_INCLUDE_DEPENDENT|RCM_INCLUDE_SUBTREE)), 8987c478bd9Sstevel@tonic-gate &info, &dummy_error, client_props, &depend_info); 8997c478bd9Sstevel@tonic-gate if (dummy_error) 9007c478bd9Sstevel@tonic-gate (void) free(dummy_error); 9017c478bd9Sstevel@tonic-gate } else if (cmd != CMD_GETINFO) { 9027c478bd9Sstevel@tonic-gate nvlist_free(client_props); 9037c478bd9Sstevel@tonic-gate client_props = NULL; 9047c478bd9Sstevel@tonic-gate } 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate if (client_props) { 9077c478bd9Sstevel@tonic-gate add_busy_rsrc_to_list(client->alias, client->pid, client->state, 9087c478bd9Sstevel@tonic-gate targ->seq_num, client->module->name, info, error, 9097c478bd9Sstevel@tonic-gate client_props, targ->info); 9107c478bd9Sstevel@tonic-gate nvlist_free(client_props); 9117c478bd9Sstevel@tonic-gate } 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate if (info) 9147c478bd9Sstevel@tonic-gate (void) free(info); 9157c478bd9Sstevel@tonic-gate if (error) 9167c478bd9Sstevel@tonic-gate (void) free(error); 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate if (depend_info) { 9197c478bd9Sstevel@tonic-gate if (targ->info) { 9207c478bd9Sstevel@tonic-gate (void) rcm_append_info(targ->info, depend_info); 9217c478bd9Sstevel@tonic-gate } else { 9227c478bd9Sstevel@tonic-gate rcm_free_info(depend_info); 9237c478bd9Sstevel@tonic-gate } 9247c478bd9Sstevel@tonic-gate } 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate rcm_handle_free(hdl); 9277c478bd9Sstevel@tonic-gate return (rval); 9287c478bd9Sstevel@tonic-gate } 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate /* 9317c478bd9Sstevel@tonic-gate * invoke a callback into a list of clients, return 0 if all success 9327c478bd9Sstevel@tonic-gate */ 9337c478bd9Sstevel@tonic-gate int 9347c478bd9Sstevel@tonic-gate rsrc_client_action_list(client_t *list, int cmd, void *arg) 9357c478bd9Sstevel@tonic-gate { 9367c478bd9Sstevel@tonic-gate int error, rval = RCM_SUCCESS; 937*25e8c5aaSvikram tree_walk_arg_t *targ = (tree_walk_arg_t *)arg; 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate while (list) { 9407c478bd9Sstevel@tonic-gate client_t *client = list; 9417c478bd9Sstevel@tonic-gate list = client->next; 9427c478bd9Sstevel@tonic-gate 943*25e8c5aaSvikram /* 944*25e8c5aaSvikram * Make offline idempotent in the retire 945*25e8c5aaSvikram * case 946*25e8c5aaSvikram */ 947*25e8c5aaSvikram if ((targ->flag & RCM_RETIRE_REQUEST) && 948*25e8c5aaSvikram client->state == RCM_STATE_REMOVE) { 949*25e8c5aaSvikram client->state = RCM_STATE_ONLINE; 950*25e8c5aaSvikram rcm_log_message(RCM_DEBUG, "RETIRE: idempotent client " 951*25e8c5aaSvikram "state: REMOVE -> ONLINE: %s\n", client->alias); 952*25e8c5aaSvikram } 953*25e8c5aaSvikram 9547c478bd9Sstevel@tonic-gate if (client->state == RCM_STATE_REMOVE) 9557c478bd9Sstevel@tonic-gate continue; 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate error = rsrc_client_action(client, cmd, arg); 9587c478bd9Sstevel@tonic-gate if (error != RCM_SUCCESS) { 9597c478bd9Sstevel@tonic-gate rval = error; 9607c478bd9Sstevel@tonic-gate } 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate return (rval); 9647c478bd9Sstevel@tonic-gate } 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate /* 9677c478bd9Sstevel@tonic-gate * Node realted operations: 9687c478bd9Sstevel@tonic-gate * 9697c478bd9Sstevel@tonic-gate * rn_alloc, rn_free, rn_find_child, 9707c478bd9Sstevel@tonic-gate * rn_get_child, rn_get_sibling, 9717c478bd9Sstevel@tonic-gate * rsrc_node_find, rsrc_node_add_user, rsrc_node_remove_user, 9727c478bd9Sstevel@tonic-gate */ 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate /* Allocate node based on a logical or physical name */ 9757c478bd9Sstevel@tonic-gate static rsrc_node_t * 9767c478bd9Sstevel@tonic-gate rn_alloc(char *name, int type) 9777c478bd9Sstevel@tonic-gate { 9787c478bd9Sstevel@tonic-gate rsrc_node_t *node; 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE4, "rn_alloc(%s, %d)\n", name, type); 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate node = s_calloc(1, sizeof (*node)); 9837c478bd9Sstevel@tonic-gate node->name = s_strdup(name); 9847c478bd9Sstevel@tonic-gate node->type = type; 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate return (node); 9877c478bd9Sstevel@tonic-gate } 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate /* 9907c478bd9Sstevel@tonic-gate * Free node along with its siblings and children 9917c478bd9Sstevel@tonic-gate */ 9927c478bd9Sstevel@tonic-gate static void 9937c478bd9Sstevel@tonic-gate rn_free(rsrc_node_t *node) 9947c478bd9Sstevel@tonic-gate { 9957c478bd9Sstevel@tonic-gate if (node == NULL) { 9967c478bd9Sstevel@tonic-gate return; 9977c478bd9Sstevel@tonic-gate } 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate if (node->child) { 10007c478bd9Sstevel@tonic-gate rn_free(node->child); 10017c478bd9Sstevel@tonic-gate } 10027c478bd9Sstevel@tonic-gate 10037c478bd9Sstevel@tonic-gate if (node->sibling) { 10047c478bd9Sstevel@tonic-gate rn_free(node->sibling); 10057c478bd9Sstevel@tonic-gate } 10067c478bd9Sstevel@tonic-gate 10077c478bd9Sstevel@tonic-gate rsrc_clients_free(node->users); 10087c478bd9Sstevel@tonic-gate free(node->name); 10097c478bd9Sstevel@tonic-gate free(node); 10107c478bd9Sstevel@tonic-gate } 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate /* 10137c478bd9Sstevel@tonic-gate * Find next sibling 10147c478bd9Sstevel@tonic-gate */ 10157c478bd9Sstevel@tonic-gate static rsrc_node_t * 10167c478bd9Sstevel@tonic-gate rn_get_sibling(rsrc_node_t *node) 10177c478bd9Sstevel@tonic-gate { 10187c478bd9Sstevel@tonic-gate return (node->sibling); 10197c478bd9Sstevel@tonic-gate } 10207c478bd9Sstevel@tonic-gate 10217c478bd9Sstevel@tonic-gate /* 10227c478bd9Sstevel@tonic-gate * Find first child 10237c478bd9Sstevel@tonic-gate */ 10247c478bd9Sstevel@tonic-gate static rsrc_node_t * 10257c478bd9Sstevel@tonic-gate rn_get_child(rsrc_node_t *node) 10267c478bd9Sstevel@tonic-gate { 10277c478bd9Sstevel@tonic-gate return (node->child); 10287c478bd9Sstevel@tonic-gate } 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate /* 10317c478bd9Sstevel@tonic-gate * Find child named childname. Create it if flag is RSRC_NODE_CRTEATE 10327c478bd9Sstevel@tonic-gate */ 10337c478bd9Sstevel@tonic-gate static rsrc_node_t * 10347c478bd9Sstevel@tonic-gate rn_find_child(rsrc_node_t *parent, char *childname, int flag, int type) 10357c478bd9Sstevel@tonic-gate { 10367c478bd9Sstevel@tonic-gate rsrc_node_t *child = parent->child; 10377c478bd9Sstevel@tonic-gate rsrc_node_t *new, *prev = NULL; 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE4, 10407c478bd9Sstevel@tonic-gate "rn_find_child(parent=%s, child=%s, 0x%x, %d)\n", 10417c478bd9Sstevel@tonic-gate parent->name, childname, flag, type); 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate /* 10447c478bd9Sstevel@tonic-gate * Children are ordered based on strcmp. 10457c478bd9Sstevel@tonic-gate */ 10467c478bd9Sstevel@tonic-gate while (child && (strcmp(child->name, childname) < 0)) { 10477c478bd9Sstevel@tonic-gate prev = child; 10487c478bd9Sstevel@tonic-gate child = child->sibling; 10497c478bd9Sstevel@tonic-gate } 10507c478bd9Sstevel@tonic-gate 10517c478bd9Sstevel@tonic-gate if (child && (strcmp(child->name, childname) == 0)) { 10527c478bd9Sstevel@tonic-gate return (child); 10537c478bd9Sstevel@tonic-gate } 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate if (flag != RSRC_NODE_CREATE) 10567c478bd9Sstevel@tonic-gate return (NULL); 10577c478bd9Sstevel@tonic-gate 10587c478bd9Sstevel@tonic-gate new = rn_alloc(childname, type); 10597c478bd9Sstevel@tonic-gate new->parent = parent; 10607c478bd9Sstevel@tonic-gate new->sibling = child; 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate /* 10637c478bd9Sstevel@tonic-gate * Set this linkage last so we don't break ongoing operations. 10647c478bd9Sstevel@tonic-gate * 10657c478bd9Sstevel@tonic-gate * N.B. Assume setting a pointer is an atomic operation. 10667c478bd9Sstevel@tonic-gate */ 10677c478bd9Sstevel@tonic-gate if (prev == NULL) { 10687c478bd9Sstevel@tonic-gate parent->child = new; 10697c478bd9Sstevel@tonic-gate } else { 10707c478bd9Sstevel@tonic-gate prev->sibling = new; 10717c478bd9Sstevel@tonic-gate } 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate return (new); 10747c478bd9Sstevel@tonic-gate } 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate /* 10777c478bd9Sstevel@tonic-gate * Pathname related help functions 10787c478bd9Sstevel@tonic-gate */ 10797c478bd9Sstevel@tonic-gate static void 10807c478bd9Sstevel@tonic-gate pn_preprocess(char *pathname, int type) 10817c478bd9Sstevel@tonic-gate { 10827c478bd9Sstevel@tonic-gate char *tmp; 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate if (type != RSRC_TYPE_DEVICE) 10857c478bd9Sstevel@tonic-gate return; 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate /* 10887c478bd9Sstevel@tonic-gate * For devices, convert ':' to '/' (treat minor nodes and children) 10897c478bd9Sstevel@tonic-gate */ 10907c478bd9Sstevel@tonic-gate tmp = strchr(pathname, ':'); 10917c478bd9Sstevel@tonic-gate if (tmp == NULL) 10927c478bd9Sstevel@tonic-gate return; 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate *tmp = '/'; 10957c478bd9Sstevel@tonic-gate } 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate static char * 10987c478bd9Sstevel@tonic-gate pn_getnextcomp(char *pathname, char **lasts) 10997c478bd9Sstevel@tonic-gate { 11007c478bd9Sstevel@tonic-gate char *slash; 11017c478bd9Sstevel@tonic-gate 11027c478bd9Sstevel@tonic-gate if (pathname == NULL) 11037c478bd9Sstevel@tonic-gate return (NULL); 11047c478bd9Sstevel@tonic-gate 11057c478bd9Sstevel@tonic-gate /* skip slashes' */ 11067c478bd9Sstevel@tonic-gate while (*pathname == '/') 11077c478bd9Sstevel@tonic-gate ++pathname; 11087c478bd9Sstevel@tonic-gate 11097c478bd9Sstevel@tonic-gate if (*pathname == '\0') 11107c478bd9Sstevel@tonic-gate return (NULL); 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate slash = strchr(pathname, '/'); 11137c478bd9Sstevel@tonic-gate if (slash != NULL) { 11147c478bd9Sstevel@tonic-gate *slash = '\0'; 11157c478bd9Sstevel@tonic-gate *lasts = slash + 1; 11167c478bd9Sstevel@tonic-gate } else { 11177c478bd9Sstevel@tonic-gate *lasts = NULL; 11187c478bd9Sstevel@tonic-gate } 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate return (pathname); 11217c478bd9Sstevel@tonic-gate } 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate /* 11247c478bd9Sstevel@tonic-gate * Find a node in tree based on device, which is the physical pathname 11257c478bd9Sstevel@tonic-gate * of the form /sbus@.../esp@.../sd@... 11267c478bd9Sstevel@tonic-gate */ 11277c478bd9Sstevel@tonic-gate int 11287c478bd9Sstevel@tonic-gate rsrc_node_find(char *rsrcname, int flag, rsrc_node_t **nodep) 11297c478bd9Sstevel@tonic-gate { 11307c478bd9Sstevel@tonic-gate char *pathname, *nodename, *lasts; 11317c478bd9Sstevel@tonic-gate rsrc_node_t *node; 11327c478bd9Sstevel@tonic-gate int type; 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE4, "rn_node_find(%s, 0x%x)\n", rsrcname, flag); 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate /* 11377c478bd9Sstevel@tonic-gate * For RSRC_TYPE_ABSTRACT, look under /ABSTRACT. For other types, 11387c478bd9Sstevel@tonic-gate * look under /SYSTEM. 11397c478bd9Sstevel@tonic-gate */ 11407c478bd9Sstevel@tonic-gate pathname = resolve_name(rsrcname); 11417c478bd9Sstevel@tonic-gate if (pathname == NULL) 11427c478bd9Sstevel@tonic-gate return (EINVAL); 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate type = rsrc_get_type(pathname); 11457c478bd9Sstevel@tonic-gate switch (type) { 11467c478bd9Sstevel@tonic-gate case RSRC_TYPE_DEVICE: 11477c478bd9Sstevel@tonic-gate case RSRC_TYPE_NORMAL: 11487c478bd9Sstevel@tonic-gate node = rn_find_child(rsrc_root, "SYSTEM", RSRC_NODE_CREATE, 11497c478bd9Sstevel@tonic-gate RSRC_TYPE_NORMAL); 11507c478bd9Sstevel@tonic-gate break; 11517c478bd9Sstevel@tonic-gate 11527c478bd9Sstevel@tonic-gate case RSRC_TYPE_ABSTRACT: 11537c478bd9Sstevel@tonic-gate node = rn_find_child(rsrc_root, "ABSTRACT", RSRC_NODE_CREATE, 11547c478bd9Sstevel@tonic-gate RSRC_TYPE_NORMAL); 11557c478bd9Sstevel@tonic-gate break; 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate default: 11587c478bd9Sstevel@tonic-gate /* just to make sure */ 11597c478bd9Sstevel@tonic-gate free(pathname); 11607c478bd9Sstevel@tonic-gate return (EINVAL); 11617c478bd9Sstevel@tonic-gate } 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate /* 11647c478bd9Sstevel@tonic-gate * Find position of device within tree. Upon exiting the loop, device 11657c478bd9Sstevel@tonic-gate * should be placed between prev and curr. 11667c478bd9Sstevel@tonic-gate */ 11677c478bd9Sstevel@tonic-gate pn_preprocess(pathname, type); 11687c478bd9Sstevel@tonic-gate lasts = pathname; 11697c478bd9Sstevel@tonic-gate while ((nodename = pn_getnextcomp(lasts, &lasts)) != NULL) { 11707c478bd9Sstevel@tonic-gate rsrc_node_t *parent = node; 11717c478bd9Sstevel@tonic-gate node = rn_find_child(parent, nodename, flag, type); 11727c478bd9Sstevel@tonic-gate if (node == NULL) { 11737c478bd9Sstevel@tonic-gate assert((flag & RSRC_NODE_CREATE) == 0); 11747c478bd9Sstevel@tonic-gate free(pathname); 11757c478bd9Sstevel@tonic-gate *nodep = NULL; 11767c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 11777c478bd9Sstevel@tonic-gate } 11787c478bd9Sstevel@tonic-gate } 11797c478bd9Sstevel@tonic-gate free(pathname); 11807c478bd9Sstevel@tonic-gate *nodep = node; 11817c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 11827c478bd9Sstevel@tonic-gate } 11837c478bd9Sstevel@tonic-gate 11847c478bd9Sstevel@tonic-gate /* 11857c478bd9Sstevel@tonic-gate * add a usage client to a node 11867c478bd9Sstevel@tonic-gate */ 11877c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11887c478bd9Sstevel@tonic-gate int 11897c478bd9Sstevel@tonic-gate rsrc_node_add_user(rsrc_node_t *node, char *alias, char *modname, pid_t pid, 11907c478bd9Sstevel@tonic-gate uint_t flag) 11917c478bd9Sstevel@tonic-gate { 11927c478bd9Sstevel@tonic-gate client_t *user; 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE3, 11957c478bd9Sstevel@tonic-gate "rsrc_node_add_user(%s, %s, %s, %ld, 0x%x)\n", 11967c478bd9Sstevel@tonic-gate node->name, alias, modname, pid, flag); 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate user = rsrc_client_find(modname, pid, &node->users); 11997c478bd9Sstevel@tonic-gate 12007c478bd9Sstevel@tonic-gate /* 12017c478bd9Sstevel@tonic-gate * If a client_t already exists, add the registration and return 12027c478bd9Sstevel@tonic-gate * success if it's a valid registration request. 12037c478bd9Sstevel@tonic-gate * 12047c478bd9Sstevel@tonic-gate * Return EALREADY if the resource is already registered. 12057c478bd9Sstevel@tonic-gate * This means either the client_t already has the requested 12067c478bd9Sstevel@tonic-gate * registration flagged, or that a DR registration was attempted 12077c478bd9Sstevel@tonic-gate * on a resource already in use in the DR operations state model. 12087c478bd9Sstevel@tonic-gate */ 12097c478bd9Sstevel@tonic-gate if (user != NULL) { 12107c478bd9Sstevel@tonic-gate 12117c478bd9Sstevel@tonic-gate if (user->flag & (flag & RCM_REGISTER_MASK)) { 12127c478bd9Sstevel@tonic-gate return (EALREADY); 12137c478bd9Sstevel@tonic-gate } 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate if ((flag & RCM_REGISTER_DR) && 12167c478bd9Sstevel@tonic-gate (user->state != RCM_STATE_REMOVE)) { 12177c478bd9Sstevel@tonic-gate return (EALREADY); 12187c478bd9Sstevel@tonic-gate } 12197c478bd9Sstevel@tonic-gate 12207c478bd9Sstevel@tonic-gate user->flag |= (flag & RCM_REGISTER_MASK); 12217c478bd9Sstevel@tonic-gate if ((flag & RCM_REGISTER_DR) || 12227c478bd9Sstevel@tonic-gate (user->state == RCM_STATE_REMOVE)) { 12237c478bd9Sstevel@tonic-gate user->state = RCM_STATE_ONLINE; 12247c478bd9Sstevel@tonic-gate } 12257c478bd9Sstevel@tonic-gate 12267c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 12277c478bd9Sstevel@tonic-gate } 12287c478bd9Sstevel@tonic-gate 12297c478bd9Sstevel@tonic-gate /* 12307c478bd9Sstevel@tonic-gate * Otherwise create a new client_t and create a new registration. 12317c478bd9Sstevel@tonic-gate */ 12327c478bd9Sstevel@tonic-gate if ((user = rsrc_client_alloc(alias, modname, pid, flag)) != NULL) { 12337c478bd9Sstevel@tonic-gate rsrc_client_add(user, &node->users); 12347c478bd9Sstevel@tonic-gate } 12357c478bd9Sstevel@tonic-gate if (flag & RCM_FILESYS) 12367c478bd9Sstevel@tonic-gate node->type = RSRC_TYPE_FILESYS; 12377c478bd9Sstevel@tonic-gate 12387c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 12397c478bd9Sstevel@tonic-gate } 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate /* 12427c478bd9Sstevel@tonic-gate * remove a usage client of a node 12437c478bd9Sstevel@tonic-gate */ 12447c478bd9Sstevel@tonic-gate int 12457c478bd9Sstevel@tonic-gate rsrc_node_remove_user(rsrc_node_t *node, char *modname, pid_t pid, uint_t flag) 12467c478bd9Sstevel@tonic-gate { 12477c478bd9Sstevel@tonic-gate client_t *user; 12487c478bd9Sstevel@tonic-gate 12497c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE3, 12507c478bd9Sstevel@tonic-gate "rsrc_node_remove_user(%s, %s, %ld, 0x%x)\n", node->name, modname, 12517c478bd9Sstevel@tonic-gate pid, flag); 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate user = rsrc_client_find(modname, pid, &node->users); 12547c478bd9Sstevel@tonic-gate if ((user == NULL) || (user->state == RCM_STATE_REMOVE)) { 12557c478bd9Sstevel@tonic-gate rcm_log_message(RCM_NOTICE, gettext( 12567c478bd9Sstevel@tonic-gate "client not registered: module=%s, pid=%d, dev=%s\n"), 12577c478bd9Sstevel@tonic-gate modname, pid, node->name); 12587c478bd9Sstevel@tonic-gate return (ENOENT); 12597c478bd9Sstevel@tonic-gate } 12607c478bd9Sstevel@tonic-gate 12617c478bd9Sstevel@tonic-gate /* Strip off the registration being removed (DR, event, capacity) */ 12627c478bd9Sstevel@tonic-gate user->flag = user->flag & (~(flag & RCM_REGISTER_MASK)); 12637c478bd9Sstevel@tonic-gate 12647c478bd9Sstevel@tonic-gate /* 12657c478bd9Sstevel@tonic-gate * Mark the client as removed if all registrations have been removed 12667c478bd9Sstevel@tonic-gate */ 12677c478bd9Sstevel@tonic-gate if ((user->flag & RCM_REGISTER_MASK) == 0) 12687c478bd9Sstevel@tonic-gate user->state = RCM_STATE_REMOVE; 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 12717c478bd9Sstevel@tonic-gate } 12727c478bd9Sstevel@tonic-gate 12737c478bd9Sstevel@tonic-gate /* 12747c478bd9Sstevel@tonic-gate * Tree walking function - rsrc_walk 12757c478bd9Sstevel@tonic-gate */ 12767c478bd9Sstevel@tonic-gate 12777c478bd9Sstevel@tonic-gate #define MAX_TREE_DEPTH 32 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate #define RN_WALK_CONTINUE 0 12807c478bd9Sstevel@tonic-gate #define RN_WALK_PRUNESIB 1 12817c478bd9Sstevel@tonic-gate #define RN_WALK_PRUNECHILD 2 12827c478bd9Sstevel@tonic-gate #define RN_WALK_TERMINATE 3 12837c478bd9Sstevel@tonic-gate 12847c478bd9Sstevel@tonic-gate #define EMPTY_STACK(sp) ((sp)->depth == 0) 12857c478bd9Sstevel@tonic-gate #define TOP_NODE(sp) ((sp)->node[(sp)->depth - 1]) 12867c478bd9Sstevel@tonic-gate #define PRUNE_SIB(sp) ((sp)->prunesib[(sp)->depth - 1]) 12877c478bd9Sstevel@tonic-gate #define PRUNE_CHILD(sp) ((sp)->prunechild[(sp)->depth - 1]) 12887c478bd9Sstevel@tonic-gate #define POP_STACK(sp) ((sp)->depth)-- 12897c478bd9Sstevel@tonic-gate #define PUSH_STACK(sp, rn) \ 12907c478bd9Sstevel@tonic-gate (sp)->node[(sp)->depth] = (rn); \ 12917c478bd9Sstevel@tonic-gate (sp)->prunesib[(sp)->depth] = 0; \ 12927c478bd9Sstevel@tonic-gate (sp)->prunechild[(sp)->depth] = 0; \ 12937c478bd9Sstevel@tonic-gate ((sp)->depth)++ 12947c478bd9Sstevel@tonic-gate 12957c478bd9Sstevel@tonic-gate struct rn_stack { 12967c478bd9Sstevel@tonic-gate rsrc_node_t *node[MAX_TREE_DEPTH]; 12977c478bd9Sstevel@tonic-gate char prunesib[MAX_TREE_DEPTH]; 12987c478bd9Sstevel@tonic-gate char prunechild[MAX_TREE_DEPTH]; 12997c478bd9Sstevel@tonic-gate int depth; 13007c478bd9Sstevel@tonic-gate }; 13017c478bd9Sstevel@tonic-gate 13027c478bd9Sstevel@tonic-gate /* walking one node and update node stack */ 13037c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 13047c478bd9Sstevel@tonic-gate static void 13057c478bd9Sstevel@tonic-gate walk_one_node(struct rn_stack *sp, void *arg, 13067c478bd9Sstevel@tonic-gate int (*node_callback)(rsrc_node_t *, void *)) 13077c478bd9Sstevel@tonic-gate { 13087c478bd9Sstevel@tonic-gate int prunesib; 13097c478bd9Sstevel@tonic-gate rsrc_node_t *child, *sibling; 13107c478bd9Sstevel@tonic-gate rsrc_node_t *node = TOP_NODE(sp); 13117c478bd9Sstevel@tonic-gate 13127c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE4, "walk_one_node(%s)\n", node->name); 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate switch (node_callback(node, arg)) { 13157c478bd9Sstevel@tonic-gate case RN_WALK_TERMINATE: 13167c478bd9Sstevel@tonic-gate POP_STACK(sp); 13177c478bd9Sstevel@tonic-gate while (!EMPTY_STACK(sp)) { 13187c478bd9Sstevel@tonic-gate node = TOP_NODE(sp); 13197c478bd9Sstevel@tonic-gate POP_STACK(sp); 13207c478bd9Sstevel@tonic-gate } 13217c478bd9Sstevel@tonic-gate return; 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate case RN_WALK_PRUNESIB: 13247c478bd9Sstevel@tonic-gate PRUNE_SIB(sp) = 1; 13257c478bd9Sstevel@tonic-gate break; 13267c478bd9Sstevel@tonic-gate 13277c478bd9Sstevel@tonic-gate case RN_WALK_PRUNECHILD: 13287c478bd9Sstevel@tonic-gate PRUNE_CHILD(sp) = 1; 13297c478bd9Sstevel@tonic-gate break; 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate case RN_WALK_CONTINUE: 13327c478bd9Sstevel@tonic-gate default: 13337c478bd9Sstevel@tonic-gate break; 13347c478bd9Sstevel@tonic-gate } 13357c478bd9Sstevel@tonic-gate 13367c478bd9Sstevel@tonic-gate /* 13377c478bd9Sstevel@tonic-gate * Push child on the stack 13387c478bd9Sstevel@tonic-gate */ 13397c478bd9Sstevel@tonic-gate if (!PRUNE_CHILD(sp) && (child = rn_get_child(node)) != NULL) { 13407c478bd9Sstevel@tonic-gate PUSH_STACK(sp, child); 13417c478bd9Sstevel@tonic-gate return; 13427c478bd9Sstevel@tonic-gate } 13437c478bd9Sstevel@tonic-gate 13447c478bd9Sstevel@tonic-gate /* 13457c478bd9Sstevel@tonic-gate * Pop the stack till a node's sibling can be pushed 13467c478bd9Sstevel@tonic-gate */ 13477c478bd9Sstevel@tonic-gate prunesib = PRUNE_SIB(sp); 13487c478bd9Sstevel@tonic-gate POP_STACK(sp); 13497c478bd9Sstevel@tonic-gate while (!EMPTY_STACK(sp) && 13507c478bd9Sstevel@tonic-gate (prunesib || (sibling = rn_get_sibling(node)) == NULL)) { 13517c478bd9Sstevel@tonic-gate node = TOP_NODE(sp); 13527c478bd9Sstevel@tonic-gate prunesib = PRUNE_SIB(sp); 13537c478bd9Sstevel@tonic-gate POP_STACK(sp); 13547c478bd9Sstevel@tonic-gate } 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate if (EMPTY_STACK(sp)) { 13577c478bd9Sstevel@tonic-gate return; 13587c478bd9Sstevel@tonic-gate } 13597c478bd9Sstevel@tonic-gate 13607c478bd9Sstevel@tonic-gate /* 13617c478bd9Sstevel@tonic-gate * push sibling onto the stack 13627c478bd9Sstevel@tonic-gate */ 13637c478bd9Sstevel@tonic-gate PUSH_STACK(sp, sibling); 13647c478bd9Sstevel@tonic-gate } 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate /* 13677c478bd9Sstevel@tonic-gate * walk tree rooted at root in child-first order 13687c478bd9Sstevel@tonic-gate */ 13697c478bd9Sstevel@tonic-gate static void 13707c478bd9Sstevel@tonic-gate rsrc_walk(rsrc_node_t *root, void *arg, 13717c478bd9Sstevel@tonic-gate int (*node_callback)(rsrc_node_t *, void *)) 13727c478bd9Sstevel@tonic-gate { 13737c478bd9Sstevel@tonic-gate struct rn_stack stack; 13747c478bd9Sstevel@tonic-gate 13757c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE3, "rsrc_walk(%s)\n", root->name); 13767c478bd9Sstevel@tonic-gate 13777c478bd9Sstevel@tonic-gate /* 13787c478bd9Sstevel@tonic-gate * Push root on stack and walk in child-first order 13797c478bd9Sstevel@tonic-gate */ 13807c478bd9Sstevel@tonic-gate stack.depth = 0; 13817c478bd9Sstevel@tonic-gate PUSH_STACK(&stack, root); 13827c478bd9Sstevel@tonic-gate PRUNE_SIB(&stack) = 1; 13837c478bd9Sstevel@tonic-gate 13847c478bd9Sstevel@tonic-gate while (!EMPTY_STACK(&stack)) { 13857c478bd9Sstevel@tonic-gate walk_one_node(&stack, arg, node_callback); 13867c478bd9Sstevel@tonic-gate } 13877c478bd9Sstevel@tonic-gate } 13887c478bd9Sstevel@tonic-gate 13897c478bd9Sstevel@tonic-gate /* 13907c478bd9Sstevel@tonic-gate * Callback for a command action on a node 13917c478bd9Sstevel@tonic-gate */ 13927c478bd9Sstevel@tonic-gate static int 13937c478bd9Sstevel@tonic-gate node_action(rsrc_node_t *node, void *arg) 13947c478bd9Sstevel@tonic-gate { 13957c478bd9Sstevel@tonic-gate tree_walk_arg_t *targ = (tree_walk_arg_t *)arg; 13967c478bd9Sstevel@tonic-gate uint_t flag = targ->flag; 13977c478bd9Sstevel@tonic-gate 13987c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE4, "node_action(%s)\n", node->name); 13997c478bd9Sstevel@tonic-gate 14007c478bd9Sstevel@tonic-gate /* 14017c478bd9Sstevel@tonic-gate * If flag indicates operation on a filesystem, we don't callback on 14027c478bd9Sstevel@tonic-gate * the filesystem root to avoid infinite recursion on filesystem module. 14037c478bd9Sstevel@tonic-gate * 14047c478bd9Sstevel@tonic-gate * N.B. Such request should only come from filesystem RCM module. 14057c478bd9Sstevel@tonic-gate */ 14067c478bd9Sstevel@tonic-gate if (flag & RCM_FILESYS) { 14077c478bd9Sstevel@tonic-gate assert(node->type == RSRC_TYPE_FILESYS); 14087c478bd9Sstevel@tonic-gate targ->flag &= ~RCM_FILESYS; 14097c478bd9Sstevel@tonic-gate return (RN_WALK_CONTINUE); 14107c478bd9Sstevel@tonic-gate } 14117c478bd9Sstevel@tonic-gate 14127c478bd9Sstevel@tonic-gate /* 14137c478bd9Sstevel@tonic-gate * Execute state change callback 14147c478bd9Sstevel@tonic-gate */ 14157c478bd9Sstevel@tonic-gate (void) rsrc_client_action_list(node->users, targ->cmd, arg); 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate /* 14187c478bd9Sstevel@tonic-gate * Upon hitting a filesys root, prune children. 14197c478bd9Sstevel@tonic-gate * The filesys module should have taken care of 14207c478bd9Sstevel@tonic-gate * children by now. 14217c478bd9Sstevel@tonic-gate */ 14227c478bd9Sstevel@tonic-gate if (node->type == RSRC_TYPE_FILESYS) 14237c478bd9Sstevel@tonic-gate return (RN_WALK_PRUNECHILD); 14247c478bd9Sstevel@tonic-gate 14257c478bd9Sstevel@tonic-gate return (RN_WALK_CONTINUE); 14267c478bd9Sstevel@tonic-gate } 14277c478bd9Sstevel@tonic-gate 14287c478bd9Sstevel@tonic-gate /* 14297c478bd9Sstevel@tonic-gate * Execute a command on a subtree under root. 14307c478bd9Sstevel@tonic-gate */ 14317c478bd9Sstevel@tonic-gate int 14327c478bd9Sstevel@tonic-gate rsrc_tree_action(rsrc_node_t *root, int cmd, tree_walk_arg_t *arg) 14337c478bd9Sstevel@tonic-gate { 14347c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, "tree_action(%s, %d)\n", root->name, cmd); 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate arg->cmd = cmd; 1437*25e8c5aaSvikram 1438*25e8c5aaSvikram /* 1439*25e8c5aaSvikram * If RCM_RETIRE_REQUEST is set, just walk one node and preset 1440*25e8c5aaSvikram * retcode to NO_CONSTRAINT 1441*25e8c5aaSvikram */ 1442*25e8c5aaSvikram if (arg->flag & RCM_RETIRE_REQUEST) { 1443*25e8c5aaSvikram rcm_log_message(RCM_TRACE1, "tree_action: RETIRE_REQ: walking " 1444*25e8c5aaSvikram "only root node: %s\n", root->name); 1445*25e8c5aaSvikram arg->retcode = RCM_NO_CONSTRAINT; 1446*25e8c5aaSvikram (void) node_action(root, arg); 1447*25e8c5aaSvikram } else { 14487c478bd9Sstevel@tonic-gate arg->retcode = RCM_SUCCESS; 14497c478bd9Sstevel@tonic-gate rsrc_walk(root, (void *)arg, node_action); 1450*25e8c5aaSvikram } 14517c478bd9Sstevel@tonic-gate 14527c478bd9Sstevel@tonic-gate return (arg->retcode); 14537c478bd9Sstevel@tonic-gate } 14547c478bd9Sstevel@tonic-gate 14557c478bd9Sstevel@tonic-gate /* 14567c478bd9Sstevel@tonic-gate * Get info on current regsitrations 14577c478bd9Sstevel@tonic-gate */ 14587c478bd9Sstevel@tonic-gate int 14597c478bd9Sstevel@tonic-gate rsrc_usage_info(char **rsrcnames, uint_t flag, int seq_num, rcm_info_t **info) 14607c478bd9Sstevel@tonic-gate { 14617c478bd9Sstevel@tonic-gate rsrc_node_t *node; 14627c478bd9Sstevel@tonic-gate rcm_info_t *result = NULL; 14637c478bd9Sstevel@tonic-gate tree_walk_arg_t arg; 14647c478bd9Sstevel@tonic-gate int initial_req; 14657c478bd9Sstevel@tonic-gate int rv; 14667c478bd9Sstevel@tonic-gate int i; 14677c478bd9Sstevel@tonic-gate 14687c478bd9Sstevel@tonic-gate arg.flag = flag; 14697c478bd9Sstevel@tonic-gate arg.info = &result; 14707c478bd9Sstevel@tonic-gate arg.seq_num = seq_num; 14717c478bd9Sstevel@tonic-gate 14727c478bd9Sstevel@tonic-gate for (i = 0; rsrcnames[i] != NULL; i++) { 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, "rsrc_usage_info(%s, 0x%x, %d)\n", 14757c478bd9Sstevel@tonic-gate rsrcnames[i], flag, seq_num); 14767c478bd9Sstevel@tonic-gate 14777c478bd9Sstevel@tonic-gate if (flag & RCM_INCLUDE_DEPENDENT) { 14787c478bd9Sstevel@tonic-gate initial_req = ((seq_num & SEQ_NUM_MASK) == 0); 14797c478bd9Sstevel@tonic-gate 14807c478bd9Sstevel@tonic-gate /* 14817c478bd9Sstevel@tonic-gate * if redundant request, skip the operation 14827c478bd9Sstevel@tonic-gate */ 14837c478bd9Sstevel@tonic-gate if (info_req_add(rsrcnames[i], flag, seq_num) != 0) { 14847c478bd9Sstevel@tonic-gate continue; 14857c478bd9Sstevel@tonic-gate } 14867c478bd9Sstevel@tonic-gate } 14877c478bd9Sstevel@tonic-gate 14887c478bd9Sstevel@tonic-gate rv = rsrc_node_find(rsrcnames[i], 0, &node); 14897c478bd9Sstevel@tonic-gate if ((rv != RCM_SUCCESS) || (node == NULL)) { 14907c478bd9Sstevel@tonic-gate if ((flag & RCM_INCLUDE_DEPENDENT) && initial_req) 14917c478bd9Sstevel@tonic-gate info_req_remove(seq_num); 14927c478bd9Sstevel@tonic-gate continue; 14937c478bd9Sstevel@tonic-gate } 14947c478bd9Sstevel@tonic-gate 14957c478bd9Sstevel@tonic-gate /* 14967c478bd9Sstevel@tonic-gate * Based on RCM_INCLUDE_SUBTREE flag, query either the subtree 14977c478bd9Sstevel@tonic-gate * or just the node. 14987c478bd9Sstevel@tonic-gate */ 14997c478bd9Sstevel@tonic-gate if (flag & RCM_INCLUDE_SUBTREE) { 15007c478bd9Sstevel@tonic-gate (void) rsrc_tree_action(node, CMD_GETINFO, &arg); 15017c478bd9Sstevel@tonic-gate } else { 15027c478bd9Sstevel@tonic-gate arg.cmd = CMD_GETINFO; 15037c478bd9Sstevel@tonic-gate (void) node_action(node, (void *)&arg); 15047c478bd9Sstevel@tonic-gate } 15057c478bd9Sstevel@tonic-gate 15067c478bd9Sstevel@tonic-gate if ((flag & RCM_INCLUDE_DEPENDENT) && initial_req) 15077c478bd9Sstevel@tonic-gate info_req_remove(seq_num); 15087c478bd9Sstevel@tonic-gate } 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate out: 15117c478bd9Sstevel@tonic-gate (void) rcm_append_info(info, result); 15127c478bd9Sstevel@tonic-gate return (rv); 15137c478bd9Sstevel@tonic-gate } 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate /* 15167c478bd9Sstevel@tonic-gate * Get the list of currently loaded module 15177c478bd9Sstevel@tonic-gate */ 15187c478bd9Sstevel@tonic-gate rcm_info_t * 15197c478bd9Sstevel@tonic-gate rsrc_mod_info() 15207c478bd9Sstevel@tonic-gate { 15217c478bd9Sstevel@tonic-gate module_t *mod; 15227c478bd9Sstevel@tonic-gate rcm_info_t *info = NULL; 15237c478bd9Sstevel@tonic-gate 15247c478bd9Sstevel@tonic-gate (void) mutex_lock(&mod_lock); 15257c478bd9Sstevel@tonic-gate mod = module_head; 15267c478bd9Sstevel@tonic-gate while (mod) { 15277c478bd9Sstevel@tonic-gate char *modinfo = s_strdup(module_info(mod)); 15287c478bd9Sstevel@tonic-gate add_busy_rsrc_to_list("dummy", 0, 0, 0, mod->name, 15297c478bd9Sstevel@tonic-gate modinfo, NULL, NULL, &info); 15307c478bd9Sstevel@tonic-gate mod = mod->next; 15317c478bd9Sstevel@tonic-gate } 15327c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mod_lock); 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate return (info); 15357c478bd9Sstevel@tonic-gate } 15367c478bd9Sstevel@tonic-gate 15377c478bd9Sstevel@tonic-gate /* 15387c478bd9Sstevel@tonic-gate * Initialize resource map - load all modules 15397c478bd9Sstevel@tonic-gate */ 15407c478bd9Sstevel@tonic-gate void 15417c478bd9Sstevel@tonic-gate rcmd_db_init() 15427c478bd9Sstevel@tonic-gate { 15437c478bd9Sstevel@tonic-gate char *tmp; 15447c478bd9Sstevel@tonic-gate DIR *mod_dir; 15454bc0a2efScasper struct dirent *entp; 15467c478bd9Sstevel@tonic-gate int i; 15477c478bd9Sstevel@tonic-gate char *dir_name; 15487c478bd9Sstevel@tonic-gate int rcm_script; 15497c478bd9Sstevel@tonic-gate 15507c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "rcmd_db_init(): initialize database\n"); 15517c478bd9Sstevel@tonic-gate 15527c478bd9Sstevel@tonic-gate if (script_main_init() == -1) 15537c478bd9Sstevel@tonic-gate rcmd_exit(errno); 15547c478bd9Sstevel@tonic-gate 15557c478bd9Sstevel@tonic-gate rsrc_root = rn_alloc("/", RSRC_TYPE_NORMAL); 15567c478bd9Sstevel@tonic-gate 15577c478bd9Sstevel@tonic-gate for (i = 0; (dir_name = rcm_dir(i, &rcm_script)) != NULL; i++) { 15587c478bd9Sstevel@tonic-gate 15597c478bd9Sstevel@tonic-gate if ((mod_dir = opendir(dir_name)) == NULL) { 15607c478bd9Sstevel@tonic-gate continue; /* try next directory */ 15617c478bd9Sstevel@tonic-gate } 15627c478bd9Sstevel@tonic-gate 15637c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, "search directory %s\n", dir_name); 15647c478bd9Sstevel@tonic-gate 15654bc0a2efScasper while ((entp = readdir(mod_dir)) != NULL) { 15667c478bd9Sstevel@tonic-gate module_t *module; 15677c478bd9Sstevel@tonic-gate 15687c478bd9Sstevel@tonic-gate if (strcmp(entp->d_name, ".") == 0 || 15697c478bd9Sstevel@tonic-gate strcmp(entp->d_name, "..") == 0) 15707c478bd9Sstevel@tonic-gate continue; 15717c478bd9Sstevel@tonic-gate 15727c478bd9Sstevel@tonic-gate if (rcm_script == 0) { 15737c478bd9Sstevel@tonic-gate /* rcm module */ 15747c478bd9Sstevel@tonic-gate if (((tmp = strstr(entp->d_name, 15757c478bd9Sstevel@tonic-gate RCM_MODULE_SUFFIX)) == NULL) || 15767c478bd9Sstevel@tonic-gate (tmp[strlen(RCM_MODULE_SUFFIX)] != '\0')) { 15777c478bd9Sstevel@tonic-gate continue; 15787c478bd9Sstevel@tonic-gate } 15797c478bd9Sstevel@tonic-gate } 15807c478bd9Sstevel@tonic-gate 15817c478bd9Sstevel@tonic-gate module = cli_module_hold(entp->d_name); 15827c478bd9Sstevel@tonic-gate if (module == NULL) { 15837c478bd9Sstevel@tonic-gate if (rcm_script == 0) 15847c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, 15857c478bd9Sstevel@tonic-gate gettext("%s: failed to load\n"), 15867c478bd9Sstevel@tonic-gate entp->d_name); 15877c478bd9Sstevel@tonic-gate continue; 15887c478bd9Sstevel@tonic-gate } 15897c478bd9Sstevel@tonic-gate 15907c478bd9Sstevel@tonic-gate if (module->ref_count == MOD_REFCNT_INIT) { 15917c478bd9Sstevel@tonic-gate /* 15927c478bd9Sstevel@tonic-gate * ask module to register for resource 1st time 15937c478bd9Sstevel@tonic-gate */ 15947c478bd9Sstevel@tonic-gate module_attach(module); 15957c478bd9Sstevel@tonic-gate } 15967c478bd9Sstevel@tonic-gate cli_module_rele(module); 15977c478bd9Sstevel@tonic-gate } 15987c478bd9Sstevel@tonic-gate (void) closedir(mod_dir); 15997c478bd9Sstevel@tonic-gate } 16007c478bd9Sstevel@tonic-gate 16017c478bd9Sstevel@tonic-gate rcmd_db_print(); 16027c478bd9Sstevel@tonic-gate } 16037c478bd9Sstevel@tonic-gate 16047c478bd9Sstevel@tonic-gate /* 16057c478bd9Sstevel@tonic-gate * sync resource map - ask all modules to register again 16067c478bd9Sstevel@tonic-gate */ 16077c478bd9Sstevel@tonic-gate void 16087c478bd9Sstevel@tonic-gate rcmd_db_sync() 16097c478bd9Sstevel@tonic-gate { 16107c478bd9Sstevel@tonic-gate static time_t sync_time = (time_t)-1; 16117c478bd9Sstevel@tonic-gate const time_t interval = 5; /* resync at most every 5 sec */ 16127c478bd9Sstevel@tonic-gate 16137c478bd9Sstevel@tonic-gate module_t *mod; 16147c478bd9Sstevel@tonic-gate time_t curr = time(NULL); 16157c478bd9Sstevel@tonic-gate 16167c478bd9Sstevel@tonic-gate if ((sync_time != (time_t)-1) && (curr - sync_time < interval)) 16177c478bd9Sstevel@tonic-gate return; 16187c478bd9Sstevel@tonic-gate 16197c478bd9Sstevel@tonic-gate sync_time = curr; 16207c478bd9Sstevel@tonic-gate (void) mutex_lock(&mod_lock); 16217c478bd9Sstevel@tonic-gate mod = module_head; 16227c478bd9Sstevel@tonic-gate while (mod) { 16237c478bd9Sstevel@tonic-gate /* 16247c478bd9Sstevel@tonic-gate * Hold module by incrementing ref count and release 16257c478bd9Sstevel@tonic-gate * mod_lock to avoid deadlock, since rcmop_register() 16267c478bd9Sstevel@tonic-gate * may callback into the daemon and request mod_lock. 16277c478bd9Sstevel@tonic-gate */ 16287c478bd9Sstevel@tonic-gate mod->ref_count++; 16297c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mod_lock); 16307c478bd9Sstevel@tonic-gate 16317c478bd9Sstevel@tonic-gate mod->modops->rcmop_register(mod->rcmhandle); 16327c478bd9Sstevel@tonic-gate 16337c478bd9Sstevel@tonic-gate (void) mutex_lock(&mod_lock); 16347c478bd9Sstevel@tonic-gate mod->ref_count--; 16357c478bd9Sstevel@tonic-gate mod = mod->next; 16367c478bd9Sstevel@tonic-gate } 16377c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mod_lock); 16387c478bd9Sstevel@tonic-gate } 16397c478bd9Sstevel@tonic-gate 16407c478bd9Sstevel@tonic-gate /* 16417c478bd9Sstevel@tonic-gate * Determine if a process is alive 16427c478bd9Sstevel@tonic-gate */ 16437c478bd9Sstevel@tonic-gate int 16447c478bd9Sstevel@tonic-gate proc_exist(pid_t pid) 16457c478bd9Sstevel@tonic-gate { 16467c478bd9Sstevel@tonic-gate char path[64]; 16477c478bd9Sstevel@tonic-gate const char *procfs = "/proc"; 16487c478bd9Sstevel@tonic-gate struct stat sb; 16497c478bd9Sstevel@tonic-gate 16507c478bd9Sstevel@tonic-gate if (pid == (pid_t)0) { 16517c478bd9Sstevel@tonic-gate return (1); 16527c478bd9Sstevel@tonic-gate } 16537c478bd9Sstevel@tonic-gate 16547c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s/%ld", procfs, pid); 16557c478bd9Sstevel@tonic-gate return (stat(path, &sb) == 0); 16567c478bd9Sstevel@tonic-gate } 16577c478bd9Sstevel@tonic-gate 16587c478bd9Sstevel@tonic-gate /* 16597c478bd9Sstevel@tonic-gate * Cleaup client list 16607c478bd9Sstevel@tonic-gate * 16617c478bd9Sstevel@tonic-gate * N.B. This routine runs in a single-threaded environment only. It is only 16627c478bd9Sstevel@tonic-gate * called by the cleanup thread, which never runs in parallel with other 16637c478bd9Sstevel@tonic-gate * threads. 16647c478bd9Sstevel@tonic-gate */ 16657c478bd9Sstevel@tonic-gate static void 16667c478bd9Sstevel@tonic-gate clean_client_list(client_t **listp) 16677c478bd9Sstevel@tonic-gate { 16687c478bd9Sstevel@tonic-gate client_t *client = *listp; 16697c478bd9Sstevel@tonic-gate 16707c478bd9Sstevel@tonic-gate /* 16717c478bd9Sstevel@tonic-gate * Cleanup notification clients for which pid no longer exists 16727c478bd9Sstevel@tonic-gate */ 16737c478bd9Sstevel@tonic-gate while (client) { 16747c478bd9Sstevel@tonic-gate if ((client->state != RCM_STATE_REMOVE) && 16757c478bd9Sstevel@tonic-gate proc_exist(client->pid)) { 16767c478bd9Sstevel@tonic-gate listp = &client->next; 16777c478bd9Sstevel@tonic-gate client = *listp; 16787c478bd9Sstevel@tonic-gate continue; 16797c478bd9Sstevel@tonic-gate } 16807c478bd9Sstevel@tonic-gate 16817c478bd9Sstevel@tonic-gate /* 16827c478bd9Sstevel@tonic-gate * Destroy this client_t. rsrc_client_remove updates 16837c478bd9Sstevel@tonic-gate * listp to point to the next client. 16847c478bd9Sstevel@tonic-gate */ 16857c478bd9Sstevel@tonic-gate rsrc_client_remove(client, listp); 16867c478bd9Sstevel@tonic-gate client = *listp; 16877c478bd9Sstevel@tonic-gate } 16887c478bd9Sstevel@tonic-gate } 16897c478bd9Sstevel@tonic-gate 16907c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 16917c478bd9Sstevel@tonic-gate static int 16927c478bd9Sstevel@tonic-gate clean_node(rsrc_node_t *node, void *arg) 16937c478bd9Sstevel@tonic-gate { 16947c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE4, "clean_node(%s)\n", node->name); 16957c478bd9Sstevel@tonic-gate 16967c478bd9Sstevel@tonic-gate clean_client_list(&node->users); 16977c478bd9Sstevel@tonic-gate 16987c478bd9Sstevel@tonic-gate return (RN_WALK_CONTINUE); 16997c478bd9Sstevel@tonic-gate } 17007c478bd9Sstevel@tonic-gate 17017c478bd9Sstevel@tonic-gate static void 17027c478bd9Sstevel@tonic-gate clean_rsrc_tree() 17037c478bd9Sstevel@tonic-gate { 17047c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE4, 17057c478bd9Sstevel@tonic-gate "clean_rsrc_tree(): delete stale dr clients\n"); 17067c478bd9Sstevel@tonic-gate 17077c478bd9Sstevel@tonic-gate rsrc_walk(rsrc_root, NULL, clean_node); 17087c478bd9Sstevel@tonic-gate } 17097c478bd9Sstevel@tonic-gate 17107c478bd9Sstevel@tonic-gate static void 17117c478bd9Sstevel@tonic-gate db_clean() 17127c478bd9Sstevel@tonic-gate { 17137c478bd9Sstevel@tonic-gate extern barrier_t barrier; 17147c478bd9Sstevel@tonic-gate extern void clean_dr_list(); 17157c478bd9Sstevel@tonic-gate 17167c478bd9Sstevel@tonic-gate for (;;) { 17177c478bd9Sstevel@tonic-gate (void) mutex_lock(&rcm_req_lock); 17187c478bd9Sstevel@tonic-gate start_polling_thread(); 17197c478bd9Sstevel@tonic-gate (void) mutex_unlock(&rcm_req_lock); 17207c478bd9Sstevel@tonic-gate 17217c478bd9Sstevel@tonic-gate (void) mutex_lock(&barrier.lock); 17227c478bd9Sstevel@tonic-gate while (need_cleanup == 0) 17237c478bd9Sstevel@tonic-gate (void) cond_wait(&barrier.cv, &barrier.lock); 17247c478bd9Sstevel@tonic-gate (void) mutex_unlock(&barrier.lock); 17257c478bd9Sstevel@tonic-gate 17267c478bd9Sstevel@tonic-gate /* 17277c478bd9Sstevel@tonic-gate * Make sure all other threads are either blocked or exited. 17287c478bd9Sstevel@tonic-gate */ 17297c478bd9Sstevel@tonic-gate rcmd_set_state(RCMD_CLEANUP); 17307c478bd9Sstevel@tonic-gate 17317c478bd9Sstevel@tonic-gate need_cleanup = 0; 17327c478bd9Sstevel@tonic-gate 17337c478bd9Sstevel@tonic-gate /* 17347c478bd9Sstevel@tonic-gate * clean dr_req_list 17357c478bd9Sstevel@tonic-gate */ 17367c478bd9Sstevel@tonic-gate clean_dr_list(); 17377c478bd9Sstevel@tonic-gate 17387c478bd9Sstevel@tonic-gate /* 17397c478bd9Sstevel@tonic-gate * clean resource tree 17407c478bd9Sstevel@tonic-gate */ 17417c478bd9Sstevel@tonic-gate clean_rsrc_tree(); 17427c478bd9Sstevel@tonic-gate 17437c478bd9Sstevel@tonic-gate rcmd_set_state(RCMD_NORMAL); 17447c478bd9Sstevel@tonic-gate } 17457c478bd9Sstevel@tonic-gate } 17467c478bd9Sstevel@tonic-gate 17477c478bd9Sstevel@tonic-gate void 17487c478bd9Sstevel@tonic-gate rcmd_db_clean() 17497c478bd9Sstevel@tonic-gate { 17507c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, 17517c478bd9Sstevel@tonic-gate "rcm_db_clean(): launch thread to clean database\n"); 17527c478bd9Sstevel@tonic-gate 17537c478bd9Sstevel@tonic-gate if (thr_create(NULL, NULL, (void *(*)(void *))db_clean, 17547c478bd9Sstevel@tonic-gate NULL, THR_DETACHED, NULL) != 0) { 17557c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING, 17567c478bd9Sstevel@tonic-gate gettext("failed to create cleanup thread %s\n"), 17577c478bd9Sstevel@tonic-gate strerror(errno)); 17587c478bd9Sstevel@tonic-gate } 17597c478bd9Sstevel@tonic-gate } 17607c478bd9Sstevel@tonic-gate 17617c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 17627c478bd9Sstevel@tonic-gate static int 17637c478bd9Sstevel@tonic-gate print_node(rsrc_node_t *node, void *arg) 17647c478bd9Sstevel@tonic-gate { 17657c478bd9Sstevel@tonic-gate client_t *user; 17667c478bd9Sstevel@tonic-gate 17677c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "rscname: %s, state = 0x%x\n", node->name); 17687c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, " users:\n"); 17697c478bd9Sstevel@tonic-gate 17707c478bd9Sstevel@tonic-gate if ((user = node->users) == NULL) { 17717c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, " none\n"); 17727c478bd9Sstevel@tonic-gate return (RN_WALK_CONTINUE); 17737c478bd9Sstevel@tonic-gate } 17747c478bd9Sstevel@tonic-gate 17757c478bd9Sstevel@tonic-gate while (user) { 17767c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, " %s, %d, %s\n", 17777c478bd9Sstevel@tonic-gate user->module->name, user->pid, user->alias); 17787c478bd9Sstevel@tonic-gate user = user->next; 17797c478bd9Sstevel@tonic-gate } 17807c478bd9Sstevel@tonic-gate return (RN_WALK_CONTINUE); 17817c478bd9Sstevel@tonic-gate } 17827c478bd9Sstevel@tonic-gate 17837c478bd9Sstevel@tonic-gate static void 17847c478bd9Sstevel@tonic-gate rcmd_db_print() 17857c478bd9Sstevel@tonic-gate { 17867c478bd9Sstevel@tonic-gate module_t *mod; 17877c478bd9Sstevel@tonic-gate 17887c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "modules:\n"); 17897c478bd9Sstevel@tonic-gate (void) mutex_lock(&mod_lock); 17907c478bd9Sstevel@tonic-gate mod = module_head; 17917c478bd9Sstevel@tonic-gate while (mod) { 17927c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, " %s\n", mod->name); 17937c478bd9Sstevel@tonic-gate mod = mod->next; 17947c478bd9Sstevel@tonic-gate } 17957c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mod_lock); 17967c478bd9Sstevel@tonic-gate 17977c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "\nresource tree:\n"); 17987c478bd9Sstevel@tonic-gate 17997c478bd9Sstevel@tonic-gate rsrc_walk(rsrc_root, NULL, print_node); 18007c478bd9Sstevel@tonic-gate 18017c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "\n"); 18027c478bd9Sstevel@tonic-gate } 18037c478bd9Sstevel@tonic-gate 18047c478bd9Sstevel@tonic-gate /* 18057c478bd9Sstevel@tonic-gate * Allocate handle from calling into each RCM module 18067c478bd9Sstevel@tonic-gate */ 18077c478bd9Sstevel@tonic-gate static rcm_handle_t * 18087c478bd9Sstevel@tonic-gate rcm_handle_alloc(module_t *module) 18097c478bd9Sstevel@tonic-gate { 18107c478bd9Sstevel@tonic-gate rcm_handle_t *hdl; 18117c478bd9Sstevel@tonic-gate 18127c478bd9Sstevel@tonic-gate hdl = s_malloc(sizeof (rcm_handle_t)); 18137c478bd9Sstevel@tonic-gate 18147c478bd9Sstevel@tonic-gate hdl->modname = module->name; 18157c478bd9Sstevel@tonic-gate hdl->pid = 0; 18167c478bd9Sstevel@tonic-gate hdl->lrcm_ops = &rcm_ops; /* for callback into daemon directly */ 18177c478bd9Sstevel@tonic-gate hdl->module = module; 18187c478bd9Sstevel@tonic-gate 18197c478bd9Sstevel@tonic-gate return (hdl); 18207c478bd9Sstevel@tonic-gate } 18217c478bd9Sstevel@tonic-gate 18227c478bd9Sstevel@tonic-gate /* 18237c478bd9Sstevel@tonic-gate * Free rcm_handle_t 18247c478bd9Sstevel@tonic-gate */ 18257c478bd9Sstevel@tonic-gate static void 18267c478bd9Sstevel@tonic-gate rcm_handle_free(rcm_handle_t *handle) 18277c478bd9Sstevel@tonic-gate { 18287c478bd9Sstevel@tonic-gate free(handle); 18297c478bd9Sstevel@tonic-gate } 18307c478bd9Sstevel@tonic-gate 18317c478bd9Sstevel@tonic-gate /* 18327c478bd9Sstevel@tonic-gate * help function that exit on memory outage 18337c478bd9Sstevel@tonic-gate */ 18347c478bd9Sstevel@tonic-gate void * 18357c478bd9Sstevel@tonic-gate s_malloc(size_t size) 18367c478bd9Sstevel@tonic-gate { 18377c478bd9Sstevel@tonic-gate void *buf = malloc(size); 18387c478bd9Sstevel@tonic-gate 18397c478bd9Sstevel@tonic-gate if (buf == NULL) { 18407c478bd9Sstevel@tonic-gate rcmd_exit(ENOMEM); 18417c478bd9Sstevel@tonic-gate } 18427c478bd9Sstevel@tonic-gate return (buf); 18437c478bd9Sstevel@tonic-gate } 18447c478bd9Sstevel@tonic-gate 18457c478bd9Sstevel@tonic-gate void * 18467c478bd9Sstevel@tonic-gate s_calloc(int n, size_t size) 18477c478bd9Sstevel@tonic-gate { 18487c478bd9Sstevel@tonic-gate void *buf = calloc(n, size); 18497c478bd9Sstevel@tonic-gate 18507c478bd9Sstevel@tonic-gate if (buf == NULL) { 18517c478bd9Sstevel@tonic-gate rcmd_exit(ENOMEM); 18527c478bd9Sstevel@tonic-gate } 18537c478bd9Sstevel@tonic-gate return (buf); 18547c478bd9Sstevel@tonic-gate } 18557c478bd9Sstevel@tonic-gate 18567c478bd9Sstevel@tonic-gate void * 18577c478bd9Sstevel@tonic-gate s_realloc(void *ptr, size_t size) 18587c478bd9Sstevel@tonic-gate { 18597c478bd9Sstevel@tonic-gate void *new = realloc(ptr, size); 18607c478bd9Sstevel@tonic-gate 18617c478bd9Sstevel@tonic-gate if (new == NULL) { 18627c478bd9Sstevel@tonic-gate rcmd_exit(ENOMEM); 18637c478bd9Sstevel@tonic-gate } 18647c478bd9Sstevel@tonic-gate return (new); 18657c478bd9Sstevel@tonic-gate } 18667c478bd9Sstevel@tonic-gate 18677c478bd9Sstevel@tonic-gate char * 18687c478bd9Sstevel@tonic-gate s_strdup(const char *str) 18697c478bd9Sstevel@tonic-gate { 18707c478bd9Sstevel@tonic-gate char *buf = strdup(str); 18717c478bd9Sstevel@tonic-gate 18727c478bd9Sstevel@tonic-gate if (buf == NULL) { 18737c478bd9Sstevel@tonic-gate rcmd_exit(ENOMEM); 18747c478bd9Sstevel@tonic-gate } 18757c478bd9Sstevel@tonic-gate return (buf); 18767c478bd9Sstevel@tonic-gate } 18777c478bd9Sstevel@tonic-gate 18787c478bd9Sstevel@tonic-gate /* 18797c478bd9Sstevel@tonic-gate * Convert a version 1 ops vector to current ops vector 18807c478bd9Sstevel@tonic-gate * Fields missing in version 1 are set to NULL. 18817c478bd9Sstevel@tonic-gate */ 18827c478bd9Sstevel@tonic-gate static struct rcm_mod_ops * 18837c478bd9Sstevel@tonic-gate modops_from_v1(void *ops_v1) 18847c478bd9Sstevel@tonic-gate { 18857c478bd9Sstevel@tonic-gate struct rcm_mod_ops *ops; 18867c478bd9Sstevel@tonic-gate 18877c478bd9Sstevel@tonic-gate ops = s_calloc(1, sizeof (struct rcm_mod_ops)); 18887c478bd9Sstevel@tonic-gate bcopy(ops_v1, ops, sizeof (struct rcm_mod_ops_v1)); 18897c478bd9Sstevel@tonic-gate return (ops); 18907c478bd9Sstevel@tonic-gate } 18917c478bd9Sstevel@tonic-gate 18927c478bd9Sstevel@tonic-gate /* call a module's getinfo routine; detects v1 ops and adjusts the call */ 18937c478bd9Sstevel@tonic-gate static int 18947c478bd9Sstevel@tonic-gate call_getinfo(struct rcm_mod_ops *ops, rcm_handle_t *hdl, char *alias, id_t pid, 18957c478bd9Sstevel@tonic-gate uint_t flag, char **info, char **error, nvlist_t *client_props, 18967c478bd9Sstevel@tonic-gate rcm_info_t **infop) 18977c478bd9Sstevel@tonic-gate { 18987c478bd9Sstevel@tonic-gate int rval; 18997c478bd9Sstevel@tonic-gate struct rcm_mod_ops_v1 *v1_ops; 19007c478bd9Sstevel@tonic-gate 19017c478bd9Sstevel@tonic-gate if (ops->version == RCM_MOD_OPS_V1) { 19027c478bd9Sstevel@tonic-gate v1_ops = (struct rcm_mod_ops_v1 *)ops; 19037c478bd9Sstevel@tonic-gate rval = v1_ops->rcmop_get_info(hdl, alias, pid, flag, info, 19047c478bd9Sstevel@tonic-gate infop); 19057c478bd9Sstevel@tonic-gate if (rval != RCM_SUCCESS && *info != NULL) 19067c478bd9Sstevel@tonic-gate *error = strdup(*info); 19077c478bd9Sstevel@tonic-gate return (rval); 19087c478bd9Sstevel@tonic-gate } else { 19097c478bd9Sstevel@tonic-gate return (ops->rcmop_get_info(hdl, alias, pid, flag, info, error, 19107c478bd9Sstevel@tonic-gate client_props, infop)); 19117c478bd9Sstevel@tonic-gate } 19127c478bd9Sstevel@tonic-gate } 19137c478bd9Sstevel@tonic-gate 19147c478bd9Sstevel@tonic-gate void 19157c478bd9Sstevel@tonic-gate rcm_init_queue(rcm_queue_t *head) 19167c478bd9Sstevel@tonic-gate { 19177c478bd9Sstevel@tonic-gate head->next = head->prev = head; 19187c478bd9Sstevel@tonic-gate } 19197c478bd9Sstevel@tonic-gate 19207c478bd9Sstevel@tonic-gate void 19217c478bd9Sstevel@tonic-gate rcm_enqueue_head(rcm_queue_t *head, rcm_queue_t *element) 19227c478bd9Sstevel@tonic-gate { 19237c478bd9Sstevel@tonic-gate rcm_enqueue(head, element); 19247c478bd9Sstevel@tonic-gate } 19257c478bd9Sstevel@tonic-gate 19267c478bd9Sstevel@tonic-gate void 19277c478bd9Sstevel@tonic-gate rcm_enqueue_tail(rcm_queue_t *head, rcm_queue_t *element) 19287c478bd9Sstevel@tonic-gate { 19297c478bd9Sstevel@tonic-gate rcm_enqueue(head->prev, element); 19307c478bd9Sstevel@tonic-gate } 19317c478bd9Sstevel@tonic-gate 19327c478bd9Sstevel@tonic-gate void 19337c478bd9Sstevel@tonic-gate rcm_enqueue(rcm_queue_t *list_element, rcm_queue_t *element) 19347c478bd9Sstevel@tonic-gate { 19357c478bd9Sstevel@tonic-gate element->next = list_element->next; 19367c478bd9Sstevel@tonic-gate element->prev = list_element; 19377c478bd9Sstevel@tonic-gate element->next->prev = element; 19387c478bd9Sstevel@tonic-gate list_element->next = element; 19397c478bd9Sstevel@tonic-gate } 19407c478bd9Sstevel@tonic-gate 19417c478bd9Sstevel@tonic-gate rcm_queue_t * 19427c478bd9Sstevel@tonic-gate rcm_dequeue_head(rcm_queue_t *head) 19437c478bd9Sstevel@tonic-gate { 19447c478bd9Sstevel@tonic-gate rcm_queue_t *element = head->next; 19457c478bd9Sstevel@tonic-gate rcm_dequeue(element); 19467c478bd9Sstevel@tonic-gate return (element); 19477c478bd9Sstevel@tonic-gate } 19487c478bd9Sstevel@tonic-gate 19497c478bd9Sstevel@tonic-gate rcm_queue_t * 19507c478bd9Sstevel@tonic-gate rcm_dequeue_tail(rcm_queue_t *head) 19517c478bd9Sstevel@tonic-gate { 19527c478bd9Sstevel@tonic-gate rcm_queue_t *element = head->prev; 19537c478bd9Sstevel@tonic-gate rcm_dequeue(element); 19547c478bd9Sstevel@tonic-gate return (element); 19557c478bd9Sstevel@tonic-gate } 19567c478bd9Sstevel@tonic-gate 19577c478bd9Sstevel@tonic-gate void 19587c478bd9Sstevel@tonic-gate rcm_dequeue(rcm_queue_t *element) 19597c478bd9Sstevel@tonic-gate { 19607c478bd9Sstevel@tonic-gate element->prev->next = element->next; 19617c478bd9Sstevel@tonic-gate element->next->prev = element->prev; 19627c478bd9Sstevel@tonic-gate element->next = element->prev = NULL; 19637c478bd9Sstevel@tonic-gate } 1964