xref: /illumos-gate/usr/src/uts/common/fs/dev/sdev_comm.c (revision d3d50737)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * routines to invoke user level name lookup services
28  */
29 
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>
35 #include <sys/user.h>
36 #include <sys/time.h>
37 #include <sys/vfs.h>
38 #include <sys/vnode.h>
39 #include <sys/file.h>
40 #include <sys/fcntl.h>
41 #include <sys/flock.h>
42 #include <sys/kmem.h>
43 #include <sys/uio.h>
44 #include <sys/errno.h>
45 #include <sys/stat.h>
46 #include <sys/cred.h>
47 #include <sys/dirent.h>
48 #include <sys/pathname.h>
49 #include <sys/cmn_err.h>
50 #include <sys/debug.h>
51 #include <sys/mode.h>
52 #include <sys/policy.h>
53 #include <sys/disp.h>
54 #include <sys/door.h>
55 #include <fs/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>
63 #include <sys/conf.h>
64 #include <sys/modctl.h>
65 #include <sys/ddi.h>
66 
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)
70 
71 /* atomic bitset for devfsadm status */
72 volatile uint_t devfsadm_state;
73 
74 static kmutex_t devfsadm_lock;
75 static kcondvar_t devfsadm_cv;
76 
77 static int dev_node_wait_timeout = DEV_NODE_WAIT_TIMEOUT;
78 static int dev_devfsadm_startup =  DEV_DEVFSADM_STARTUP;
79 
80 /*
81  * Door used to communicate with devfsadmd
82  */
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;
87 
88 static int sdev_devfsadm_revoked(void);
89 static int sdev_ki_call_devfsadmd(sdev_door_arg_t *, sdev_door_res_t *);
90 
91 void
sdev_devfsadm_lockinit(void)92 sdev_devfsadm_lockinit(void)
93 {
94 	mutex_init(&devfsadm_lock, NULL, MUTEX_DEFAULT, NULL);
95 	cv_init(&devfsadm_cv, NULL, CV_DEFAULT, NULL);
96 }
97 
98 void
sdev_devfsadm_lockdestroy(void)99 sdev_devfsadm_lockdestroy(void)
100 {
101 	mutex_destroy(&devfsadm_lock);
102 	cv_destroy(&devfsadm_cv);
103 }
104 
105 /*
106  * Wait for node to be created
107  */
108 int
sdev_wait4lookup(struct sdev_node * dv,int cmd)109 sdev_wait4lookup(struct sdev_node *dv, int cmd)
110 {
111 	clock_t	expire;
112 	clock_t rv;
113 	clock_t wakeup = drv_usectohz(2 * 1000000);
114 	int rval = ENOENT;
115 	int is_lookup = (cmd == SDEV_LOOKUP);
116 
117 	ASSERT(cmd == SDEV_LOOKUP || cmd == SDEV_READDIR);
118 	ASSERT(MUTEX_HELD(&dv->sdev_lookup_lock));
119 
120 	/* tick value at which wait expires */
121 	expire = ddi_get_lbolt() +
122 	    drv_usectohz(dev_node_wait_timeout * 1000000);
123 
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));
127 
128 	if (SDEV_IS_LGWAITING(dv)) {
129 		/* devfsadm nodes */
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);
135 
136 			if (is_lookup && (rv > 0)) {
137 				/* was this node constructed ? */
138 				if (dv->sdev_state == SDEV_READY) {
139 					rval = 0;
140 				}
141 				sdcmn_err6(("%s: wait done, %screated %d\n",
142 				    dv->sdev_name, rval ? "not " : "",
143 				    dv->sdev_state));
144 				break;
145 			} else if (rv == 0) {
146 				/* interrupted */
147 				sdcmn_err6(("%s: wait interrupted\n",
148 				    dv->sdev_name));
149 				break;
150 			} else if ((rv == -1) &&
151 			    (ddi_get_lbolt() >= expire)) {
152 				sdcmn_err6(("%s: wait time is up\n",
153 				    dv->sdev_name));
154 				break;
155 			}
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()));
160 		}
161 	} else {
162 		/*
163 		 * for the nodes created by
164 		 * devname_lookup_func callback
165 		 * or plug-in modules
166 		 */
167 		while (SDEV_IS_LOOKUP(dv) || SDEV_IS_READDIR(dv)) {
168 			cv_wait(&dv->sdev_lookup_cv, &dv->sdev_lookup_lock);
169 		}
170 		rval = 0;
171 	}
172 
173 	sdcmn_err6(("wait4lookup unblocking %s state 0x%x %d\n",
174 	    dv->sdev_name, devfsadm_state, dv->sdev_state));
175 
176 	if (is_lookup) {
177 		SDEV_UNBLOCK_OTHERS(dv, SDEV_LOOKUP);
178 	} else {
179 		SDEV_UNBLOCK_OTHERS(dv, SDEV_READDIR);
180 	}
181 
182 	return (rval);
183 }
184 
185 void
sdev_unblock_others(struct sdev_node * dv,uint_t cmd)186 sdev_unblock_others(struct sdev_node *dv, uint_t cmd)
187 {
188 	ASSERT(MUTEX_HELD(&dv->sdev_lookup_lock));
189 
190 	SDEV_CLEAR_LOOKUP_FLAGS(dv, cmd);
191 	if (SDEV_IS_LGWAITING(dv)) {
192 		SDEV_CLEAR_LOOKUP_FLAGS(dv, SDEV_LGWAITING);
193 	}
194 	cv_broadcast(&dv->sdev_lookup_cv);
195 }
196 
197 /*
198  * In the case devfsadmd is down, it is re-started by syseventd
199  * upon receiving an event subscribed to by devfsadmd.
200  */
201 static int
sdev_start_devfsadmd()202 sdev_start_devfsadmd()
203 {
204 	int		se_err = 0;
205 	sysevent_t	*ev;
206 	sysevent_id_t	eid;
207 
208 	ev = sysevent_alloc(EC_DEVFS, ESC_DEVFS_START, EP_DDI, SE_SLEEP);
209 	ASSERT(ev);
210 	if ((se_err = log_sysevent(ev, SE_SLEEP, &eid)) != 0) {
211 		switch (se_err) {
212 		case SE_NO_TRANSPORT:
213 			cmn_err(CE_WARN, "unable to start devfsadm - "
214 			    "syseventd may not be responding\n");
215 			break;
216 		default:
217 			cmn_err(CE_WARN, "unable to start devfsadm - "
218 			    "sysevent error %d\n", se_err);
219 			break;
220 		}
221 	}
222 
223 	sysevent_free(ev);
224 	return (se_err);
225 }
226 
227 static int
sdev_open_upcall_door()228 sdev_open_upcall_door()
229 {
230 	int error;
231 	clock_t rv;
232 	clock_t expire;
233 
234 	ASSERT(sdev_upcall_door == NULL);
235 
236 	/* timeout expires this many ticks in the future */
237 	expire = ddi_get_lbolt() + drv_usectohz(dev_devfsadm_startup * 1000000);
238 
239 	if (sdev_door_upcall_filename == NULL) {
240 		if ((error = sdev_start_devfsadmd()) != 0) {
241 			return (error);
242 		}
243 
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,
250 			    expire);
251 			sdcmn_err6(("dev_door wait rv %ld\n", rv));
252 			if (rv <= 0) {
253 				sdcmn_err6(("devfsadmd startup error\n"));
254 				mutex_exit(&devfsadm_lock);
255 				return (EBADF);
256 			}
257 		}
258 		sdcmn_err6(("devfsadmd is ready\n"));
259 		mutex_exit(&devfsadm_lock);
260 	}
261 
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",
265 		    error));
266 		return (error);
267 	}
268 
269 	return (0);
270 }
271 
272 static void
sdev_release_door()273 sdev_release_door()
274 {
275 	if (sdev_upcall_door) {
276 		door_ki_rele(sdev_upcall_door);
277 		sdev_upcall_door = NULL;
278 	}
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;
283 	}
284 }
285 
286 static int
sdev_ki_call_devfsadmd(sdev_door_arg_t * argp,sdev_door_res_t * resultp)287 sdev_ki_call_devfsadmd(sdev_door_arg_t *argp, sdev_door_res_t *resultp)
288 {
289 	door_arg_t	darg, save_arg;
290 	int		error;
291 	int		retry;
292 
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"));
297 		return (error);
298 	}
299 
300 	ASSERT(argp);
301 	darg.data_ptr = (char *)argp;
302 	darg.data_size = sizeof (struct sdev_door_arg);
303 	darg.desc_ptr = NULL;
304 	darg.desc_num = 0;
305 	darg.rbuf = (char *)(resultp);
306 	darg.rsize = sizeof (struct sdev_door_res);
307 
308 	ASSERT(sdev_upcall_door);
309 	save_arg = darg;
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"));
315 			break;
316 		}
317 
318 		/*
319 		 * handle door call errors
320 		 */
321 		if (sdev_devfsadm_revoked()) {
322 			sdcmn_err6(("upcall lookup door revoked, "
323 			    "error %d\n", error));
324 			return (error);
325 		}
326 
327 		switch (error) {
328 		case EINTR:
329 			/* return error here? */
330 			sdcmn_err6(("sdev_ki_call_devfsadm: EINTR\n"));
331 			delay(hz);
332 			break;
333 		case EAGAIN:
334 			sdcmn_err6(("sdev_ki_call_devfsadm: EAGAIN\n"));
335 			delay(2 * hz);
336 			break;
337 		case EBADF:
338 			if (retry > 4) {
339 				sdcmn_err6(("sdev_ki_call_devfsadm: EBADF\n"));
340 				return (EBADF);
341 			}
342 			sdcmn_err6((
343 			    "sdev_ki_call_devfsadm: EBADF, re-binding\n"));
344 			sdev_release_door();
345 			delay(retry * hz);
346 			error = sdev_open_upcall_door();
347 			if (error != 0) {
348 				sdcmn_err6(("sdev_ki_call_devfsadm: "
349 				    "EBADF lookup error %d\n", error));
350 				if (!sdev_devfsadm_revoked())
351 					cmn_err(CE_NOTE,
352 					    "?unable to invoke devfsadm - "
353 					    "please run manually\n");
354 				return (EBADF);
355 			}
356 			break;
357 		case EINVAL:
358 		default:
359 			cmn_err(CE_CONT,
360 			    "?sdev: door_ki_upcall unexpected result %d\n",
361 			    error);
362 			return (error);
363 		}
364 
365 		darg = save_arg;
366 	}
367 
368 	if (!error) {
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;
374 		}
375 	} else {
376 		sdcmn_err6(("sdev_ki_call_devfsadmd with error %d\n", error));
377 	}
378 
379 	return (error);
380 }
381 
382 static int
sdev_devfsadm_revoked(void)383 sdev_devfsadm_revoked(void)
384 {
385 	struct door_info info;
386 	int rv;
387 	extern int sys_shutdown;
388 
389 	if (sys_shutdown) {
390 		sdcmn_err6(("dev: shutdown observed\n"));
391 		return (1);
392 	}
393 
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;
399 		}
400 	}
401 
402 	return (sdev_upcall_door_revoked);
403 }
404 
405 /*ARGSUSED*/
406 static void
sdev_config_all_thread(struct sdev_node * dv)407 sdev_config_all_thread(struct sdev_node *dv)
408 {
409 	int32_t error = 0;
410 	sdev_door_arg_t	*argp;
411 	sdev_door_res_t result;
412 
413 	argp = kmem_zalloc(sizeof (sdev_door_arg_t), KM_SLEEP);
414 	argp->devfsadm_cmd = DEVFSADMD_RUN_ALL;
415 
416 	error = sdev_ki_call_devfsadmd(argp, &result);
417 	if (!error) {
418 		sdcmn_err6(("devfsadm result error: %d\n",
419 		    result.devfsadm_error));
420 		if (!result.devfsadm_error) {
421 			DEVNAME_DEVFSADM_SET_RUN(devfsadm_state);
422 		} else {
423 			DEVNAME_DEVFSADM_SET_STOP(devfsadm_state);
424 		}
425 	} else {
426 		DEVNAME_DEVFSADM_SET_STOP(devfsadm_state);
427 	}
428 
429 	kmem_free(argp, sizeof (sdev_door_arg_t));
430 done:
431 	sdcmn_err6(("sdev_config_all_thread: stopping, devfsadm state 0x%x\n",
432 	    devfsadm_state));
433 	thread_exit();
434 }
435 
436 /*
437  * launch an asynchronous thread to do the devfsadm dev_config_all
438  */
439 /*ARGSUSED*/
440 void
sdev_devfsadmd_thread(struct sdev_node * ddv,struct sdev_node * dv,struct cred * cred)441 sdev_devfsadmd_thread(struct sdev_node *ddv, struct sdev_node *dv,
442     struct cred *cred)
443 {
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);
448 }
449 
450 int
devname_filename_register(char * name)451 devname_filename_register(char *name)
452 {
453 	int error = 0;
454 	char *strbuf;
455 	char *namep;
456 	int n;
457 
458 	strbuf = kmem_zalloc(MOD_MAXPATH, KM_SLEEP);
459 
460 	if (copyinstr(name, strbuf, MOD_MAXPATH, 0)) {
461 		sdcmn_err6(("error copyin \n"));
462 		error = EFAULT;
463 	} else {
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);
469 		sdev_release_door();
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);
477 	}
478 
479 	kmem_free(strbuf, MOD_MAXPATH);
480 	return (error);
481 }
482