diff options
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); +} |