10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*4845Svikram * Common Development and Distribution License (the "License").
6*4845Svikram * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate *
21*4845Svikram * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
220Sstevel@tonic-gate * Use is subject to license terms.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
260Sstevel@tonic-gate
270Sstevel@tonic-gate #include "rcm_impl.h"
280Sstevel@tonic-gate #include "rcm_module.h"
290Sstevel@tonic-gate
300Sstevel@tonic-gate /*
310Sstevel@tonic-gate * Short-circuits unloading of modules with no registrations, so that
320Sstevel@tonic-gate * they are present during the next db_sync cycle.
330Sstevel@tonic-gate */
340Sstevel@tonic-gate #define MOD_REFCNT_INIT 2
350Sstevel@tonic-gate
360Sstevel@tonic-gate int need_cleanup; /* flag indicating if clean up is needed */
370Sstevel@tonic-gate
380Sstevel@tonic-gate static mutex_t mod_lock; /* protects module list */
390Sstevel@tonic-gate static module_t *module_head; /* linked list of modules */
400Sstevel@tonic-gate static rsrc_node_t *rsrc_root; /* root of all resources */
410Sstevel@tonic-gate
420Sstevel@tonic-gate /*
430Sstevel@tonic-gate * Misc help routines
440Sstevel@tonic-gate */
450Sstevel@tonic-gate static void rcmd_db_print();
460Sstevel@tonic-gate static void rcm_handle_free(rcm_handle_t *);
470Sstevel@tonic-gate static rcm_handle_t *rcm_handle_alloc(module_t *);
480Sstevel@tonic-gate static void rsrc_clients_free(client_t *);
490Sstevel@tonic-gate static struct rcm_mod_ops *modops_from_v1(void *);
500Sstevel@tonic-gate static int call_getinfo(struct rcm_mod_ops *, rcm_handle_t *, char *, id_t,
510Sstevel@tonic-gate uint_t, char **, char **, nvlist_t *, rcm_info_t **);
520Sstevel@tonic-gate static int node_action(rsrc_node_t *, void *);
530Sstevel@tonic-gate
540Sstevel@tonic-gate extern void start_polling_thread();
550Sstevel@tonic-gate
560Sstevel@tonic-gate /*
570Sstevel@tonic-gate * translate /dev name to a /devices path
580Sstevel@tonic-gate *
590Sstevel@tonic-gate * N.B. This routine can be enhanced to understand network names
600Sstevel@tonic-gate * and friendly names in the future.
610Sstevel@tonic-gate */
620Sstevel@tonic-gate char *
resolve_name(char * alias)630Sstevel@tonic-gate resolve_name(char *alias)
640Sstevel@tonic-gate {
650Sstevel@tonic-gate char *tmp;
660Sstevel@tonic-gate const char *dev = "/dev/";
670Sstevel@tonic-gate
680Sstevel@tonic-gate if (strlen(alias) == 0)
690Sstevel@tonic-gate return (NULL);
700Sstevel@tonic-gate
710Sstevel@tonic-gate if (strncmp(alias, dev, strlen(dev)) == 0) {
720Sstevel@tonic-gate /*
730Sstevel@tonic-gate * Treat /dev/... as a symbolic link
740Sstevel@tonic-gate */
750Sstevel@tonic-gate tmp = s_malloc(PATH_MAX);
760Sstevel@tonic-gate if (realpath(alias, tmp) != NULL) {
770Sstevel@tonic-gate return (tmp);
780Sstevel@tonic-gate } else {
790Sstevel@tonic-gate free(tmp);
800Sstevel@tonic-gate }
810Sstevel@tonic-gate /* Fail to resolve /dev/ name, use the name as is */
820Sstevel@tonic-gate }
830Sstevel@tonic-gate
840Sstevel@tonic-gate return (s_strdup(alias));
850Sstevel@tonic-gate }
860Sstevel@tonic-gate
870Sstevel@tonic-gate /*
880Sstevel@tonic-gate * Figure out resource type based on "resolved" name
890Sstevel@tonic-gate *
900Sstevel@tonic-gate * N.B. This routine does not figure out file system mount points.
910Sstevel@tonic-gate * This is determined at runtime when filesys module register
920Sstevel@tonic-gate * with RCM_FILESYS flag.
930Sstevel@tonic-gate */
940Sstevel@tonic-gate int
rsrc_get_type(const char * resolved_name)950Sstevel@tonic-gate rsrc_get_type(const char *resolved_name)
960Sstevel@tonic-gate {
970Sstevel@tonic-gate if (resolved_name[0] != '/')
980Sstevel@tonic-gate return (RSRC_TYPE_ABSTRACT);
990Sstevel@tonic-gate
1000Sstevel@tonic-gate if (strncmp("/devices/", resolved_name, 9) == 0)
1010Sstevel@tonic-gate return (RSRC_TYPE_DEVICE);
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate return (RSRC_TYPE_NORMAL);
1040Sstevel@tonic-gate }
1050Sstevel@tonic-gate
1060Sstevel@tonic-gate /*
1070Sstevel@tonic-gate * Module operations:
1080Sstevel@tonic-gate * module_load, module_unload, module_info, module_attach, module_detach,
1090Sstevel@tonic-gate * cli_module_hold, cli_module_rele
1100Sstevel@tonic-gate */
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate #ifdef ENABLE_MODULE_DETACH
1130Sstevel@tonic-gate /*
1140Sstevel@tonic-gate * call unregister() entry point to allow module to unregister for
1150Sstevel@tonic-gate * resources without getting confused.
1160Sstevel@tonic-gate */
1170Sstevel@tonic-gate static void
module_detach(module_t * module)1180Sstevel@tonic-gate module_detach(module_t *module)
1190Sstevel@tonic-gate {
1200Sstevel@tonic-gate struct rcm_mod_ops *ops = module->modops;
1210Sstevel@tonic-gate
1220Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, "module_detach(name=%s)\n", module->name);
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate ops->rcmop_unregister(module->rcmhandle);
1250Sstevel@tonic-gate }
1260Sstevel@tonic-gate #endif /* ENABLE_MODULE_DETACH */
1270Sstevel@tonic-gate
1280Sstevel@tonic-gate /*
1290Sstevel@tonic-gate * call register() entry point to allow module to register for resources
1300Sstevel@tonic-gate */
1310Sstevel@tonic-gate static void
module_attach(module_t * module)1320Sstevel@tonic-gate module_attach(module_t *module)
1330Sstevel@tonic-gate {
1340Sstevel@tonic-gate struct rcm_mod_ops *ops = module->modops;
1350Sstevel@tonic-gate
1360Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, "module_attach(name=%s)\n", module->name);
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate if (ops->rcmop_register(module->rcmhandle) != RCM_SUCCESS) {
1390Sstevel@tonic-gate rcm_log_message(RCM_WARNING,
1400Sstevel@tonic-gate gettext("module %s register() failed\n"), module->name);
1410Sstevel@tonic-gate }
1420Sstevel@tonic-gate }
1430Sstevel@tonic-gate
1440Sstevel@tonic-gate struct rcm_mod_ops *
module_init(module_t * module)1450Sstevel@tonic-gate module_init(module_t *module)
1460Sstevel@tonic-gate {
1470Sstevel@tonic-gate if (module->dlhandle)
1480Sstevel@tonic-gate /* rcm module */
1490Sstevel@tonic-gate return (module->init());
1500Sstevel@tonic-gate else
1510Sstevel@tonic-gate /* rcm script */
1520Sstevel@tonic-gate return (script_init(module));
1530Sstevel@tonic-gate }
1540Sstevel@tonic-gate
1550Sstevel@tonic-gate /*
1560Sstevel@tonic-gate * call rmc_mod_info() entry of module
1570Sstevel@tonic-gate */
1580Sstevel@tonic-gate static const char *
module_info(module_t * module)1590Sstevel@tonic-gate module_info(module_t *module)
1600Sstevel@tonic-gate {
1610Sstevel@tonic-gate if (module->dlhandle)
1620Sstevel@tonic-gate /* rcm module */
1630Sstevel@tonic-gate return (module->info());
1640Sstevel@tonic-gate else
1650Sstevel@tonic-gate /* rcm script */
1660Sstevel@tonic-gate return (script_info(module));
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate int
module_fini(module_t * module)1700Sstevel@tonic-gate module_fini(module_t *module)
1710Sstevel@tonic-gate {
1720Sstevel@tonic-gate if (module->dlhandle)
1730Sstevel@tonic-gate /* rcm module */
1740Sstevel@tonic-gate return (module->fini());
1750Sstevel@tonic-gate else
1760Sstevel@tonic-gate /* rcm script */
1770Sstevel@tonic-gate return (script_fini(module));
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate
1800Sstevel@tonic-gate /*
1810Sstevel@tonic-gate * call rmc_mod_fini() entry of module, dlclose module, and free memory
1820Sstevel@tonic-gate */
1830Sstevel@tonic-gate static void
module_unload(module_t * module)1840Sstevel@tonic-gate module_unload(module_t *module)
1850Sstevel@tonic-gate {
1860Sstevel@tonic-gate int version = module->modops->version;
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "module_unload(name=%s)\n", module->name);
1890Sstevel@tonic-gate
1900Sstevel@tonic-gate (void) module_fini(module);
1910Sstevel@tonic-gate
1920Sstevel@tonic-gate rcm_handle_free(module->rcmhandle);
1930Sstevel@tonic-gate free(module->name);
1940Sstevel@tonic-gate
1950Sstevel@tonic-gate switch (version) {
1960Sstevel@tonic-gate case RCM_MOD_OPS_V1:
1970Sstevel@tonic-gate /*
1980Sstevel@tonic-gate * Free memory associated with converted ops vector
1990Sstevel@tonic-gate */
2000Sstevel@tonic-gate free(module->modops);
2010Sstevel@tonic-gate break;
2020Sstevel@tonic-gate
2030Sstevel@tonic-gate case RCM_MOD_OPS_VERSION:
2040Sstevel@tonic-gate default:
2050Sstevel@tonic-gate break;
2060Sstevel@tonic-gate }
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate if (module->dlhandle)
2090Sstevel@tonic-gate rcm_module_close(module->dlhandle);
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate free(module);
2120Sstevel@tonic-gate }
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate /*
2150Sstevel@tonic-gate * Locate the module, execute rcm_mod_init() and check ops vector version
2160Sstevel@tonic-gate */
2170Sstevel@tonic-gate static module_t *
module_load(char * modname)2180Sstevel@tonic-gate module_load(char *modname)
2190Sstevel@tonic-gate {
2200Sstevel@tonic-gate module_t *module;
2210Sstevel@tonic-gate
2220Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "module_load(name=%s)\n", modname);
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate /*
2250Sstevel@tonic-gate * dlopen the module
2260Sstevel@tonic-gate */
2270Sstevel@tonic-gate module = s_calloc(1, sizeof (*module));
2280Sstevel@tonic-gate module->name = s_strdup(modname);
2290Sstevel@tonic-gate module->modops = NULL;
2300Sstevel@tonic-gate rcm_init_queue(&module->client_q);
2310Sstevel@tonic-gate
2320Sstevel@tonic-gate if (rcm_is_script(modname) == 0) {
2330Sstevel@tonic-gate /* rcm module */
2340Sstevel@tonic-gate module->dlhandle = rcm_module_open(modname);
2350Sstevel@tonic-gate
2360Sstevel@tonic-gate if (module->dlhandle == NULL) {
2370Sstevel@tonic-gate rcm_log_message(RCM_NOTICE,
2380Sstevel@tonic-gate gettext("cannot open module %s\n"), modname);
2390Sstevel@tonic-gate goto fail;
2400Sstevel@tonic-gate }
2410Sstevel@tonic-gate
2420Sstevel@tonic-gate /*
2430Sstevel@tonic-gate * dlsym rcm_mod_init/fini/info() entry points
2440Sstevel@tonic-gate */
2450Sstevel@tonic-gate module->init = (struct rcm_mod_ops *(*)())dlsym(
2460Sstevel@tonic-gate module->dlhandle, "rcm_mod_init");
2470Sstevel@tonic-gate module->fini = (int (*)())dlsym(
2480Sstevel@tonic-gate module->dlhandle, "rcm_mod_fini");
2490Sstevel@tonic-gate module->info = (const char *(*)())dlsym(module->dlhandle,
2500Sstevel@tonic-gate "rcm_mod_info");
2510Sstevel@tonic-gate if (module->init == NULL || module->fini == NULL ||
2520Sstevel@tonic-gate module->info == NULL) {
2530Sstevel@tonic-gate rcm_log_message(RCM_ERROR,
2540Sstevel@tonic-gate gettext("missing entries in module %s\n"), modname);
2550Sstevel@tonic-gate goto fail;
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate } else {
2590Sstevel@tonic-gate /* rcm script */
2600Sstevel@tonic-gate module->dlhandle = NULL;
2610Sstevel@tonic-gate module->init = (struct rcm_mod_ops *(*)()) NULL;
2620Sstevel@tonic-gate module->fini = (int (*)()) NULL;
2630Sstevel@tonic-gate module->info = (const char *(*)()) NULL;
2640Sstevel@tonic-gate }
2650Sstevel@tonic-gate
2660Sstevel@tonic-gate if ((module->modops = module_init(module)) == NULL) {
2670Sstevel@tonic-gate if (module->dlhandle)
2680Sstevel@tonic-gate rcm_log_message(RCM_ERROR,
2690Sstevel@tonic-gate gettext("cannot init module %s\n"), modname);
2700Sstevel@tonic-gate goto fail;
2710Sstevel@tonic-gate }
2720Sstevel@tonic-gate
2730Sstevel@tonic-gate /*
2740Sstevel@tonic-gate * Check ops vector version
2750Sstevel@tonic-gate */
2760Sstevel@tonic-gate switch (module->modops->version) {
2770Sstevel@tonic-gate case RCM_MOD_OPS_V1:
2780Sstevel@tonic-gate module->modops = modops_from_v1((void *)module->modops);
2790Sstevel@tonic-gate break;
2800Sstevel@tonic-gate
2810Sstevel@tonic-gate case RCM_MOD_OPS_VERSION:
2820Sstevel@tonic-gate break;
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate default:
2850Sstevel@tonic-gate rcm_log_message(RCM_ERROR,
2860Sstevel@tonic-gate gettext("module %s rejected: version %d not supported\n"),
2870Sstevel@tonic-gate modname, module->modops->version);
2880Sstevel@tonic-gate (void) module_fini(module);
2890Sstevel@tonic-gate goto fail;
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate /*
2930Sstevel@tonic-gate * Make sure all fields are set
2940Sstevel@tonic-gate */
2950Sstevel@tonic-gate if ((module->modops->rcmop_register == NULL) ||
2960Sstevel@tonic-gate (module->modops->rcmop_unregister == NULL) ||
2970Sstevel@tonic-gate (module->modops->rcmop_get_info == NULL) ||
2980Sstevel@tonic-gate (module->modops->rcmop_request_suspend == NULL) ||
2990Sstevel@tonic-gate (module->modops->rcmop_notify_resume == NULL) ||
3000Sstevel@tonic-gate (module->modops->rcmop_request_offline == NULL) ||
3010Sstevel@tonic-gate (module->modops->rcmop_notify_online == NULL) ||
3020Sstevel@tonic-gate (module->modops->rcmop_notify_remove == NULL)) {
3030Sstevel@tonic-gate rcm_log_message(RCM_ERROR,
3040Sstevel@tonic-gate gettext("module %s rejected: has NULL ops fields\n"),
3050Sstevel@tonic-gate modname);
3060Sstevel@tonic-gate (void) module_fini(module);
3070Sstevel@tonic-gate goto fail;
3080Sstevel@tonic-gate }
3090Sstevel@tonic-gate
3100Sstevel@tonic-gate module->rcmhandle = rcm_handle_alloc(module);
3110Sstevel@tonic-gate return (module);
3120Sstevel@tonic-gate
3130Sstevel@tonic-gate fail:
3140Sstevel@tonic-gate if (module->modops && module->modops->version == RCM_MOD_OPS_V1)
3150Sstevel@tonic-gate free(module->modops);
3160Sstevel@tonic-gate
3170Sstevel@tonic-gate if (module->dlhandle)
3180Sstevel@tonic-gate rcm_module_close(module->dlhandle);
3190Sstevel@tonic-gate
3200Sstevel@tonic-gate free(module->name);
3210Sstevel@tonic-gate free(module);
3220Sstevel@tonic-gate return (NULL);
3230Sstevel@tonic-gate }
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate /*
3260Sstevel@tonic-gate * add one to module hold count. load the module if not loaded
3270Sstevel@tonic-gate */
3280Sstevel@tonic-gate static module_t *
cli_module_hold(char * modname)3290Sstevel@tonic-gate cli_module_hold(char *modname)
3300Sstevel@tonic-gate {
3310Sstevel@tonic-gate module_t *module;
3320Sstevel@tonic-gate
3330Sstevel@tonic-gate rcm_log_message(RCM_TRACE3, "cli_module_hold(%s)\n", modname);
3340Sstevel@tonic-gate
3350Sstevel@tonic-gate (void) mutex_lock(&mod_lock);
3360Sstevel@tonic-gate module = module_head;
3370Sstevel@tonic-gate while (module) {
3380Sstevel@tonic-gate if (strcmp(module->name, modname) == 0) {
3390Sstevel@tonic-gate break;
3400Sstevel@tonic-gate }
3410Sstevel@tonic-gate module = module->next;
3420Sstevel@tonic-gate }
3430Sstevel@tonic-gate
3440Sstevel@tonic-gate if (module) {
3450Sstevel@tonic-gate module->ref_count++;
3460Sstevel@tonic-gate (void) mutex_unlock(&mod_lock);
3470Sstevel@tonic-gate return (module);
3480Sstevel@tonic-gate }
3490Sstevel@tonic-gate
3500Sstevel@tonic-gate /*
3510Sstevel@tonic-gate * Module not found, attempt to load it
3520Sstevel@tonic-gate */
3530Sstevel@tonic-gate if ((module = module_load(modname)) == NULL) {
3540Sstevel@tonic-gate (void) mutex_unlock(&mod_lock);
3550Sstevel@tonic-gate return (NULL);
3560Sstevel@tonic-gate }
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate /*
3590Sstevel@tonic-gate * Hold module and link module into module list
3600Sstevel@tonic-gate */
3610Sstevel@tonic-gate module->ref_count = MOD_REFCNT_INIT;
3620Sstevel@tonic-gate module->next = module_head;
3630Sstevel@tonic-gate module_head = module;
3640Sstevel@tonic-gate
3650Sstevel@tonic-gate (void) mutex_unlock(&mod_lock);
3660Sstevel@tonic-gate
3670Sstevel@tonic-gate return (module);
3680Sstevel@tonic-gate }
3690Sstevel@tonic-gate
3700Sstevel@tonic-gate /*
3710Sstevel@tonic-gate * decrement module hold count. Unload it if no reference
3720Sstevel@tonic-gate */
3730Sstevel@tonic-gate static void
cli_module_rele(module_t * module)3740Sstevel@tonic-gate cli_module_rele(module_t *module)
3750Sstevel@tonic-gate {
3760Sstevel@tonic-gate module_t *curr = module_head, *prev = NULL;
3770Sstevel@tonic-gate
3780Sstevel@tonic-gate rcm_log_message(RCM_TRACE3, "cli_module_rele(name=%s)\n", module->name);
3790Sstevel@tonic-gate
3800Sstevel@tonic-gate (void) mutex_lock(&mod_lock);
3810Sstevel@tonic-gate if (--(module->ref_count) != 0) {
3820Sstevel@tonic-gate (void) mutex_unlock(&mod_lock);
3830Sstevel@tonic-gate return;
3840Sstevel@tonic-gate }
3850Sstevel@tonic-gate
3860Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, "unloading module %s\n", module->name);
3870Sstevel@tonic-gate
3880Sstevel@tonic-gate /*
3890Sstevel@tonic-gate * Unlink the module from list
3900Sstevel@tonic-gate */
3910Sstevel@tonic-gate while (curr && (curr != module)) {
3920Sstevel@tonic-gate prev = curr;
3930Sstevel@tonic-gate curr = curr->next;
3940Sstevel@tonic-gate }
3950Sstevel@tonic-gate if (curr == NULL) {
3960Sstevel@tonic-gate rcm_log_message(RCM_ERROR,
3970Sstevel@tonic-gate gettext("Unexpected error: module %s not found.\n"),
3980Sstevel@tonic-gate module->name);
3990Sstevel@tonic-gate } else if (prev == NULL) {
4000Sstevel@tonic-gate module_head = curr->next;
4010Sstevel@tonic-gate } else {
4020Sstevel@tonic-gate prev->next = curr->next;
4030Sstevel@tonic-gate }
4040Sstevel@tonic-gate (void) mutex_unlock(&mod_lock);
4050Sstevel@tonic-gate
4060Sstevel@tonic-gate module_unload(module);
4070Sstevel@tonic-gate }
4080Sstevel@tonic-gate
4090Sstevel@tonic-gate /*
4100Sstevel@tonic-gate * Gather usage info be passed back to requester. Discard info if user does
4110Sstevel@tonic-gate * not care (list == NULL).
4120Sstevel@tonic-gate */
4130Sstevel@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)4140Sstevel@tonic-gate add_busy_rsrc_to_list(char *alias, pid_t pid, int state, int seq_num,
4150Sstevel@tonic-gate char *modname, const char *infostr, const char *errstr,
4160Sstevel@tonic-gate nvlist_t *client_props, rcm_info_t **list)
4170Sstevel@tonic-gate {
4180Sstevel@tonic-gate rcm_info_t *info;
4190Sstevel@tonic-gate rcm_info_t *tmp;
4200Sstevel@tonic-gate char *buf = NULL;
4210Sstevel@tonic-gate size_t buflen = 0;
4220Sstevel@tonic-gate
4230Sstevel@tonic-gate if (list == NULL) {
4240Sstevel@tonic-gate return;
4250Sstevel@tonic-gate }
4260Sstevel@tonic-gate
4270Sstevel@tonic-gate info = s_calloc(1, sizeof (*info));
4280Sstevel@tonic-gate if (errno = nvlist_alloc(&(info->info), NV_UNIQUE_NAME, 0)) {
4290Sstevel@tonic-gate rcm_log_message(RCM_ERROR, "failed (nvlist_alloc=%s).\n",
4300Sstevel@tonic-gate strerror(errno));
4310Sstevel@tonic-gate rcmd_exit(errno);
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate /*LINTED*/
4350Sstevel@tonic-gate if ((errno = nvlist_add_string(info->info, RCM_RSRCNAME, alias)) ||
4360Sstevel@tonic-gate (errno = nvlist_add_int32(info->info, RCM_SEQ_NUM, seq_num)) ||
4370Sstevel@tonic-gate (errno = nvlist_add_int64(info->info, RCM_CLIENT_ID, pid)) ||
4380Sstevel@tonic-gate (errno = nvlist_add_int32(info->info, RCM_RSRCSTATE, state))) {
4390Sstevel@tonic-gate rcm_log_message(RCM_ERROR, "failed (nvlist_add=%s).\n",
4400Sstevel@tonic-gate strerror(errno));
4410Sstevel@tonic-gate rcmd_exit(errno);
4420Sstevel@tonic-gate }
4430Sstevel@tonic-gate
4440Sstevel@tonic-gate /*
4450Sstevel@tonic-gate * Daemon calls to add_busy_rsrc_to_list may pass in
4460Sstevel@tonic-gate * error/info. Add these through librcm interfaces.
4470Sstevel@tonic-gate */
4480Sstevel@tonic-gate if (errstr) {
4490Sstevel@tonic-gate rcm_log_message(RCM_TRACE3, "adding error string: %s\n",
4500Sstevel@tonic-gate errstr);
4510Sstevel@tonic-gate if (errno = nvlist_add_string(info->info, RCM_CLIENT_ERROR,
4520Sstevel@tonic-gate (char *)errstr)) {
4530Sstevel@tonic-gate rcm_log_message(RCM_ERROR, "failed (nvlist_add=%s).\n",
4540Sstevel@tonic-gate strerror(errno));
4550Sstevel@tonic-gate rcmd_exit(errno);
4560Sstevel@tonic-gate }
4570Sstevel@tonic-gate }
4580Sstevel@tonic-gate
4590Sstevel@tonic-gate if (infostr) {
4600Sstevel@tonic-gate if (errno = nvlist_add_string(info->info, RCM_CLIENT_INFO,
4610Sstevel@tonic-gate (char *)infostr)) {
4620Sstevel@tonic-gate rcm_log_message(RCM_ERROR, "failed (nvlist_add=%s).\n",
4630Sstevel@tonic-gate strerror(errno));
4640Sstevel@tonic-gate rcmd_exit(errno);
4650Sstevel@tonic-gate }
4660Sstevel@tonic-gate }
4670Sstevel@tonic-gate
4680Sstevel@tonic-gate if (modname) {
4690Sstevel@tonic-gate if (errno = nvlist_add_string(info->info, RCM_CLIENT_MODNAME,
4700Sstevel@tonic-gate modname)) {
4710Sstevel@tonic-gate rcm_log_message(RCM_ERROR, "failed (nvlist_add=%s).\n",
4720Sstevel@tonic-gate strerror(errno));
4730Sstevel@tonic-gate rcmd_exit(errno);
4740Sstevel@tonic-gate }
4750Sstevel@tonic-gate }
4760Sstevel@tonic-gate
4770Sstevel@tonic-gate if (client_props) {
4780Sstevel@tonic-gate if (errno = nvlist_pack(client_props, &buf, &buflen,
4790Sstevel@tonic-gate NV_ENCODE_NATIVE, 0)) {
4800Sstevel@tonic-gate rcm_log_message(RCM_ERROR, "failed (nvlist_pack=%s).\n",
4810Sstevel@tonic-gate strerror(errno));
4820Sstevel@tonic-gate rcmd_exit(errno);
4830Sstevel@tonic-gate }
4840Sstevel@tonic-gate if (errno = nvlist_add_byte_array(info->info,
4850Sstevel@tonic-gate RCM_CLIENT_PROPERTIES, (uchar_t *)buf, buflen)) {
4860Sstevel@tonic-gate rcm_log_message(RCM_ERROR, "failed (nvlist_add=%s).\n",
4870Sstevel@tonic-gate strerror(errno));
4880Sstevel@tonic-gate rcmd_exit(errno);
4890Sstevel@tonic-gate }
4900Sstevel@tonic-gate (void) free(buf);
4910Sstevel@tonic-gate }
4920Sstevel@tonic-gate
4930Sstevel@tonic-gate
4940Sstevel@tonic-gate /* link info at end of list */
4950Sstevel@tonic-gate if (*list) {
4960Sstevel@tonic-gate tmp = *list;
4970Sstevel@tonic-gate while (tmp->next)
4980Sstevel@tonic-gate tmp = tmp->next;
4990Sstevel@tonic-gate tmp->next = info;
5000Sstevel@tonic-gate } else {
5010Sstevel@tonic-gate *list = info;
5020Sstevel@tonic-gate }
5030Sstevel@tonic-gate }
5040Sstevel@tonic-gate
5050Sstevel@tonic-gate /*
5060Sstevel@tonic-gate * Resource client realted operations:
5070Sstevel@tonic-gate * rsrc_client_alloc, rsrc_client_find, rsrc_client_add,
5080Sstevel@tonic-gate * rsrc_client_remove, rsrc_client_action, rsrc_client_action_list
5090Sstevel@tonic-gate */
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate /* Allocate rsrc_client_t structure. Load module if necessary. */
5120Sstevel@tonic-gate /*ARGSUSED*/
5130Sstevel@tonic-gate static client_t *
rsrc_client_alloc(char * alias,char * modname,pid_t pid,uint_t flag)5140Sstevel@tonic-gate rsrc_client_alloc(char *alias, char *modname, pid_t pid, uint_t flag)
5150Sstevel@tonic-gate {
5160Sstevel@tonic-gate client_t *client;
5170Sstevel@tonic-gate module_t *mod;
5180Sstevel@tonic-gate
5190Sstevel@tonic-gate assert((alias != NULL) && (modname != NULL));
5200Sstevel@tonic-gate
5210Sstevel@tonic-gate rcm_log_message(RCM_TRACE4, "rsrc_client_alloc(%s, %s, %ld)\n",
5220Sstevel@tonic-gate alias, modname, pid);
5230Sstevel@tonic-gate
5240Sstevel@tonic-gate if ((mod = cli_module_hold(modname)) == NULL) {
5250Sstevel@tonic-gate return (NULL);
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate
5280Sstevel@tonic-gate client = s_calloc(1, sizeof (client_t));
5290Sstevel@tonic-gate client->module = mod;
5300Sstevel@tonic-gate client->pid = pid;
5310Sstevel@tonic-gate client->alias = s_strdup(alias);
5320Sstevel@tonic-gate client->prv_flags = 0;
5330Sstevel@tonic-gate client->state = RCM_STATE_ONLINE;
5340Sstevel@tonic-gate client->flag = flag;
5350Sstevel@tonic-gate
5360Sstevel@tonic-gate /* This queue is protected by rcm_req_lock */
5370Sstevel@tonic-gate rcm_enqueue_tail(&mod->client_q, &client->queue);
5380Sstevel@tonic-gate
5390Sstevel@tonic-gate return (client);
5400Sstevel@tonic-gate }
5410Sstevel@tonic-gate
5420Sstevel@tonic-gate /* Find client in list matching modname and pid */
5430Sstevel@tonic-gate client_t *
rsrc_client_find(char * modname,pid_t pid,client_t ** list)5440Sstevel@tonic-gate rsrc_client_find(char *modname, pid_t pid, client_t **list)
5450Sstevel@tonic-gate {
5460Sstevel@tonic-gate client_t *client = *list;
5470Sstevel@tonic-gate
5480Sstevel@tonic-gate rcm_log_message(RCM_TRACE4, "rsrc_client_find(%s, %ld, %p)\n",
5490Sstevel@tonic-gate modname, pid, (void *)list);
5500Sstevel@tonic-gate
5510Sstevel@tonic-gate while (client) {
5520Sstevel@tonic-gate if ((client->pid == pid) &&
5530Sstevel@tonic-gate strcmp(modname, client->module->name) == 0) {
5540Sstevel@tonic-gate break;
5550Sstevel@tonic-gate }
5560Sstevel@tonic-gate client = client->next;
5570Sstevel@tonic-gate }
5580Sstevel@tonic-gate return (client);
5590Sstevel@tonic-gate }
5600Sstevel@tonic-gate
5610Sstevel@tonic-gate /* Add a client to client list */
5620Sstevel@tonic-gate static void
rsrc_client_add(client_t * client,client_t ** list)5630Sstevel@tonic-gate rsrc_client_add(client_t *client, client_t **list)
5640Sstevel@tonic-gate {
5650Sstevel@tonic-gate rcm_log_message(RCM_TRACE4, "rsrc_client_add: %s, %s, %ld\n",
5660Sstevel@tonic-gate client->alias, client->module->name, client->pid);
5670Sstevel@tonic-gate
5680Sstevel@tonic-gate client->next = *list;
5690Sstevel@tonic-gate *list = client;
5700Sstevel@tonic-gate }
5710Sstevel@tonic-gate
5720Sstevel@tonic-gate /* Remove client from list and destroy it */
5730Sstevel@tonic-gate static void
rsrc_client_remove(client_t * client,client_t ** list)5740Sstevel@tonic-gate rsrc_client_remove(client_t *client, client_t **list)
5750Sstevel@tonic-gate {
5760Sstevel@tonic-gate client_t *tmp, *prev = NULL;
5770Sstevel@tonic-gate
5780Sstevel@tonic-gate rcm_log_message(RCM_TRACE4, "rsrc_client_remove: %s, %s, %ld\n",
5790Sstevel@tonic-gate client->alias, client->module->name, client->pid);
5800Sstevel@tonic-gate
5810Sstevel@tonic-gate tmp = *list;
5820Sstevel@tonic-gate while (tmp) {
5830Sstevel@tonic-gate if (client != tmp) {
5840Sstevel@tonic-gate prev = tmp;
5850Sstevel@tonic-gate tmp = tmp->next;
5860Sstevel@tonic-gate continue;
5870Sstevel@tonic-gate }
5880Sstevel@tonic-gate if (prev) {
5890Sstevel@tonic-gate prev->next = tmp->next;
5900Sstevel@tonic-gate } else {
5910Sstevel@tonic-gate *list = tmp->next;
5920Sstevel@tonic-gate }
5930Sstevel@tonic-gate tmp->next = NULL;
5940Sstevel@tonic-gate rsrc_clients_free(tmp);
5950Sstevel@tonic-gate return;
5960Sstevel@tonic-gate }
5970Sstevel@tonic-gate }
5980Sstevel@tonic-gate
5990Sstevel@tonic-gate /* Free a list of clients. Called from cleanup thread only */
6000Sstevel@tonic-gate static void
rsrc_clients_free(client_t * list)6010Sstevel@tonic-gate rsrc_clients_free(client_t *list)
6020Sstevel@tonic-gate {
6030Sstevel@tonic-gate client_t *client = list;
6040Sstevel@tonic-gate
6050Sstevel@tonic-gate while (client) {
6060Sstevel@tonic-gate
6070Sstevel@tonic-gate /*
6080Sstevel@tonic-gate * Note that the rcm daemon is single threaded while
6090Sstevel@tonic-gate * executing this routine. So there is no need to acquire
6100Sstevel@tonic-gate * rcm_req_lock here while dequeuing.
6110Sstevel@tonic-gate */
6120Sstevel@tonic-gate rcm_dequeue(&client->queue);
6130Sstevel@tonic-gate
6140Sstevel@tonic-gate if (client->module) {
6150Sstevel@tonic-gate cli_module_rele(client->module);
6160Sstevel@tonic-gate }
6170Sstevel@tonic-gate list = client->next;
6180Sstevel@tonic-gate if (client->alias) {
6190Sstevel@tonic-gate free(client->alias);
6200Sstevel@tonic-gate }
6210Sstevel@tonic-gate free(client);
6220Sstevel@tonic-gate client = list;
6230Sstevel@tonic-gate }
6240Sstevel@tonic-gate }
6250Sstevel@tonic-gate
6260Sstevel@tonic-gate /*
6270Sstevel@tonic-gate * Invoke a callback into a single client
6280Sstevel@tonic-gate * This is the core of rcm_mod_ops interface
6290Sstevel@tonic-gate */
6300Sstevel@tonic-gate static int
rsrc_client_action(client_t * client,int cmd,void * arg)6310Sstevel@tonic-gate rsrc_client_action(client_t *client, int cmd, void *arg)
6320Sstevel@tonic-gate {
6330Sstevel@tonic-gate int rval = RCM_SUCCESS;
6340Sstevel@tonic-gate char *dummy_error = NULL;
6350Sstevel@tonic-gate char *error = NULL;
6360Sstevel@tonic-gate char *info = NULL;
6370Sstevel@tonic-gate rcm_handle_t *hdl;
6380Sstevel@tonic-gate nvlist_t *client_props = NULL;
6390Sstevel@tonic-gate rcm_info_t *depend_info = NULL;
6400Sstevel@tonic-gate struct rcm_mod_ops *ops = client->module->modops;
6410Sstevel@tonic-gate tree_walk_arg_t *targ = (tree_walk_arg_t *)arg;
6420Sstevel@tonic-gate
6430Sstevel@tonic-gate rcm_log_message(RCM_TRACE4,
6440Sstevel@tonic-gate "rsrc_client_action: %s, %s, cmd=%d, flag=0x%x\n", client->alias,
6450Sstevel@tonic-gate client->module->name, cmd, targ->flag);
6460Sstevel@tonic-gate
6470Sstevel@tonic-gate /*
6480Sstevel@tonic-gate * Create a per-operation handle, increment seq_num by 1 so we will
6490Sstevel@tonic-gate * know if a module uses this handle to callback into rcm_daemon.
6500Sstevel@tonic-gate */
6510Sstevel@tonic-gate hdl = rcm_handle_alloc(client->module);
6520Sstevel@tonic-gate hdl->seq_num = targ->seq_num + 1;
6530Sstevel@tonic-gate
6540Sstevel@tonic-gate /*
6550Sstevel@tonic-gate * Filter out operations for which the client didn't register.
6560Sstevel@tonic-gate */
6570Sstevel@tonic-gate switch (cmd) {
6580Sstevel@tonic-gate case CMD_SUSPEND:
6590Sstevel@tonic-gate case CMD_RESUME:
6600Sstevel@tonic-gate case CMD_OFFLINE:
6610Sstevel@tonic-gate case CMD_ONLINE:
6620Sstevel@tonic-gate case CMD_REMOVE:
6630Sstevel@tonic-gate if ((client->flag & RCM_REGISTER_DR) == 0) {
6640Sstevel@tonic-gate rcm_handle_free(hdl);
6650Sstevel@tonic-gate return (RCM_SUCCESS);
6660Sstevel@tonic-gate }
6670Sstevel@tonic-gate break;
6680Sstevel@tonic-gate case CMD_REQUEST_CHANGE:
6690Sstevel@tonic-gate case CMD_NOTIFY_CHANGE:
6700Sstevel@tonic-gate if ((client->flag & RCM_REGISTER_CAPACITY) == 0) {
6710Sstevel@tonic-gate rcm_handle_free(hdl);
6720Sstevel@tonic-gate return (RCM_SUCCESS);
6730Sstevel@tonic-gate }
6740Sstevel@tonic-gate break;
6750Sstevel@tonic-gate case CMD_EVENT:
6760Sstevel@tonic-gate if ((client->flag & RCM_REGISTER_EVENT) == 0) {
6770Sstevel@tonic-gate rcm_handle_free(hdl);
6780Sstevel@tonic-gate return (RCM_SUCCESS);
6790Sstevel@tonic-gate }
6800Sstevel@tonic-gate break;
6810Sstevel@tonic-gate }
6820Sstevel@tonic-gate
6830Sstevel@tonic-gate /*
6840Sstevel@tonic-gate * Create nvlist_t for any client-specific properties.
6850Sstevel@tonic-gate */
6860Sstevel@tonic-gate if (errno = nvlist_alloc(&client_props, NV_UNIQUE_NAME, 0)) {
6870Sstevel@tonic-gate rcm_log_message(RCM_ERROR,
6880Sstevel@tonic-gate "client action failed (nvlist_alloc=%s)\n",
6890Sstevel@tonic-gate strerror(errno));
6900Sstevel@tonic-gate rcmd_exit(errno);
6910Sstevel@tonic-gate }
6920Sstevel@tonic-gate
6930Sstevel@tonic-gate /*
6940Sstevel@tonic-gate * Process the operation via a callback to the client module.
6950Sstevel@tonic-gate */
6960Sstevel@tonic-gate switch (cmd) {
6970Sstevel@tonic-gate case CMD_GETINFO:
6980Sstevel@tonic-gate rval = call_getinfo(ops, hdl, client->alias, client->pid,
6990Sstevel@tonic-gate targ->flag, &info, &error, client_props, &depend_info);
7000Sstevel@tonic-gate break;
7010Sstevel@tonic-gate
7020Sstevel@tonic-gate case CMD_SUSPEND:
7030Sstevel@tonic-gate if (((targ->flag & RCM_QUERY_CANCEL) == 0) &&
7040Sstevel@tonic-gate (client->state == RCM_STATE_SUSPEND)) {
7050Sstevel@tonic-gate break;
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate
7080Sstevel@tonic-gate if ((targ->flag & RCM_QUERY) == 0) {
7090Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "suspending %s\n",
7100Sstevel@tonic-gate client->alias);
7110Sstevel@tonic-gate } else if ((targ->flag & RCM_QUERY_CANCEL) == 0) {
7120Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "suspend query %s\n",
7130Sstevel@tonic-gate client->alias);
7140Sstevel@tonic-gate } else {
7150Sstevel@tonic-gate rcm_log_message(RCM_DEBUG,
7160Sstevel@tonic-gate "suspend query %s cancelled\n", client->alias);
7170Sstevel@tonic-gate }
7180Sstevel@tonic-gate
7190Sstevel@tonic-gate /*
7200Sstevel@tonic-gate * Update the client's state before the operation.
7210Sstevel@tonic-gate * If this is a cancelled query, then updating the state is
7220Sstevel@tonic-gate * the only thing that needs to be done, so break afterwards.
7230Sstevel@tonic-gate */
7240Sstevel@tonic-gate if ((targ->flag & RCM_QUERY) == 0) {
7250Sstevel@tonic-gate client->state = RCM_STATE_SUSPENDING;
7260Sstevel@tonic-gate } else if ((targ->flag & RCM_QUERY_CANCEL) == 0) {
7270Sstevel@tonic-gate client->state = RCM_STATE_SUSPEND_QUERYING;
7280Sstevel@tonic-gate } else {
7290Sstevel@tonic-gate client->state = RCM_STATE_ONLINE;
7300Sstevel@tonic-gate break;
7310Sstevel@tonic-gate }
7320Sstevel@tonic-gate
7330Sstevel@tonic-gate rval = ops->rcmop_request_suspend(hdl, client->alias,
7340Sstevel@tonic-gate client->pid, targ->interval, targ->flag, &error,
7350Sstevel@tonic-gate &depend_info);
7360Sstevel@tonic-gate
7370Sstevel@tonic-gate /* Update the client's state after the operation. */
7380Sstevel@tonic-gate if ((targ->flag & RCM_QUERY) == 0) {
7390Sstevel@tonic-gate if (rval == RCM_SUCCESS) {
7400Sstevel@tonic-gate client->state = RCM_STATE_SUSPEND;
7410Sstevel@tonic-gate } else {
7420Sstevel@tonic-gate client->state = RCM_STATE_SUSPEND_FAIL;
7430Sstevel@tonic-gate }
7440Sstevel@tonic-gate } else {
7450Sstevel@tonic-gate if (rval == RCM_SUCCESS) {
7460Sstevel@tonic-gate client->state = RCM_STATE_SUSPEND_QUERY;
7470Sstevel@tonic-gate } else {
7480Sstevel@tonic-gate client->state = RCM_STATE_SUSPEND_QUERY_FAIL;
7490Sstevel@tonic-gate }
7500Sstevel@tonic-gate }
7510Sstevel@tonic-gate break;
7520Sstevel@tonic-gate
7530Sstevel@tonic-gate case CMD_RESUME:
7540Sstevel@tonic-gate if (client->state == RCM_STATE_ONLINE) {
7550Sstevel@tonic-gate break;
7560Sstevel@tonic-gate }
7570Sstevel@tonic-gate client->state = RCM_STATE_RESUMING;
7580Sstevel@tonic-gate rval = ops->rcmop_notify_resume(hdl, client->alias, client->pid,
7590Sstevel@tonic-gate targ->flag, &error, &depend_info);
7600Sstevel@tonic-gate
7610Sstevel@tonic-gate /* online state is unconditional */
7620Sstevel@tonic-gate client->state = RCM_STATE_ONLINE;
7630Sstevel@tonic-gate break;
7640Sstevel@tonic-gate
7650Sstevel@tonic-gate case CMD_OFFLINE:
7660Sstevel@tonic-gate if (((targ->flag & RCM_QUERY_CANCEL) == 0) &&
7670Sstevel@tonic-gate (client->state == RCM_STATE_OFFLINE)) {
7680Sstevel@tonic-gate break;
7690Sstevel@tonic-gate }
7700Sstevel@tonic-gate
7710Sstevel@tonic-gate if ((targ->flag & RCM_QUERY) == 0) {
7720Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "offlining %s\n",
7730Sstevel@tonic-gate client->alias);
7740Sstevel@tonic-gate } else if ((targ->flag & RCM_QUERY_CANCEL) == 0) {
7750Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "offline query %s\n",
7760Sstevel@tonic-gate client->alias);
7770Sstevel@tonic-gate } else {
7780Sstevel@tonic-gate rcm_log_message(RCM_DEBUG,
7790Sstevel@tonic-gate "offline query %s cancelled\n", client->alias);
7800Sstevel@tonic-gate }
7810Sstevel@tonic-gate
7820Sstevel@tonic-gate /*
7830Sstevel@tonic-gate * Update the client's state before the operation.
7840Sstevel@tonic-gate * If this is a cancelled query, then updating the state is
7850Sstevel@tonic-gate * the only thing that needs to be done, so break afterwards.
7860Sstevel@tonic-gate */
7870Sstevel@tonic-gate if ((targ->flag & RCM_QUERY) == 0) {
7880Sstevel@tonic-gate client->state = RCM_STATE_OFFLINING;
7890Sstevel@tonic-gate } else if ((targ->flag & RCM_QUERY_CANCEL) == 0) {
7900Sstevel@tonic-gate client->state = RCM_STATE_OFFLINE_QUERYING;
7910Sstevel@tonic-gate } else {
7920Sstevel@tonic-gate client->state = RCM_STATE_ONLINE;
7930Sstevel@tonic-gate break;
7940Sstevel@tonic-gate }
7950Sstevel@tonic-gate
7960Sstevel@tonic-gate rval = ops->rcmop_request_offline(hdl, client->alias,
7970Sstevel@tonic-gate client->pid, targ->flag, &error, &depend_info);
7980Sstevel@tonic-gate
799*4845Svikram /*
800*4845Svikram * If this is a retire operation and we managed to call
801*4845Svikram * into at least one client, set retcode to RCM_SUCCESS to
802*4845Svikram * indicate that retire has been subject to constraints
803*4845Svikram * This retcode will be further modified by actual return
804*4845Svikram * code.
805*4845Svikram */
806*4845Svikram if ((targ->flag & RCM_RETIRE_REQUEST) &&
807*4845Svikram (targ->retcode == RCM_NO_CONSTRAINT)) {
808*4845Svikram rcm_log_message(RCM_DEBUG,
809*4845Svikram "at least 1 client, constraint applied: %s\n",
810*4845Svikram client->alias);
811*4845Svikram targ->retcode = RCM_SUCCESS;
812*4845Svikram }
813*4845Svikram
8140Sstevel@tonic-gate /* Update the client's state after the operation. */
8150Sstevel@tonic-gate if ((targ->flag & RCM_QUERY) == 0) {
8160Sstevel@tonic-gate if (rval == RCM_SUCCESS) {
8170Sstevel@tonic-gate client->state = RCM_STATE_OFFLINE;
8180Sstevel@tonic-gate } else {
8190Sstevel@tonic-gate client->state = RCM_STATE_OFFLINE_FAIL;
8200Sstevel@tonic-gate }
8210Sstevel@tonic-gate } else {
8220Sstevel@tonic-gate if (rval == RCM_SUCCESS) {
8230Sstevel@tonic-gate client->state = RCM_STATE_OFFLINE_QUERY;
8240Sstevel@tonic-gate } else {
8250Sstevel@tonic-gate client->state = RCM_STATE_OFFLINE_QUERY_FAIL;
8260Sstevel@tonic-gate }
8270Sstevel@tonic-gate }
8280Sstevel@tonic-gate break;
8290Sstevel@tonic-gate
8300Sstevel@tonic-gate case CMD_ONLINE:
8310Sstevel@tonic-gate if (client->state == RCM_STATE_ONLINE) {
8320Sstevel@tonic-gate break;
8330Sstevel@tonic-gate }
8340Sstevel@tonic-gate
8350Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "onlining %s\n", client->alias);
8360Sstevel@tonic-gate
8370Sstevel@tonic-gate client->state = RCM_STATE_ONLINING;
8380Sstevel@tonic-gate rval = ops->rcmop_notify_online(hdl, client->alias, client->pid,
8390Sstevel@tonic-gate targ->flag, &error, &depend_info);
8400Sstevel@tonic-gate client->state = RCM_STATE_ONLINE;
8410Sstevel@tonic-gate break;
8420Sstevel@tonic-gate
8430Sstevel@tonic-gate case CMD_REMOVE:
8440Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "removing %s\n", client->alias);
8450Sstevel@tonic-gate client->state = RCM_STATE_REMOVING;
8460Sstevel@tonic-gate rval = ops->rcmop_notify_remove(hdl, client->alias, client->pid,
8470Sstevel@tonic-gate targ->flag, &error, &depend_info);
8480Sstevel@tonic-gate client->state = RCM_STATE_REMOVE;
8490Sstevel@tonic-gate break;
8500Sstevel@tonic-gate
8510Sstevel@tonic-gate case CMD_REQUEST_CHANGE:
8520Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "requesting state change of %s\n",
8530Sstevel@tonic-gate client->alias);
8540Sstevel@tonic-gate if (ops->rcmop_request_capacity_change)
8550Sstevel@tonic-gate rval = ops->rcmop_request_capacity_change(hdl,
8560Sstevel@tonic-gate client->alias, client->pid, targ->flag, targ->nvl,
8570Sstevel@tonic-gate &error, &depend_info);
8580Sstevel@tonic-gate break;
8590Sstevel@tonic-gate
8600Sstevel@tonic-gate case CMD_NOTIFY_CHANGE:
8610Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "requesting state change of %s\n",
8620Sstevel@tonic-gate client->alias);
8630Sstevel@tonic-gate if (ops->rcmop_notify_capacity_change)
8640Sstevel@tonic-gate rval = ops->rcmop_notify_capacity_change(hdl,
8650Sstevel@tonic-gate client->alias, client->pid, targ->flag, targ->nvl,
8660Sstevel@tonic-gate &error, &depend_info);
8670Sstevel@tonic-gate break;
8680Sstevel@tonic-gate
8690Sstevel@tonic-gate case CMD_EVENT:
8700Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "delivering event to %s\n",
8710Sstevel@tonic-gate client->alias);
8720Sstevel@tonic-gate if (ops->rcmop_notify_event)
8730Sstevel@tonic-gate rval = ops->rcmop_notify_event(hdl, client->alias,
8740Sstevel@tonic-gate client->pid, targ->flag, &error, targ->nvl,
8750Sstevel@tonic-gate &depend_info);
8760Sstevel@tonic-gate break;
8770Sstevel@tonic-gate
8780Sstevel@tonic-gate default:
8790Sstevel@tonic-gate rcm_log_message(RCM_ERROR, gettext("unknown command %d\n"),
8800Sstevel@tonic-gate cmd);
8810Sstevel@tonic-gate rval = RCM_FAILURE;
8820Sstevel@tonic-gate break;
8830Sstevel@tonic-gate }
8840Sstevel@tonic-gate
8850Sstevel@tonic-gate /* reset error code to the most significant error */
8860Sstevel@tonic-gate if (rval != RCM_SUCCESS)
8870Sstevel@tonic-gate targ->retcode = rval;
8880Sstevel@tonic-gate
8890Sstevel@tonic-gate /*
8900Sstevel@tonic-gate * XXX - The code below may produce duplicate rcm_info_t's on error?
8910Sstevel@tonic-gate */
8920Sstevel@tonic-gate if ((cmd != CMD_GETINFO) &&
8930Sstevel@tonic-gate ((rval != RCM_SUCCESS) ||
8940Sstevel@tonic-gate (error != NULL) ||
8950Sstevel@tonic-gate (targ->flag & RCM_SCOPE))) {
8960Sstevel@tonic-gate (void) call_getinfo(ops, hdl, client->alias, client->pid,
8970Sstevel@tonic-gate targ->flag & (~(RCM_INCLUDE_DEPENDENT|RCM_INCLUDE_SUBTREE)),
8980Sstevel@tonic-gate &info, &dummy_error, client_props, &depend_info);
8990Sstevel@tonic-gate if (dummy_error)
9000Sstevel@tonic-gate (void) free(dummy_error);
9010Sstevel@tonic-gate } else if (cmd != CMD_GETINFO) {
9020Sstevel@tonic-gate nvlist_free(client_props);
9030Sstevel@tonic-gate client_props = NULL;
9040Sstevel@tonic-gate }
9050Sstevel@tonic-gate
9060Sstevel@tonic-gate if (client_props) {
9070Sstevel@tonic-gate add_busy_rsrc_to_list(client->alias, client->pid, client->state,
9080Sstevel@tonic-gate targ->seq_num, client->module->name, info, error,
9090Sstevel@tonic-gate client_props, targ->info);
9100Sstevel@tonic-gate nvlist_free(client_props);
9110Sstevel@tonic-gate }
9120Sstevel@tonic-gate
9130Sstevel@tonic-gate if (info)
9140Sstevel@tonic-gate (void) free(info);
9150Sstevel@tonic-gate if (error)
9160Sstevel@tonic-gate (void) free(error);
9170Sstevel@tonic-gate
9180Sstevel@tonic-gate if (depend_info) {
9190Sstevel@tonic-gate if (targ->info) {
9200Sstevel@tonic-gate (void) rcm_append_info(targ->info, depend_info);
9210Sstevel@tonic-gate } else {
9220Sstevel@tonic-gate rcm_free_info(depend_info);
9230Sstevel@tonic-gate }
9240Sstevel@tonic-gate }
9250Sstevel@tonic-gate
9260Sstevel@tonic-gate rcm_handle_free(hdl);
9270Sstevel@tonic-gate return (rval);
9280Sstevel@tonic-gate }
9290Sstevel@tonic-gate
9300Sstevel@tonic-gate /*
9310Sstevel@tonic-gate * invoke a callback into a list of clients, return 0 if all success
9320Sstevel@tonic-gate */
9330Sstevel@tonic-gate int
rsrc_client_action_list(client_t * list,int cmd,void * arg)9340Sstevel@tonic-gate rsrc_client_action_list(client_t *list, int cmd, void *arg)
9350Sstevel@tonic-gate {
9360Sstevel@tonic-gate int error, rval = RCM_SUCCESS;
937*4845Svikram tree_walk_arg_t *targ = (tree_walk_arg_t *)arg;
9380Sstevel@tonic-gate
9390Sstevel@tonic-gate while (list) {
9400Sstevel@tonic-gate client_t *client = list;
9410Sstevel@tonic-gate list = client->next;
9420Sstevel@tonic-gate
943*4845Svikram /*
944*4845Svikram * Make offline idempotent in the retire
945*4845Svikram * case
946*4845Svikram */
947*4845Svikram if ((targ->flag & RCM_RETIRE_REQUEST) &&
948*4845Svikram client->state == RCM_STATE_REMOVE) {
949*4845Svikram client->state = RCM_STATE_ONLINE;
950*4845Svikram rcm_log_message(RCM_DEBUG, "RETIRE: idempotent client "
951*4845Svikram "state: REMOVE -> ONLINE: %s\n", client->alias);
952*4845Svikram }
953*4845Svikram
9540Sstevel@tonic-gate if (client->state == RCM_STATE_REMOVE)
9550Sstevel@tonic-gate continue;
9560Sstevel@tonic-gate
9570Sstevel@tonic-gate error = rsrc_client_action(client, cmd, arg);
9580Sstevel@tonic-gate if (error != RCM_SUCCESS) {
9590Sstevel@tonic-gate rval = error;
9600Sstevel@tonic-gate }
9610Sstevel@tonic-gate }
9620Sstevel@tonic-gate
9630Sstevel@tonic-gate return (rval);
9640Sstevel@tonic-gate }
9650Sstevel@tonic-gate
9660Sstevel@tonic-gate /*
9670Sstevel@tonic-gate * Node realted operations:
9680Sstevel@tonic-gate *
9690Sstevel@tonic-gate * rn_alloc, rn_free, rn_find_child,
9700Sstevel@tonic-gate * rn_get_child, rn_get_sibling,
9710Sstevel@tonic-gate * rsrc_node_find, rsrc_node_add_user, rsrc_node_remove_user,
9720Sstevel@tonic-gate */
9730Sstevel@tonic-gate
9740Sstevel@tonic-gate /* Allocate node based on a logical or physical name */
9750Sstevel@tonic-gate static rsrc_node_t *
rn_alloc(char * name,int type)9760Sstevel@tonic-gate rn_alloc(char *name, int type)
9770Sstevel@tonic-gate {
9780Sstevel@tonic-gate rsrc_node_t *node;
9790Sstevel@tonic-gate
9800Sstevel@tonic-gate rcm_log_message(RCM_TRACE4, "rn_alloc(%s, %d)\n", name, type);
9810Sstevel@tonic-gate
9820Sstevel@tonic-gate node = s_calloc(1, sizeof (*node));
9830Sstevel@tonic-gate node->name = s_strdup(name);
9840Sstevel@tonic-gate node->type = type;
9850Sstevel@tonic-gate
9860Sstevel@tonic-gate return (node);
9870Sstevel@tonic-gate }
9880Sstevel@tonic-gate
9890Sstevel@tonic-gate /*
9900Sstevel@tonic-gate * Free node along with its siblings and children
9910Sstevel@tonic-gate */
9920Sstevel@tonic-gate static void
rn_free(rsrc_node_t * node)9930Sstevel@tonic-gate rn_free(rsrc_node_t *node)
9940Sstevel@tonic-gate {
9950Sstevel@tonic-gate if (node == NULL) {
9960Sstevel@tonic-gate return;
9970Sstevel@tonic-gate }
9980Sstevel@tonic-gate
9990Sstevel@tonic-gate if (node->child) {
10000Sstevel@tonic-gate rn_free(node->child);
10010Sstevel@tonic-gate }
10020Sstevel@tonic-gate
10030Sstevel@tonic-gate if (node->sibling) {
10040Sstevel@tonic-gate rn_free(node->sibling);
10050Sstevel@tonic-gate }
10060Sstevel@tonic-gate
10070Sstevel@tonic-gate rsrc_clients_free(node->users);
10080Sstevel@tonic-gate free(node->name);
10090Sstevel@tonic-gate free(node);
10100Sstevel@tonic-gate }
10110Sstevel@tonic-gate
10120Sstevel@tonic-gate /*
10130Sstevel@tonic-gate * Find next sibling
10140Sstevel@tonic-gate */
10150Sstevel@tonic-gate static rsrc_node_t *
rn_get_sibling(rsrc_node_t * node)10160Sstevel@tonic-gate rn_get_sibling(rsrc_node_t *node)
10170Sstevel@tonic-gate {
10180Sstevel@tonic-gate return (node->sibling);
10190Sstevel@tonic-gate }
10200Sstevel@tonic-gate
10210Sstevel@tonic-gate /*
10220Sstevel@tonic-gate * Find first child
10230Sstevel@tonic-gate */
10240Sstevel@tonic-gate static rsrc_node_t *
rn_get_child(rsrc_node_t * node)10250Sstevel@tonic-gate rn_get_child(rsrc_node_t *node)
10260Sstevel@tonic-gate {
10270Sstevel@tonic-gate return (node->child);
10280Sstevel@tonic-gate }
10290Sstevel@tonic-gate
10300Sstevel@tonic-gate /*
10310Sstevel@tonic-gate * Find child named childname. Create it if flag is RSRC_NODE_CRTEATE
10320Sstevel@tonic-gate */
10330Sstevel@tonic-gate static rsrc_node_t *
rn_find_child(rsrc_node_t * parent,char * childname,int flag,int type)10340Sstevel@tonic-gate rn_find_child(rsrc_node_t *parent, char *childname, int flag, int type)
10350Sstevel@tonic-gate {
10360Sstevel@tonic-gate rsrc_node_t *child = parent->child;
10370Sstevel@tonic-gate rsrc_node_t *new, *prev = NULL;
10380Sstevel@tonic-gate
10390Sstevel@tonic-gate rcm_log_message(RCM_TRACE4,
10400Sstevel@tonic-gate "rn_find_child(parent=%s, child=%s, 0x%x, %d)\n",
10410Sstevel@tonic-gate parent->name, childname, flag, type);
10420Sstevel@tonic-gate
10430Sstevel@tonic-gate /*
10440Sstevel@tonic-gate * Children are ordered based on strcmp.
10450Sstevel@tonic-gate */
10460Sstevel@tonic-gate while (child && (strcmp(child->name, childname) < 0)) {
10470Sstevel@tonic-gate prev = child;
10480Sstevel@tonic-gate child = child->sibling;
10490Sstevel@tonic-gate }
10500Sstevel@tonic-gate
10510Sstevel@tonic-gate if (child && (strcmp(child->name, childname) == 0)) {
10520Sstevel@tonic-gate return (child);
10530Sstevel@tonic-gate }
10540Sstevel@tonic-gate
10550Sstevel@tonic-gate if (flag != RSRC_NODE_CREATE)
10560Sstevel@tonic-gate return (NULL);
10570Sstevel@tonic-gate
10580Sstevel@tonic-gate new = rn_alloc(childname, type);
10590Sstevel@tonic-gate new->parent = parent;
10600Sstevel@tonic-gate new->sibling = child;
10610Sstevel@tonic-gate
10620Sstevel@tonic-gate /*
10630Sstevel@tonic-gate * Set this linkage last so we don't break ongoing operations.
10640Sstevel@tonic-gate *
10650Sstevel@tonic-gate * N.B. Assume setting a pointer is an atomic operation.
10660Sstevel@tonic-gate */
10670Sstevel@tonic-gate if (prev == NULL) {
10680Sstevel@tonic-gate parent->child = new;
10690Sstevel@tonic-gate } else {
10700Sstevel@tonic-gate prev->sibling = new;
10710Sstevel@tonic-gate }
10720Sstevel@tonic-gate
10730Sstevel@tonic-gate return (new);
10740Sstevel@tonic-gate }
10750Sstevel@tonic-gate
10760Sstevel@tonic-gate /*
10770Sstevel@tonic-gate * Pathname related help functions
10780Sstevel@tonic-gate */
10790Sstevel@tonic-gate static void
pn_preprocess(char * pathname,int type)10800Sstevel@tonic-gate pn_preprocess(char *pathname, int type)
10810Sstevel@tonic-gate {
10820Sstevel@tonic-gate char *tmp;
10830Sstevel@tonic-gate
10840Sstevel@tonic-gate if (type != RSRC_TYPE_DEVICE)
10850Sstevel@tonic-gate return;
10860Sstevel@tonic-gate
10870Sstevel@tonic-gate /*
10880Sstevel@tonic-gate * For devices, convert ':' to '/' (treat minor nodes and children)
10890Sstevel@tonic-gate */
10900Sstevel@tonic-gate tmp = strchr(pathname, ':');
10910Sstevel@tonic-gate if (tmp == NULL)
10920Sstevel@tonic-gate return;
10930Sstevel@tonic-gate
10940Sstevel@tonic-gate *tmp = '/';
10950Sstevel@tonic-gate }
10960Sstevel@tonic-gate
10970Sstevel@tonic-gate static char *
pn_getnextcomp(char * pathname,char ** lasts)10980Sstevel@tonic-gate pn_getnextcomp(char *pathname, char **lasts)
10990Sstevel@tonic-gate {
11000Sstevel@tonic-gate char *slash;
11010Sstevel@tonic-gate
11020Sstevel@tonic-gate if (pathname == NULL)
11030Sstevel@tonic-gate return (NULL);
11040Sstevel@tonic-gate
11050Sstevel@tonic-gate /* skip slashes' */
11060Sstevel@tonic-gate while (*pathname == '/')
11070Sstevel@tonic-gate ++pathname;
11080Sstevel@tonic-gate
11090Sstevel@tonic-gate if (*pathname == '\0')
11100Sstevel@tonic-gate return (NULL);
11110Sstevel@tonic-gate
11120Sstevel@tonic-gate slash = strchr(pathname, '/');
11130Sstevel@tonic-gate if (slash != NULL) {
11140Sstevel@tonic-gate *slash = '\0';
11150Sstevel@tonic-gate *lasts = slash + 1;
11160Sstevel@tonic-gate } else {
11170Sstevel@tonic-gate *lasts = NULL;
11180Sstevel@tonic-gate }
11190Sstevel@tonic-gate
11200Sstevel@tonic-gate return (pathname);
11210Sstevel@tonic-gate }
11220Sstevel@tonic-gate
11230Sstevel@tonic-gate /*
11240Sstevel@tonic-gate * Find a node in tree based on device, which is the physical pathname
11250Sstevel@tonic-gate * of the form /sbus@.../esp@.../sd@...
11260Sstevel@tonic-gate */
11270Sstevel@tonic-gate int
rsrc_node_find(char * rsrcname,int flag,rsrc_node_t ** nodep)11280Sstevel@tonic-gate rsrc_node_find(char *rsrcname, int flag, rsrc_node_t **nodep)
11290Sstevel@tonic-gate {
11300Sstevel@tonic-gate char *pathname, *nodename, *lasts;
11310Sstevel@tonic-gate rsrc_node_t *node;
11320Sstevel@tonic-gate int type;
11330Sstevel@tonic-gate
11340Sstevel@tonic-gate rcm_log_message(RCM_TRACE4, "rn_node_find(%s, 0x%x)\n", rsrcname, flag);
11350Sstevel@tonic-gate
11360Sstevel@tonic-gate /*
11370Sstevel@tonic-gate * For RSRC_TYPE_ABSTRACT, look under /ABSTRACT. For other types,
11380Sstevel@tonic-gate * look under /SYSTEM.
11390Sstevel@tonic-gate */
11400Sstevel@tonic-gate pathname = resolve_name(rsrcname);
11410Sstevel@tonic-gate if (pathname == NULL)
11420Sstevel@tonic-gate return (EINVAL);
11430Sstevel@tonic-gate
11440Sstevel@tonic-gate type = rsrc_get_type(pathname);
11450Sstevel@tonic-gate switch (type) {
11460Sstevel@tonic-gate case RSRC_TYPE_DEVICE:
11470Sstevel@tonic-gate case RSRC_TYPE_NORMAL:
11480Sstevel@tonic-gate node = rn_find_child(rsrc_root, "SYSTEM", RSRC_NODE_CREATE,
11490Sstevel@tonic-gate RSRC_TYPE_NORMAL);
11500Sstevel@tonic-gate break;
11510Sstevel@tonic-gate
11520Sstevel@tonic-gate case RSRC_TYPE_ABSTRACT:
11530Sstevel@tonic-gate node = rn_find_child(rsrc_root, "ABSTRACT", RSRC_NODE_CREATE,
11540Sstevel@tonic-gate RSRC_TYPE_NORMAL);
11550Sstevel@tonic-gate break;
11560Sstevel@tonic-gate
11570Sstevel@tonic-gate default:
11580Sstevel@tonic-gate /* just to make sure */
11590Sstevel@tonic-gate free(pathname);
11600Sstevel@tonic-gate return (EINVAL);
11610Sstevel@tonic-gate }
11620Sstevel@tonic-gate
11630Sstevel@tonic-gate /*
11640Sstevel@tonic-gate * Find position of device within tree. Upon exiting the loop, device
11650Sstevel@tonic-gate * should be placed between prev and curr.
11660Sstevel@tonic-gate */
11670Sstevel@tonic-gate pn_preprocess(pathname, type);
11680Sstevel@tonic-gate lasts = pathname;
11690Sstevel@tonic-gate while ((nodename = pn_getnextcomp(lasts, &lasts)) != NULL) {
11700Sstevel@tonic-gate rsrc_node_t *parent = node;
11710Sstevel@tonic-gate node = rn_find_child(parent, nodename, flag, type);
11720Sstevel@tonic-gate if (node == NULL) {
11730Sstevel@tonic-gate assert((flag & RSRC_NODE_CREATE) == 0);
11740Sstevel@tonic-gate free(pathname);
11750Sstevel@tonic-gate *nodep = NULL;
11760Sstevel@tonic-gate return (RCM_SUCCESS);
11770Sstevel@tonic-gate }
11780Sstevel@tonic-gate }
11790Sstevel@tonic-gate free(pathname);
11800Sstevel@tonic-gate *nodep = node;
11810Sstevel@tonic-gate return (RCM_SUCCESS);
11820Sstevel@tonic-gate }
11830Sstevel@tonic-gate
11840Sstevel@tonic-gate /*
11850Sstevel@tonic-gate * add a usage client to a node
11860Sstevel@tonic-gate */
11870Sstevel@tonic-gate /*ARGSUSED*/
11880Sstevel@tonic-gate int
rsrc_node_add_user(rsrc_node_t * node,char * alias,char * modname,pid_t pid,uint_t flag)11890Sstevel@tonic-gate rsrc_node_add_user(rsrc_node_t *node, char *alias, char *modname, pid_t pid,
11900Sstevel@tonic-gate uint_t flag)
11910Sstevel@tonic-gate {
11920Sstevel@tonic-gate client_t *user;
11930Sstevel@tonic-gate
11940Sstevel@tonic-gate rcm_log_message(RCM_TRACE3,
11950Sstevel@tonic-gate "rsrc_node_add_user(%s, %s, %s, %ld, 0x%x)\n",
11960Sstevel@tonic-gate node->name, alias, modname, pid, flag);
11970Sstevel@tonic-gate
11980Sstevel@tonic-gate user = rsrc_client_find(modname, pid, &node->users);
11990Sstevel@tonic-gate
12000Sstevel@tonic-gate /*
12010Sstevel@tonic-gate * If a client_t already exists, add the registration and return
12020Sstevel@tonic-gate * success if it's a valid registration request.
12030Sstevel@tonic-gate *
12040Sstevel@tonic-gate * Return EALREADY if the resource is already registered.
12050Sstevel@tonic-gate * This means either the client_t already has the requested
12060Sstevel@tonic-gate * registration flagged, or that a DR registration was attempted
12070Sstevel@tonic-gate * on a resource already in use in the DR operations state model.
12080Sstevel@tonic-gate */
12090Sstevel@tonic-gate if (user != NULL) {
12100Sstevel@tonic-gate
12110Sstevel@tonic-gate if (user->flag & (flag & RCM_REGISTER_MASK)) {
12120Sstevel@tonic-gate return (EALREADY);
12130Sstevel@tonic-gate }
12140Sstevel@tonic-gate
12150Sstevel@tonic-gate if ((flag & RCM_REGISTER_DR) &&
12160Sstevel@tonic-gate (user->state != RCM_STATE_REMOVE)) {
12170Sstevel@tonic-gate return (EALREADY);
12180Sstevel@tonic-gate }
12190Sstevel@tonic-gate
12200Sstevel@tonic-gate user->flag |= (flag & RCM_REGISTER_MASK);
12210Sstevel@tonic-gate if ((flag & RCM_REGISTER_DR) ||
12220Sstevel@tonic-gate (user->state == RCM_STATE_REMOVE)) {
12230Sstevel@tonic-gate user->state = RCM_STATE_ONLINE;
12240Sstevel@tonic-gate }
12250Sstevel@tonic-gate
12260Sstevel@tonic-gate return (RCM_SUCCESS);
12270Sstevel@tonic-gate }
12280Sstevel@tonic-gate
12290Sstevel@tonic-gate /*
12300Sstevel@tonic-gate * Otherwise create a new client_t and create a new registration.
12310Sstevel@tonic-gate */
12320Sstevel@tonic-gate if ((user = rsrc_client_alloc(alias, modname, pid, flag)) != NULL) {
12330Sstevel@tonic-gate rsrc_client_add(user, &node->users);
12340Sstevel@tonic-gate }
12350Sstevel@tonic-gate if (flag & RCM_FILESYS)
12360Sstevel@tonic-gate node->type = RSRC_TYPE_FILESYS;
12370Sstevel@tonic-gate
12380Sstevel@tonic-gate return (RCM_SUCCESS);
12390Sstevel@tonic-gate }
12400Sstevel@tonic-gate
12410Sstevel@tonic-gate /*
12420Sstevel@tonic-gate * remove a usage client of a node
12430Sstevel@tonic-gate */
12440Sstevel@tonic-gate int
rsrc_node_remove_user(rsrc_node_t * node,char * modname,pid_t pid,uint_t flag)12450Sstevel@tonic-gate rsrc_node_remove_user(rsrc_node_t *node, char *modname, pid_t pid, uint_t flag)
12460Sstevel@tonic-gate {
12470Sstevel@tonic-gate client_t *user;
12480Sstevel@tonic-gate
12490Sstevel@tonic-gate rcm_log_message(RCM_TRACE3,
12500Sstevel@tonic-gate "rsrc_node_remove_user(%s, %s, %ld, 0x%x)\n", node->name, modname,
12510Sstevel@tonic-gate pid, flag);
12520Sstevel@tonic-gate
12530Sstevel@tonic-gate user = rsrc_client_find(modname, pid, &node->users);
12540Sstevel@tonic-gate if ((user == NULL) || (user->state == RCM_STATE_REMOVE)) {
12550Sstevel@tonic-gate rcm_log_message(RCM_NOTICE, gettext(
12560Sstevel@tonic-gate "client not registered: module=%s, pid=%d, dev=%s\n"),
12570Sstevel@tonic-gate modname, pid, node->name);
12580Sstevel@tonic-gate return (ENOENT);
12590Sstevel@tonic-gate }
12600Sstevel@tonic-gate
12610Sstevel@tonic-gate /* Strip off the registration being removed (DR, event, capacity) */
12620Sstevel@tonic-gate user->flag = user->flag & (~(flag & RCM_REGISTER_MASK));
12630Sstevel@tonic-gate
12640Sstevel@tonic-gate /*
12650Sstevel@tonic-gate * Mark the client as removed if all registrations have been removed
12660Sstevel@tonic-gate */
12670Sstevel@tonic-gate if ((user->flag & RCM_REGISTER_MASK) == 0)
12680Sstevel@tonic-gate user->state = RCM_STATE_REMOVE;
12690Sstevel@tonic-gate
12700Sstevel@tonic-gate return (RCM_SUCCESS);
12710Sstevel@tonic-gate }
12720Sstevel@tonic-gate
12730Sstevel@tonic-gate /*
12740Sstevel@tonic-gate * Tree walking function - rsrc_walk
12750Sstevel@tonic-gate */
12760Sstevel@tonic-gate
12770Sstevel@tonic-gate #define MAX_TREE_DEPTH 32
12780Sstevel@tonic-gate
12790Sstevel@tonic-gate #define RN_WALK_CONTINUE 0
12800Sstevel@tonic-gate #define RN_WALK_PRUNESIB 1
12810Sstevel@tonic-gate #define RN_WALK_PRUNECHILD 2
12820Sstevel@tonic-gate #define RN_WALK_TERMINATE 3
12830Sstevel@tonic-gate
12840Sstevel@tonic-gate #define EMPTY_STACK(sp) ((sp)->depth == 0)
12850Sstevel@tonic-gate #define TOP_NODE(sp) ((sp)->node[(sp)->depth - 1])
12860Sstevel@tonic-gate #define PRUNE_SIB(sp) ((sp)->prunesib[(sp)->depth - 1])
12870Sstevel@tonic-gate #define PRUNE_CHILD(sp) ((sp)->prunechild[(sp)->depth - 1])
12880Sstevel@tonic-gate #define POP_STACK(sp) ((sp)->depth)--
12890Sstevel@tonic-gate #define PUSH_STACK(sp, rn) \
12900Sstevel@tonic-gate (sp)->node[(sp)->depth] = (rn); \
12910Sstevel@tonic-gate (sp)->prunesib[(sp)->depth] = 0; \
12920Sstevel@tonic-gate (sp)->prunechild[(sp)->depth] = 0; \
12930Sstevel@tonic-gate ((sp)->depth)++
12940Sstevel@tonic-gate
12950Sstevel@tonic-gate struct rn_stack {
12960Sstevel@tonic-gate rsrc_node_t *node[MAX_TREE_DEPTH];
12970Sstevel@tonic-gate char prunesib[MAX_TREE_DEPTH];
12980Sstevel@tonic-gate char prunechild[MAX_TREE_DEPTH];
12990Sstevel@tonic-gate int depth;
13000Sstevel@tonic-gate };
13010Sstevel@tonic-gate
13020Sstevel@tonic-gate /* walking one node and update node stack */
13030Sstevel@tonic-gate /*ARGSUSED*/
13040Sstevel@tonic-gate static void
walk_one_node(struct rn_stack * sp,void * arg,int (* node_callback)(rsrc_node_t *,void *))13050Sstevel@tonic-gate walk_one_node(struct rn_stack *sp, void *arg,
13060Sstevel@tonic-gate int (*node_callback)(rsrc_node_t *, void *))
13070Sstevel@tonic-gate {
13080Sstevel@tonic-gate int prunesib;
13090Sstevel@tonic-gate rsrc_node_t *child, *sibling;
13100Sstevel@tonic-gate rsrc_node_t *node = TOP_NODE(sp);
13110Sstevel@tonic-gate
13120Sstevel@tonic-gate rcm_log_message(RCM_TRACE4, "walk_one_node(%s)\n", node->name);
13130Sstevel@tonic-gate
13140Sstevel@tonic-gate switch (node_callback(node, arg)) {
13150Sstevel@tonic-gate case RN_WALK_TERMINATE:
13160Sstevel@tonic-gate POP_STACK(sp);
13170Sstevel@tonic-gate while (!EMPTY_STACK(sp)) {
13180Sstevel@tonic-gate node = TOP_NODE(sp);
13190Sstevel@tonic-gate POP_STACK(sp);
13200Sstevel@tonic-gate }
13210Sstevel@tonic-gate return;
13220Sstevel@tonic-gate
13230Sstevel@tonic-gate case RN_WALK_PRUNESIB:
13240Sstevel@tonic-gate PRUNE_SIB(sp) = 1;
13250Sstevel@tonic-gate break;
13260Sstevel@tonic-gate
13270Sstevel@tonic-gate case RN_WALK_PRUNECHILD:
13280Sstevel@tonic-gate PRUNE_CHILD(sp) = 1;
13290Sstevel@tonic-gate break;
13300Sstevel@tonic-gate
13310Sstevel@tonic-gate case RN_WALK_CONTINUE:
13320Sstevel@tonic-gate default:
13330Sstevel@tonic-gate break;
13340Sstevel@tonic-gate }
13350Sstevel@tonic-gate
13360Sstevel@tonic-gate /*
13370Sstevel@tonic-gate * Push child on the stack
13380Sstevel@tonic-gate */
13390Sstevel@tonic-gate if (!PRUNE_CHILD(sp) && (child = rn_get_child(node)) != NULL) {
13400Sstevel@tonic-gate PUSH_STACK(sp, child);
13410Sstevel@tonic-gate return;
13420Sstevel@tonic-gate }
13430Sstevel@tonic-gate
13440Sstevel@tonic-gate /*
13450Sstevel@tonic-gate * Pop the stack till a node's sibling can be pushed
13460Sstevel@tonic-gate */
13470Sstevel@tonic-gate prunesib = PRUNE_SIB(sp);
13480Sstevel@tonic-gate POP_STACK(sp);
13490Sstevel@tonic-gate while (!EMPTY_STACK(sp) &&
13500Sstevel@tonic-gate (prunesib || (sibling = rn_get_sibling(node)) == NULL)) {
13510Sstevel@tonic-gate node = TOP_NODE(sp);
13520Sstevel@tonic-gate prunesib = PRUNE_SIB(sp);
13530Sstevel@tonic-gate POP_STACK(sp);
13540Sstevel@tonic-gate }
13550Sstevel@tonic-gate
13560Sstevel@tonic-gate if (EMPTY_STACK(sp)) {
13570Sstevel@tonic-gate return;
13580Sstevel@tonic-gate }
13590Sstevel@tonic-gate
13600Sstevel@tonic-gate /*
13610Sstevel@tonic-gate * push sibling onto the stack
13620Sstevel@tonic-gate */
13630Sstevel@tonic-gate PUSH_STACK(sp, sibling);
13640Sstevel@tonic-gate }
13650Sstevel@tonic-gate
13660Sstevel@tonic-gate /*
13670Sstevel@tonic-gate * walk tree rooted at root in child-first order
13680Sstevel@tonic-gate */
13690Sstevel@tonic-gate static void
rsrc_walk(rsrc_node_t * root,void * arg,int (* node_callback)(rsrc_node_t *,void *))13700Sstevel@tonic-gate rsrc_walk(rsrc_node_t *root, void *arg,
13710Sstevel@tonic-gate int (*node_callback)(rsrc_node_t *, void *))
13720Sstevel@tonic-gate {
13730Sstevel@tonic-gate struct rn_stack stack;
13740Sstevel@tonic-gate
13750Sstevel@tonic-gate rcm_log_message(RCM_TRACE3, "rsrc_walk(%s)\n", root->name);
13760Sstevel@tonic-gate
13770Sstevel@tonic-gate /*
13780Sstevel@tonic-gate * Push root on stack and walk in child-first order
13790Sstevel@tonic-gate */
13800Sstevel@tonic-gate stack.depth = 0;
13810Sstevel@tonic-gate PUSH_STACK(&stack, root);
13820Sstevel@tonic-gate PRUNE_SIB(&stack) = 1;
13830Sstevel@tonic-gate
13840Sstevel@tonic-gate while (!EMPTY_STACK(&stack)) {
13850Sstevel@tonic-gate walk_one_node(&stack, arg, node_callback);
13860Sstevel@tonic-gate }
13870Sstevel@tonic-gate }
13880Sstevel@tonic-gate
13890Sstevel@tonic-gate /*
13900Sstevel@tonic-gate * Callback for a command action on a node
13910Sstevel@tonic-gate */
13920Sstevel@tonic-gate static int
node_action(rsrc_node_t * node,void * arg)13930Sstevel@tonic-gate node_action(rsrc_node_t *node, void *arg)
13940Sstevel@tonic-gate {
13950Sstevel@tonic-gate tree_walk_arg_t *targ = (tree_walk_arg_t *)arg;
13960Sstevel@tonic-gate uint_t flag = targ->flag;
13970Sstevel@tonic-gate
13980Sstevel@tonic-gate rcm_log_message(RCM_TRACE4, "node_action(%s)\n", node->name);
13990Sstevel@tonic-gate
14000Sstevel@tonic-gate /*
14010Sstevel@tonic-gate * If flag indicates operation on a filesystem, we don't callback on
14020Sstevel@tonic-gate * the filesystem root to avoid infinite recursion on filesystem module.
14030Sstevel@tonic-gate *
14040Sstevel@tonic-gate * N.B. Such request should only come from filesystem RCM module.
14050Sstevel@tonic-gate */
14060Sstevel@tonic-gate if (flag & RCM_FILESYS) {
14070Sstevel@tonic-gate assert(node->type == RSRC_TYPE_FILESYS);
14080Sstevel@tonic-gate targ->flag &= ~RCM_FILESYS;
14090Sstevel@tonic-gate return (RN_WALK_CONTINUE);
14100Sstevel@tonic-gate }
14110Sstevel@tonic-gate
14120Sstevel@tonic-gate /*
14130Sstevel@tonic-gate * Execute state change callback
14140Sstevel@tonic-gate */
14150Sstevel@tonic-gate (void) rsrc_client_action_list(node->users, targ->cmd, arg);
14160Sstevel@tonic-gate
14170Sstevel@tonic-gate /*
14180Sstevel@tonic-gate * Upon hitting a filesys root, prune children.
14190Sstevel@tonic-gate * The filesys module should have taken care of
14200Sstevel@tonic-gate * children by now.
14210Sstevel@tonic-gate */
14220Sstevel@tonic-gate if (node->type == RSRC_TYPE_FILESYS)
14230Sstevel@tonic-gate return (RN_WALK_PRUNECHILD);
14240Sstevel@tonic-gate
14250Sstevel@tonic-gate return (RN_WALK_CONTINUE);
14260Sstevel@tonic-gate }
14270Sstevel@tonic-gate
14280Sstevel@tonic-gate /*
14290Sstevel@tonic-gate * Execute a command on a subtree under root.
14300Sstevel@tonic-gate */
14310Sstevel@tonic-gate int
rsrc_tree_action(rsrc_node_t * root,int cmd,tree_walk_arg_t * arg)14320Sstevel@tonic-gate rsrc_tree_action(rsrc_node_t *root, int cmd, tree_walk_arg_t *arg)
14330Sstevel@tonic-gate {
14340Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, "tree_action(%s, %d)\n", root->name, cmd);
14350Sstevel@tonic-gate
14360Sstevel@tonic-gate arg->cmd = cmd;
1437*4845Svikram
1438*4845Svikram /*
1439*4845Svikram * If RCM_RETIRE_REQUEST is set, just walk one node and preset
1440*4845Svikram * retcode to NO_CONSTRAINT
1441*4845Svikram */
1442*4845Svikram if (arg->flag & RCM_RETIRE_REQUEST) {
1443*4845Svikram rcm_log_message(RCM_TRACE1, "tree_action: RETIRE_REQ: walking "
1444*4845Svikram "only root node: %s\n", root->name);
1445*4845Svikram arg->retcode = RCM_NO_CONSTRAINT;
1446*4845Svikram (void) node_action(root, arg);
1447*4845Svikram } else {
1448*4845Svikram arg->retcode = RCM_SUCCESS;
1449*4845Svikram rsrc_walk(root, (void *)arg, node_action);
1450*4845Svikram }
14510Sstevel@tonic-gate
14520Sstevel@tonic-gate return (arg->retcode);
14530Sstevel@tonic-gate }
14540Sstevel@tonic-gate
14550Sstevel@tonic-gate /*
14560Sstevel@tonic-gate * Get info on current regsitrations
14570Sstevel@tonic-gate */
14580Sstevel@tonic-gate int
rsrc_usage_info(char ** rsrcnames,uint_t flag,int seq_num,rcm_info_t ** info)14590Sstevel@tonic-gate rsrc_usage_info(char **rsrcnames, uint_t flag, int seq_num, rcm_info_t **info)
14600Sstevel@tonic-gate {
14610Sstevel@tonic-gate rsrc_node_t *node;
14620Sstevel@tonic-gate rcm_info_t *result = NULL;
14630Sstevel@tonic-gate tree_walk_arg_t arg;
14640Sstevel@tonic-gate int initial_req;
14650Sstevel@tonic-gate int rv;
14660Sstevel@tonic-gate int i;
14670Sstevel@tonic-gate
14680Sstevel@tonic-gate arg.flag = flag;
14690Sstevel@tonic-gate arg.info = &result;
14700Sstevel@tonic-gate arg.seq_num = seq_num;
14710Sstevel@tonic-gate
14720Sstevel@tonic-gate for (i = 0; rsrcnames[i] != NULL; i++) {
14730Sstevel@tonic-gate
14740Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, "rsrc_usage_info(%s, 0x%x, %d)\n",
14750Sstevel@tonic-gate rsrcnames[i], flag, seq_num);
14760Sstevel@tonic-gate
14770Sstevel@tonic-gate if (flag & RCM_INCLUDE_DEPENDENT) {
14780Sstevel@tonic-gate initial_req = ((seq_num & SEQ_NUM_MASK) == 0);
14790Sstevel@tonic-gate
14800Sstevel@tonic-gate /*
14810Sstevel@tonic-gate * if redundant request, skip the operation
14820Sstevel@tonic-gate */
14830Sstevel@tonic-gate if (info_req_add(rsrcnames[i], flag, seq_num) != 0) {
14840Sstevel@tonic-gate continue;
14850Sstevel@tonic-gate }
14860Sstevel@tonic-gate }
14870Sstevel@tonic-gate
14880Sstevel@tonic-gate rv = rsrc_node_find(rsrcnames[i], 0, &node);
14890Sstevel@tonic-gate if ((rv != RCM_SUCCESS) || (node == NULL)) {
14900Sstevel@tonic-gate if ((flag & RCM_INCLUDE_DEPENDENT) && initial_req)
14910Sstevel@tonic-gate info_req_remove(seq_num);
14920Sstevel@tonic-gate continue;
14930Sstevel@tonic-gate }
14940Sstevel@tonic-gate
14950Sstevel@tonic-gate /*
14960Sstevel@tonic-gate * Based on RCM_INCLUDE_SUBTREE flag, query either the subtree
14970Sstevel@tonic-gate * or just the node.
14980Sstevel@tonic-gate */
14990Sstevel@tonic-gate if (flag & RCM_INCLUDE_SUBTREE) {
15000Sstevel@tonic-gate (void) rsrc_tree_action(node, CMD_GETINFO, &arg);
15010Sstevel@tonic-gate } else {
15020Sstevel@tonic-gate arg.cmd = CMD_GETINFO;
15030Sstevel@tonic-gate (void) node_action(node, (void *)&arg);
15040Sstevel@tonic-gate }
15050Sstevel@tonic-gate
15060Sstevel@tonic-gate if ((flag & RCM_INCLUDE_DEPENDENT) && initial_req)
15070Sstevel@tonic-gate info_req_remove(seq_num);
15080Sstevel@tonic-gate }
15090Sstevel@tonic-gate
15100Sstevel@tonic-gate out:
15110Sstevel@tonic-gate (void) rcm_append_info(info, result);
15120Sstevel@tonic-gate return (rv);
15130Sstevel@tonic-gate }
15140Sstevel@tonic-gate
15150Sstevel@tonic-gate /*
15160Sstevel@tonic-gate * Get the list of currently loaded module
15170Sstevel@tonic-gate */
15180Sstevel@tonic-gate rcm_info_t *
rsrc_mod_info()15190Sstevel@tonic-gate rsrc_mod_info()
15200Sstevel@tonic-gate {
15210Sstevel@tonic-gate module_t *mod;
15220Sstevel@tonic-gate rcm_info_t *info = NULL;
15230Sstevel@tonic-gate
15240Sstevel@tonic-gate (void) mutex_lock(&mod_lock);
15250Sstevel@tonic-gate mod = module_head;
15260Sstevel@tonic-gate while (mod) {
15270Sstevel@tonic-gate char *modinfo = s_strdup(module_info(mod));
15280Sstevel@tonic-gate add_busy_rsrc_to_list("dummy", 0, 0, 0, mod->name,
15290Sstevel@tonic-gate modinfo, NULL, NULL, &info);
15300Sstevel@tonic-gate mod = mod->next;
15310Sstevel@tonic-gate }
15320Sstevel@tonic-gate (void) mutex_unlock(&mod_lock);
15330Sstevel@tonic-gate
15340Sstevel@tonic-gate return (info);
15350Sstevel@tonic-gate }
15360Sstevel@tonic-gate
15370Sstevel@tonic-gate /*
15380Sstevel@tonic-gate * Initialize resource map - load all modules
15390Sstevel@tonic-gate */
15400Sstevel@tonic-gate void
rcmd_db_init()15410Sstevel@tonic-gate rcmd_db_init()
15420Sstevel@tonic-gate {
15430Sstevel@tonic-gate char *tmp;
15440Sstevel@tonic-gate DIR *mod_dir;
1545871Scasper struct dirent *entp;
15460Sstevel@tonic-gate int i;
15470Sstevel@tonic-gate char *dir_name;
15480Sstevel@tonic-gate int rcm_script;
15490Sstevel@tonic-gate
15500Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "rcmd_db_init(): initialize database\n");
15510Sstevel@tonic-gate
15520Sstevel@tonic-gate if (script_main_init() == -1)
15530Sstevel@tonic-gate rcmd_exit(errno);
15540Sstevel@tonic-gate
15550Sstevel@tonic-gate rsrc_root = rn_alloc("/", RSRC_TYPE_NORMAL);
15560Sstevel@tonic-gate
15570Sstevel@tonic-gate for (i = 0; (dir_name = rcm_dir(i, &rcm_script)) != NULL; i++) {
15580Sstevel@tonic-gate
15590Sstevel@tonic-gate if ((mod_dir = opendir(dir_name)) == NULL) {
15600Sstevel@tonic-gate continue; /* try next directory */
15610Sstevel@tonic-gate }
15620Sstevel@tonic-gate
15630Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, "search directory %s\n", dir_name);
15640Sstevel@tonic-gate
1565871Scasper while ((entp = readdir(mod_dir)) != NULL) {
15660Sstevel@tonic-gate module_t *module;
15670Sstevel@tonic-gate
15680Sstevel@tonic-gate if (strcmp(entp->d_name, ".") == 0 ||
15690Sstevel@tonic-gate strcmp(entp->d_name, "..") == 0)
15700Sstevel@tonic-gate continue;
15710Sstevel@tonic-gate
15720Sstevel@tonic-gate if (rcm_script == 0) {
15730Sstevel@tonic-gate /* rcm module */
15740Sstevel@tonic-gate if (((tmp = strstr(entp->d_name,
15750Sstevel@tonic-gate RCM_MODULE_SUFFIX)) == NULL) ||
15760Sstevel@tonic-gate (tmp[strlen(RCM_MODULE_SUFFIX)] != '\0')) {
15770Sstevel@tonic-gate continue;
15780Sstevel@tonic-gate }
15790Sstevel@tonic-gate }
15800Sstevel@tonic-gate
15810Sstevel@tonic-gate module = cli_module_hold(entp->d_name);
15820Sstevel@tonic-gate if (module == NULL) {
15830Sstevel@tonic-gate if (rcm_script == 0)
15840Sstevel@tonic-gate rcm_log_message(RCM_ERROR,
15850Sstevel@tonic-gate gettext("%s: failed to load\n"),
15860Sstevel@tonic-gate entp->d_name);
15870Sstevel@tonic-gate continue;
15880Sstevel@tonic-gate }
15890Sstevel@tonic-gate
15900Sstevel@tonic-gate if (module->ref_count == MOD_REFCNT_INIT) {
15910Sstevel@tonic-gate /*
15920Sstevel@tonic-gate * ask module to register for resource 1st time
15930Sstevel@tonic-gate */
15940Sstevel@tonic-gate module_attach(module);
15950Sstevel@tonic-gate }
15960Sstevel@tonic-gate cli_module_rele(module);
15970Sstevel@tonic-gate }
15980Sstevel@tonic-gate (void) closedir(mod_dir);
15990Sstevel@tonic-gate }
16000Sstevel@tonic-gate
16010Sstevel@tonic-gate rcmd_db_print();
16020Sstevel@tonic-gate }
16030Sstevel@tonic-gate
16040Sstevel@tonic-gate /*
16050Sstevel@tonic-gate * sync resource map - ask all modules to register again
16060Sstevel@tonic-gate */
16070Sstevel@tonic-gate void
rcmd_db_sync()16080Sstevel@tonic-gate rcmd_db_sync()
16090Sstevel@tonic-gate {
16100Sstevel@tonic-gate static time_t sync_time = (time_t)-1;
16110Sstevel@tonic-gate const time_t interval = 5; /* resync at most every 5 sec */
16120Sstevel@tonic-gate
16130Sstevel@tonic-gate module_t *mod;
16140Sstevel@tonic-gate time_t curr = time(NULL);
16150Sstevel@tonic-gate
16160Sstevel@tonic-gate if ((sync_time != (time_t)-1) && (curr - sync_time < interval))
16170Sstevel@tonic-gate return;
16180Sstevel@tonic-gate
16190Sstevel@tonic-gate sync_time = curr;
16200Sstevel@tonic-gate (void) mutex_lock(&mod_lock);
16210Sstevel@tonic-gate mod = module_head;
16220Sstevel@tonic-gate while (mod) {
16230Sstevel@tonic-gate /*
16240Sstevel@tonic-gate * Hold module by incrementing ref count and release
16250Sstevel@tonic-gate * mod_lock to avoid deadlock, since rcmop_register()
16260Sstevel@tonic-gate * may callback into the daemon and request mod_lock.
16270Sstevel@tonic-gate */
16280Sstevel@tonic-gate mod->ref_count++;
16290Sstevel@tonic-gate (void) mutex_unlock(&mod_lock);
16300Sstevel@tonic-gate
16310Sstevel@tonic-gate mod->modops->rcmop_register(mod->rcmhandle);
16320Sstevel@tonic-gate
16330Sstevel@tonic-gate (void) mutex_lock(&mod_lock);
16340Sstevel@tonic-gate mod->ref_count--;
16350Sstevel@tonic-gate mod = mod->next;
16360Sstevel@tonic-gate }
16370Sstevel@tonic-gate (void) mutex_unlock(&mod_lock);
16380Sstevel@tonic-gate }
16390Sstevel@tonic-gate
16400Sstevel@tonic-gate /*
16410Sstevel@tonic-gate * Determine if a process is alive
16420Sstevel@tonic-gate */
16430Sstevel@tonic-gate int
proc_exist(pid_t pid)16440Sstevel@tonic-gate proc_exist(pid_t pid)
16450Sstevel@tonic-gate {
16460Sstevel@tonic-gate char path[64];
16470Sstevel@tonic-gate const char *procfs = "/proc";
16480Sstevel@tonic-gate struct stat sb;
16490Sstevel@tonic-gate
16500Sstevel@tonic-gate if (pid == (pid_t)0) {
16510Sstevel@tonic-gate return (1);
16520Sstevel@tonic-gate }
16530Sstevel@tonic-gate
16540Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s/%ld", procfs, pid);
16550Sstevel@tonic-gate return (stat(path, &sb) == 0);
16560Sstevel@tonic-gate }
16570Sstevel@tonic-gate
16580Sstevel@tonic-gate /*
16590Sstevel@tonic-gate * Cleaup client list
16600Sstevel@tonic-gate *
16610Sstevel@tonic-gate * N.B. This routine runs in a single-threaded environment only. It is only
16620Sstevel@tonic-gate * called by the cleanup thread, which never runs in parallel with other
16630Sstevel@tonic-gate * threads.
16640Sstevel@tonic-gate */
16650Sstevel@tonic-gate static void
clean_client_list(client_t ** listp)16660Sstevel@tonic-gate clean_client_list(client_t **listp)
16670Sstevel@tonic-gate {
16680Sstevel@tonic-gate client_t *client = *listp;
16690Sstevel@tonic-gate
16700Sstevel@tonic-gate /*
16710Sstevel@tonic-gate * Cleanup notification clients for which pid no longer exists
16720Sstevel@tonic-gate */
16730Sstevel@tonic-gate while (client) {
16740Sstevel@tonic-gate if ((client->state != RCM_STATE_REMOVE) &&
16750Sstevel@tonic-gate proc_exist(client->pid)) {
16760Sstevel@tonic-gate listp = &client->next;
16770Sstevel@tonic-gate client = *listp;
16780Sstevel@tonic-gate continue;
16790Sstevel@tonic-gate }
16800Sstevel@tonic-gate
16810Sstevel@tonic-gate /*
16820Sstevel@tonic-gate * Destroy this client_t. rsrc_client_remove updates
16830Sstevel@tonic-gate * listp to point to the next client.
16840Sstevel@tonic-gate */
16850Sstevel@tonic-gate rsrc_client_remove(client, listp);
16860Sstevel@tonic-gate client = *listp;
16870Sstevel@tonic-gate }
16880Sstevel@tonic-gate }
16890Sstevel@tonic-gate
16900Sstevel@tonic-gate /*ARGSUSED*/
16910Sstevel@tonic-gate static int
clean_node(rsrc_node_t * node,void * arg)16920Sstevel@tonic-gate clean_node(rsrc_node_t *node, void *arg)
16930Sstevel@tonic-gate {
16940Sstevel@tonic-gate rcm_log_message(RCM_TRACE4, "clean_node(%s)\n", node->name);
16950Sstevel@tonic-gate
16960Sstevel@tonic-gate clean_client_list(&node->users);
16970Sstevel@tonic-gate
16980Sstevel@tonic-gate return (RN_WALK_CONTINUE);
16990Sstevel@tonic-gate }
17000Sstevel@tonic-gate
17010Sstevel@tonic-gate static void
clean_rsrc_tree()17020Sstevel@tonic-gate clean_rsrc_tree()
17030Sstevel@tonic-gate {
17040Sstevel@tonic-gate rcm_log_message(RCM_TRACE4,
17050Sstevel@tonic-gate "clean_rsrc_tree(): delete stale dr clients\n");
17060Sstevel@tonic-gate
17070Sstevel@tonic-gate rsrc_walk(rsrc_root, NULL, clean_node);
17080Sstevel@tonic-gate }
17090Sstevel@tonic-gate
17100Sstevel@tonic-gate static void
db_clean()17110Sstevel@tonic-gate db_clean()
17120Sstevel@tonic-gate {
17130Sstevel@tonic-gate extern barrier_t barrier;
17140Sstevel@tonic-gate extern void clean_dr_list();
17150Sstevel@tonic-gate
17160Sstevel@tonic-gate for (;;) {
17170Sstevel@tonic-gate (void) mutex_lock(&rcm_req_lock);
17180Sstevel@tonic-gate start_polling_thread();
17190Sstevel@tonic-gate (void) mutex_unlock(&rcm_req_lock);
17200Sstevel@tonic-gate
17210Sstevel@tonic-gate (void) mutex_lock(&barrier.lock);
17220Sstevel@tonic-gate while (need_cleanup == 0)
17230Sstevel@tonic-gate (void) cond_wait(&barrier.cv, &barrier.lock);
17240Sstevel@tonic-gate (void) mutex_unlock(&barrier.lock);
17250Sstevel@tonic-gate
17260Sstevel@tonic-gate /*
17270Sstevel@tonic-gate * Make sure all other threads are either blocked or exited.
17280Sstevel@tonic-gate */
17290Sstevel@tonic-gate rcmd_set_state(RCMD_CLEANUP);
17300Sstevel@tonic-gate
17310Sstevel@tonic-gate need_cleanup = 0;
17320Sstevel@tonic-gate
17330Sstevel@tonic-gate /*
17340Sstevel@tonic-gate * clean dr_req_list
17350Sstevel@tonic-gate */
17360Sstevel@tonic-gate clean_dr_list();
17370Sstevel@tonic-gate
17380Sstevel@tonic-gate /*
17390Sstevel@tonic-gate * clean resource tree
17400Sstevel@tonic-gate */
17410Sstevel@tonic-gate clean_rsrc_tree();
17420Sstevel@tonic-gate
17430Sstevel@tonic-gate rcmd_set_state(RCMD_NORMAL);
17440Sstevel@tonic-gate }
17450Sstevel@tonic-gate }
17460Sstevel@tonic-gate
17470Sstevel@tonic-gate void
rcmd_db_clean()17480Sstevel@tonic-gate rcmd_db_clean()
17490Sstevel@tonic-gate {
17500Sstevel@tonic-gate rcm_log_message(RCM_DEBUG,
17510Sstevel@tonic-gate "rcm_db_clean(): launch thread to clean database\n");
17520Sstevel@tonic-gate
17530Sstevel@tonic-gate if (thr_create(NULL, NULL, (void *(*)(void *))db_clean,
17540Sstevel@tonic-gate NULL, THR_DETACHED, NULL) != 0) {
17550Sstevel@tonic-gate rcm_log_message(RCM_WARNING,
17560Sstevel@tonic-gate gettext("failed to create cleanup thread %s\n"),
17570Sstevel@tonic-gate strerror(errno));
17580Sstevel@tonic-gate }
17590Sstevel@tonic-gate }
17600Sstevel@tonic-gate
17610Sstevel@tonic-gate /*ARGSUSED*/
17620Sstevel@tonic-gate static int
print_node(rsrc_node_t * node,void * arg)17630Sstevel@tonic-gate print_node(rsrc_node_t *node, void *arg)
17640Sstevel@tonic-gate {
17650Sstevel@tonic-gate client_t *user;
17660Sstevel@tonic-gate
17670Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "rscname: %s, state = 0x%x\n", node->name);
17680Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, " users:\n");
17690Sstevel@tonic-gate
17700Sstevel@tonic-gate if ((user = node->users) == NULL) {
17710Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, " none\n");
17720Sstevel@tonic-gate return (RN_WALK_CONTINUE);
17730Sstevel@tonic-gate }
17740Sstevel@tonic-gate
17750Sstevel@tonic-gate while (user) {
17760Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, " %s, %d, %s\n",
17770Sstevel@tonic-gate user->module->name, user->pid, user->alias);
17780Sstevel@tonic-gate user = user->next;
17790Sstevel@tonic-gate }
17800Sstevel@tonic-gate return (RN_WALK_CONTINUE);
17810Sstevel@tonic-gate }
17820Sstevel@tonic-gate
17830Sstevel@tonic-gate static void
rcmd_db_print()17840Sstevel@tonic-gate rcmd_db_print()
17850Sstevel@tonic-gate {
17860Sstevel@tonic-gate module_t *mod;
17870Sstevel@tonic-gate
17880Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "modules:\n");
17890Sstevel@tonic-gate (void) mutex_lock(&mod_lock);
17900Sstevel@tonic-gate mod = module_head;
17910Sstevel@tonic-gate while (mod) {
17920Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, " %s\n", mod->name);
17930Sstevel@tonic-gate mod = mod->next;
17940Sstevel@tonic-gate }
17950Sstevel@tonic-gate (void) mutex_unlock(&mod_lock);
17960Sstevel@tonic-gate
17970Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "\nresource tree:\n");
17980Sstevel@tonic-gate
17990Sstevel@tonic-gate rsrc_walk(rsrc_root, NULL, print_node);
18000Sstevel@tonic-gate
18010Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "\n");
18020Sstevel@tonic-gate }
18030Sstevel@tonic-gate
18040Sstevel@tonic-gate /*
18050Sstevel@tonic-gate * Allocate handle from calling into each RCM module
18060Sstevel@tonic-gate */
18070Sstevel@tonic-gate static rcm_handle_t *
rcm_handle_alloc(module_t * module)18080Sstevel@tonic-gate rcm_handle_alloc(module_t *module)
18090Sstevel@tonic-gate {
18100Sstevel@tonic-gate rcm_handle_t *hdl;
18110Sstevel@tonic-gate
18120Sstevel@tonic-gate hdl = s_malloc(sizeof (rcm_handle_t));
18130Sstevel@tonic-gate
18140Sstevel@tonic-gate hdl->modname = module->name;
18150Sstevel@tonic-gate hdl->pid = 0;
18160Sstevel@tonic-gate hdl->lrcm_ops = &rcm_ops; /* for callback into daemon directly */
18170Sstevel@tonic-gate hdl->module = module;
18180Sstevel@tonic-gate
18190Sstevel@tonic-gate return (hdl);
18200Sstevel@tonic-gate }
18210Sstevel@tonic-gate
18220Sstevel@tonic-gate /*
18230Sstevel@tonic-gate * Free rcm_handle_t
18240Sstevel@tonic-gate */
18250Sstevel@tonic-gate static void
rcm_handle_free(rcm_handle_t * handle)18260Sstevel@tonic-gate rcm_handle_free(rcm_handle_t *handle)
18270Sstevel@tonic-gate {
18280Sstevel@tonic-gate free(handle);
18290Sstevel@tonic-gate }
18300Sstevel@tonic-gate
18310Sstevel@tonic-gate /*
18320Sstevel@tonic-gate * help function that exit on memory outage
18330Sstevel@tonic-gate */
18340Sstevel@tonic-gate void *
s_malloc(size_t size)18350Sstevel@tonic-gate s_malloc(size_t size)
18360Sstevel@tonic-gate {
18370Sstevel@tonic-gate void *buf = malloc(size);
18380Sstevel@tonic-gate
18390Sstevel@tonic-gate if (buf == NULL) {
18400Sstevel@tonic-gate rcmd_exit(ENOMEM);
18410Sstevel@tonic-gate }
18420Sstevel@tonic-gate return (buf);
18430Sstevel@tonic-gate }
18440Sstevel@tonic-gate
18450Sstevel@tonic-gate void *
s_calloc(int n,size_t size)18460Sstevel@tonic-gate s_calloc(int n, size_t size)
18470Sstevel@tonic-gate {
18480Sstevel@tonic-gate void *buf = calloc(n, size);
18490Sstevel@tonic-gate
18500Sstevel@tonic-gate if (buf == NULL) {
18510Sstevel@tonic-gate rcmd_exit(ENOMEM);
18520Sstevel@tonic-gate }
18530Sstevel@tonic-gate return (buf);
18540Sstevel@tonic-gate }
18550Sstevel@tonic-gate
18560Sstevel@tonic-gate void *
s_realloc(void * ptr,size_t size)18570Sstevel@tonic-gate s_realloc(void *ptr, size_t size)
18580Sstevel@tonic-gate {
18590Sstevel@tonic-gate void *new = realloc(ptr, size);
18600Sstevel@tonic-gate
18610Sstevel@tonic-gate if (new == NULL) {
18620Sstevel@tonic-gate rcmd_exit(ENOMEM);
18630Sstevel@tonic-gate }
18640Sstevel@tonic-gate return (new);
18650Sstevel@tonic-gate }
18660Sstevel@tonic-gate
18670Sstevel@tonic-gate char *
s_strdup(const char * str)18680Sstevel@tonic-gate s_strdup(const char *str)
18690Sstevel@tonic-gate {
18700Sstevel@tonic-gate char *buf = strdup(str);
18710Sstevel@tonic-gate
18720Sstevel@tonic-gate if (buf == NULL) {
18730Sstevel@tonic-gate rcmd_exit(ENOMEM);
18740Sstevel@tonic-gate }
18750Sstevel@tonic-gate return (buf);
18760Sstevel@tonic-gate }
18770Sstevel@tonic-gate
18780Sstevel@tonic-gate /*
18790Sstevel@tonic-gate * Convert a version 1 ops vector to current ops vector
18800Sstevel@tonic-gate * Fields missing in version 1 are set to NULL.
18810Sstevel@tonic-gate */
18820Sstevel@tonic-gate static struct rcm_mod_ops *
modops_from_v1(void * ops_v1)18830Sstevel@tonic-gate modops_from_v1(void *ops_v1)
18840Sstevel@tonic-gate {
18850Sstevel@tonic-gate struct rcm_mod_ops *ops;
18860Sstevel@tonic-gate
18870Sstevel@tonic-gate ops = s_calloc(1, sizeof (struct rcm_mod_ops));
18880Sstevel@tonic-gate bcopy(ops_v1, ops, sizeof (struct rcm_mod_ops_v1));
18890Sstevel@tonic-gate return (ops);
18900Sstevel@tonic-gate }
18910Sstevel@tonic-gate
18920Sstevel@tonic-gate /* call a module's getinfo routine; detects v1 ops and adjusts the call */
18930Sstevel@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)18940Sstevel@tonic-gate call_getinfo(struct rcm_mod_ops *ops, rcm_handle_t *hdl, char *alias, id_t pid,
18950Sstevel@tonic-gate uint_t flag, char **info, char **error, nvlist_t *client_props,
18960Sstevel@tonic-gate rcm_info_t **infop)
18970Sstevel@tonic-gate {
18980Sstevel@tonic-gate int rval;
18990Sstevel@tonic-gate struct rcm_mod_ops_v1 *v1_ops;
19000Sstevel@tonic-gate
19010Sstevel@tonic-gate if (ops->version == RCM_MOD_OPS_V1) {
19020Sstevel@tonic-gate v1_ops = (struct rcm_mod_ops_v1 *)ops;
19030Sstevel@tonic-gate rval = v1_ops->rcmop_get_info(hdl, alias, pid, flag, info,
19040Sstevel@tonic-gate infop);
19050Sstevel@tonic-gate if (rval != RCM_SUCCESS && *info != NULL)
19060Sstevel@tonic-gate *error = strdup(*info);
19070Sstevel@tonic-gate return (rval);
19080Sstevel@tonic-gate } else {
19090Sstevel@tonic-gate return (ops->rcmop_get_info(hdl, alias, pid, flag, info, error,
19100Sstevel@tonic-gate client_props, infop));
19110Sstevel@tonic-gate }
19120Sstevel@tonic-gate }
19130Sstevel@tonic-gate
19140Sstevel@tonic-gate void
rcm_init_queue(rcm_queue_t * head)19150Sstevel@tonic-gate rcm_init_queue(rcm_queue_t *head)
19160Sstevel@tonic-gate {
19170Sstevel@tonic-gate head->next = head->prev = head;
19180Sstevel@tonic-gate }
19190Sstevel@tonic-gate
19200Sstevel@tonic-gate void
rcm_enqueue_head(rcm_queue_t * head,rcm_queue_t * element)19210Sstevel@tonic-gate rcm_enqueue_head(rcm_queue_t *head, rcm_queue_t *element)
19220Sstevel@tonic-gate {
19230Sstevel@tonic-gate rcm_enqueue(head, element);
19240Sstevel@tonic-gate }
19250Sstevel@tonic-gate
19260Sstevel@tonic-gate void
rcm_enqueue_tail(rcm_queue_t * head,rcm_queue_t * element)19270Sstevel@tonic-gate rcm_enqueue_tail(rcm_queue_t *head, rcm_queue_t *element)
19280Sstevel@tonic-gate {
19290Sstevel@tonic-gate rcm_enqueue(head->prev, element);
19300Sstevel@tonic-gate }
19310Sstevel@tonic-gate
19320Sstevel@tonic-gate void
rcm_enqueue(rcm_queue_t * list_element,rcm_queue_t * element)19330Sstevel@tonic-gate rcm_enqueue(rcm_queue_t *list_element, rcm_queue_t *element)
19340Sstevel@tonic-gate {
19350Sstevel@tonic-gate element->next = list_element->next;
19360Sstevel@tonic-gate element->prev = list_element;
19370Sstevel@tonic-gate element->next->prev = element;
19380Sstevel@tonic-gate list_element->next = element;
19390Sstevel@tonic-gate }
19400Sstevel@tonic-gate
19410Sstevel@tonic-gate rcm_queue_t *
rcm_dequeue_head(rcm_queue_t * head)19420Sstevel@tonic-gate rcm_dequeue_head(rcm_queue_t *head)
19430Sstevel@tonic-gate {
19440Sstevel@tonic-gate rcm_queue_t *element = head->next;
19450Sstevel@tonic-gate rcm_dequeue(element);
19460Sstevel@tonic-gate return (element);
19470Sstevel@tonic-gate }
19480Sstevel@tonic-gate
19490Sstevel@tonic-gate rcm_queue_t *
rcm_dequeue_tail(rcm_queue_t * head)19500Sstevel@tonic-gate rcm_dequeue_tail(rcm_queue_t *head)
19510Sstevel@tonic-gate {
19520Sstevel@tonic-gate rcm_queue_t *element = head->prev;
19530Sstevel@tonic-gate rcm_dequeue(element);
19540Sstevel@tonic-gate return (element);
19550Sstevel@tonic-gate }
19560Sstevel@tonic-gate
19570Sstevel@tonic-gate void
rcm_dequeue(rcm_queue_t * element)19580Sstevel@tonic-gate rcm_dequeue(rcm_queue_t *element)
19590Sstevel@tonic-gate {
19600Sstevel@tonic-gate element->prev->next = element->next;
19610Sstevel@tonic-gate element->next->prev = element->prev;
19620Sstevel@tonic-gate element->next = element->prev = NULL;
19630Sstevel@tonic-gate }
1964