xref: /illumos-gate/usr/src/uts/common/fs/dev/sdev_comm.c (revision 6e375c8351497b82ffa4f33cbf61d712999b4605)
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 2008 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_limited(sdev_upcall_door, &darg,
328 		    NULL, SIZE_MAX, 0)) == 0) {
329 			sdcmn_err6(("call devfsadm: upcall lookup ok\n"));
330 			break;
331 		}
332 
333 		/*
334 		 * handle door call errors
335 		 */
336 		if (sdev_devfsadm_revoked()) {
337 			sdcmn_err6(("upcall lookup door revoked, "
338 			    "error %d\n", error));
339 			return (error);
340 		}
341 
342 		switch (error) {
343 		case EINTR:
344 			/* return error here? */
345 			sdcmn_err6(("sdev_ki_call_devfsadm: EINTR\n"));
346 			delay(hz);
347 			break;
348 		case EAGAIN:
349 			sdcmn_err6(("sdev_ki_call_devfsadm: EAGAIN\n"));
350 			delay(2 * hz);
351 			break;
352 		case EBADF:
353 			if (retry > 4) {
354 				sdcmn_err6(("sdev_ki_call_devfsadm: EBADF\n"));
355 				return (EBADF);
356 			}
357 			sdcmn_err6((
358 			    "sdev_ki_call_devfsadm: EBADF, re-binding\n"));
359 			sdev_release_door();
360 			delay(retry * hz);
361 			error = sdev_open_upcall_door();
362 			if (error != 0) {
363 				sdcmn_err6(("sdev_ki_call_devfsadm: "
364 				    "EBADF lookup error %d\n", error));
365 				if (!sdev_devfsadm_revoked())
366 					cmn_err(CE_NOTE,
367 					    "?unable to invoke devfsadm - "
368 					    "please run manually\n");
369 				return (EBADF);
370 			}
371 			break;
372 		case EINVAL:
373 		default:
374 			cmn_err(CE_CONT,
375 			    "?sdev: door_ki_upcall unexpected result %d\n",
376 			    error);
377 			return (error);
378 		}
379 
380 		darg = save_arg;
381 	}
382 
383 	if (!error) {
384 		ASSERT((struct sdev_door_res *)(intptr_t)darg.rbuf == resultp);
385 		if (resultp->devfsadm_error != 0) {
386 			sdcmn_err6(("sdev_ki_call_devfsadmd: result %d\n",
387 			    resultp->devfsadm_error));
388 			error = resultp->devfsadm_error;
389 		}
390 	} else {
391 		sdcmn_err6(("sdev_ki_call_devfsadmd with error %d\n", error));
392 	}
393 
394 	return (error);
395 }
396 
397 static int
398 sdev_devfsadm_revoked(void)
399 {
400 	struct door_info info;
401 	int rv;
402 	extern int sys_shutdown;
403 
404 	if (sys_shutdown) {
405 		sdcmn_err6(("dev: shutdown observed\n"));
406 		return (1);
407 	}
408 
409 	if (sdev_upcall_door && !sdev_upcall_door_revoked) {
410 		rv = door_ki_info(sdev_upcall_door, &info);
411 		if ((rv == 0) && info.di_attributes & DOOR_REVOKED) {
412 			sdcmn_err6(("lookup door: revoked\n"));
413 			sdev_upcall_door_revoked = 1;
414 		}
415 	}
416 
417 	return (sdev_upcall_door_revoked);
418 }
419 
420 /*ARGSUSED*/
421 static void
422 sdev_config_all_thread(struct sdev_node *dv)
423 {
424 	int32_t error = 0;
425 	sdev_door_arg_t	*argp;
426 	sdev_door_res_t result;
427 
428 	argp = kmem_zalloc(sizeof (sdev_door_arg_t), KM_SLEEP);
429 	argp->devfsadm_cmd = DEVFSADMD_RUN_ALL;
430 
431 	error = sdev_ki_call_devfsadmd(argp, &result);
432 	if (!error) {
433 		sdcmn_err6(("devfsadm result error: %d\n",
434 		    result.devfsadm_error));
435 		if (!result.devfsadm_error) {
436 			DEVNAME_DEVFSADM_SET_RUN(devfsadm_state);
437 		} else {
438 			DEVNAME_DEVFSADM_SET_STOP(devfsadm_state);
439 		}
440 	} else {
441 		DEVNAME_DEVFSADM_SET_STOP(devfsadm_state);
442 	}
443 
444 	kmem_free(argp, sizeof (sdev_door_arg_t));
445 done:
446 	sdcmn_err6(("sdev_config_all_thread: stopping, devfsadm state 0x%x\n",
447 	    devfsadm_state));
448 	thread_exit();
449 }
450 
451 /*
452  * launch an asynchronous thread to do the devfsadm dev_config_all
453  */
454 /*ARGSUSED*/
455 void
456 sdev_devfsadmd_thread(struct sdev_node *ddv, struct sdev_node *dv,
457     struct cred *cred)
458 {
459 	ASSERT(i_ddi_io_initialized());
460 	DEVNAME_DEVFSADM_SET_RUNNING(devfsadm_state);
461 	(void) thread_create(NULL, 0, sdev_config_all_thread, dv, 0,
462 	    &p0, TS_RUN, MINCLSYSPRI);
463 }
464 
465 int
466 devname_filename_register(int cmd, char *name)
467 {
468 	int error = 0;
469 	char *strbuf;
470 	char *namep;
471 	int n;
472 
473 	ASSERT(cmd == MODDEVNAME_LOOKUPDOOR ||
474 	    cmd == MODDEVNAME_DEVFSADMNODE);
475 
476 	strbuf = kmem_zalloc(MOD_MAXPATH, KM_SLEEP);
477 
478 	if (copyinstr(name, strbuf, MOD_MAXPATH, 0)) {
479 		sdcmn_err6(("error copyin \n"));
480 		error = EFAULT;
481 	} else {
482 		sdcmn_err6(("file %s is registering\n", strbuf));
483 		switch (cmd) {
484 		case MODDEVNAME_LOOKUPDOOR:
485 			/* handling the daemon re-start situations */
486 			n = strlen(strbuf) + 1;
487 			namep = i_ddi_strdup(strbuf, KM_SLEEP);
488 			mutex_enter(&devfsadm_lock);
489 			sdev_release_door();
490 			sdev_door_upcall_filename_size = n;
491 			sdev_door_upcall_filename = namep;
492 			sdcmn_err6(("size %d file name %s\n",
493 			    sdev_door_upcall_filename_size,
494 			    sdev_door_upcall_filename));
495 			cv_broadcast(&devfsadm_cv);
496 			mutex_exit(&devfsadm_lock);
497 			break;
498 		case MODDEVNAME_DEVFSADMNODE:
499 			break;
500 		}
501 	}
502 
503 	kmem_free(strbuf, MOD_MAXPATH);
504 	return (error);
505 }
506 static void
507 sdev_nsrdr_thread(void)
508 {
509 	sdev_nsrdr_work_t *work;
510 
511 	for (;;) {
512 		mutex_enter(&sdev_nsrdr_thread_lock);
513 		if (sdev_nsrdr_thread_workq == NULL) {
514 			cv_wait(&sdev_nsrdr_thread_cv, &sdev_nsrdr_thread_lock);
515 		}
516 		work = sdev_nsrdr_thread_workq;
517 		sdev_nsrdr_thread_workq = work->next;
518 		if (sdev_nsrdr_thread_tail == work)
519 			sdev_nsrdr_thread_tail = work->next;
520 		mutex_exit(&sdev_nsrdr_thread_lock);
521 		sdev_devfsadmd_nsrdr(work);
522 	}
523 	/*NOTREACHED*/
524 }
525 
526 int
527 devname_nsmaps_register(char *nvlbuf, size_t nvlsize)
528 {
529 	int error = 0;
530 	nvlist_t *nvl, *attrs;
531 	nvpair_t *nvp = NULL;
532 	nvpair_t *kvp = NULL;
533 	char *buf;
534 	char *key;
535 	char *dirname = NULL;
536 	char *dirmodule = NULL;
537 	char *dirmap = NULL;
538 	char *orig_module;
539 	char *orig_map;
540 	int len = 0;
541 	char *tmpmap;
542 	int mapcount = 0;
543 
544 	buf = kmem_zalloc(nvlsize, KM_SLEEP);
545 	if ((error = ddi_copyin(nvlbuf, buf, nvlsize, 0)) != 0) {
546 		kmem_free(buf, nvlsize);
547 		return (error);
548 	}
549 
550 	ASSERT(buf);
551 	sdcmn_err6(("devname_nsmaps_register: nsmap buf %p\n", (void *)buf));
552 	nvl = NULL;
553 	error = nvlist_unpack(buf, nvlsize, &nvl, KM_SLEEP);
554 	kmem_free(buf, nvlsize);
555 	if (error || (nvl == NULL))
556 		return (error);
557 
558 	/* invalidate all the nsmaps */
559 	mutex_enter(&devname_nsmaps_lock);
560 	sdev_invalidate_nsmaps();
561 	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
562 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
563 		dirname = nvpair_name(nvp);
564 		if (dirname == NULL) {
565 			nvlist_free(nvl);
566 			mutex_exit(&devname_nsmaps_lock);
567 			return (-1);
568 		}
569 
570 		sdcmn_err6(("dirname %s\n", dirname));
571 		(void) nvpair_value_nvlist(nvp, &attrs);
572 		for (kvp = nvlist_next_nvpair(attrs, NULL); kvp;
573 		    kvp = nvlist_next_nvpair(attrs, kvp)) {
574 			key = nvpair_name(kvp);
575 			sdcmn_err6(("key %s\n", key));
576 			if (strcmp(key, "module") == 0) {
577 				(void) nvpair_value_string(kvp, &orig_module);
578 				sdcmn_err6(("module %s\n", orig_module));
579 				dirmodule = i_ddi_strdup(orig_module, KM_SLEEP);
580 				if (strcmp(dirmodule, "devname_null") == 0)
581 					dirmodule = NULL;
582 			}
583 
584 			if (strcmp(key, "nsconfig") == 0) {
585 				(void) nvpair_value_string(kvp, &orig_map);
586 				sdcmn_err6(("dirmap %s\n", orig_map));
587 				dirmap = i_ddi_strdup(orig_map, KM_SLEEP);
588 				if (strcmp(dirmap, "devname_null") == 0)
589 					dirmap = NULL;
590 				else if (dirmap[0] != '/') {
591 					len = strlen(dirmap) +
592 					    strlen(ETC_DEV_DIR) + 2;
593 					tmpmap = i_ddi_strdup(dirmap, KM_SLEEP);
594 					(void) snprintf(dirmap, len, "%s/%s",
595 					    ETC_DEV_DIR, tmpmap);
596 					kmem_free(tmpmap, strlen(tmpmap) + 1);
597 				}
598 			}
599 		}
600 
601 		if (dirmodule == NULL && dirmap == NULL) {
602 			nvlist_free(nvl);
603 			mutex_exit(&devname_nsmaps_lock);
604 			return (-1);
605 		}
606 
607 		sdcmn_err6(("sdev_nsmaps_register: dir %s module %s map %s\n",
608 		    dirname, dirmodule, dirmap));
609 		sdev_insert_nsmap(dirname, dirmodule, dirmap);
610 		mapcount++;
611 	}
612 
613 	if (mapcount > 0)
614 		devname_nsmaps_loaded = 1;
615 
616 	/* clean up obsolete nsmaps */
617 	sdev_validate_nsmaps();
618 	mutex_exit(&devname_nsmaps_lock);
619 	if (nvl)
620 		nvlist_free(nvl);
621 
622 	if (sdev_nsrdr_thread_created) {
623 		return (0);
624 	}
625 
626 	mutex_init(&sdev_nsrdr_thread_lock, NULL, MUTEX_DEFAULT, NULL);
627 	cv_init(&sdev_nsrdr_thread_cv, NULL, CV_DEFAULT, NULL);
628 	(void) thread_create(NULL, 0, (void (*)())sdev_nsrdr_thread, NULL, 0,
629 	    &p0, TS_RUN, minclsyspri);
630 	sdev_nsrdr_thread_created = 1;
631 
632 	return (0);
633 }
634 
635 void
636 sdev_dispatch_to_nsrdr_thread(struct sdev_node *ddv, char *dir_map,
637     devname_rdr_result_t *result)
638 {
639 	sdev_nsrdr_work_t *new_work;
640 
641 	new_work = kmem_zalloc(sizeof (sdev_nsrdr_work_t), KM_SLEEP);
642 	new_work->dir_name = i_ddi_strdup(ddv->sdev_name, KM_SLEEP);
643 	new_work->dir_map = i_ddi_strdup(dir_map, KM_SLEEP);
644 	new_work->dir_dv = ddv;
645 	new_work->result = &result;
646 	mutex_enter(&sdev_nsrdr_thread_lock);
647 	if (sdev_nsrdr_thread_workq == NULL) {
648 		sdev_nsrdr_thread_workq = new_work;
649 		sdev_nsrdr_thread_tail = new_work;
650 		new_work->next = NULL;
651 	} else {
652 		sdev_nsrdr_thread_tail->next = new_work;
653 		sdev_nsrdr_thread_tail = new_work;
654 		new_work->next = NULL;
655 	}
656 	cv_signal(&sdev_nsrdr_thread_cv);
657 	mutex_exit(&sdev_nsrdr_thread_lock);
658 }
659 
660 static void
661 sdev_devfsadmd_nsrdr(sdev_nsrdr_work_t *work)
662 {
663 	int32_t error;
664 	struct sdev_door_arg *argp;
665 	struct sdev_door_res res;
666 	struct sdev_node *ddv = work->dir_dv;
667 	uint32_t mapcount;
668 
669 	argp = kmem_zalloc(sizeof (sdev_door_arg_t), KM_SLEEP);
670 	argp->devfsadm_cmd = DEVFSADMD_NS_READDIR;
671 
672 	(void) snprintf(argp->ns_hdl.ns_name,
673 	    strlen(work->dir_dv->sdev_path) + 1, "%s", work->dir_dv->sdev_path);
674 	(void) snprintf(argp->ns_hdl.ns_map, strlen(work->dir_map) + 1, "%s",
675 	    work->dir_map);
676 
677 	sdcmn_err6(("sdev_devfsadmd_nsrdr: ns_name %s, ns_map %s\n",
678 	    argp->ns_hdl.ns_name, argp->ns_hdl.ns_map));
679 	error = sdev_ki_call_devfsadmd(argp, &res);
680 	sdcmn_err6(("sdev_devfsadmd_nsrdr error %d\n", error));
681 	if (error == 0) {
682 		error = res.devfsadm_error;
683 		if (error) {
684 			goto out;
685 		}
686 
687 		mapcount = (uint32_t)res.ns_rdr_hdl.ns_mapcount;
688 		sdcmn_err6(("nsmapcount %d\n", mapcount));
689 		if (mapcount > 0) {
690 			struct devname_nsmap *map =
691 			    ddv->sdev_mapinfo;
692 			ASSERT(map && map->dir_map);
693 			rw_enter(&map->dir_lock, RW_WRITER);
694 			map->dir_maploaded = 1;
695 			rw_exit(&map->dir_lock);
696 		}
697 	}
698 
699 out:
700 	mutex_enter(&ddv->sdev_lookup_lock);
701 	SDEV_UNBLOCK_OTHERS(ddv, SDEV_READDIR);
702 	mutex_exit(&ddv->sdev_lookup_lock);
703 
704 	kmem_free(argp, sizeof (sdev_door_arg_t));
705 }
706 
707 
708 int
709 devname_nsmap_lookup(devname_lkp_arg_t *args, devname_lkp_result_t **result)
710 {
711 	int32_t error = 0;
712 	struct sdev_door_arg *argp;
713 	struct sdev_door_res resp;
714 	char *link;
715 	devname_spec_t spec;
716 
717 	argp = kmem_zalloc(sizeof (sdev_door_arg_t), KM_SLEEP);
718 	argp->devfsadm_cmd = DEVFSADMD_NS_LOOKUP;
719 
720 	(void) snprintf(argp->ns_hdl.ns_name, strlen(args->devname_name) + 1,
721 	    "%s", args->devname_name);
722 	(void) snprintf(argp->ns_hdl.ns_map, strlen(args->devname_map) + 1,
723 	    "%s", args->devname_map);
724 
725 	error = sdev_ki_call_devfsadmd(argp, &resp);
726 	if (error == 0) {
727 		error = resp.devfsadm_error;
728 		sdcmn_err6(("devfsadm: error %d\n", error));
729 		if (error) {
730 			goto done;
731 		}
732 		link = resp.ns_lkp_hdl.devfsadm_link;
733 		if (link == NULL) {
734 			error = ENOENT;
735 			goto done;
736 		}
737 		spec = resp.ns_lkp_hdl.devfsadm_spec;
738 		sdcmn_err6(("devfsadm_link %s spec %d\n",
739 		    link, (int)spec));
740 
741 
742 		(*result)->devname_spec = (devname_spec_t)spec;
743 		(*result)->devname_link = i_ddi_strdup(link, KM_SLEEP);
744 	} else {
745 		(*result)->devname_spec = DEVNAME_NS_NONE;
746 		(*result)->devname_link = NULL;
747 	}
748 done:
749 	kmem_free(argp, sizeof (sdev_door_arg_t));
750 	return (error);
751 }
752