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