xref: /onnv-gate/usr/src/uts/common/fs/dev/sdev_comm.c (revision 6997:056043f166c6)
12621Sllai1 /*
22621Sllai1  * CDDL HEADER START
32621Sllai1  *
42621Sllai1  * The contents of this file are subject to the terms of the
52621Sllai1  * Common Development and Distribution License (the "License").
62621Sllai1  * You may not use this file except in compliance with the License.
72621Sllai1  *
82621Sllai1  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92621Sllai1  * or http://www.opensolaris.org/os/licensing.
102621Sllai1  * See the License for the specific language governing permissions
112621Sllai1  * and limitations under the License.
122621Sllai1  *
132621Sllai1  * When distributing Covered Code, include this CDDL HEADER in each
142621Sllai1  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152621Sllai1  * If applicable, add the following below this CDDL HEADER, with the
162621Sllai1  * fields enclosed by brackets "[]" replaced with your own identifying
172621Sllai1  * information: Portions Copyright [yyyy] [name of copyright owner]
182621Sllai1  *
192621Sllai1  * CDDL HEADER END
202621Sllai1  */
212621Sllai1 /*
22*6997Sjwadams  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
232621Sllai1  * Use is subject to license terms.
242621Sllai1  */
252621Sllai1 
262621Sllai1 #pragma ident	"%Z%%M%	%I%	%E% SMI"
272621Sllai1 
282621Sllai1 /*
292621Sllai1  * routines to invoke user level name lookup services
302621Sllai1  */
312621Sllai1 
322621Sllai1 #include <sys/types.h>
332621Sllai1 #include <sys/param.h>
342621Sllai1 #include <sys/t_lock.h>
352621Sllai1 #include <sys/systm.h>
362621Sllai1 #include <sys/sysmacros.h>
372621Sllai1 #include <sys/user.h>
382621Sllai1 #include <sys/time.h>
392621Sllai1 #include <sys/vfs.h>
402621Sllai1 #include <sys/vnode.h>
412621Sllai1 #include <sys/file.h>
422621Sllai1 #include <sys/fcntl.h>
432621Sllai1 #include <sys/flock.h>
442621Sllai1 #include <sys/kmem.h>
452621Sllai1 #include <sys/uio.h>
462621Sllai1 #include <sys/errno.h>
472621Sllai1 #include <sys/stat.h>
482621Sllai1 #include <sys/cred.h>
492621Sllai1 #include <sys/dirent.h>
502621Sllai1 #include <sys/pathname.h>
512621Sllai1 #include <sys/cmn_err.h>
522621Sllai1 #include <sys/debug.h>
532621Sllai1 #include <sys/mode.h>
542621Sllai1 #include <sys/policy.h>
552621Sllai1 #include <sys/disp.h>
562621Sllai1 #include <sys/door.h>
572621Sllai1 #include <fs/fs_subr.h>
582621Sllai1 #include <sys/mount.h>
592621Sllai1 #include <sys/fs/snode.h>
602621Sllai1 #include <sys/fs/dv_node.h>
612621Sllai1 #include <sys/fs/sdev_impl.h>
622621Sllai1 #include <sys/fs/sdev_node.h>
632621Sllai1 #include <sys/sunndi.h>
642621Sllai1 #include <sys/sunddi.h>
652621Sllai1 #include <sys/sunmdi.h>
662621Sllai1 #include <sys/conf.h>
672621Sllai1 #include <sys/modctl.h>
682621Sllai1 #include <sys/ddi.h>
692621Sllai1 
702621Sllai1 /* default timeout to wait for devfsadm response in seconds */
712621Sllai1 #define	DEV_DEVFSADM_STARTUP	(1 * 60)
722621Sllai1 #define	DEV_NODE_WAIT_TIMEOUT	(5 * 60)
732621Sllai1 
742621Sllai1 /* atomic bitset for devfsadm status */
752621Sllai1 volatile uint_t devfsadm_state;
762621Sllai1 
772621Sllai1 static kmutex_t devfsadm_lock;
782621Sllai1 static kcondvar_t devfsadm_cv;
792621Sllai1 
802621Sllai1 int devname_nsmaps_loaded = 0;
812621Sllai1 static int dev_node_wait_timeout = DEV_NODE_WAIT_TIMEOUT;
822621Sllai1 static int dev_devfsadm_startup =  DEV_DEVFSADM_STARTUP;
832621Sllai1 
842621Sllai1 /*
852621Sllai1  * Door used to communicate with devfsadmd
862621Sllai1  */
872621Sllai1 static door_handle_t	sdev_upcall_door = NULL;	/* Door for upcalls */
882621Sllai1 static char		*sdev_door_upcall_filename = NULL;
892621Sllai1 static int		sdev_upcall_door_revoked = 0;
902621Sllai1 static int		sdev_door_upcall_filename_size;
912621Sllai1 
922621Sllai1 static void sdev_devfsadmd_nsrdr(sdev_nsrdr_work_t *);
932621Sllai1 static int sdev_devfsadm_revoked(void);
942621Sllai1 static int sdev_ki_call_devfsadmd(sdev_door_arg_t *, sdev_door_res_t *);
952621Sllai1 
962621Sllai1 /*
972621Sllai1  * nsmap_readdir processing thread
982621Sllai1  */
992621Sllai1 static uint_t			sdev_nsrdr_thread_created = 0;
1002621Sllai1 static kmutex_t			sdev_nsrdr_thread_lock;
1012621Sllai1 static kcondvar_t		sdev_nsrdr_thread_cv;
1022621Sllai1 static sdev_nsrdr_work_t	*sdev_nsrdr_thread_workq = NULL;
1032621Sllai1 static sdev_nsrdr_work_t	*sdev_nsrdr_thread_tail = NULL;
1042621Sllai1 
1052621Sllai1 void
1062621Sllai1 sdev_devfsadm_lockinit(void)
1072621Sllai1 {
1082621Sllai1 	mutex_init(&devfsadm_lock, NULL, MUTEX_DEFAULT, NULL);
1092621Sllai1 	cv_init(&devfsadm_cv, NULL, CV_DEFAULT, NULL);
1102621Sllai1 }
1112621Sllai1 
1122621Sllai1 void
1132621Sllai1 sdev_devfsadm_lockdestroy(void)
1142621Sllai1 {
1152621Sllai1 	mutex_destroy(&devfsadm_lock);
1162621Sllai1 	cv_destroy(&devfsadm_cv);
1172621Sllai1 }
1182621Sllai1 
1192621Sllai1 /*
1202621Sllai1  * Wait for node to be created
1212621Sllai1  */
1222621Sllai1 int
1232621Sllai1 sdev_wait4lookup(struct sdev_node *dv, int cmd)
1242621Sllai1 {
1252621Sllai1 	clock_t	expire;
1262621Sllai1 	clock_t rv;
1272621Sllai1 	int rval = ENOENT;
1282621Sllai1 	int is_lookup = (cmd == SDEV_LOOKUP);
1292621Sllai1 
1302621Sllai1 	ASSERT(cmd == SDEV_LOOKUP || cmd == SDEV_READDIR);
1312621Sllai1 	ASSERT(MUTEX_HELD(&dv->sdev_lookup_lock));
1322621Sllai1 
1332621Sllai1 	/* tick value at which wait expires */
1342621Sllai1 	expire = ddi_get_lbolt() +
1352621Sllai1 	    drv_usectohz(dev_node_wait_timeout * 1000000);
1362621Sllai1 
1372621Sllai1 	sdcmn_err6(("wait4lookup %s %s, %ld %d\n",
1382621Sllai1 	    is_lookup ? "lookup" : "readdir",
1392621Sllai1 	    dv->sdev_name, expire - ddi_get_lbolt(), dv->sdev_state));
1402621Sllai1 
1412621Sllai1 	if (SDEV_IS_LGWAITING(dv)) {
1422621Sllai1 		/* devfsadm nodes */
1432621Sllai1 		while (DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state) &&
1442621Sllai1 		    !sdev_devfsadm_revoked()) {
1452621Sllai1 			/* wait 2 sec and check devfsadm completion */
1462621Sllai1 			rv = cv_timedwait_sig(&dv->sdev_lookup_cv,
1472621Sllai1 			    &dv->sdev_lookup_lock, ddi_get_lbolt() +
1482621Sllai1 			    drv_usectohz(2 * 1000000));
1492621Sllai1 
1502621Sllai1 			if (is_lookup && (rv > 0)) {
1512621Sllai1 				/* was this node constructed ? */
1522621Sllai1 				if (dv->sdev_state == SDEV_READY) {
1532621Sllai1 					rval = 0;
1542621Sllai1 				}
1552621Sllai1 				sdcmn_err6(("%s: wait done, %screated %d\n",
1562621Sllai1 				    dv->sdev_name, rval ? "not " : "",
1572621Sllai1 				    dv->sdev_state));
1582621Sllai1 				break;
1592621Sllai1 			} else if (rv == 0) {
1602621Sllai1 				/* interrupted */
1612621Sllai1 				sdcmn_err6(("%s: wait interrupted\n",
1622621Sllai1 				    dv->sdev_name));
1632621Sllai1 				break;
1642621Sllai1 			} else if ((rv == -1) &&
1652621Sllai1 			    (ddi_get_lbolt() >= expire)) {
1662621Sllai1 				sdcmn_err6(("%s: wait time is up\n",
1672621Sllai1 					dv->sdev_name));
1682621Sllai1 				break;
1692621Sllai1 			}
1702621Sllai1 			sdcmn_err6(("%s: wait "
1712621Sllai1 			    "rv %ld state 0x%x expire %ld\n",
1722621Sllai1 			    dv->sdev_name, rv, devfsadm_state,
1732621Sllai1 			    expire - ddi_get_lbolt()));
1742621Sllai1 		}
1752621Sllai1 	} else {
1762621Sllai1 		/*
1772621Sllai1 		 * for the nodes created by
1782621Sllai1 		 * devname_lookup_func callback
1792621Sllai1 		 * or plug-in modules
1802621Sllai1 		 */
1812621Sllai1 		while (SDEV_IS_LOOKUP(dv) || SDEV_IS_READDIR(dv)) {
1822621Sllai1 			cv_wait(&dv->sdev_lookup_cv, &dv->sdev_lookup_lock);
1832621Sllai1 		}
1842621Sllai1 		rval = 0;
1852621Sllai1 	}
1862621Sllai1 
1872621Sllai1 	sdcmn_err6(("wait4lookup unblocking %s state 0x%x %d\n",
1882621Sllai1 	    dv->sdev_name, devfsadm_state, dv->sdev_state));
1892621Sllai1 
1902621Sllai1 	if (is_lookup) {
1912621Sllai1 		SDEV_UNBLOCK_OTHERS(dv, SDEV_LOOKUP);
1922621Sllai1 	} else {
1932621Sllai1 		SDEV_UNBLOCK_OTHERS(dv, SDEV_READDIR);
1942621Sllai1 	}
1952621Sllai1 
1962621Sllai1 	return (rval);
1972621Sllai1 }
1982621Sllai1 
1992621Sllai1 void
2002621Sllai1 sdev_unblock_others(struct sdev_node *dv, uint_t cmd)
2012621Sllai1 {
2022621Sllai1 	ASSERT(MUTEX_HELD(&dv->sdev_lookup_lock));
2032621Sllai1 
2042621Sllai1 	SDEV_CLEAR_LOOKUP_FLAGS(dv, cmd);
2052621Sllai1 	if (SDEV_IS_LGWAITING(dv)) {
2062621Sllai1 		SDEV_CLEAR_LOOKUP_FLAGS(dv, SDEV_LGWAITING);
2072621Sllai1 	}
2082621Sllai1 	cv_broadcast(&dv->sdev_lookup_cv);
2092621Sllai1 }
2102621Sllai1 
2112621Sllai1 /*
2122621Sllai1  * In the case devfsadmd is down, it is re-started by syseventd
2132621Sllai1  * upon receiving an event subscribed to by devfsadmd.
2142621Sllai1  */
2152621Sllai1 static int
2162621Sllai1 sdev_start_devfsadmd()
2172621Sllai1 {
2182621Sllai1 	int		se_err = 0;
2192621Sllai1 	sysevent_t	*ev;
2202621Sllai1 	sysevent_id_t	eid;
2212621Sllai1 
2222621Sllai1 	ev = sysevent_alloc(EC_DEVFS, ESC_DEVFS_START, EP_DDI, SE_SLEEP);
2232621Sllai1 	ASSERT(ev);
2242621Sllai1 	if ((se_err = log_sysevent(ev, SE_SLEEP, &eid)) != 0) {
2252621Sllai1 		switch (se_err) {
2262621Sllai1 		case SE_NO_TRANSPORT:
2272621Sllai1 			cmn_err(CE_WARN, "unable to start devfsadm - "
2282621Sllai1 			    "syseventd may not be responding\n");
2292621Sllai1 			break;
2302621Sllai1 		default:
2312621Sllai1 			cmn_err(CE_WARN, "unable to start devfsadm - "
2322621Sllai1 			    "sysevent error %d\n", se_err);
2332621Sllai1 			break;
2342621Sllai1 		}
2352621Sllai1 	}
2362621Sllai1 
2372621Sllai1 	sysevent_free(ev);
2382621Sllai1 	return (se_err);
2392621Sllai1 }
2402621Sllai1 
2412621Sllai1 static int
2422621Sllai1 sdev_open_upcall_door()
2432621Sllai1 {
2442621Sllai1 	int error;
2452621Sllai1 	clock_t rv;
2462621Sllai1 	clock_t expire;
2472621Sllai1 
2482621Sllai1 	ASSERT(sdev_upcall_door == NULL);
2492621Sllai1 
2502621Sllai1 	/* tick value at which wait expires */
2512621Sllai1 	expire = ddi_get_lbolt() +
2522621Sllai1 	    drv_usectohz(dev_devfsadm_startup * 1000000);
2532621Sllai1 
2542621Sllai1 	if (sdev_door_upcall_filename == NULL) {
2552621Sllai1 		if ((error = sdev_start_devfsadmd()) != 0) {
2562621Sllai1 			return (error);
2572621Sllai1 		}
2582621Sllai1 
2592621Sllai1 		/* wait for devfsadmd start */
2602621Sllai1 		mutex_enter(&devfsadm_lock);
2612621Sllai1 		while (sdev_door_upcall_filename == NULL) {
2622621Sllai1 			sdcmn_err6(("waiting for dev_door creation, %ld\n",
2632621Sllai1 			    expire - ddi_get_lbolt()));
2642621Sllai1 			rv = cv_timedwait_sig(&devfsadm_cv, &devfsadm_lock,
2652621Sllai1 			    expire);
2662621Sllai1 			sdcmn_err6(("dev_door wait rv %ld\n", rv));
2672621Sllai1 			if (rv <= 0) {
2682621Sllai1 				sdcmn_err6(("devfsadmd startup error\n"));
2692621Sllai1 				mutex_exit(&devfsadm_lock);
2702621Sllai1 				return (EBADF);
2712621Sllai1 			}
2722621Sllai1 		}
2732621Sllai1 		sdcmn_err6(("devfsadmd is ready\n"));
2742621Sllai1 		mutex_exit(&devfsadm_lock);
2752621Sllai1 	}
2762621Sllai1 
2772621Sllai1 	if ((error = door_ki_open(sdev_door_upcall_filename,
2782621Sllai1 	    &sdev_upcall_door)) != 0) {
2792621Sllai1 		sdcmn_err6(("upcall_lookup: door open error %d\n",
2802621Sllai1 		    error));
2812621Sllai1 		return (error);
2822621Sllai1 	}
2832621Sllai1 
2842621Sllai1 	return (0);
2852621Sllai1 }
2862621Sllai1 
2872621Sllai1 static void
2882621Sllai1 sdev_release_door()
2892621Sllai1 {
2902621Sllai1 	if (sdev_upcall_door) {
2912621Sllai1 		door_ki_rele(sdev_upcall_door);
2922621Sllai1 		sdev_upcall_door = NULL;
2932621Sllai1 	}
2942621Sllai1 	if (sdev_door_upcall_filename) {
2952621Sllai1 		kmem_free(sdev_door_upcall_filename,
2962621Sllai1 		    sdev_door_upcall_filename_size);
2972621Sllai1 		sdev_door_upcall_filename = NULL;
2982621Sllai1 	}
2992621Sllai1 }
3002621Sllai1 
3012621Sllai1 static int
3022621Sllai1 sdev_ki_call_devfsadmd(sdev_door_arg_t *argp, sdev_door_res_t *resultp)
3032621Sllai1 {
3042621Sllai1 	door_arg_t	darg, save_arg;
3052621Sllai1 	int		error;
3062621Sllai1 	int		retry;
3072621Sllai1 
3082621Sllai1 	if (((sdev_upcall_door == NULL) &&
3092621Sllai1 	    ((error = sdev_open_upcall_door()) != 0)) ||
3102621Sllai1 	    sdev_devfsadm_revoked()) {
3112621Sllai1 		sdcmn_err6(("call_devfsadm: upcall lookup error\n"));
3122621Sllai1 		return (error);
3132621Sllai1 	}
3142621Sllai1 
3152621Sllai1 	ASSERT(argp);
3162621Sllai1 	darg.data_ptr = (char *)argp;
3172621Sllai1 	darg.data_size = sizeof (struct sdev_door_arg);
3182621Sllai1 	darg.desc_ptr = NULL;
3192621Sllai1 	darg.desc_num = 0;
3202621Sllai1 	darg.rbuf = (char *)(resultp);
3212621Sllai1 	darg.rsize = sizeof (struct sdev_door_res);
3222621Sllai1 
3232621Sllai1 	ASSERT(sdev_upcall_door);
3242621Sllai1 	save_arg = darg;
3252621Sllai1 	for (retry = 0; ; retry++) {
3262621Sllai1 		sdcmn_err6(("call devfsadm: upcall lookup, retry %d\n", retry));
327*6997Sjwadams 		if ((error = door_ki_upcall_limited(sdev_upcall_door, &darg,
328*6997Sjwadams 		    NULL, SIZE_MAX, 0)) == 0) {
3292621Sllai1 			sdcmn_err6(("call devfsadm: upcall lookup ok\n"));
3302621Sllai1 			break;
3312621Sllai1 		}
3322621Sllai1 
3332621Sllai1 		/*
3342621Sllai1 		 * handle door call errors
3352621Sllai1 		 */
3362621Sllai1 		if (sdev_devfsadm_revoked()) {
3372621Sllai1 			sdcmn_err6(("upcall lookup door revoked, "
3382621Sllai1 			    "error %d\n", error));
3392621Sllai1 			return (error);
3402621Sllai1 		}
3412621Sllai1 
3422621Sllai1 		switch (error) {
3432621Sllai1 		case EINTR:
3442621Sllai1 			/* return error here? */
3452621Sllai1 			sdcmn_err6(("sdev_ki_call_devfsadm: EINTR\n"));
3462621Sllai1 			delay(hz);
3472621Sllai1 			break;
3482621Sllai1 		case EAGAIN:
3492621Sllai1 			sdcmn_err6(("sdev_ki_call_devfsadm: EAGAIN\n"));
3502621Sllai1 			delay(2 * hz);
3512621Sllai1 			break;
3522621Sllai1 		case EBADF:
3532621Sllai1 			if (retry > 4) {
3542621Sllai1 				sdcmn_err6(("sdev_ki_call_devfsadm: EBADF\n"));
3552621Sllai1 				return (EBADF);
3562621Sllai1 			}
3572621Sllai1 			sdcmn_err6((
3582621Sllai1 			    "sdev_ki_call_devfsadm: EBADF, re-binding\n"));
3592621Sllai1 			sdev_release_door();
3602621Sllai1 			delay(retry * hz);
3612621Sllai1 			error = sdev_open_upcall_door();
3622621Sllai1 			if (error != 0) {
3632621Sllai1 				sdcmn_err6(("sdev_ki_call_devfsadm: "
3642621Sllai1 				    "EBADF lookup error %d\n", error));
3652621Sllai1 				if (!sdev_devfsadm_revoked())
3662621Sllai1 					cmn_err(CE_NOTE,
3672621Sllai1 					    "?unable to invoke devfsadm - "
3682621Sllai1 					    "please run manually\n");
3692621Sllai1 				return (EBADF);
3702621Sllai1 			}
3712621Sllai1 			break;
3722621Sllai1 		case EINVAL:
3732621Sllai1 		default:
3742621Sllai1 			cmn_err(CE_CONT,
3752621Sllai1 			    "?sdev: door_ki_upcall unexpected result %d\n",
3762621Sllai1 			    error);
3772621Sllai1 			return (error);
3782621Sllai1 		}
3792621Sllai1 
3802621Sllai1 		darg = save_arg;
3812621Sllai1 	}
3822621Sllai1 
3832621Sllai1 	if (!error) {
3843133Sjg 		ASSERT((struct sdev_door_res *)(intptr_t)darg.rbuf == resultp);
3852621Sllai1 		if (resultp->devfsadm_error != 0) {
3862621Sllai1 			sdcmn_err6(("sdev_ki_call_devfsadmd: result %d\n",
3872621Sllai1 			    resultp->devfsadm_error));
3882621Sllai1 			error = resultp->devfsadm_error;
3892621Sllai1 		}
3902621Sllai1 	} else {
3912621Sllai1 		sdcmn_err6(("sdev_ki_call_devfsadmd with error %d\n", error));
3922621Sllai1 	}
3932621Sllai1 
3942621Sllai1 	return (error);
3952621Sllai1 }
3962621Sllai1 
3972621Sllai1 static int
3982621Sllai1 sdev_devfsadm_revoked(void)
3992621Sllai1 {
4002621Sllai1 	struct door_info info;
4012621Sllai1 	int rv;
4022621Sllai1 	extern int sys_shutdown;
4032621Sllai1 
4042621Sllai1 	if (sys_shutdown) {
4052621Sllai1 		sdcmn_err6(("dev: shutdown observed\n"));
4062621Sllai1 		return (1);
4072621Sllai1 	}
4082621Sllai1 
4092621Sllai1 	if (sdev_upcall_door && !sdev_upcall_door_revoked) {
4102621Sllai1 		rv = door_ki_info(sdev_upcall_door, &info);
4112621Sllai1 		if ((rv == 0) && info.di_attributes & DOOR_REVOKED) {
4122621Sllai1 			sdcmn_err6(("lookup door: revoked\n"));
4132621Sllai1 			sdev_upcall_door_revoked = 1;
4142621Sllai1 		}
4152621Sllai1 	}
4162621Sllai1 
4172621Sllai1 	return (sdev_upcall_door_revoked);
4182621Sllai1 }
4192621Sllai1 
4202621Sllai1 /*ARGSUSED*/
4212621Sllai1 static void
4222621Sllai1 sdev_config_all_thread(struct sdev_node *dv)
4232621Sllai1 {
4242621Sllai1 	int32_t error = 0;
4252621Sllai1 	sdev_door_arg_t	*argp;
4262621Sllai1 	sdev_door_res_t result;
4272621Sllai1 
4282621Sllai1 	argp = kmem_zalloc(sizeof (sdev_door_arg_t), KM_SLEEP);
4292621Sllai1 	argp->devfsadm_cmd = DEVFSADMD_RUN_ALL;
4302621Sllai1 
4312621Sllai1 	error = sdev_ki_call_devfsadmd(argp, &result);
4322621Sllai1 	if (!error) {
4332621Sllai1 		sdcmn_err6(("devfsadm result error: %d\n",
4342621Sllai1 		    result.devfsadm_error));
4352621Sllai1 		if (!result.devfsadm_error) {
4362621Sllai1 			DEVNAME_DEVFSADM_SET_RUN(devfsadm_state);
4372621Sllai1 		} else {
4382621Sllai1 			DEVNAME_DEVFSADM_SET_STOP(devfsadm_state);
4392621Sllai1 		}
4402621Sllai1 	} else {
4412621Sllai1 		DEVNAME_DEVFSADM_SET_STOP(devfsadm_state);
4422621Sllai1 	}
4432621Sllai1 
4442621Sllai1 	kmem_free(argp, sizeof (sdev_door_arg_t));
4452621Sllai1 done:
4462621Sllai1 	sdcmn_err6(("sdev_config_all_thread: stopping, devfsadm state 0x%x\n",
4472621Sllai1 	    devfsadm_state));
4482621Sllai1 	thread_exit();
4492621Sllai1 }
4502621Sllai1 
4512621Sllai1 /*
4522621Sllai1  * launch an asynchronous thread to do the devfsadm dev_config_all
4532621Sllai1  */
4542621Sllai1 /*ARGSUSED*/
4552621Sllai1 void
4562621Sllai1 sdev_devfsadmd_thread(struct sdev_node *ddv, struct sdev_node *dv,
4572621Sllai1     struct cred *cred)
4582621Sllai1 {
4592621Sllai1 	ASSERT(i_ddi_io_initialized());
4602621Sllai1 	DEVNAME_DEVFSADM_SET_RUNNING(devfsadm_state);
4612621Sllai1 	(void) thread_create(NULL, 0, sdev_config_all_thread, dv, 0,
4622621Sllai1 	    &p0, TS_RUN, MINCLSYSPRI);
4632621Sllai1 }
4642621Sllai1 
4652621Sllai1 int
4662621Sllai1 devname_filename_register(int cmd, char *name)
4672621Sllai1 {
4682621Sllai1 	int error = 0;
4692621Sllai1 	char *strbuf;
4702621Sllai1 	char *namep;
4712621Sllai1 	int n;
4722621Sllai1 
4732621Sllai1 	ASSERT(cmd == MODDEVNAME_LOOKUPDOOR ||
4742621Sllai1 	    cmd == MODDEVNAME_DEVFSADMNODE);
4752621Sllai1 
4762621Sllai1 	strbuf = kmem_zalloc(MOD_MAXPATH, KM_SLEEP);
4772621Sllai1 
4782621Sllai1 	if (copyinstr(name, strbuf, MOD_MAXPATH, 0)) {
4792621Sllai1 		sdcmn_err6(("error copyin \n"));
4802621Sllai1 		error = EFAULT;
4812621Sllai1 	} else {
4822621Sllai1 		sdcmn_err6(("file %s is registering\n", strbuf));
4832621Sllai1 		switch (cmd) {
4842621Sllai1 		case MODDEVNAME_LOOKUPDOOR:
4852621Sllai1 			/* handling the daemon re-start situations */
4862621Sllai1 			n = strlen(strbuf) + 1;
4872621Sllai1 			namep = i_ddi_strdup(strbuf, KM_SLEEP);
4882621Sllai1 			mutex_enter(&devfsadm_lock);
4892621Sllai1 			sdev_release_door();
4902621Sllai1 			sdev_door_upcall_filename_size = n;
4912621Sllai1 			sdev_door_upcall_filename = namep;
4922621Sllai1 			sdcmn_err6(("size %d file name %s\n",
4932621Sllai1 			    sdev_door_upcall_filename_size,
4942621Sllai1 			    sdev_door_upcall_filename));
4952621Sllai1 			cv_broadcast(&devfsadm_cv);
4962621Sllai1 			mutex_exit(&devfsadm_lock);
4972621Sllai1 			break;
4982621Sllai1 		case MODDEVNAME_DEVFSADMNODE:
4992621Sllai1 			break;
5002621Sllai1 		}
5012621Sllai1 	}
5022621Sllai1 
5032621Sllai1 	kmem_free(strbuf, MOD_MAXPATH);
5042621Sllai1 	return (error);
5052621Sllai1 }
5062621Sllai1 static void
5072621Sllai1 sdev_nsrdr_thread(void)
5082621Sllai1 {
5092621Sllai1 	sdev_nsrdr_work_t *work;
5102621Sllai1 
5112621Sllai1 	for (;;) {
5122621Sllai1 		mutex_enter(&sdev_nsrdr_thread_lock);
5132621Sllai1 		if (sdev_nsrdr_thread_workq == NULL) {
5142621Sllai1 			cv_wait(&sdev_nsrdr_thread_cv, &sdev_nsrdr_thread_lock);
5152621Sllai1 		}
5162621Sllai1 		work = sdev_nsrdr_thread_workq;
5172621Sllai1 		sdev_nsrdr_thread_workq = work->next;
5182621Sllai1 		if (sdev_nsrdr_thread_tail == work)
5192621Sllai1 			sdev_nsrdr_thread_tail = work->next;
5202621Sllai1 		mutex_exit(&sdev_nsrdr_thread_lock);
5212621Sllai1 		sdev_devfsadmd_nsrdr(work);
5222621Sllai1 	}
5232621Sllai1 	/*NOTREACHED*/
5242621Sllai1 }
5252621Sllai1 
5262621Sllai1 int
5272621Sllai1 devname_nsmaps_register(char *nvlbuf, size_t nvlsize)
5282621Sllai1 {
5292621Sllai1 	int error = 0;
5302621Sllai1 	nvlist_t *nvl, *attrs;
5312621Sllai1 	nvpair_t *nvp = NULL;
5322621Sllai1 	nvpair_t *kvp = NULL;
5332621Sllai1 	char *buf;
5342621Sllai1 	char *key;
5352621Sllai1 	char *dirname = NULL;
5362621Sllai1 	char *dirmodule = NULL;
5372621Sllai1 	char *dirmap = NULL;
5382621Sllai1 	char *orig_module;
5392621Sllai1 	char *orig_map;
5402621Sllai1 	int len = 0;
5412621Sllai1 	char *tmpmap;
5422621Sllai1 	int mapcount = 0;
5432621Sllai1 
5442621Sllai1 	buf = kmem_zalloc(nvlsize, KM_SLEEP);
5452621Sllai1 	if ((error = ddi_copyin(nvlbuf, buf, nvlsize, 0)) != 0) {
5462621Sllai1 		kmem_free(buf, nvlsize);
5472621Sllai1 		return (error);
5482621Sllai1 	}
5492621Sllai1 
5502621Sllai1 	ASSERT(buf);
5512621Sllai1 	sdcmn_err6(("devname_nsmaps_register: nsmap buf %p\n", (void *)buf));
5522621Sllai1 	nvl = NULL;
5532621Sllai1 	error = nvlist_unpack(buf, nvlsize, &nvl, KM_SLEEP);
5542621Sllai1 	kmem_free(buf, nvlsize);
5552621Sllai1 	if (error || (nvl == NULL))
5562621Sllai1 		return (error);
5572621Sllai1 
5582621Sllai1 	/* invalidate all the nsmaps */
5592621Sllai1 	mutex_enter(&devname_nsmaps_lock);
5602621Sllai1 	sdev_invalidate_nsmaps();
5612621Sllai1 	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
5622621Sllai1 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
5632621Sllai1 		dirname = nvpair_name(nvp);
5642621Sllai1 		if (dirname == NULL) {
5652621Sllai1 			nvlist_free(nvl);
5662621Sllai1 			mutex_exit(&devname_nsmaps_lock);
5672621Sllai1 			return (-1);
5682621Sllai1 		}
5692621Sllai1 
5702621Sllai1 		sdcmn_err6(("dirname %s\n", dirname));
5712621Sllai1 		(void) nvpair_value_nvlist(nvp, &attrs);
5722621Sllai1 		for (kvp = nvlist_next_nvpair(attrs, NULL); kvp;
5732621Sllai1 		    kvp = nvlist_next_nvpair(attrs, kvp)) {
5742621Sllai1 			key = nvpair_name(kvp);
5752621Sllai1 			sdcmn_err6(("key %s\n", key));
5762621Sllai1 			if (strcmp(key, "module") == 0) {
5772621Sllai1 				(void) nvpair_value_string(kvp, &orig_module);
5782621Sllai1 				sdcmn_err6(("module %s\n", orig_module));
5792621Sllai1 				dirmodule = i_ddi_strdup(orig_module, KM_SLEEP);
5802621Sllai1 				if (strcmp(dirmodule, "devname_null") == 0)
5812621Sllai1 					dirmodule = NULL;
5822621Sllai1 			}
5832621Sllai1 
5842621Sllai1 			if (strcmp(key, "nsconfig") == 0) {
5852621Sllai1 				(void) nvpair_value_string(kvp, &orig_map);
5862621Sllai1 				sdcmn_err6(("dirmap %s\n", orig_map));
5872621Sllai1 				dirmap = i_ddi_strdup(orig_map, KM_SLEEP);
5882621Sllai1 				if (strcmp(dirmap, "devname_null") == 0)
5892621Sllai1 					dirmap = NULL;
5902621Sllai1 				else if (dirmap[0] != '/') {
5912621Sllai1 					len = strlen(dirmap) +
5922621Sllai1 					    strlen(ETC_DEV_DIR) + 2;
5932621Sllai1 					tmpmap = i_ddi_strdup(dirmap, KM_SLEEP);
5942621Sllai1 					(void) snprintf(dirmap, len, "%s/%s",
5952621Sllai1 					    ETC_DEV_DIR, tmpmap);
5962621Sllai1 					kmem_free(tmpmap, strlen(tmpmap) + 1);
5972621Sllai1 				}
5982621Sllai1 			}
5992621Sllai1 		}
6002621Sllai1 
6012621Sllai1 		if (dirmodule == NULL && dirmap == NULL) {
6022621Sllai1 			nvlist_free(nvl);
6032621Sllai1 			mutex_exit(&devname_nsmaps_lock);
6042621Sllai1 			return (-1);
6052621Sllai1 		}
6062621Sllai1 
6072621Sllai1 		sdcmn_err6(("sdev_nsmaps_register: dir %s module %s map %s\n",
6082621Sllai1 		    dirname, dirmodule, dirmap));
6092621Sllai1 		sdev_insert_nsmap(dirname, dirmodule, dirmap);
6102621Sllai1 		mapcount++;
6112621Sllai1 	}
6122621Sllai1 
6132621Sllai1 	if (mapcount > 0)
6142621Sllai1 		devname_nsmaps_loaded = 1;
6152621Sllai1 
6162621Sllai1 	/* clean up obsolete nsmaps */
6172621Sllai1 	sdev_validate_nsmaps();
6182621Sllai1 	mutex_exit(&devname_nsmaps_lock);
6192621Sllai1 	if (nvl)
6202621Sllai1 		nvlist_free(nvl);
6212621Sllai1 
6222621Sllai1 	if (sdev_nsrdr_thread_created) {
6232621Sllai1 		return (0);
6242621Sllai1 	}
6252621Sllai1 
6262621Sllai1 	mutex_init(&sdev_nsrdr_thread_lock, NULL, MUTEX_DEFAULT, NULL);
6272621Sllai1 	cv_init(&sdev_nsrdr_thread_cv, NULL, CV_DEFAULT, NULL);
6282621Sllai1 	(void) thread_create(NULL, 0, (void (*)())sdev_nsrdr_thread, NULL, 0,
6292621Sllai1 	    &p0, TS_RUN, minclsyspri);
6302621Sllai1 	sdev_nsrdr_thread_created = 1;
6312621Sllai1 
6322621Sllai1 	return (0);
6332621Sllai1 }
6342621Sllai1 
6352621Sllai1 void
6362621Sllai1 sdev_dispatch_to_nsrdr_thread(struct sdev_node *ddv, char *dir_map,
6372621Sllai1     devname_rdr_result_t *result)
6382621Sllai1 {
6392621Sllai1 	sdev_nsrdr_work_t *new_work;
6402621Sllai1 
6412621Sllai1 	new_work = kmem_zalloc(sizeof (sdev_nsrdr_work_t), KM_SLEEP);
6422621Sllai1 	new_work->dir_name = i_ddi_strdup(ddv->sdev_name, KM_SLEEP);
6432621Sllai1 	new_work->dir_map = i_ddi_strdup(dir_map, KM_SLEEP);
6442621Sllai1 	new_work->dir_dv = ddv;
6452621Sllai1 	new_work->result = &result;
6462621Sllai1 	mutex_enter(&sdev_nsrdr_thread_lock);
6472621Sllai1 	if (sdev_nsrdr_thread_workq == NULL) {
6482621Sllai1 		sdev_nsrdr_thread_workq = new_work;
6492621Sllai1 		sdev_nsrdr_thread_tail = new_work;
6502621Sllai1 		new_work->next = NULL;
6512621Sllai1 	} else {
6522621Sllai1 		sdev_nsrdr_thread_tail->next = new_work;
6532621Sllai1 		sdev_nsrdr_thread_tail = new_work;
6542621Sllai1 		new_work->next = NULL;
6552621Sllai1 	}
6562621Sllai1 	cv_signal(&sdev_nsrdr_thread_cv);
6572621Sllai1 	mutex_exit(&sdev_nsrdr_thread_lock);
6582621Sllai1 }
6592621Sllai1 
6602621Sllai1 static void
6612621Sllai1 sdev_devfsadmd_nsrdr(sdev_nsrdr_work_t *work)
6622621Sllai1 {
6632621Sllai1 	int32_t error;
6642621Sllai1 	struct sdev_door_arg *argp;
6652621Sllai1 	struct sdev_door_res res;
6662621Sllai1 	struct sdev_node *ddv = work->dir_dv;
6672621Sllai1 	uint32_t mapcount;
6682621Sllai1 
6692621Sllai1 	argp = kmem_zalloc(sizeof (sdev_door_arg_t), KM_SLEEP);
6702621Sllai1 	argp->devfsadm_cmd = DEVFSADMD_NS_READDIR;
6712621Sllai1 
6722621Sllai1 	(void) snprintf(argp->ns_hdl.ns_name,
6732621Sllai1 	    strlen(work->dir_dv->sdev_path) + 1, "%s", work->dir_dv->sdev_path);
6742621Sllai1 	(void) snprintf(argp->ns_hdl.ns_map, strlen(work->dir_map) + 1, "%s",
6752621Sllai1 	    work->dir_map);
6762621Sllai1 
6772621Sllai1 	sdcmn_err6(("sdev_devfsadmd_nsrdr: ns_name %s, ns_map %s\n",
6782621Sllai1 	    argp->ns_hdl.ns_name, argp->ns_hdl.ns_map));
6792621Sllai1 	error = sdev_ki_call_devfsadmd(argp, &res);
6802621Sllai1 	sdcmn_err6(("sdev_devfsadmd_nsrdr error %d\n", error));
6812621Sllai1 	if (error == 0) {
6822621Sllai1 		error = res.devfsadm_error;
6832621Sllai1 		if (error) {
6842621Sllai1 			goto out;
6852621Sllai1 		}
6862621Sllai1 
6872621Sllai1 		mapcount = (uint32_t)res.ns_rdr_hdl.ns_mapcount;
6882621Sllai1 		sdcmn_err6(("nsmapcount %d\n", mapcount));
6892621Sllai1 		if (mapcount > 0) {
6902621Sllai1 			struct devname_nsmap *map =
6912621Sllai1 			    ddv->sdev_mapinfo;
6922621Sllai1 			ASSERT(map && map->dir_map);
6932621Sllai1 			rw_enter(&map->dir_lock, RW_WRITER);
6942621Sllai1 			map->dir_maploaded = 1;
6952621Sllai1 			rw_exit(&map->dir_lock);
6962621Sllai1 		}
6972621Sllai1 	}
6982621Sllai1 
6992621Sllai1 out:
7002621Sllai1 	mutex_enter(&ddv->sdev_lookup_lock);
7012621Sllai1 	SDEV_UNBLOCK_OTHERS(ddv, SDEV_READDIR);
7022621Sllai1 	mutex_exit(&ddv->sdev_lookup_lock);
7032621Sllai1 
7042621Sllai1 	kmem_free(argp, sizeof (sdev_door_arg_t));
7052621Sllai1 }
7062621Sllai1 
7072621Sllai1 
7082621Sllai1 int
7092621Sllai1 devname_nsmap_lookup(devname_lkp_arg_t *args, devname_lkp_result_t **result)
7102621Sllai1 {
7112621Sllai1 	int32_t error = 0;
7122621Sllai1 	struct sdev_door_arg *argp;
7132621Sllai1 	struct sdev_door_res resp;
7142621Sllai1 	char *link;
7153133Sjg 	devname_spec_t spec;
7162621Sllai1 
7172621Sllai1 	argp = kmem_zalloc(sizeof (sdev_door_arg_t), KM_SLEEP);
7182621Sllai1 	argp->devfsadm_cmd = DEVFSADMD_NS_LOOKUP;
7192621Sllai1 
7202621Sllai1 	(void) snprintf(argp->ns_hdl.ns_name, strlen(args->devname_name) + 1,
7212621Sllai1 	    "%s", args->devname_name);
7222621Sllai1 	(void) snprintf(argp->ns_hdl.ns_map, strlen(args->devname_map) + 1,
7232621Sllai1 	    "%s", args->devname_map);
7242621Sllai1 
7252621Sllai1 	error = sdev_ki_call_devfsadmd(argp, &resp);
7262621Sllai1 	if (error == 0) {
7272621Sllai1 		error = resp.devfsadm_error;
7282621Sllai1 		sdcmn_err6(("devfsadm: error %d\n", error));
7292621Sllai1 		if (error) {
7302621Sllai1 			goto done;
7312621Sllai1 		}
7322621Sllai1 		link = resp.ns_lkp_hdl.devfsadm_link;
7332621Sllai1 		if (link == NULL) {
7342621Sllai1 			error = ENOENT;
7352621Sllai1 			goto done;
7362621Sllai1 		}
7372621Sllai1 		spec = resp.ns_lkp_hdl.devfsadm_spec;
7383133Sjg 		sdcmn_err6(("devfsadm_link %s spec %d\n",
7393133Sjg 		    link, (int)spec));
7402621Sllai1 
7412621Sllai1 
7422621Sllai1 		(*result)->devname_spec = (devname_spec_t)spec;
7432621Sllai1 		(*result)->devname_link = i_ddi_strdup(link, KM_SLEEP);
7442621Sllai1 	} else {
7452621Sllai1 		(*result)->devname_spec = DEVNAME_NS_NONE;
7462621Sllai1 		(*result)->devname_link = NULL;
7472621Sllai1 	}
7482621Sllai1 done:
7492621Sllai1 	kmem_free(argp, sizeof (sdev_door_arg_t));
7502621Sllai1 	return (error);
7512621Sllai1 }
752