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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * routines to invoke user level name lookup services
30 #include <sys/types.h>
31 #include <sys/param.h>
32 #include <sys/t_lock.h>
33 #include <sys/systm.h>
34 #include <sys/sysmacros.h>
38 #include <sys/vnode.h>
40 #include <sys/fcntl.h>
41 #include <sys/flock.h>
44 #include <sys/errno.h>
47 #include <sys/dirent.h>
48 #include <sys/pathname.h>
49 #include <sys/cmn_err.h>
50 #include <sys/debug.h>
52 #include <sys/policy.h>
55 #include <sys/fs_subr.h>
56 #include <sys/mount.h>
57 #include <sys/fs/snode.h>
58 #include <sys/fs/dv_node.h>
59 #include <sys/fs/sdev_impl.h>
60 #include <sys/sunndi.h>
61 #include <sys/sunddi.h>
62 #include <sys/sunmdi.h>
64 #include <sys/modctl.h>
67 /* default timeout to wait for devfsadm response in seconds */
68 #define DEV_DEVFSADM_STARTUP (1 * 60)
69 #define DEV_NODE_WAIT_TIMEOUT (5 * 60)
71 /* atomic bitset for devfsadm status */
72 volatile uint_t devfsadm_state
;
74 static kmutex_t devfsadm_lock
;
75 static kcondvar_t devfsadm_cv
;
77 static int dev_node_wait_timeout
= DEV_NODE_WAIT_TIMEOUT
;
78 static int dev_devfsadm_startup
= DEV_DEVFSADM_STARTUP
;
81 * Door used to communicate with devfsadmd
83 static door_handle_t sdev_upcall_door
= NULL
; /* Door for upcalls */
84 static char *sdev_door_upcall_filename
= NULL
;
85 static int sdev_upcall_door_revoked
= 0;
86 static int sdev_door_upcall_filename_size
;
88 static int sdev_devfsadm_revoked(void);
89 static int sdev_ki_call_devfsadmd(sdev_door_arg_t
*, sdev_door_res_t
*);
92 sdev_devfsadm_lockinit(void)
94 mutex_init(&devfsadm_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
95 cv_init(&devfsadm_cv
, NULL
, CV_DEFAULT
, NULL
);
99 sdev_devfsadm_lockdestroy(void)
101 mutex_destroy(&devfsadm_lock
);
102 cv_destroy(&devfsadm_cv
);
106 * Wait for node to be created
109 sdev_wait4lookup(struct sdev_node
*dv
, int cmd
)
113 clock_t wakeup
= drv_usectohz(2 * 1000000);
115 int is_lookup
= (cmd
== SDEV_LOOKUP
);
117 ASSERT(cmd
== SDEV_LOOKUP
|| cmd
== SDEV_READDIR
);
118 ASSERT(MUTEX_HELD(&dv
->sdev_lookup_lock
));
120 /* tick value at which wait expires */
121 expire
= ddi_get_lbolt() +
122 drv_usectohz(dev_node_wait_timeout
* 1000000);
124 sdcmn_err6(("wait4lookup %s %s, %ld %d\n",
125 is_lookup
? "lookup" : "readdir",
126 dv
->sdev_name
, expire
- ddi_get_lbolt(), dv
->sdev_state
));
128 if (SDEV_IS_LGWAITING(dv
)) {
130 while (DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state
) &&
131 !sdev_devfsadm_revoked()) {
132 /* wait 2 sec and check devfsadm completion */
133 rv
= cv_reltimedwait_sig(&dv
->sdev_lookup_cv
,
134 &dv
->sdev_lookup_lock
, wakeup
, TR_CLOCK_TICK
);
136 if (is_lookup
&& (rv
> 0)) {
137 /* was this node constructed ? */
138 if (dv
->sdev_state
== SDEV_READY
) {
141 sdcmn_err6(("%s: wait done, %screated %d\n",
142 dv
->sdev_name
, rval
? "not " : "",
145 } else if (rv
== 0) {
147 sdcmn_err6(("%s: wait interrupted\n",
150 } else if ((rv
== -1) &&
151 (ddi_get_lbolt() >= expire
)) {
152 sdcmn_err6(("%s: wait time is up\n",
156 sdcmn_err6(("%s: wait "
157 "rv %ld state 0x%x expire %ld\n",
158 dv
->sdev_name
, rv
, devfsadm_state
,
159 expire
- ddi_get_lbolt()));
163 * for the nodes created by
164 * devname_lookup_func callback
167 while (SDEV_IS_LOOKUP(dv
) || SDEV_IS_READDIR(dv
)) {
168 cv_wait(&dv
->sdev_lookup_cv
, &dv
->sdev_lookup_lock
);
173 sdcmn_err6(("wait4lookup unblocking %s state 0x%x %d\n",
174 dv
->sdev_name
, devfsadm_state
, dv
->sdev_state
));
177 SDEV_UNBLOCK_OTHERS(dv
, SDEV_LOOKUP
);
179 SDEV_UNBLOCK_OTHERS(dv
, SDEV_READDIR
);
186 sdev_unblock_others(struct sdev_node
*dv
, uint_t cmd
)
188 ASSERT(MUTEX_HELD(&dv
->sdev_lookup_lock
));
190 SDEV_CLEAR_LOOKUP_FLAGS(dv
, cmd
);
191 if (SDEV_IS_LGWAITING(dv
)) {
192 SDEV_CLEAR_LOOKUP_FLAGS(dv
, SDEV_LGWAITING
);
194 cv_broadcast(&dv
->sdev_lookup_cv
);
198 * In the case devfsadmd is down, it is re-started by syseventd
199 * upon receiving an event subscribed to by devfsadmd.
202 sdev_start_devfsadmd()
208 ev
= sysevent_alloc(EC_DEVFS
, ESC_DEVFS_START
, EP_DDI
, SE_SLEEP
);
210 if ((se_err
= log_sysevent(ev
, SE_SLEEP
, &eid
)) != 0) {
212 case SE_NO_TRANSPORT
:
213 cmn_err(CE_WARN
, "unable to start devfsadm - "
214 "syseventd may not be responding\n");
217 cmn_err(CE_WARN
, "unable to start devfsadm - "
218 "sysevent error %d\n", se_err
);
228 sdev_open_upcall_door()
234 ASSERT(sdev_upcall_door
== NULL
);
236 /* timeout expires this many ticks in the future */
237 expire
= ddi_get_lbolt() + drv_usectohz(dev_devfsadm_startup
* 1000000);
239 if (sdev_door_upcall_filename
== NULL
) {
240 if ((error
= sdev_start_devfsadmd()) != 0) {
244 /* wait for devfsadmd start */
245 mutex_enter(&devfsadm_lock
);
246 while (sdev_door_upcall_filename
== NULL
) {
247 sdcmn_err6(("waiting for dev_door creation, %ld\n",
248 expire
- ddi_get_lbolt()));
249 rv
= cv_timedwait_sig(&devfsadm_cv
, &devfsadm_lock
,
251 sdcmn_err6(("dev_door wait rv %ld\n", rv
));
253 sdcmn_err6(("devfsadmd startup error\n"));
254 mutex_exit(&devfsadm_lock
);
258 sdcmn_err6(("devfsadmd is ready\n"));
259 mutex_exit(&devfsadm_lock
);
262 if ((error
= door_ki_open(sdev_door_upcall_filename
,
263 &sdev_upcall_door
)) != 0) {
264 sdcmn_err6(("upcall_lookup: door open error %d\n",
275 if (sdev_upcall_door
) {
276 door_ki_rele(sdev_upcall_door
);
277 sdev_upcall_door
= NULL
;
279 if (sdev_door_upcall_filename
) {
280 kmem_free(sdev_door_upcall_filename
,
281 sdev_door_upcall_filename_size
);
282 sdev_door_upcall_filename
= NULL
;
287 sdev_ki_call_devfsadmd(sdev_door_arg_t
*argp
, sdev_door_res_t
*resultp
)
289 door_arg_t darg
, save_arg
;
293 if (((sdev_upcall_door
== NULL
) &&
294 ((error
= sdev_open_upcall_door()) != 0)) ||
295 sdev_devfsadm_revoked()) {
296 sdcmn_err6(("call_devfsadm: upcall lookup error\n"));
301 darg
.data_ptr
= (char *)argp
;
302 darg
.data_size
= sizeof (struct sdev_door_arg
);
303 darg
.desc_ptr
= NULL
;
305 darg
.rbuf
= (char *)(resultp
);
306 darg
.rsize
= sizeof (struct sdev_door_res
);
308 ASSERT(sdev_upcall_door
);
310 for (retry
= 0; ; retry
++) {
311 sdcmn_err6(("call devfsadm: upcall lookup, retry %d\n", retry
));
312 if ((error
= door_ki_upcall_limited(sdev_upcall_door
, &darg
,
313 NULL
, SIZE_MAX
, 0)) == 0) {
314 sdcmn_err6(("call devfsadm: upcall lookup ok\n"));
319 * handle door call errors
321 if (sdev_devfsadm_revoked()) {
322 sdcmn_err6(("upcall lookup door revoked, "
323 "error %d\n", error
));
329 /* return error here? */
330 sdcmn_err6(("sdev_ki_call_devfsadm: EINTR\n"));
334 sdcmn_err6(("sdev_ki_call_devfsadm: EAGAIN\n"));
339 sdcmn_err6(("sdev_ki_call_devfsadm: EBADF\n"));
343 "sdev_ki_call_devfsadm: EBADF, re-binding\n"));
346 error
= sdev_open_upcall_door();
348 sdcmn_err6(("sdev_ki_call_devfsadm: "
349 "EBADF lookup error %d\n", error
));
350 if (!sdev_devfsadm_revoked())
352 "?unable to invoke devfsadm - "
353 "please run manually\n");
360 "?sdev: door_ki_upcall unexpected result %d\n",
369 ASSERT((struct sdev_door_res
*)(intptr_t)darg
.rbuf
== resultp
);
370 if (resultp
->devfsadm_error
!= 0) {
371 sdcmn_err6(("sdev_ki_call_devfsadmd: result %d\n",
372 resultp
->devfsadm_error
));
373 error
= resultp
->devfsadm_error
;
376 sdcmn_err6(("sdev_ki_call_devfsadmd with error %d\n", error
));
383 sdev_devfsadm_revoked(void)
385 struct door_info info
;
387 extern int sys_shutdown
;
390 sdcmn_err6(("dev: shutdown observed\n"));
394 if (sdev_upcall_door
&& !sdev_upcall_door_revoked
) {
395 rv
= door_ki_info(sdev_upcall_door
, &info
);
396 if ((rv
== 0) && info
.di_attributes
& DOOR_REVOKED
) {
397 sdcmn_err6(("lookup door: revoked\n"));
398 sdev_upcall_door_revoked
= 1;
402 return (sdev_upcall_door_revoked
);
407 sdev_config_all_thread(struct sdev_node
*dv
)
410 sdev_door_arg_t
*argp
;
411 sdev_door_res_t result
;
413 argp
= kmem_zalloc(sizeof (sdev_door_arg_t
), KM_SLEEP
);
414 argp
->devfsadm_cmd
= DEVFSADMD_RUN_ALL
;
416 error
= sdev_ki_call_devfsadmd(argp
, &result
);
418 sdcmn_err6(("devfsadm result error: %d\n",
419 result
.devfsadm_error
));
420 if (!result
.devfsadm_error
) {
421 DEVNAME_DEVFSADM_SET_RUN(devfsadm_state
);
423 DEVNAME_DEVFSADM_SET_STOP(devfsadm_state
);
426 DEVNAME_DEVFSADM_SET_STOP(devfsadm_state
);
429 kmem_free(argp
, sizeof (sdev_door_arg_t
));
431 sdcmn_err6(("sdev_config_all_thread: stopping, devfsadm state 0x%x\n",
437 * launch an asynchronous thread to do the devfsadm dev_config_all
441 sdev_devfsadmd_thread(struct sdev_node
*ddv
, struct sdev_node
*dv
,
444 ASSERT(i_ddi_io_initialized());
445 DEVNAME_DEVFSADM_SET_RUNNING(devfsadm_state
);
446 (void) thread_create(NULL
, 0, sdev_config_all_thread
, dv
, 0,
447 &p0
, TS_RUN
, MINCLSYSPRI
);
451 devname_filename_register(char *name
)
458 strbuf
= kmem_zalloc(MOD_MAXPATH
, KM_SLEEP
);
460 if (copyinstr(name
, strbuf
, MOD_MAXPATH
, 0)) {
461 sdcmn_err6(("error copyin \n"));
464 sdcmn_err6(("file %s is registering\n", strbuf
));
465 /* handling the daemon re-start situations */
466 n
= strlen(strbuf
) + 1;
467 namep
= i_ddi_strdup(strbuf
, KM_SLEEP
);
468 mutex_enter(&devfsadm_lock
);
470 sdev_door_upcall_filename_size
= n
;
471 sdev_door_upcall_filename
= namep
;
472 sdcmn_err6(("size %d file name %s\n",
473 sdev_door_upcall_filename_size
,
474 sdev_door_upcall_filename
));
475 cv_broadcast(&devfsadm_cv
);
476 mutex_exit(&devfsadm_lock
);
479 kmem_free(strbuf
, MOD_MAXPATH
);