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 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 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 109 sdev_wait4lookup(struct sdev_node *dv, int cmd) 110 { 111 clock_t expire; 112 clock_t rv; 113 clock_t wakeup = drv_sectohz(2); 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_sectohz(dev_node_wait_timeout); 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 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 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 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_sectohz(dev_devfsadm_startup); 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 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 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 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 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 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 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 }