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 int rval = ENOENT; 114 int is_lookup = (cmd == SDEV_LOOKUP); 115 116 ASSERT(cmd == SDEV_LOOKUP || cmd == SDEV_READDIR); 117 ASSERT(MUTEX_HELD(&dv->sdev_lookup_lock)); 118 119 /* tick value at which wait expires */ 120 expire = ddi_get_lbolt() + 121 drv_usectohz(dev_node_wait_timeout * 1000000); 122 123 sdcmn_err6(("wait4lookup %s %s, %ld %d\n", 124 is_lookup ? "lookup" : "readdir", 125 dv->sdev_name, expire - ddi_get_lbolt(), dv->sdev_state)); 126 127 if (SDEV_IS_LGWAITING(dv)) { 128 /* devfsadm nodes */ 129 while (DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state) && 130 !sdev_devfsadm_revoked()) { 131 /* wait 2 sec and check devfsadm completion */ 132 rv = cv_timedwait_sig(&dv->sdev_lookup_cv, 133 &dv->sdev_lookup_lock, ddi_get_lbolt() + 134 drv_usectohz(2 * 1000000)); 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 /* tick value at which wait expires */ 237 expire = ddi_get_lbolt() + 238 drv_usectohz(dev_devfsadm_startup * 1000000); 239 240 if (sdev_door_upcall_filename == NULL) { 241 if ((error = sdev_start_devfsadmd()) != 0) { 242 return (error); 243 } 244 245 /* wait for devfsadmd start */ 246 mutex_enter(&devfsadm_lock); 247 while (sdev_door_upcall_filename == NULL) { 248 sdcmn_err6(("waiting for dev_door creation, %ld\n", 249 expire - ddi_get_lbolt())); 250 rv = cv_timedwait_sig(&devfsadm_cv, &devfsadm_lock, 251 expire); 252 sdcmn_err6(("dev_door wait rv %ld\n", rv)); 253 if (rv <= 0) { 254 sdcmn_err6(("devfsadmd startup error\n")); 255 mutex_exit(&devfsadm_lock); 256 return (EBADF); 257 } 258 } 259 sdcmn_err6(("devfsadmd is ready\n")); 260 mutex_exit(&devfsadm_lock); 261 } 262 263 if ((error = door_ki_open(sdev_door_upcall_filename, 264 &sdev_upcall_door)) != 0) { 265 sdcmn_err6(("upcall_lookup: door open error %d\n", 266 error)); 267 return (error); 268 } 269 270 return (0); 271 } 272 273 static void 274 sdev_release_door() 275 { 276 if (sdev_upcall_door) { 277 door_ki_rele(sdev_upcall_door); 278 sdev_upcall_door = NULL; 279 } 280 if (sdev_door_upcall_filename) { 281 kmem_free(sdev_door_upcall_filename, 282 sdev_door_upcall_filename_size); 283 sdev_door_upcall_filename = NULL; 284 } 285 } 286 287 static int 288 sdev_ki_call_devfsadmd(sdev_door_arg_t *argp, sdev_door_res_t *resultp) 289 { 290 door_arg_t darg, save_arg; 291 int error; 292 int retry; 293 294 if (((sdev_upcall_door == NULL) && 295 ((error = sdev_open_upcall_door()) != 0)) || 296 sdev_devfsadm_revoked()) { 297 sdcmn_err6(("call_devfsadm: upcall lookup error\n")); 298 return (error); 299 } 300 301 ASSERT(argp); 302 darg.data_ptr = (char *)argp; 303 darg.data_size = sizeof (struct sdev_door_arg); 304 darg.desc_ptr = NULL; 305 darg.desc_num = 0; 306 darg.rbuf = (char *)(resultp); 307 darg.rsize = sizeof (struct sdev_door_res); 308 309 ASSERT(sdev_upcall_door); 310 save_arg = darg; 311 for (retry = 0; ; retry++) { 312 sdcmn_err6(("call devfsadm: upcall lookup, retry %d\n", retry)); 313 if ((error = door_ki_upcall_limited(sdev_upcall_door, &darg, 314 NULL, SIZE_MAX, 0)) == 0) { 315 sdcmn_err6(("call devfsadm: upcall lookup ok\n")); 316 break; 317 } 318 319 /* 320 * handle door call errors 321 */ 322 if (sdev_devfsadm_revoked()) { 323 sdcmn_err6(("upcall lookup door revoked, " 324 "error %d\n", error)); 325 return (error); 326 } 327 328 switch (error) { 329 case EINTR: 330 /* return error here? */ 331 sdcmn_err6(("sdev_ki_call_devfsadm: EINTR\n")); 332 delay(hz); 333 break; 334 case EAGAIN: 335 sdcmn_err6(("sdev_ki_call_devfsadm: EAGAIN\n")); 336 delay(2 * hz); 337 break; 338 case EBADF: 339 if (retry > 4) { 340 sdcmn_err6(("sdev_ki_call_devfsadm: EBADF\n")); 341 return (EBADF); 342 } 343 sdcmn_err6(( 344 "sdev_ki_call_devfsadm: EBADF, re-binding\n")); 345 sdev_release_door(); 346 delay(retry * hz); 347 error = sdev_open_upcall_door(); 348 if (error != 0) { 349 sdcmn_err6(("sdev_ki_call_devfsadm: " 350 "EBADF lookup error %d\n", error)); 351 if (!sdev_devfsadm_revoked()) 352 cmn_err(CE_NOTE, 353 "?unable to invoke devfsadm - " 354 "please run manually\n"); 355 return (EBADF); 356 } 357 break; 358 case EINVAL: 359 default: 360 cmn_err(CE_CONT, 361 "?sdev: door_ki_upcall unexpected result %d\n", 362 error); 363 return (error); 364 } 365 366 darg = save_arg; 367 } 368 369 if (!error) { 370 ASSERT((struct sdev_door_res *)(intptr_t)darg.rbuf == resultp); 371 if (resultp->devfsadm_error != 0) { 372 sdcmn_err6(("sdev_ki_call_devfsadmd: result %d\n", 373 resultp->devfsadm_error)); 374 error = resultp->devfsadm_error; 375 } 376 } else { 377 sdcmn_err6(("sdev_ki_call_devfsadmd with error %d\n", error)); 378 } 379 380 return (error); 381 } 382 383 static int 384 sdev_devfsadm_revoked(void) 385 { 386 struct door_info info; 387 int rv; 388 extern int sys_shutdown; 389 390 if (sys_shutdown) { 391 sdcmn_err6(("dev: shutdown observed\n")); 392 return (1); 393 } 394 395 if (sdev_upcall_door && !sdev_upcall_door_revoked) { 396 rv = door_ki_info(sdev_upcall_door, &info); 397 if ((rv == 0) && info.di_attributes & DOOR_REVOKED) { 398 sdcmn_err6(("lookup door: revoked\n")); 399 sdev_upcall_door_revoked = 1; 400 } 401 } 402 403 return (sdev_upcall_door_revoked); 404 } 405 406 /*ARGSUSED*/ 407 static void 408 sdev_config_all_thread(struct sdev_node *dv) 409 { 410 int32_t error = 0; 411 sdev_door_arg_t *argp; 412 sdev_door_res_t result; 413 414 argp = kmem_zalloc(sizeof (sdev_door_arg_t), KM_SLEEP); 415 argp->devfsadm_cmd = DEVFSADMD_RUN_ALL; 416 417 error = sdev_ki_call_devfsadmd(argp, &result); 418 if (!error) { 419 sdcmn_err6(("devfsadm result error: %d\n", 420 result.devfsadm_error)); 421 if (!result.devfsadm_error) { 422 DEVNAME_DEVFSADM_SET_RUN(devfsadm_state); 423 } else { 424 DEVNAME_DEVFSADM_SET_STOP(devfsadm_state); 425 } 426 } else { 427 DEVNAME_DEVFSADM_SET_STOP(devfsadm_state); 428 } 429 430 kmem_free(argp, sizeof (sdev_door_arg_t)); 431 done: 432 sdcmn_err6(("sdev_config_all_thread: stopping, devfsadm state 0x%x\n", 433 devfsadm_state)); 434 thread_exit(); 435 } 436 437 /* 438 * launch an asynchronous thread to do the devfsadm dev_config_all 439 */ 440 /*ARGSUSED*/ 441 void 442 sdev_devfsadmd_thread(struct sdev_node *ddv, struct sdev_node *dv, 443 struct cred *cred) 444 { 445 ASSERT(i_ddi_io_initialized()); 446 DEVNAME_DEVFSADM_SET_RUNNING(devfsadm_state); 447 (void) thread_create(NULL, 0, sdev_config_all_thread, dv, 0, 448 &p0, TS_RUN, MINCLSYSPRI); 449 } 450 451 int 452 devname_filename_register(char *name) 453 { 454 int error = 0; 455 char *strbuf; 456 char *namep; 457 int n; 458 459 strbuf = kmem_zalloc(MOD_MAXPATH, KM_SLEEP); 460 461 if (copyinstr(name, strbuf, MOD_MAXPATH, 0)) { 462 sdcmn_err6(("error copyin \n")); 463 error = EFAULT; 464 } else { 465 sdcmn_err6(("file %s is registering\n", strbuf)); 466 /* handling the daemon re-start situations */ 467 n = strlen(strbuf) + 1; 468 namep = i_ddi_strdup(strbuf, KM_SLEEP); 469 mutex_enter(&devfsadm_lock); 470 sdev_release_door(); 471 sdev_door_upcall_filename_size = n; 472 sdev_door_upcall_filename = namep; 473 sdcmn_err6(("size %d file name %s\n", 474 sdev_door_upcall_filename_size, 475 sdev_door_upcall_filename)); 476 cv_broadcast(&devfsadm_cv); 477 mutex_exit(&devfsadm_lock); 478 } 479 480 kmem_free(strbuf, MOD_MAXPATH); 481 return (error); 482 } 483