diff options
author | llai1 <none@none> | 2006-08-25 17:24:25 -0700 |
---|---|---|
committer | llai1 <none@none> | 2006-08-25 17:24:25 -0700 |
commit | facf4a8d7b59fde89a8662b4f4c73a758e6c402c (patch) | |
tree | 4e0024c5508351006df1496ec4be6e7b564c3ce8 /usr/src/uts/common/fs/dev/sdev_comm.c | |
parent | adcafb0fe4c49c4d46c0b393dfba36d4e1b55c0e (diff) | |
download | illumos-gate-facf4a8d7b59fde89a8662b4f4c73a758e6c402c.tar.gz |
PSARC/2003/246 Filesystem Driven Device Naming
5050715 logical device names not created during early boot
6292952 devfsadm mishandles optarg
6362924 devfsadm secondary link generation is not zones aware
6413127 Integrate the Devname Project
6464196 bfu should remove pt_chmod, obsoleted by /dev filesystem
--HG--
rename : usr/src/cmd/pt_chmod/Makefile => deleted_files/usr/src/cmd/pt_chmod/Makefile
rename : usr/src/cmd/pt_chmod/pt_chmod.c => deleted_files/usr/src/cmd/pt_chmod/pt_chmod.c
Diffstat (limited to 'usr/src/uts/common/fs/dev/sdev_comm.c')
-rw-r--r-- | usr/src/uts/common/fs/dev/sdev_comm.c | 749 |
1 files changed, 749 insertions, 0 deletions
diff --git a/usr/src/uts/common/fs/dev/sdev_comm.c b/usr/src/uts/common/fs/dev/sdev_comm.c new file mode 100644 index 0000000000..d82afffd07 --- /dev/null +++ b/usr/src/uts/common/fs/dev/sdev_comm.c @@ -0,0 +1,749 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * routines to invoke user level name lookup services + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/t_lock.h> +#include <sys/systm.h> +#include <sys/sysmacros.h> +#include <sys/user.h> +#include <sys/time.h> +#include <sys/vfs.h> +#include <sys/vnode.h> +#include <sys/file.h> +#include <sys/fcntl.h> +#include <sys/flock.h> +#include <sys/kmem.h> +#include <sys/uio.h> +#include <sys/errno.h> +#include <sys/stat.h> +#include <sys/cred.h> +#include <sys/dirent.h> +#include <sys/pathname.h> +#include <sys/cmn_err.h> +#include <sys/debug.h> +#include <sys/mode.h> +#include <sys/policy.h> +#include <sys/disp.h> +#include <sys/door.h> +#include <fs/fs_subr.h> +#include <sys/mount.h> +#include <sys/fs/snode.h> +#include <sys/fs/dv_node.h> +#include <sys/fs/sdev_impl.h> +#include <sys/fs/sdev_node.h> +#include <sys/sunndi.h> +#include <sys/sunddi.h> +#include <sys/sunmdi.h> +#include <sys/conf.h> +#include <sys/modctl.h> +#include <sys/ddi.h> + +/* default timeout to wait for devfsadm response in seconds */ +#define DEV_DEVFSADM_STARTUP (1 * 60) +#define DEV_NODE_WAIT_TIMEOUT (5 * 60) + +/* atomic bitset for devfsadm status */ +volatile uint_t devfsadm_state; + +static kmutex_t devfsadm_lock; +static kcondvar_t devfsadm_cv; + +int devname_nsmaps_loaded = 0; +static int dev_node_wait_timeout = DEV_NODE_WAIT_TIMEOUT; +static int dev_devfsadm_startup = DEV_DEVFSADM_STARTUP; + +/* + * Door used to communicate with devfsadmd + */ +static door_handle_t sdev_upcall_door = NULL; /* Door for upcalls */ +static char *sdev_door_upcall_filename = NULL; +static int sdev_upcall_door_revoked = 0; +static int sdev_door_upcall_filename_size; + +static void sdev_devfsadmd_nsrdr(sdev_nsrdr_work_t *); +static int sdev_devfsadm_revoked(void); +static int sdev_ki_call_devfsadmd(sdev_door_arg_t *, sdev_door_res_t *); + +/* + * nsmap_readdir processing thread + */ +static uint_t sdev_nsrdr_thread_created = 0; +static kmutex_t sdev_nsrdr_thread_lock; +static kcondvar_t sdev_nsrdr_thread_cv; +static sdev_nsrdr_work_t *sdev_nsrdr_thread_workq = NULL; +static sdev_nsrdr_work_t *sdev_nsrdr_thread_tail = NULL; + +void +sdev_devfsadm_lockinit(void) +{ + mutex_init(&devfsadm_lock, NULL, MUTEX_DEFAULT, NULL); + cv_init(&devfsadm_cv, NULL, CV_DEFAULT, NULL); +} + +void +sdev_devfsadm_lockdestroy(void) +{ + mutex_destroy(&devfsadm_lock); + cv_destroy(&devfsadm_cv); +} + +/* + * Wait for node to be created + */ +int +sdev_wait4lookup(struct sdev_node *dv, int cmd) +{ + clock_t expire; + clock_t rv; + int rval = ENOENT; + int is_lookup = (cmd == SDEV_LOOKUP); + + ASSERT(cmd == SDEV_LOOKUP || cmd == SDEV_READDIR); + ASSERT(MUTEX_HELD(&dv->sdev_lookup_lock)); + + /* tick value at which wait expires */ + expire = ddi_get_lbolt() + + drv_usectohz(dev_node_wait_timeout * 1000000); + + sdcmn_err6(("wait4lookup %s %s, %ld %d\n", + is_lookup ? "lookup" : "readdir", + dv->sdev_name, expire - ddi_get_lbolt(), dv->sdev_state)); + + if (SDEV_IS_LGWAITING(dv)) { + /* devfsadm nodes */ + while (DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state) && + !sdev_devfsadm_revoked()) { + /* wait 2 sec and check devfsadm completion */ + rv = cv_timedwait_sig(&dv->sdev_lookup_cv, + &dv->sdev_lookup_lock, ddi_get_lbolt() + + drv_usectohz(2 * 1000000)); + + if (is_lookup && (rv > 0)) { + /* was this node constructed ? */ + if (dv->sdev_state == SDEV_READY) { + rval = 0; + } + sdcmn_err6(("%s: wait done, %screated %d\n", + dv->sdev_name, rval ? "not " : "", + dv->sdev_state)); + break; + } else if (rv == 0) { + /* interrupted */ + sdcmn_err6(("%s: wait interrupted\n", + dv->sdev_name)); + break; + } else if ((rv == -1) && + (ddi_get_lbolt() >= expire)) { + sdcmn_err6(("%s: wait time is up\n", + dv->sdev_name)); + break; + } + sdcmn_err6(("%s: wait " + "rv %ld state 0x%x expire %ld\n", + dv->sdev_name, rv, devfsadm_state, + expire - ddi_get_lbolt())); + } + } else { + /* + * for the nodes created by + * devname_lookup_func callback + * or plug-in modules + */ + while (SDEV_IS_LOOKUP(dv) || SDEV_IS_READDIR(dv)) { + cv_wait(&dv->sdev_lookup_cv, &dv->sdev_lookup_lock); + } + rval = 0; + } + + sdcmn_err6(("wait4lookup unblocking %s state 0x%x %d\n", + dv->sdev_name, devfsadm_state, dv->sdev_state)); + + if (is_lookup) { + SDEV_UNBLOCK_OTHERS(dv, SDEV_LOOKUP); + } else { + SDEV_UNBLOCK_OTHERS(dv, SDEV_READDIR); + } + + return (rval); +} + +void +sdev_unblock_others(struct sdev_node *dv, uint_t cmd) +{ + ASSERT(MUTEX_HELD(&dv->sdev_lookup_lock)); + + SDEV_CLEAR_LOOKUP_FLAGS(dv, cmd); + if (SDEV_IS_LGWAITING(dv)) { + SDEV_CLEAR_LOOKUP_FLAGS(dv, SDEV_LGWAITING); + } + cv_broadcast(&dv->sdev_lookup_cv); +} + +/* + * In the case devfsadmd is down, it is re-started by syseventd + * upon receiving an event subscribed to by devfsadmd. + */ +static int +sdev_start_devfsadmd() +{ + int se_err = 0; + sysevent_t *ev; + sysevent_id_t eid; + + ev = sysevent_alloc(EC_DEVFS, ESC_DEVFS_START, EP_DDI, SE_SLEEP); + ASSERT(ev); + if ((se_err = log_sysevent(ev, SE_SLEEP, &eid)) != 0) { + switch (se_err) { + case SE_NO_TRANSPORT: + cmn_err(CE_WARN, "unable to start devfsadm - " + "syseventd may not be responding\n"); + break; + default: + cmn_err(CE_WARN, "unable to start devfsadm - " + "sysevent error %d\n", se_err); + break; + } + } + + sysevent_free(ev); + return (se_err); +} + +static int +sdev_open_upcall_door() +{ + int error; + clock_t rv; + clock_t expire; + + ASSERT(sdev_upcall_door == NULL); + + /* tick value at which wait expires */ + expire = ddi_get_lbolt() + + drv_usectohz(dev_devfsadm_startup * 1000000); + + if (sdev_door_upcall_filename == NULL) { + if ((error = sdev_start_devfsadmd()) != 0) { + return (error); + } + + /* wait for devfsadmd start */ + mutex_enter(&devfsadm_lock); + while (sdev_door_upcall_filename == NULL) { + sdcmn_err6(("waiting for dev_door creation, %ld\n", + expire - ddi_get_lbolt())); + rv = cv_timedwait_sig(&devfsadm_cv, &devfsadm_lock, + expire); + sdcmn_err6(("dev_door wait rv %ld\n", rv)); + if (rv <= 0) { + sdcmn_err6(("devfsadmd startup error\n")); + mutex_exit(&devfsadm_lock); + return (EBADF); + } + } + sdcmn_err6(("devfsadmd is ready\n")); + mutex_exit(&devfsadm_lock); + } + + if ((error = door_ki_open(sdev_door_upcall_filename, + &sdev_upcall_door)) != 0) { + sdcmn_err6(("upcall_lookup: door open error %d\n", + error)); + return (error); + } + + return (0); +} + +static void +sdev_release_door() +{ + if (sdev_upcall_door) { + door_ki_rele(sdev_upcall_door); + sdev_upcall_door = NULL; + } + if (sdev_door_upcall_filename) { + kmem_free(sdev_door_upcall_filename, + sdev_door_upcall_filename_size); + sdev_door_upcall_filename = NULL; + } +} + +static int +sdev_ki_call_devfsadmd(sdev_door_arg_t *argp, sdev_door_res_t *resultp) +{ + door_arg_t darg, save_arg; + int error; + int retry; + + if (((sdev_upcall_door == NULL) && + ((error = sdev_open_upcall_door()) != 0)) || + sdev_devfsadm_revoked()) { + sdcmn_err6(("call_devfsadm: upcall lookup error\n")); + return (error); + } + + ASSERT(argp); + darg.data_ptr = (char *)argp; + darg.data_size = sizeof (struct sdev_door_arg); + darg.desc_ptr = NULL; + darg.desc_num = 0; + darg.rbuf = (char *)(resultp); + darg.rsize = sizeof (struct sdev_door_res); + + ASSERT(sdev_upcall_door); + save_arg = darg; + for (retry = 0; ; retry++) { + sdcmn_err6(("call devfsadm: upcall lookup, retry %d\n", retry)); + if ((error = door_ki_upcall(sdev_upcall_door, &darg)) == 0) { + sdcmn_err6(("call devfsadm: upcall lookup ok\n")); + break; + } + + /* + * handle door call errors + */ + if (sdev_devfsadm_revoked()) { + sdcmn_err6(("upcall lookup door revoked, " + "error %d\n", error)); + return (error); + } + + switch (error) { + case EINTR: + /* return error here? */ + sdcmn_err6(("sdev_ki_call_devfsadm: EINTR\n")); + delay(hz); + break; + case EAGAIN: + sdcmn_err6(("sdev_ki_call_devfsadm: EAGAIN\n")); + delay(2 * hz); + break; + case EBADF: + if (retry > 4) { + sdcmn_err6(("sdev_ki_call_devfsadm: EBADF\n")); + return (EBADF); + } + sdcmn_err6(( + "sdev_ki_call_devfsadm: EBADF, re-binding\n")); + sdev_release_door(); + delay(retry * hz); + error = sdev_open_upcall_door(); + if (error != 0) { + sdcmn_err6(("sdev_ki_call_devfsadm: " + "EBADF lookup error %d\n", error)); + if (!sdev_devfsadm_revoked()) + cmn_err(CE_NOTE, + "?unable to invoke devfsadm - " + "please run manually\n"); + return (EBADF); + } + break; + case EINVAL: + default: + cmn_err(CE_CONT, + "?sdev: door_ki_upcall unexpected result %d\n", + error); + return (error); + } + + darg = save_arg; + } + + if (!error) { + ASSERT((struct sdev_door_res *)darg.rbuf == resultp); + if (resultp->devfsadm_error != 0) { + sdcmn_err6(("sdev_ki_call_devfsadmd: result %d\n", + resultp->devfsadm_error)); + error = resultp->devfsadm_error; + } + } else { + sdcmn_err6(("sdev_ki_call_devfsadmd with error %d\n", error)); + } + + return (error); +} + +static int +sdev_devfsadm_revoked(void) +{ + struct door_info info; + int rv; + extern int sys_shutdown; + + if (sys_shutdown) { + sdcmn_err6(("dev: shutdown observed\n")); + return (1); + } + + if (sdev_upcall_door && !sdev_upcall_door_revoked) { + rv = door_ki_info(sdev_upcall_door, &info); + if ((rv == 0) && info.di_attributes & DOOR_REVOKED) { + sdcmn_err6(("lookup door: revoked\n")); + sdev_upcall_door_revoked = 1; + } + } + + return (sdev_upcall_door_revoked); +} + +/*ARGSUSED*/ +static void +sdev_config_all_thread(struct sdev_node *dv) +{ + int32_t error = 0; + sdev_door_arg_t *argp; + sdev_door_res_t result; + + argp = kmem_zalloc(sizeof (sdev_door_arg_t), KM_SLEEP); + argp->devfsadm_cmd = DEVFSADMD_RUN_ALL; + + error = sdev_ki_call_devfsadmd(argp, &result); + if (!error) { + sdcmn_err6(("devfsadm result error: %d\n", + result.devfsadm_error)); + if (!result.devfsadm_error) { + DEVNAME_DEVFSADM_SET_RUN(devfsadm_state); + } else { + DEVNAME_DEVFSADM_SET_STOP(devfsadm_state); + } + } else { + DEVNAME_DEVFSADM_SET_STOP(devfsadm_state); + } + + kmem_free(argp, sizeof (sdev_door_arg_t)); +done: + sdcmn_err6(("sdev_config_all_thread: stopping, devfsadm state 0x%x\n", + devfsadm_state)); + thread_exit(); +} + +/* + * launch an asynchronous thread to do the devfsadm dev_config_all + */ +/*ARGSUSED*/ +void +sdev_devfsadmd_thread(struct sdev_node *ddv, struct sdev_node *dv, + struct cred *cred) +{ + ASSERT(i_ddi_io_initialized()); + DEVNAME_DEVFSADM_SET_RUNNING(devfsadm_state); + (void) thread_create(NULL, 0, sdev_config_all_thread, dv, 0, + &p0, TS_RUN, MINCLSYSPRI); +} + +int +devname_filename_register(int cmd, char *name) +{ + int error = 0; + char *strbuf; + char *namep; + int n; + + ASSERT(cmd == MODDEVNAME_LOOKUPDOOR || + cmd == MODDEVNAME_DEVFSADMNODE); + + strbuf = kmem_zalloc(MOD_MAXPATH, KM_SLEEP); + + if (copyinstr(name, strbuf, MOD_MAXPATH, 0)) { + sdcmn_err6(("error copyin \n")); + error = EFAULT; + } else { + sdcmn_err6(("file %s is registering\n", strbuf)); + switch (cmd) { + case MODDEVNAME_LOOKUPDOOR: + /* handling the daemon re-start situations */ + n = strlen(strbuf) + 1; + namep = i_ddi_strdup(strbuf, KM_SLEEP); + mutex_enter(&devfsadm_lock); + sdev_release_door(); + sdev_door_upcall_filename_size = n; + sdev_door_upcall_filename = namep; + sdcmn_err6(("size %d file name %s\n", + sdev_door_upcall_filename_size, + sdev_door_upcall_filename)); + cv_broadcast(&devfsadm_cv); + mutex_exit(&devfsadm_lock); + break; + case MODDEVNAME_DEVFSADMNODE: + break; + } + } + + kmem_free(strbuf, MOD_MAXPATH); + return (error); +} +static void +sdev_nsrdr_thread(void) +{ + sdev_nsrdr_work_t *work; + + for (;;) { + mutex_enter(&sdev_nsrdr_thread_lock); + if (sdev_nsrdr_thread_workq == NULL) { + cv_wait(&sdev_nsrdr_thread_cv, &sdev_nsrdr_thread_lock); + } + work = sdev_nsrdr_thread_workq; + sdev_nsrdr_thread_workq = work->next; + if (sdev_nsrdr_thread_tail == work) + sdev_nsrdr_thread_tail = work->next; + mutex_exit(&sdev_nsrdr_thread_lock); + sdev_devfsadmd_nsrdr(work); + } + /*NOTREACHED*/ +} + +int +devname_nsmaps_register(char *nvlbuf, size_t nvlsize) +{ + int error = 0; + nvlist_t *nvl, *attrs; + nvpair_t *nvp = NULL; + nvpair_t *kvp = NULL; + char *buf; + char *key; + char *dirname = NULL; + char *dirmodule = NULL; + char *dirmap = NULL; + char *orig_module; + char *orig_map; + int len = 0; + char *tmpmap; + int mapcount = 0; + + buf = kmem_zalloc(nvlsize, KM_SLEEP); + if ((error = ddi_copyin(nvlbuf, buf, nvlsize, 0)) != 0) { + kmem_free(buf, nvlsize); + return (error); + } + + ASSERT(buf); + sdcmn_err6(("devname_nsmaps_register: nsmap buf %p\n", (void *)buf)); + nvl = NULL; + error = nvlist_unpack(buf, nvlsize, &nvl, KM_SLEEP); + kmem_free(buf, nvlsize); + if (error || (nvl == NULL)) + return (error); + + /* invalidate all the nsmaps */ + mutex_enter(&devname_nsmaps_lock); + sdev_invalidate_nsmaps(); + for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; + nvp = nvlist_next_nvpair(nvl, nvp)) { + dirname = nvpair_name(nvp); + if (dirname == NULL) { + nvlist_free(nvl); + mutex_exit(&devname_nsmaps_lock); + return (-1); + } + + sdcmn_err6(("dirname %s\n", dirname)); + (void) nvpair_value_nvlist(nvp, &attrs); + for (kvp = nvlist_next_nvpair(attrs, NULL); kvp; + kvp = nvlist_next_nvpair(attrs, kvp)) { + key = nvpair_name(kvp); + sdcmn_err6(("key %s\n", key)); + if (strcmp(key, "module") == 0) { + (void) nvpair_value_string(kvp, &orig_module); + sdcmn_err6(("module %s\n", orig_module)); + dirmodule = i_ddi_strdup(orig_module, KM_SLEEP); + if (strcmp(dirmodule, "devname_null") == 0) + dirmodule = NULL; + } + + if (strcmp(key, "nsconfig") == 0) { + (void) nvpair_value_string(kvp, &orig_map); + sdcmn_err6(("dirmap %s\n", orig_map)); + dirmap = i_ddi_strdup(orig_map, KM_SLEEP); + if (strcmp(dirmap, "devname_null") == 0) + dirmap = NULL; + else if (dirmap[0] != '/') { + len = strlen(dirmap) + + strlen(ETC_DEV_DIR) + 2; + tmpmap = i_ddi_strdup(dirmap, KM_SLEEP); + (void) snprintf(dirmap, len, "%s/%s", + ETC_DEV_DIR, tmpmap); + kmem_free(tmpmap, strlen(tmpmap) + 1); + } + } + } + + if (dirmodule == NULL && dirmap == NULL) { + nvlist_free(nvl); + mutex_exit(&devname_nsmaps_lock); + return (-1); + } + + sdcmn_err6(("sdev_nsmaps_register: dir %s module %s map %s\n", + dirname, dirmodule, dirmap)); + sdev_insert_nsmap(dirname, dirmodule, dirmap); + mapcount++; + } + + if (mapcount > 0) + devname_nsmaps_loaded = 1; + + /* clean up obsolete nsmaps */ + sdev_validate_nsmaps(); + mutex_exit(&devname_nsmaps_lock); + if (nvl) + nvlist_free(nvl); + + if (sdev_nsrdr_thread_created) { + return (0); + } + + mutex_init(&sdev_nsrdr_thread_lock, NULL, MUTEX_DEFAULT, NULL); + cv_init(&sdev_nsrdr_thread_cv, NULL, CV_DEFAULT, NULL); + (void) thread_create(NULL, 0, (void (*)())sdev_nsrdr_thread, NULL, 0, + &p0, TS_RUN, minclsyspri); + sdev_nsrdr_thread_created = 1; + + return (0); +} + +void +sdev_dispatch_to_nsrdr_thread(struct sdev_node *ddv, char *dir_map, + devname_rdr_result_t *result) +{ + sdev_nsrdr_work_t *new_work; + + new_work = kmem_zalloc(sizeof (sdev_nsrdr_work_t), KM_SLEEP); + new_work->dir_name = i_ddi_strdup(ddv->sdev_name, KM_SLEEP); + new_work->dir_map = i_ddi_strdup(dir_map, KM_SLEEP); + new_work->dir_dv = ddv; + new_work->result = &result; + mutex_enter(&sdev_nsrdr_thread_lock); + if (sdev_nsrdr_thread_workq == NULL) { + sdev_nsrdr_thread_workq = new_work; + sdev_nsrdr_thread_tail = new_work; + new_work->next = NULL; + } else { + sdev_nsrdr_thread_tail->next = new_work; + sdev_nsrdr_thread_tail = new_work; + new_work->next = NULL; + } + cv_signal(&sdev_nsrdr_thread_cv); + mutex_exit(&sdev_nsrdr_thread_lock); +} + +static void +sdev_devfsadmd_nsrdr(sdev_nsrdr_work_t *work) +{ + int32_t error; + struct sdev_door_arg *argp; + struct sdev_door_res res; + struct sdev_node *ddv = work->dir_dv; + uint32_t mapcount; + + argp = kmem_zalloc(sizeof (sdev_door_arg_t), KM_SLEEP); + argp->devfsadm_cmd = DEVFSADMD_NS_READDIR; + + (void) snprintf(argp->ns_hdl.ns_name, + strlen(work->dir_dv->sdev_path) + 1, "%s", work->dir_dv->sdev_path); + (void) snprintf(argp->ns_hdl.ns_map, strlen(work->dir_map) + 1, "%s", + work->dir_map); + + sdcmn_err6(("sdev_devfsadmd_nsrdr: ns_name %s, ns_map %s\n", + argp->ns_hdl.ns_name, argp->ns_hdl.ns_map)); + error = sdev_ki_call_devfsadmd(argp, &res); + sdcmn_err6(("sdev_devfsadmd_nsrdr error %d\n", error)); + if (error == 0) { + error = res.devfsadm_error; + if (error) { + goto out; + } + + mapcount = (uint32_t)res.ns_rdr_hdl.ns_mapcount; + sdcmn_err6(("nsmapcount %d\n", mapcount)); + if (mapcount > 0) { + struct devname_nsmap *map = + ddv->sdev_mapinfo; + ASSERT(map && map->dir_map); + rw_enter(&map->dir_lock, RW_WRITER); + map->dir_maploaded = 1; + rw_exit(&map->dir_lock); + } + } + +out: + mutex_enter(&ddv->sdev_lookup_lock); + SDEV_UNBLOCK_OTHERS(ddv, SDEV_READDIR); + mutex_exit(&ddv->sdev_lookup_lock); + + kmem_free(argp, sizeof (sdev_door_arg_t)); +} + + +int +devname_nsmap_lookup(devname_lkp_arg_t *args, devname_lkp_result_t **result) +{ + int32_t error = 0; + struct sdev_door_arg *argp; + struct sdev_door_res resp; + char *link; + uint8_t spec; + + argp = kmem_zalloc(sizeof (sdev_door_arg_t), KM_SLEEP); + argp->devfsadm_cmd = DEVFSADMD_NS_LOOKUP; + + (void) snprintf(argp->ns_hdl.ns_name, strlen(args->devname_name) + 1, + "%s", args->devname_name); + (void) snprintf(argp->ns_hdl.ns_map, strlen(args->devname_map) + 1, + "%s", args->devname_map); + + error = sdev_ki_call_devfsadmd(argp, &resp); + if (error == 0) { + error = resp.devfsadm_error; + sdcmn_err6(("devfsadm: error %d\n", error)); + if (error) { + goto done; + } + link = resp.ns_lkp_hdl.devfsadm_link; + if (link == NULL) { + error = ENOENT; + goto done; + } + spec = resp.ns_lkp_hdl.devfsadm_spec; + sdcmn_err6(("devfsadm_link %s spec %d\n", link, spec)); + + + (*result)->devname_spec = (devname_spec_t)spec; + (*result)->devname_link = i_ddi_strdup(link, KM_SLEEP); + } else { + (*result)->devname_spec = DEVNAME_NS_NONE; + (*result)->devname_link = NULL; + } +done: + kmem_free(argp, sizeof (sdev_door_arg_t)); + return (error); +} |