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 *
resolve_name(char * alias)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
rsrc_get_type(const char * resolved_name)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
module_detach(module_t * module)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
module_attach(module_t * module)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 *
module_init(module_t * module)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 *
module_info(module_t * module)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
module_fini(module_t * module)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
module_unload(module_t * module)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 *
module_load(char * modname)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 *
cli_module_hold(char * modname)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
cli_module_rele(module_t * module)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
add_busy_rsrc_to_list(char * alias,pid_t pid,int state,int seq_num,char * modname,const char * infostr,const char * errstr,nvlist_t * client_props,rcm_info_t ** list)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 *
rsrc_client_alloc(char * alias,char * modname,pid_t pid,uint_t flag)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 *
rsrc_client_find(char * modname,pid_t pid,client_t ** list)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
rsrc_client_add(client_t * client,client_t ** list)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
rsrc_client_remove(client_t * client,client_t ** list)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
rsrc_clients_free(client_t * list)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
rsrc_client_action(client_t * client,int cmd,void * arg)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
rsrc_client_action_list(client_t * list,int cmd,void * arg)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 *
rn_alloc(char * name,int type)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
rn_free(rsrc_node_t * node)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 *
rn_get_sibling(rsrc_node_t * node)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 *
rn_get_child(rsrc_node_t * node)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 *
rn_find_child(rsrc_node_t * parent,char * childname,int flag,int type)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
pn_preprocess(char * pathname,int type)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 *
pn_getnextcomp(char * pathname,char ** lasts)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
rsrc_node_find(char * rsrcname,int flag,rsrc_node_t ** nodep)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
rsrc_node_add_user(rsrc_node_t * node,char * alias,char * modname,pid_t pid,uint_t flag)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
rsrc_node_remove_user(rsrc_node_t * node,char * modname,pid_t pid,uint_t flag)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
walk_one_node(struct rn_stack * sp,void * arg,int (* node_callback)(rsrc_node_t *,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
rsrc_walk(rsrc_node_t * root,void * arg,int (* node_callback)(rsrc_node_t *,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
node_action(rsrc_node_t * node,void * arg)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
rsrc_tree_action(rsrc_node_t * root,int cmd,tree_walk_arg_t * arg)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
rsrc_usage_info(char ** rsrcnames,uint_t flag,int seq_num,rcm_info_t ** info)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 *
rsrc_mod_info()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
rcmd_db_init()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
rcmd_db_sync()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
proc_exist(pid_t pid)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
clean_client_list(client_t ** listp)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
clean_node(rsrc_node_t * node,void * arg)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
clean_rsrc_tree()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
db_clean()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
rcmd_db_clean()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
print_node(rsrc_node_t * node,void * arg)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
rcmd_db_print()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 *
rcm_handle_alloc(module_t * module)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
rcm_handle_free(rcm_handle_t * handle)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 *
s_malloc(size_t size)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 *
s_calloc(int n,size_t size)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 *
s_realloc(void * ptr,size_t size)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 *
s_strdup(const char * str)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 *
modops_from_v1(void * ops_v1)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
call_getinfo(struct rcm_mod_ops * ops,rcm_handle_t * hdl,char * alias,id_t pid,uint_t flag,char ** info,char ** error,nvlist_t * client_props,rcm_info_t ** infop)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
rcm_init_queue(rcm_queue_t * head)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
rcm_enqueue_head(rcm_queue_t * head,rcm_queue_t * element)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
rcm_enqueue_tail(rcm_queue_t * head,rcm_queue_t * element)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
rcm_enqueue(rcm_queue_t * list_element,rcm_queue_t * element)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 *
rcm_dequeue_head(rcm_queue_t * head)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 *
rcm_dequeue_tail(rcm_queue_t * head)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
rcm_dequeue(rcm_queue_t * element)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