xref: /titanic_51/usr/src/uts/common/fs/dev/sdev_comm.c (revision 672986541be54a7a471bb088e60780c37e371d7e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * routines to invoke user level name lookup services
30  */
31 
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/t_lock.h>
35 #include <sys/systm.h>
36 #include <sys/sysmacros.h>
37 #include <sys/user.h>
38 #include <sys/time.h>
39 #include <sys/vfs.h>
40 #include <sys/vnode.h>
41 #include <sys/file.h>
42 #include <sys/fcntl.h>
43 #include <sys/flock.h>
44 #include <sys/kmem.h>
45 #include <sys/uio.h>
46 #include <sys/errno.h>
47 #include <sys/stat.h>
48 #include <sys/cred.h>
49 #include <sys/dirent.h>
50 #include <sys/pathname.h>
51 #include <sys/cmn_err.h>
52 #include <sys/debug.h>
53 #include <sys/mode.h>
54 #include <sys/policy.h>
55 #include <sys/disp.h>
56 #include <sys/door.h>
57 #include <fs/fs_subr.h>
58 #include <sys/mount.h>
59 #include <sys/fs/snode.h>
60 #include <sys/fs/dv_node.h>
61 #include <sys/fs/sdev_impl.h>
62 #include <sys/fs/sdev_node.h>
63 #include <sys/sunndi.h>
64 #include <sys/sunddi.h>
65 #include <sys/sunmdi.h>
66 #include <sys/conf.h>
67 #include <sys/modctl.h>
68 #include <sys/ddi.h>
69 
70 /* default timeout to wait for devfsadm response in seconds */
71 #define	DEV_DEVFSADM_STARTUP	(1 * 60)
72 #define	DEV_NODE_WAIT_TIMEOUT	(5 * 60)
73 
74 /* atomic bitset for devfsadm status */
75 volatile uint_t devfsadm_state;
76 
77 static kmutex_t devfsadm_lock;
78 static kcondvar_t devfsadm_cv;
79 
80 int devname_nsmaps_loaded = 0;
81 static int dev_node_wait_timeout = DEV_NODE_WAIT_TIMEOUT;
82 static int dev_devfsadm_startup =  DEV_DEVFSADM_STARTUP;
83 
84 /*
85  * Door used to communicate with devfsadmd
86  */
87 static door_handle_t	sdev_upcall_door = NULL;	/* Door for upcalls */
88 static char		*sdev_door_upcall_filename = NULL;
89 static int		sdev_upcall_door_revoked = 0;
90 static int		sdev_door_upcall_filename_size;
91 
92 static void sdev_devfsadmd_nsrdr(sdev_nsrdr_work_t *);
93 static int sdev_devfsadm_revoked(void);
94 static int sdev_ki_call_devfsadmd(sdev_door_arg_t *, sdev_door_res_t *);
95 
96 /*
97  * nsmap_readdir processing thread
98  */
99 static uint_t			sdev_nsrdr_thread_created = 0;
100 static kmutex_t			sdev_nsrdr_thread_lock;
101 static kcondvar_t		sdev_nsrdr_thread_cv;
102 static sdev_nsrdr_work_t	*sdev_nsrdr_thread_workq = NULL;
103 static sdev_nsrdr_work_t	*sdev_nsrdr_thread_tail = NULL;
104 
105 void
106 sdev_devfsadm_lockinit(void)
107 {
108 	mutex_init(&devfsadm_lock, NULL, MUTEX_DEFAULT, NULL);
109 	cv_init(&devfsadm_cv, NULL, CV_DEFAULT, NULL);
110 }
111 
112 void
113 sdev_devfsadm_lockdestroy(void)
114 {
115 	mutex_destroy(&devfsadm_lock);
116 	cv_destroy(&devfsadm_cv);
117 }
118 
119 /*
120  * Wait for node to be created
121  */
122 int
123 sdev_wait4lookup(struct sdev_node *dv, int cmd)
124 {
125 	clock_t	expire;
126 	clock_t rv;
127 	int rval = ENOENT;
128 	int is_lookup = (cmd == SDEV_LOOKUP);
129 
130 	ASSERT(cmd == SDEV_LOOKUP || cmd == SDEV_READDIR);
131 	ASSERT(MUTEX_HELD(&dv->sdev_lookup_lock));
132 
133 	/* tick value at which wait expires */
134 	expire = ddi_get_lbolt() +
135 	    drv_usectohz(dev_node_wait_timeout * 1000000);
136 
137 	sdcmn_err6(("wait4lookup %s %s, %ld %d\n",
138 	    is_lookup ? "lookup" : "readdir",
139 	    dv->sdev_name, expire - ddi_get_lbolt(), dv->sdev_state));
140 
141 	if (SDEV_IS_LGWAITING(dv)) {
142 		/* devfsadm nodes */
143 		while (DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state) &&
144 		    !sdev_devfsadm_revoked()) {
145 			/* wait 2 sec and check devfsadm completion */
146 			rv = cv_timedwait_sig(&dv->sdev_lookup_cv,
147 			    &dv->sdev_lookup_lock, ddi_get_lbolt() +
148 			    drv_usectohz(2 * 1000000));
149 
150 			if (is_lookup && (rv > 0)) {
151 				/* was this node constructed ? */
152 				if (dv->sdev_state == SDEV_READY) {
153 					rval = 0;
154 				}
155 				sdcmn_err6(("%s: wait done, %screated %d\n",
156 				    dv->sdev_name, rval ? "not " : "",
157 				    dv->sdev_state));
158 				break;
159 			} else if (rv == 0) {
160 				/* interrupted */
161 				sdcmn_err6(("%s: wait interrupted\n",
162 				    dv->sdev_name));
163 				break;
164 			} else if ((rv == -1) &&
165 			    (ddi_get_lbolt() >= expire)) {
166 				sdcmn_err6(("%s: wait time is up\n",
167 					dv->sdev_name));
168 				break;
169 			}
170 			sdcmn_err6(("%s: wait "
171 			    "rv %ld state 0x%x expire %ld\n",
172 			    dv->sdev_name, rv, devfsadm_state,
173 			    expire - ddi_get_lbolt()));
174 		}
175 	} else {
176 		/*
177 		 * for the nodes created by
178 		 * devname_lookup_func callback
179 		 * or plug-in modules
180 		 */
181 		while (SDEV_IS_LOOKUP(dv) || SDEV_IS_READDIR(dv)) {
182 			cv_wait(&dv->sdev_lookup_cv, &dv->sdev_lookup_lock);
183 		}
184 		rval = 0;
185 	}
186 
187 	sdcmn_err6(("wait4lookup unblocking %s state 0x%x %d\n",
188 	    dv->sdev_name, devfsadm_state, dv->sdev_state));
189 
190 	if (is_lookup) {
191 		SDEV_UNBLOCK_OTHERS(dv, SDEV_LOOKUP);
192 	} else {
193 		SDEV_UNBLOCK_OTHERS(dv, SDEV_READDIR);
194 	}
195 
196 	return (rval);
197 }
198 
199 void
200 sdev_unblock_others(struct sdev_node *dv, uint_t cmd)
201 {
202 	ASSERT(MUTEX_HELD(&dv->sdev_lookup_lock));
203 
204 	SDEV_CLEAR_LOOKUP_FLAGS(dv, cmd);
205 	if (SDEV_IS_LGWAITING(dv)) {
206 		SDEV_CLEAR_LOOKUP_FLAGS(dv, SDEV_LGWAITING);
207 	}
208 	cv_broadcast(&dv->sdev_lookup_cv);
209 }
210 
211 /*
212  * In the case devfsadmd is down, it is re-started by syseventd
213  * upon receiving an event subscribed to by devfsadmd.
214  */
215 static int
216 sdev_start_devfsadmd()
217 {
218 	int		se_err = 0;
219 	sysevent_t	*ev;
220 	sysevent_id_t	eid;
221 
222 	ev = sysevent_alloc(EC_DEVFS, ESC_DEVFS_START, EP_DDI, SE_SLEEP);
223 	ASSERT(ev);
224 	if ((se_err = log_sysevent(ev, SE_SLEEP, &eid)) != 0) {
225 		switch (se_err) {
226 		case SE_NO_TRANSPORT:
227 			cmn_err(CE_WARN, "unable to start devfsadm - "
228 			    "syseventd may not be responding\n");
229 			break;
230 		default:
231 			cmn_err(CE_WARN, "unable to start devfsadm - "
232 			    "sysevent error %d\n", se_err);
233 			break;
234 		}
235 	}
236 
237 	sysevent_free(ev);
238 	return (se_err);
239 }
240 
241 static int
242 sdev_open_upcall_door()
243 {
244 	int error;
245 	clock_t rv;
246 	clock_t expire;
247 
248 	ASSERT(sdev_upcall_door == NULL);
249 
250 	/* tick value at which wait expires */
251 	expire = ddi_get_lbolt() +
252 	    drv_usectohz(dev_devfsadm_startup * 1000000);
253 
254 	if (sdev_door_upcall_filename == NULL) {
255 		if ((error = sdev_start_devfsadmd()) != 0) {
256 			return (error);
257 		}
258 
259 		/* wait for devfsadmd start */
260 		mutex_enter(&devfsadm_lock);
261 		while (sdev_door_upcall_filename == NULL) {
262 			sdcmn_err6(("waiting for dev_door creation, %ld\n",
263 			    expire - ddi_get_lbolt()));
264 			rv = cv_timedwait_sig(&devfsadm_cv, &devfsadm_lock,
265 			    expire);
266 			sdcmn_err6(("dev_door wait rv %ld\n", rv));
267 			if (rv <= 0) {
268 				sdcmn_err6(("devfsadmd startup error\n"));
269 				mutex_exit(&devfsadm_lock);
270 				return (EBADF);
271 			}
272 		}
273 		sdcmn_err6(("devfsadmd is ready\n"));
274 		mutex_exit(&devfsadm_lock);
275 	}
276 
277 	if ((error = door_ki_open(sdev_door_upcall_filename,
278 	    &sdev_upcall_door)) != 0) {
279 		sdcmn_err6(("upcall_lookup: door open error %d\n",
280 		    error));
281 		return (error);
282 	}
283 
284 	return (0);
285 }
286 
287 static void
288 sdev_release_door()
289 {
290 	if (sdev_upcall_door) {
291 		door_ki_rele(sdev_upcall_door);
292 		sdev_upcall_door = NULL;
293 	}
294 	if (sdev_door_upcall_filename) {
295 		kmem_free(sdev_door_upcall_filename,
296 		    sdev_door_upcall_filename_size);
297 		sdev_door_upcall_filename = NULL;
298 	}
299 }
300 
301 static int
302 sdev_ki_call_devfsadmd(sdev_door_arg_t *argp, sdev_door_res_t *resultp)
303 {
304 	door_arg_t	darg, save_arg;
305 	int		error;
306 	int		retry;
307 
308 	if (((sdev_upcall_door == NULL) &&
309 	    ((error = sdev_open_upcall_door()) != 0)) ||
310 	    sdev_devfsadm_revoked()) {
311 		sdcmn_err6(("call_devfsadm: upcall lookup error\n"));
312 		return (error);
313 	}
314 
315 	ASSERT(argp);
316 	darg.data_ptr = (char *)argp;
317 	darg.data_size = sizeof (struct sdev_door_arg);
318 	darg.desc_ptr = NULL;
319 	darg.desc_num = 0;
320 	darg.rbuf = (char *)(resultp);
321 	darg.rsize = sizeof (struct sdev_door_res);
322 
323 	ASSERT(sdev_upcall_door);
324 	save_arg = darg;
325 	for (retry = 0; ; retry++) {
326 		sdcmn_err6(("call devfsadm: upcall lookup, retry %d\n", retry));
327 		if ((error = door_ki_upcall(sdev_upcall_door, &darg)) == 0) {
328 			sdcmn_err6(("call devfsadm: upcall lookup ok\n"));
329 			break;
330 		}
331 
332 		/*
333 		 * handle door call errors
334 		 */
335 		if (sdev_devfsadm_revoked()) {
336 			sdcmn_err6(("upcall lookup door revoked, "
337 			    "error %d\n", error));
338 			return (error);
339 		}
340 
341 		switch (error) {
342 		case EINTR:
343 			/* return error here? */
344 			sdcmn_err6(("sdev_ki_call_devfsadm: EINTR\n"));
345 			delay(hz);
346 			break;
347 		case EAGAIN:
348 			sdcmn_err6(("sdev_ki_call_devfsadm: EAGAIN\n"));
349 			delay(2 * hz);
350 			break;
351 		case EBADF:
352 			if (retry > 4) {
353 				sdcmn_err6(("sdev_ki_call_devfsadm: EBADF\n"));
354 				return (EBADF);
355 			}
356 			sdcmn_err6((
357 			    "sdev_ki_call_devfsadm: EBADF, re-binding\n"));
358 			sdev_release_door();
359 			delay(retry * hz);
360 			error = sdev_open_upcall_door();
361 			if (error != 0) {
362 				sdcmn_err6(("sdev_ki_call_devfsadm: "
363 				    "EBADF lookup error %d\n", error));
364 				if (!sdev_devfsadm_revoked())
365 					cmn_err(CE_NOTE,
366 					    "?unable to invoke devfsadm - "
367 					    "please run manually\n");
368 				return (EBADF);
369 			}
370 			break;
371 		case EINVAL:
372 		default:
373 			cmn_err(CE_CONT,
374 			    "?sdev: door_ki_upcall unexpected result %d\n",
375 			    error);
376 			return (error);
377 		}
378 
379 		darg = save_arg;
380 	}
381 
382 	if (!error) {
383 		ASSERT((struct sdev_door_res *)(intptr_t)darg.rbuf == resultp);
384 		if (resultp->devfsadm_error != 0) {
385 			sdcmn_err6(("sdev_ki_call_devfsadmd: result %d\n",
386 			    resultp->devfsadm_error));
387 			error = resultp->devfsadm_error;
388 		}
389 	} else {
390 		sdcmn_err6(("sdev_ki_call_devfsadmd with error %d\n", error));
391 	}
392 
393 	return (error);
394 }
395 
396 static int
397 sdev_devfsadm_revoked(void)
398 {
399 	struct door_info info;
400 	int rv;
401 	extern int sys_shutdown;
402 
403 	if (sys_shutdown) {
404 		sdcmn_err6(("dev: shutdown observed\n"));
405 		return (1);
406 	}
407 
408 	if (sdev_upcall_door && !sdev_upcall_door_revoked) {
409 		rv = door_ki_info(sdev_upcall_door, &info);
410 		if ((rv == 0) && info.di_attributes & DOOR_REVOKED) {
411 			sdcmn_err6(("lookup door: revoked\n"));
412 			sdev_upcall_door_revoked = 1;
413 		}
414 	}
415 
416 	return (sdev_upcall_door_revoked);
417 }
418 
419 /*ARGSUSED*/
420 static void
421 sdev_config_all_thread(struct sdev_node *dv)
422 {
423 	int32_t error = 0;
424 	sdev_door_arg_t	*argp;
425 	sdev_door_res_t result;
426 
427 	argp = kmem_zalloc(sizeof (sdev_door_arg_t), KM_SLEEP);
428 	argp->devfsadm_cmd = DEVFSADMD_RUN_ALL;
429 
430 	error = sdev_ki_call_devfsadmd(argp, &result);
431 	if (!error) {
432 		sdcmn_err6(("devfsadm result error: %d\n",
433 		    result.devfsadm_error));
434 		if (!result.devfsadm_error) {
435 			DEVNAME_DEVFSADM_SET_RUN(devfsadm_state);
436 		} else {
437 			DEVNAME_DEVFSADM_SET_STOP(devfsadm_state);
438 		}
439 	} else {
440 		DEVNAME_DEVFSADM_SET_STOP(devfsadm_state);
441 	}
442 
443 	kmem_free(argp, sizeof (sdev_door_arg_t));
444 done:
445 	sdcmn_err6(("sdev_config_all_thread: stopping, devfsadm state 0x%x\n",
446 	    devfsadm_state));
447 	thread_exit();
448 }
449 
450 /*
451  * launch an asynchronous thread to do the devfsadm dev_config_all
452  */
453 /*ARGSUSED*/
454 void
455 sdev_devfsadmd_thread(struct sdev_node *ddv, struct sdev_node *dv,
456     struct cred *cred)
457 {
458 	ASSERT(i_ddi_io_initialized());
459 	DEVNAME_DEVFSADM_SET_RUNNING(devfsadm_state);
460 	(void) thread_create(NULL, 0, sdev_config_all_thread, dv, 0,
461 	    &p0, TS_RUN, MINCLSYSPRI);
462 }
463 
464 int
465 devname_filename_register(int cmd, char *name)
466 {
467 	int error = 0;
468 	char *strbuf;
469 	char *namep;
470 	int n;
471 
472 	ASSERT(cmd == MODDEVNAME_LOOKUPDOOR ||
473 	    cmd == MODDEVNAME_DEVFSADMNODE);
474 
475 	strbuf = kmem_zalloc(MOD_MAXPATH, KM_SLEEP);
476 
477 	if (copyinstr(name, strbuf, MOD_MAXPATH, 0)) {
478 		sdcmn_err6(("error copyin \n"));
479 		error = EFAULT;
480 	} else {
481 		sdcmn_err6(("file %s is registering\n", strbuf));
482 		switch (cmd) {
483 		case MODDEVNAME_LOOKUPDOOR:
484 			/* handling the daemon re-start situations */
485 			n = strlen(strbuf) + 1;
486 			namep = i_ddi_strdup(strbuf, KM_SLEEP);
487 			mutex_enter(&devfsadm_lock);
488 			sdev_release_door();
489 			sdev_door_upcall_filename_size = n;
490 			sdev_door_upcall_filename = namep;
491 			sdcmn_err6(("size %d file name %s\n",
492 			    sdev_door_upcall_filename_size,
493 			    sdev_door_upcall_filename));
494 			cv_broadcast(&devfsadm_cv);
495 			mutex_exit(&devfsadm_lock);
496 			break;
497 		case MODDEVNAME_DEVFSADMNODE:
498 			break;
499 		}
500 	}
501 
502 	kmem_free(strbuf, MOD_MAXPATH);
503 	return (error);
504 }
505 static void
506 sdev_nsrdr_thread(void)
507 {
508 	sdev_nsrdr_work_t *work;
509 
510 	for (;;) {
511 		mutex_enter(&sdev_nsrdr_thread_lock);
512 		if (sdev_nsrdr_thread_workq == NULL) {
513 			cv_wait(&sdev_nsrdr_thread_cv, &sdev_nsrdr_thread_lock);
514 		}
515 		work = sdev_nsrdr_thread_workq;
516 		sdev_nsrdr_thread_workq = work->next;
517 		if (sdev_nsrdr_thread_tail == work)
518 			sdev_nsrdr_thread_tail = work->next;
519 		mutex_exit(&sdev_nsrdr_thread_lock);
520 		sdev_devfsadmd_nsrdr(work);
521 	}
522 	/*NOTREACHED*/
523 }
524 
525 int
526 devname_nsmaps_register(char *nvlbuf, size_t nvlsize)
527 {
528 	int error = 0;
529 	nvlist_t *nvl, *attrs;
530 	nvpair_t *nvp = NULL;
531 	nvpair_t *kvp = NULL;
532 	char *buf;
533 	char *key;
534 	char *dirname = NULL;
535 	char *dirmodule = NULL;
536 	char *dirmap = NULL;
537 	char *orig_module;
538 	char *orig_map;
539 	int len = 0;
540 	char *tmpmap;
541 	int mapcount = 0;
542 
543 	buf = kmem_zalloc(nvlsize, KM_SLEEP);
544 	if ((error = ddi_copyin(nvlbuf, buf, nvlsize, 0)) != 0) {
545 		kmem_free(buf, nvlsize);
546 		return (error);
547 	}
548 
549 	ASSERT(buf);
550 	sdcmn_err6(("devname_nsmaps_register: nsmap buf %p\n", (void *)buf));
551 	nvl = NULL;
552 	error = nvlist_unpack(buf, nvlsize, &nvl, KM_SLEEP);
553 	kmem_free(buf, nvlsize);
554 	if (error || (nvl == NULL))
555 		return (error);
556 
557 	/* invalidate all the nsmaps */
558 	mutex_enter(&devname_nsmaps_lock);
559 	sdev_invalidate_nsmaps();
560 	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
561 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
562 		dirname = nvpair_name(nvp);
563 		if (dirname == NULL) {
564 			nvlist_free(nvl);
565 			mutex_exit(&devname_nsmaps_lock);
566 			return (-1);
567 		}
568 
569 		sdcmn_err6(("dirname %s\n", dirname));
570 		(void) nvpair_value_nvlist(nvp, &attrs);
571 		for (kvp = nvlist_next_nvpair(attrs, NULL); kvp;
572 		    kvp = nvlist_next_nvpair(attrs, kvp)) {
573 			key = nvpair_name(kvp);
574 			sdcmn_err6(("key %s\n", key));
575 			if (strcmp(key, "module") == 0) {
576 				(void) nvpair_value_string(kvp, &orig_module);
577 				sdcmn_err6(("module %s\n", orig_module));
578 				dirmodule = i_ddi_strdup(orig_module, KM_SLEEP);
579 				if (strcmp(dirmodule, "devname_null") == 0)
580 					dirmodule = NULL;
581 			}
582 
583 			if (strcmp(key, "nsconfig") == 0) {
584 				(void) nvpair_value_string(kvp, &orig_map);
585 				sdcmn_err6(("dirmap %s\n", orig_map));
586 				dirmap = i_ddi_strdup(orig_map, KM_SLEEP);
587 				if (strcmp(dirmap, "devname_null") == 0)
588 					dirmap = NULL;
589 				else if (dirmap[0] != '/') {
590 					len = strlen(dirmap) +
591 					    strlen(ETC_DEV_DIR) + 2;
592 					tmpmap = i_ddi_strdup(dirmap, KM_SLEEP);
593 					(void) snprintf(dirmap, len, "%s/%s",
594 					    ETC_DEV_DIR, tmpmap);
595 					kmem_free(tmpmap, strlen(tmpmap) + 1);
596 				}
597 			}
598 		}
599 
600 		if (dirmodule == NULL && dirmap == NULL) {
601 			nvlist_free(nvl);
602 			mutex_exit(&devname_nsmaps_lock);
603 			return (-1);
604 		}
605 
606 		sdcmn_err6(("sdev_nsmaps_register: dir %s module %s map %s\n",
607 		    dirname, dirmodule, dirmap));
608 		sdev_insert_nsmap(dirname, dirmodule, dirmap);
609 		mapcount++;
610 	}
611 
612 	if (mapcount > 0)
613 		devname_nsmaps_loaded = 1;
614 
615 	/* clean up obsolete nsmaps */
616 	sdev_validate_nsmaps();
617 	mutex_exit(&devname_nsmaps_lock);
618 	if (nvl)
619 		nvlist_free(nvl);
620 
621 	if (sdev_nsrdr_thread_created) {
622 		return (0);
623 	}
624 
625 	mutex_init(&sdev_nsrdr_thread_lock, NULL, MUTEX_DEFAULT, NULL);
626 	cv_init(&sdev_nsrdr_thread_cv, NULL, CV_DEFAULT, NULL);
627 	(void) thread_create(NULL, 0, (void (*)())sdev_nsrdr_thread, NULL, 0,
628 	    &p0, TS_RUN, minclsyspri);
629 	sdev_nsrdr_thread_created = 1;
630 
631 	return (0);
632 }
633 
634 void
635 sdev_dispatch_to_nsrdr_thread(struct sdev_node *ddv, char *dir_map,
636     devname_rdr_result_t *result)
637 {
638 	sdev_nsrdr_work_t *new_work;
639 
640 	new_work = kmem_zalloc(sizeof (sdev_nsrdr_work_t), KM_SLEEP);
641 	new_work->dir_name = i_ddi_strdup(ddv->sdev_name, KM_SLEEP);
642 	new_work->dir_map = i_ddi_strdup(dir_map, KM_SLEEP);
643 	new_work->dir_dv = ddv;
644 	new_work->result = &result;
645 	mutex_enter(&sdev_nsrdr_thread_lock);
646 	if (sdev_nsrdr_thread_workq == NULL) {
647 		sdev_nsrdr_thread_workq = new_work;
648 		sdev_nsrdr_thread_tail = new_work;
649 		new_work->next = NULL;
650 	} else {
651 		sdev_nsrdr_thread_tail->next = new_work;
652 		sdev_nsrdr_thread_tail = new_work;
653 		new_work->next = NULL;
654 	}
655 	cv_signal(&sdev_nsrdr_thread_cv);
656 	mutex_exit(&sdev_nsrdr_thread_lock);
657 }
658 
659 static void
660 sdev_devfsadmd_nsrdr(sdev_nsrdr_work_t *work)
661 {
662 	int32_t error;
663 	struct sdev_door_arg *argp;
664 	struct sdev_door_res res;
665 	struct sdev_node *ddv = work->dir_dv;
666 	uint32_t mapcount;
667 
668 	argp = kmem_zalloc(sizeof (sdev_door_arg_t), KM_SLEEP);
669 	argp->devfsadm_cmd = DEVFSADMD_NS_READDIR;
670 
671 	(void) snprintf(argp->ns_hdl.ns_name,
672 	    strlen(work->dir_dv->sdev_path) + 1, "%s", work->dir_dv->sdev_path);
673 	(void) snprintf(argp->ns_hdl.ns_map, strlen(work->dir_map) + 1, "%s",
674 	    work->dir_map);
675 
676 	sdcmn_err6(("sdev_devfsadmd_nsrdr: ns_name %s, ns_map %s\n",
677 	    argp->ns_hdl.ns_name, argp->ns_hdl.ns_map));
678 	error = sdev_ki_call_devfsadmd(argp, &res);
679 	sdcmn_err6(("sdev_devfsadmd_nsrdr error %d\n", error));
680 	if (error == 0) {
681 		error = res.devfsadm_error;
682 		if (error) {
683 			goto out;
684 		}
685 
686 		mapcount = (uint32_t)res.ns_rdr_hdl.ns_mapcount;
687 		sdcmn_err6(("nsmapcount %d\n", mapcount));
688 		if (mapcount > 0) {
689 			struct devname_nsmap *map =
690 			    ddv->sdev_mapinfo;
691 			ASSERT(map && map->dir_map);
692 			rw_enter(&map->dir_lock, RW_WRITER);
693 			map->dir_maploaded = 1;
694 			rw_exit(&map->dir_lock);
695 		}
696 	}
697 
698 out:
699 	mutex_enter(&ddv->sdev_lookup_lock);
700 	SDEV_UNBLOCK_OTHERS(ddv, SDEV_READDIR);
701 	mutex_exit(&ddv->sdev_lookup_lock);
702 
703 	kmem_free(argp, sizeof (sdev_door_arg_t));
704 }
705 
706 
707 int
708 devname_nsmap_lookup(devname_lkp_arg_t *args, devname_lkp_result_t **result)
709 {
710 	int32_t error = 0;
711 	struct sdev_door_arg *argp;
712 	struct sdev_door_res resp;
713 	char *link;
714 	devname_spec_t spec;
715 
716 	argp = kmem_zalloc(sizeof (sdev_door_arg_t), KM_SLEEP);
717 	argp->devfsadm_cmd = DEVFSADMD_NS_LOOKUP;
718 
719 	(void) snprintf(argp->ns_hdl.ns_name, strlen(args->devname_name) + 1,
720 	    "%s", args->devname_name);
721 	(void) snprintf(argp->ns_hdl.ns_map, strlen(args->devname_map) + 1,
722 	    "%s", args->devname_map);
723 
724 	error = sdev_ki_call_devfsadmd(argp, &resp);
725 	if (error == 0) {
726 		error = resp.devfsadm_error;
727 		sdcmn_err6(("devfsadm: error %d\n", error));
728 		if (error) {
729 			goto done;
730 		}
731 		link = resp.ns_lkp_hdl.devfsadm_link;
732 		if (link == NULL) {
733 			error = ENOENT;
734 			goto done;
735 		}
736 		spec = resp.ns_lkp_hdl.devfsadm_spec;
737 		sdcmn_err6(("devfsadm_link %s spec %d\n",
738 		    link, (int)spec));
739 
740 
741 		(*result)->devname_spec = (devname_spec_t)spec;
742 		(*result)->devname_link = i_ddi_strdup(link, KM_SLEEP);
743 	} else {
744 		(*result)->devname_spec = DEVNAME_NS_NONE;
745 		(*result)->devname_link = NULL;
746 	}
747 done:
748 	kmem_free(argp, sizeof (sdev_door_arg_t));
749 	return (error);
750 }
751