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 2006 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 #include <sys/param.h> 29 #include <sys/kmem.h> 30 #include <sys/errno.h> 31 #include <sys/proc.h> 32 #include <sys/disp.h> 33 #include <sys/vfs.h> 34 #include <sys/vnode.h> 35 #include <sys/pathname.h> 36 #include <sys/cred.h> 37 #include <sys/mount.h> 38 #include <sys/cmn_err.h> 39 #include <sys/debug.h> 40 #include <sys/systm.h> 41 #include <sys/dirent.h> 42 #include <fs/fs_subr.h> 43 #include <sys/fs/autofs.h> 44 #include <sys/callb.h> 45 #include <sys/sysmacros.h> 46 #include <sys/zone.h> 47 #include <sys/door.h> 48 #include <sys/fs/mntdata.h> 49 #include <nfs/mount.h> 50 #include <rpc/clnt.h> 51 #include <rpcsvc/autofs_prot.h> 52 #include <nfs/rnode.h> 53 #include <sys/utsname.h> 54 55 /* 56 * Autofs and Zones: 57 * 58 * Zones are delegated the responsibility of managing their own autofs mounts 59 * and maps. Each zone runs its own copy of automountd, with its own timeouts, 60 * and other logically "global" parameters. kRPC and virtualization in the 61 * loopback transport (tl) will prevent a zone from communicating with another 62 * zone's automountd. 63 * 64 * Each zone has its own "rootfnnode" and associated tree of auto nodes. 65 * 66 * Each zone also has its own set of "unmounter" kernel threads; these are 67 * created and run within the zone's context (ie, they are created via 68 * zthread_create()). 69 * 70 * Cross-zone mount triggers are disallowed. There is a check in 71 * auto_trigger_mount() to this effect; EPERM is returned to indicate that the 72 * mount is not owned by the caller. 73 * 74 * autofssys() enables a caller in the global zone to clean up in-kernel (as 75 * well as regular) autofs mounts via the unmount_tree() mechanism. This is 76 * routinely done when all mounts are removed as part of zone shutdown. 77 */ 78 #define TYPICALMAXPATHLEN 64 79 80 static kmutex_t autofs_nodeid_lock; 81 82 static int auto_perform_link(fnnode_t *, struct linka *, cred_t *); 83 static int auto_perform_actions(fninfo_t *, fnnode_t *, 84 action_list *, cred_t *); 85 static int auto_getmntpnt(vnode_t *, char *, vnode_t **, cred_t *); 86 static int auto_lookup_request(fninfo_t *, char *, struct linka *, 87 bool_t, bool_t *); 88 static int auto_mount_request(fninfo_t *, char *, action_list **, 89 bool_t); 90 91 extern struct autofs_globals *autofs_zone_init(void); 92 93 /* 94 * Clears the MF_INPROG flag, and wakes up those threads sleeping on 95 * fn_cv_mount if MF_WAITING is set. 96 */ 97 void 98 auto_unblock_others( 99 fnnode_t *fnp, 100 uint_t operation) /* either MF_INPROG or MF_LOOKUP */ 101 { 102 ASSERT(operation & (MF_INPROG | MF_LOOKUP)); 103 fnp->fn_flags &= ~operation; 104 if (fnp->fn_flags & MF_WAITING) { 105 fnp->fn_flags &= ~MF_WAITING; 106 cv_broadcast(&fnp->fn_cv_mount); 107 } 108 } 109 110 int 111 auto_wait4mount(fnnode_t *fnp) 112 { 113 int error; 114 k_sigset_t smask; 115 116 AUTOFS_DPRINT((4, "auto_wait4mount: fnp=%p\n", (void *)fnp)); 117 118 mutex_enter(&fnp->fn_lock); 119 while (fnp->fn_flags & (MF_INPROG | MF_LOOKUP)) { 120 /* 121 * There is a mount or a lookup in progress. 122 */ 123 fnp->fn_flags |= MF_WAITING; 124 sigintr(&smask, 1); 125 if (!cv_wait_sig(&fnp->fn_cv_mount, &fnp->fn_lock)) { 126 /* 127 * Decided not to wait for operation to 128 * finish after all. 129 */ 130 sigunintr(&smask); 131 mutex_exit(&fnp->fn_lock); 132 return (EINTR); 133 } 134 sigunintr(&smask); 135 } 136 error = fnp->fn_error; 137 138 if (error == EINTR) { 139 /* 140 * The thread doing the mount got interrupted, we need to 141 * try again, by returning EAGAIN. 142 */ 143 error = EAGAIN; 144 } 145 mutex_exit(&fnp->fn_lock); 146 147 AUTOFS_DPRINT((5, "auto_wait4mount: fnp=%p error=%d\n", (void *)fnp, 148 error)); 149 return (error); 150 } 151 152 int 153 auto_lookup_aux(fnnode_t *fnp, char *name, cred_t *cred) 154 { 155 struct fninfo *fnip; 156 struct linka link; 157 bool_t mountreq = FALSE; 158 int error = 0; 159 160 fnip = vfstofni(fntovn(fnp)->v_vfsp); 161 bzero(&link, sizeof (link)); 162 error = auto_lookup_request(fnip, name, &link, TRUE, &mountreq); 163 if (!error) { 164 if (link.link != NULL || link.link != '\0') { 165 /* 166 * This node should be a symlink 167 */ 168 error = auto_perform_link(fnp, &link, cred); 169 } else if (mountreq) { 170 /* 171 * The automount daemon is requesting a mount, 172 * implying this entry must be a wildcard match and 173 * therefore in need of verification that the entry 174 * exists on the server. 175 */ 176 mutex_enter(&fnp->fn_lock); 177 AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG); 178 fnp->fn_error = 0; 179 180 /* 181 * Unblock other lookup requests on this node, 182 * this is needed to let the lookup generated by 183 * the mount call to complete. The caveat is 184 * other lookups on this node can also get by, 185 * i.e., another lookup on this node that occurs 186 * while this lookup is attempting the mount 187 * would return a positive result no matter what. 188 * Therefore two lookups on the this node could 189 * potentially get disparate results. 190 */ 191 AUTOFS_UNBLOCK_OTHERS(fnp, MF_LOOKUP); 192 mutex_exit(&fnp->fn_lock); 193 /* 194 * auto_new_mount_thread fires up a new thread which 195 * calls automountd finishing up the work 196 */ 197 auto_new_mount_thread(fnp, name, cred); 198 199 /* 200 * At this point, we are simply another thread 201 * waiting for the mount to complete 202 */ 203 error = auto_wait4mount(fnp); 204 if (error == AUTOFS_SHUTDOWN) 205 error = ENOENT; 206 } 207 } 208 209 if (link.link) 210 kmem_free(link.link, strlen(link.link) + 1); 211 if (link.dir) 212 kmem_free(link.dir, strlen(link.dir) + 1); 213 mutex_enter(&fnp->fn_lock); 214 fnp->fn_error = error; 215 216 /* 217 * Notify threads waiting for lookup/mount that 218 * it's done. 219 */ 220 if (mountreq) { 221 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG); 222 } else { 223 AUTOFS_UNBLOCK_OTHERS(fnp, MF_LOOKUP); 224 } 225 mutex_exit(&fnp->fn_lock); 226 return (error); 227 } 228 229 /* 230 * Starting point for thread to handle mount requests with automountd. 231 * XXX auto_mount_thread() is not suspend-safe within the scope of 232 * the present model defined for cpr to suspend the system. Calls 233 * made by the auto_mount_thread() that have been identified to be unsafe 234 * are (1) RPC client handle setup and client calls to automountd which 235 * can block deep down in the RPC library, (2) kmem_alloc() calls with the 236 * KM_SLEEP flag which can block if memory is low, and (3) VFS_*(), and 237 * lookuppnvp() calls which can result in over the wire calls to servers. 238 * The thread should be completely reevaluated to make it suspend-safe in 239 * case of future updates to the cpr model. 240 */ 241 static void 242 auto_mount_thread(struct autofs_callargs *argsp) 243 { 244 struct fninfo *fnip; 245 fnnode_t *fnp; 246 vnode_t *vp; 247 char *name; 248 size_t namelen; 249 cred_t *cred; 250 action_list *alp = NULL; 251 int error; 252 callb_cpr_t cprinfo; 253 kmutex_t auto_mount_thread_cpr_lock; 254 255 mutex_init(&auto_mount_thread_cpr_lock, NULL, MUTEX_DEFAULT, NULL); 256 CALLB_CPR_INIT(&cprinfo, &auto_mount_thread_cpr_lock, 257 callb_generic_cpr, "auto_mount_thread"); 258 259 fnp = argsp->fnc_fnp; 260 vp = fntovn(fnp); 261 fnip = vfstofni(vp->v_vfsp); 262 name = argsp->fnc_name; 263 cred = argsp->fnc_cred; 264 ASSERT(crgetzoneid(argsp->fnc_cred) == fnip->fi_zoneid); 265 266 error = auto_mount_request(fnip, name, &alp, TRUE); 267 if (!error) 268 error = auto_perform_actions(fnip, fnp, alp, cred); 269 mutex_enter(&fnp->fn_lock); 270 fnp->fn_error = error; 271 272 /* 273 * Notify threads waiting for mount that 274 * it's done. 275 */ 276 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG); 277 mutex_exit(&fnp->fn_lock); 278 279 VN_RELE(vp); 280 crfree(argsp->fnc_cred); 281 namelen = strlen(argsp->fnc_name) + 1; 282 kmem_free(argsp->fnc_name, namelen); 283 kmem_free(argsp, sizeof (*argsp)); 284 285 mutex_enter(&auto_mount_thread_cpr_lock); 286 CALLB_CPR_EXIT(&cprinfo); 287 mutex_destroy(&auto_mount_thread_cpr_lock); 288 zthread_exit(); 289 /* NOTREACHED */ 290 } 291 292 static int autofs_thr_success = 0; 293 294 /* 295 * Creates new thread which calls auto_mount_thread which does 296 * the bulk of the work calling automountd, via 'auto_perform_actions'. 297 */ 298 void 299 auto_new_mount_thread(fnnode_t *fnp, char *name, cred_t *cred) 300 { 301 struct autofs_callargs *argsp; 302 303 argsp = kmem_alloc(sizeof (*argsp), KM_SLEEP); 304 VN_HOLD(fntovn(fnp)); 305 argsp->fnc_fnp = fnp; 306 argsp->fnc_name = kmem_alloc(strlen(name) + 1, KM_SLEEP); 307 (void) strcpy(argsp->fnc_name, name); 308 argsp->fnc_origin = curthread; 309 crhold(cred); 310 argsp->fnc_cred = cred; 311 312 (void) zthread_create(NULL, 0, auto_mount_thread, argsp, 0, 313 minclsyspri); 314 autofs_thr_success++; 315 } 316 317 318 int 319 auto_calldaemon( 320 zoneid_t zoneid, 321 int which, 322 xdrproc_t xarg_func, 323 void *argsp, 324 xdrproc_t xresp_func, 325 void *resp, 326 int reslen, 327 bool_t hard) /* retry forever? */ 328 { 329 330 int retry, error = 0; 331 k_sigset_t smask; 332 door_arg_t door_args; 333 door_handle_t dh; 334 XDR xdrarg, xdrres; 335 struct autofs_globals *fngp = NULL; 336 zone_t *autofs_zone; 337 void *orig_resp = NULL; 338 int orig_reslen = reslen; 339 autofs_door_args_t *xdr_argsp; 340 int xdr_len = 0; 341 342 autofs_zone = zone_find_by_id(zoneid); 343 344 345 /* 346 * We know that the current thread is doing work on 347 * behalf of its own zone, so it's ok to use 348 * curproc->p_zone. 349 */ 350 ASSERT(zoneid == getzoneid()); 351 if (zone_status_get(curproc->p_zone) >= 352 ZONE_IS_SHUTTING_DOWN) { 353 /* 354 * There's no point in trying to talk to 355 * automountd. Plus, zone_shutdown() is 356 * waiting for us. 357 */ 358 return (ECONNREFUSED); 359 } 360 361 if ((fngp = zone_getspecific(autofs_key, autofs_zone)) == 362 NULL) { 363 fngp = autofs_zone_init(); 364 (void) zone_setspecific(autofs_key, autofs_zone, fngp); 365 } 366 367 ASSERT(fngp != NULL); 368 369 if (argsp != NULL && (xdr_len = xdr_sizeof(xarg_func, argsp)) == 0) 370 return (EINVAL); 371 xdr_argsp = kmem_zalloc(xdr_len + sizeof (*xdr_argsp), KM_SLEEP); 372 xdr_argsp->xdr_len = xdr_len; 373 xdr_argsp->cmd = which; 374 375 if (argsp) { 376 xdrmem_create(&xdrarg, (char *)&xdr_argsp->xdr_arg, 377 xdr_argsp->xdr_len, XDR_ENCODE); 378 379 if (!(*xarg_func)(&xdrarg, argsp)) { 380 kmem_free(xdr_argsp, xdr_len + sizeof (*xdr_argsp)); 381 return (EINVAL); 382 } 383 } 384 385 /* 386 * We're saving off the original pointer and length due to the 387 * possibility that the results buffer returned by the door 388 * upcall can be different then what we passed in. This is because 389 * the door will allocate new memory if the results buffer passed 390 * in isn't large enough to hold what we need to send back. 391 * In this case we need to free the memory originally allocated 392 * for that buffer. 393 */ 394 if (orig_reslen) 395 orig_resp = kmem_zalloc(orig_reslen, KM_SLEEP); 396 397 do { 398 retry = 0; 399 mutex_enter(&fngp->fng_autofs_daemon_lock); 400 dh = fngp->fng_autofs_daemon_dh; 401 if (dh) 402 door_ki_hold(dh); 403 mutex_exit(&fngp->fng_autofs_daemon_lock); 404 405 if (dh == NULL) { 406 if (orig_resp) 407 kmem_free(orig_resp, orig_reslen); 408 kmem_free(xdr_argsp, xdr_len + sizeof (*xdr_argsp)); 409 return (ENOENT); 410 } 411 door_args.data_ptr = (char *)xdr_argsp; 412 door_args.data_size = sizeof (*xdr_argsp) + xdr_argsp->xdr_len; 413 door_args.desc_ptr = NULL; 414 door_args.desc_num = 0; 415 door_args.rbuf = orig_resp ? (char *)orig_resp : NULL; 416 door_args.rsize = reslen; 417 418 sigintr(&smask, 1); 419 error = door_ki_upcall(dh, &door_args); 420 sigunintr(&smask); 421 422 door_ki_rele(dh); 423 424 if (!error) { 425 autofs_door_res_t *adr = 426 (autofs_door_res_t *)door_args.rbuf; 427 if (door_args.rbuf != NULL && 428 (error = adr->res_status)) { 429 kmem_free(xdr_argsp, 430 xdr_len + sizeof (*xdr_argsp)); 431 if (orig_resp) 432 kmem_free(orig_resp, orig_reslen); 433 return (error); 434 } 435 continue; 436 } 437 switch (error) { 438 case EINTR: 439 /* 440 * interrupts should be handled properly by the 441 * door upcall. 442 * 443 * We may have gotten EINTR for other reasons 444 * like the door being revoked on us. Instead 445 * of trying to extract this out of the door 446 * handle, sleep and try again, if still 447 * revoked we will get EBADF next time 448 * through. 449 */ 450 case EAGAIN: /* process may be forking */ 451 /* 452 * Back off for a bit 453 */ 454 delay(hz); 455 retry = 1; 456 break; 457 case EBADF: /* Invalid door */ 458 case EINVAL: /* Not a door, wrong target */ 459 /* 460 * A fatal door error, if our failing door 461 * handle is the current door handle, clean 462 * up our state. 463 */ 464 mutex_enter(&fngp->fng_autofs_daemon_lock); 465 if (dh == fngp->fng_autofs_daemon_dh) { 466 door_ki_rele(fngp->fng_autofs_daemon_dh); 467 fngp->fng_autofs_daemon_dh = NULL; 468 } 469 mutex_exit(&fngp->fng_autofs_daemon_lock); 470 AUTOFS_DPRINT((5, 471 "auto_calldaemon error=%d\n", error)); 472 if (hard) { 473 if (!fngp->fng_printed_not_running_msg) { 474 fngp->fng_printed_not_running_msg = 1; 475 zprintf(zoneid, "automountd not "\ 476 "running, retrying\n"); 477 } 478 delay(hz); 479 retry = 1; 480 break; 481 } else { 482 error = ECONNREFUSED; 483 kmem_free(xdr_argsp, 484 xdr_len + sizeof (*xdr_argsp)); 485 if (orig_resp) 486 kmem_free(orig_resp, orig_reslen); 487 return (error); 488 } 489 default: /* Unknown must be fatal */ 490 error = ENOENT; 491 kmem_free(xdr_argsp, xdr_len + sizeof (*xdr_argsp)); 492 if (orig_resp) 493 kmem_free(orig_resp, orig_reslen); 494 return (error); 495 } 496 } while (retry); 497 498 if (fngp->fng_printed_not_running_msg == 1) { 499 fngp->fng_printed_not_running_msg = 0; 500 zprintf(zoneid, "automountd OK\n"); 501 } 502 503 if (orig_resp && orig_reslen) { 504 autofs_door_res_t *door_resp; 505 door_resp = 506 (autofs_door_res_t *)door_args.rbuf; 507 if ((void *)door_args.rbuf != orig_resp) 508 kmem_free(orig_resp, orig_reslen); 509 xdrmem_create(&xdrres, (char *)&door_resp->xdr_res, 510 door_resp->xdr_len, XDR_DECODE); 511 if (!((*xresp_func)(&xdrres, resp))) 512 error = EINVAL; 513 kmem_free(door_args.rbuf, door_args.rsize); 514 } 515 kmem_free(xdr_argsp, xdr_len + sizeof (*xdr_argsp)); 516 return (error); 517 } 518 519 static int 520 auto_null_request(fninfo_t *fnip, bool_t hard) 521 { 522 int error; 523 struct autofs_globals *fngp = vntofn(fnip->fi_rootvp)->fn_globals; 524 525 AUTOFS_DPRINT((4, "\tauto_null_request\n")); 526 527 error = auto_calldaemon(fngp->fng_zoneid, 528 NULLPROC, 529 xdr_void, 530 NULL, 531 xdr_void, 532 NULL, 533 0, 534 hard); 535 536 AUTOFS_DPRINT((5, "\tauto_null_request: error=%d\n", error)); 537 return (error); 538 } 539 540 static int 541 auto_lookup_request( 542 fninfo_t *fnip, 543 char *key, 544 struct linka *lnp, 545 bool_t hard, 546 bool_t *mountreq) 547 { 548 int error; 549 struct autofs_globals *fngp; 550 struct autofs_lookupargs reqst; 551 autofs_lookupres *resp; 552 struct linka *p; 553 554 555 AUTOFS_DPRINT((4, "auto_lookup_equest: path=%s name=%s\n", 556 fnip->fi_path, key)); 557 558 fngp = vntofn(fnip->fi_rootvp)->fn_globals; 559 560 reqst.map = fnip->fi_map; 561 reqst.path = fnip->fi_path; 562 563 if (fnip->fi_flags & MF_DIRECT) 564 reqst.name = fnip->fi_key; 565 else 566 reqst.name = key; 567 AUTOFS_DPRINT((4, "auto_lookup_request: using key=%s\n", reqst.name)); 568 569 reqst.subdir = fnip->fi_subdir; 570 reqst.opts = fnip->fi_opts; 571 reqst.isdirect = fnip->fi_flags & MF_DIRECT ? TRUE : FALSE; 572 573 resp = kmem_zalloc(sizeof (*resp), KM_SLEEP); 574 575 error = auto_calldaemon(fngp->fng_zoneid, 576 AUTOFS_LOOKUP, 577 xdr_autofs_lookupargs, 578 &reqst, 579 xdr_autofs_lookupres, 580 (void *)resp, 581 sizeof (autofs_lookupres), 582 hard); 583 584 585 if (error) { 586 xdr_free(xdr_autofs_lookupres, (char *)resp); 587 kmem_free(resp, sizeof (*resp)); 588 return (error); 589 } 590 591 if (!error) { 592 fngp->fng_verbose = resp->lu_verbose; 593 switch (resp->lu_res) { 594 case AUTOFS_OK: 595 switch (resp->lu_type.action) { 596 case AUTOFS_MOUNT_RQ: 597 lnp->link = NULL; 598 lnp->dir = NULL; 599 *mountreq = TRUE; 600 break; 601 case AUTOFS_LINK_RQ: 602 p = 603 &resp->lu_type.lookup_result_type_u.lt_linka; 604 lnp->dir = kmem_alloc(strlen(p->dir) + 1, 605 KM_SLEEP); 606 (void) strcpy(lnp->dir, p->dir); 607 lnp->link = kmem_alloc(strlen(p->link) + 1, 608 KM_SLEEP); 609 (void) strcpy(lnp->link, p->link); 610 break; 611 case AUTOFS_NONE: 612 lnp->link = NULL; 613 lnp->dir = NULL; 614 break; 615 default: 616 auto_log(fngp->fng_verbose, 617 fngp->fng_zoneid, CE_WARN, 618 "auto_lookup_request: bad action type %d", 619 resp->lu_res); 620 error = ENOENT; 621 } 622 break; 623 case AUTOFS_NOENT: 624 error = ENOENT; 625 break; 626 default: 627 error = ENOENT; 628 auto_log(fngp->fng_verbose, fngp->fng_zoneid, CE_WARN, 629 "auto_lookup_request: unknown result: %d", 630 resp->lu_res); 631 break; 632 } 633 } 634 done: 635 xdr_free(xdr_autofs_lookupres, (char *)resp); 636 kmem_free(resp, sizeof (*resp)); 637 AUTOFS_DPRINT((5, "auto_lookup_request: path=%s name=%s error=%d\n", 638 fnip->fi_path, key, error)); 639 return (error); 640 } 641 642 static int 643 auto_mount_request( 644 fninfo_t *fnip, 645 char *key, 646 action_list **alpp, 647 bool_t hard) 648 { 649 int error; 650 struct autofs_globals *fngp; 651 autofs_lookupargs reqst; 652 autofs_mountres *xdrres = NULL; 653 654 AUTOFS_DPRINT((4, "auto_mount_request: path=%s name=%s\n", 655 fnip->fi_path, key)); 656 657 fngp = vntofn(fnip->fi_rootvp)->fn_globals; 658 reqst.map = fnip->fi_map; 659 reqst.path = fnip->fi_path; 660 661 if (fnip->fi_flags & MF_DIRECT) 662 reqst.name = fnip->fi_key; 663 else 664 reqst.name = key; 665 666 AUTOFS_DPRINT((4, "auto_mount_request: using key=%s\n", reqst.name)); 667 668 reqst.subdir = fnip->fi_subdir; 669 reqst.opts = fnip->fi_opts; 670 reqst.isdirect = fnip->fi_flags & MF_DIRECT ? TRUE : FALSE; 671 672 xdrres = kmem_zalloc(sizeof (*xdrres), KM_SLEEP); 673 674 error = auto_calldaemon(fngp->fng_zoneid, 675 AUTOFS_MNTINFO, 676 xdr_autofs_lookupargs, 677 &reqst, 678 xdr_autofs_mountres, 679 (void *)xdrres, 680 sizeof (autofs_mountres), 681 hard); 682 683 684 if (!error) { 685 fngp->fng_verbose = xdrres->mr_verbose; 686 switch (xdrres->mr_type.status) { 687 case AUTOFS_ACTION: 688 error = 0; 689 /* 690 * Save the action list since it is used by 691 * the caller. We NULL the action list pointer 692 * in 'result' so that xdr_free() will not free 693 * the list. 694 */ 695 *alpp = xdrres->mr_type.mount_result_type_u.list; 696 xdrres->mr_type.mount_result_type_u.list = NULL; 697 break; 698 case AUTOFS_DONE: 699 error = xdrres->mr_type.mount_result_type_u.error; 700 break; 701 default: 702 error = ENOENT; 703 auto_log(fngp->fng_verbose, fngp->fng_zoneid, CE_WARN, 704 "auto_mount_request: unknown status %d", 705 xdrres->mr_type.status); 706 break; 707 } 708 } 709 710 xdr_free(xdr_autofs_mountres, (char *)xdrres); 711 kmem_free(xdrres, sizeof (*xdrres)); 712 713 714 AUTOFS_DPRINT((5, "auto_mount_request: path=%s name=%s error=%d\n", 715 fnip->fi_path, key, error)); 716 return (error); 717 } 718 719 720 static int 721 auto_send_unmount_request( 722 fninfo_t *fnip, 723 umntrequest *ul, 724 bool_t hard) 725 { 726 int error; 727 umntres xdrres; 728 729 struct autofs_globals *fngp = vntofn(fnip->fi_rootvp)->fn_globals; 730 731 AUTOFS_DPRINT((4, "\tauto_send_unmount_request: fstype=%s " 732 " mntpnt=%s\n", ul->fstype, ul->mntpnt)); 733 734 bzero(&xdrres, sizeof (umntres)); 735 error = auto_calldaemon(fngp->fng_zoneid, 736 AUTOFS_UNMOUNT, 737 xdr_umntrequest, 738 (void *)ul, 739 xdr_umntres, 740 (void *)&xdrres, 741 sizeof (umntres), 742 hard); 743 744 AUTOFS_DPRINT((5, "\tauto_send_unmount_request: error=%d\n", error)); 745 746 return (error); 747 } 748 749 static int 750 auto_perform_link(fnnode_t *fnp, struct linka *linkp, cred_t *cred) 751 { 752 vnode_t *vp; 753 size_t len; 754 char *tmp; 755 756 AUTOFS_DPRINT((3, "auto_perform_link: fnp=%p dir=%s link=%s\n", 757 (void *)fnp, linkp->dir, linkp->link)); 758 759 len = strlen(linkp->link) + 1; /* include '\0' */ 760 tmp = kmem_zalloc(len, KM_SLEEP); 761 (void) kcopy(linkp->link, tmp, len); 762 mutex_enter(&fnp->fn_lock); 763 fnp->fn_symlink = tmp; 764 fnp->fn_symlinklen = (uint_t)len; 765 fnp->fn_flags |= MF_THISUID_MATCH_RQD; 766 crhold(cred); 767 fnp->fn_cred = cred; 768 mutex_exit(&fnp->fn_lock); 769 770 vp = fntovn(fnp); 771 vp->v_type = VLNK; 772 773 return (0); 774 } 775 776 static void 777 auto_free_autofs_args(struct mounta *m) 778 { 779 autofs_args *aargs = (autofs_args *)m->dataptr; 780 781 if (aargs->addr.buf) 782 kmem_free(aargs->addr.buf, aargs->addr.len); 783 if (aargs->path) 784 kmem_free(aargs->path, strlen(aargs->path) + 1); 785 if (aargs->opts) 786 kmem_free(aargs->opts, strlen(aargs->opts) + 1); 787 if (aargs->map) 788 kmem_free(aargs->map, strlen(aargs->map) + 1); 789 if (aargs->subdir) 790 kmem_free(aargs->subdir, strlen(aargs->subdir) + 1); 791 if (aargs->key) 792 kmem_free(aargs->key, strlen(aargs->key) + 1); 793 kmem_free(aargs, sizeof (*aargs)); 794 } 795 796 static void 797 auto_free_action_list(action_list *alp) 798 { 799 struct mounta *m; 800 action_list *lastalp; 801 char *fstype; 802 803 m = &alp->action.action_list_entry_u.mounta; 804 while (alp != NULL) { 805 fstype = alp->action.action_list_entry_u.mounta.fstype; 806 m = &alp->action.action_list_entry_u.mounta; 807 if (m->dataptr) { 808 if (strcmp(fstype, "autofs") == 0) { 809 auto_free_autofs_args(m); 810 } 811 } 812 if (m->spec) 813 kmem_free(m->spec, strlen(m->spec) + 1); 814 if (m->dir) 815 kmem_free(m->dir, strlen(m->dir) + 1); 816 if (m->fstype) 817 kmem_free(m->fstype, strlen(m->fstype) + 1); 818 if (m->optptr) 819 kmem_free(m->optptr, m->optlen); 820 lastalp = alp; 821 alp = alp->next; 822 kmem_free(lastalp, sizeof (*lastalp)); 823 } 824 } 825 826 static boolean_t 827 auto_invalid_autofs(fninfo_t *dfnip, fnnode_t *dfnp, action_list *p) 828 { 829 struct mounta *m; 830 struct autofs_args *argsp; 831 vnode_t *dvp; 832 char buff[AUTOFS_MAXPATHLEN]; 833 size_t len; 834 struct autofs_globals *fngp; 835 836 fngp = dfnp->fn_globals; 837 dvp = fntovn(dfnp); 838 839 m = &p->action.action_list_entry_u.mounta; 840 /* 841 * Make sure we aren't geting passed NULL values or a "dir" that 842 * isn't "." and doesn't begin with "./". 843 * 844 * We also only want to perform autofs mounts, so make sure 845 * no-one is trying to trick us into doing anything else. 846 */ 847 if (m->spec == NULL || m->dir == NULL || m->dir[0] != '.' || 848 (m->dir[1] != '/' && m->dir[1] != '\0') || 849 m->fstype == NULL || strcmp(m->fstype, "autofs") != 0 || 850 m->dataptr == NULL || m->datalen != sizeof (struct autofs_args) || 851 m->optptr == NULL) 852 return (B_TRUE); 853 /* 854 * We also don't like ".."s in the pathname. Symlinks are 855 * handled by the fact that we'll use NOFOLLOW when we do 856 * lookup()s. 857 */ 858 if (strstr(m->dir, "/../") != NULL || 859 (len = strlen(m->dir)) > sizeof ("/..") - 1 && 860 m->dir[len] == '.' && m->dir[len - 1] == '.' && 861 m->dir[len - 2] == '/') 862 return (B_TRUE); 863 argsp = (struct autofs_args *)m->dataptr; 864 /* 865 * We don't want NULL values here either. 866 */ 867 if (argsp->addr.buf == NULL || argsp->path == NULL || 868 argsp->opts == NULL || argsp->map == NULL || argsp->subdir == NULL) 869 return (B_TRUE); 870 /* 871 * We know what the claimed pathname *should* look like: 872 * 873 * If the parent (dfnp) is a mount point (VROOT), then 874 * the path should be (dfnip->fi_path + m->dir). 875 * 876 * Else, we know we're only two levels deep, so we use 877 * (dfnip->fi_path + dfnp->fn_name + m->dir). 878 * 879 * Furthermore, "." only makes sense if dfnp is a 880 * trigger node. 881 * 882 * At this point it seems like the passed-in path is 883 * redundant. 884 */ 885 if (dvp->v_flag & VROOT) { 886 if (m->dir[1] == '\0' && !(dfnp->fn_flags & MF_TRIGGER)) 887 return (B_TRUE); 888 (void) snprintf(buff, sizeof (buff), "%s%s", 889 dfnip->fi_path, m->dir + 1); 890 } else { 891 (void) snprintf(buff, sizeof (buff), "%s/%s%s", 892 dfnip->fi_path, dfnp->fn_name, m->dir + 1); 893 } 894 if (strcmp(argsp->path, buff) != 0) { 895 auto_log(fngp->fng_verbose, fngp->fng_zoneid, 896 CE_WARN, "autofs: expected path of '%s', " 897 "got '%s' instead.", buff, argsp->path); 898 return (B_TRUE); 899 } 900 return (B_FALSE); /* looks OK */ 901 } 902 903 /* 904 * auto_invalid_action will validate the action_list received. If all is good 905 * this function returns FALSE, if there is a problem it returns TRUE. 906 */ 907 static boolean_t 908 auto_invalid_action(fninfo_t *dfnip, fnnode_t *dfnp, action_list *alistpp) 909 { 910 911 /* 912 * Before we go any further, this better be a mount request. 913 */ 914 if (alistpp->action.action != AUTOFS_MOUNT_RQ) 915 return (B_TRUE); 916 return (auto_invalid_autofs(dfnip, dfnp, alistpp)); 917 918 } 919 920 static int 921 auto_perform_actions( 922 fninfo_t *dfnip, 923 fnnode_t *dfnp, 924 action_list *alp, 925 cred_t *cred) /* Credentials of the caller */ 926 { 927 928 action_list *p; 929 struct mounta *m, margs; 930 struct autofs_args *argsp; 931 int error, success = 0; 932 vnode_t *mvp, *dvp, *newvp; 933 fnnode_t *newfnp, *mfnp; 934 int auto_mount = 0; 935 int save_triggers = 0; 936 int update_times = 0; 937 char *mntpnt; 938 char buff[AUTOFS_MAXPATHLEN]; 939 timestruc_t now; 940 struct autofs_globals *fngp; 941 cred_t *zcred; 942 943 AUTOFS_DPRINT((4, "auto_perform_actions: alp=%p\n", 944 (void *)alp)); 945 946 fngp = dfnp->fn_globals; 947 dvp = fntovn(dfnp); 948 949 /* 950 * As automountd running in a zone may be compromised, and this may be 951 * an attack, we can't trust everything passed in by automountd, and we 952 * need to do argument verification. We'll issue a warning and drop 953 * the request if it doesn't seem right. 954 */ 955 956 for (p = alp; p != NULL; p = p->next) { 957 if (auto_invalid_action(dfnip, dfnp, p)) { 958 /* 959 * This warning should be sent to the global zone, 960 * since presumably the zone administrator is the same 961 * as the attacker. 962 */ 963 cmn_err(CE_WARN, "autofs: invalid action list received " 964 "by automountd in zone %s.", 965 curproc->p_zone->zone_name); 966 /* 967 * This conversation is over. 968 */ 969 xdr_free(xdr_action_list, (char *)alp); 970 return (EINVAL); 971 } 972 } 973 974 zcred = zone_get_kcred(getzoneid()); 975 ASSERT(zcred != NULL); 976 977 if (vn_mountedvfs(dvp) != NULL) { 978 /* 979 * The daemon successfully mounted a filesystem 980 * on the AUTOFS root node. 981 */ 982 mutex_enter(&dfnp->fn_lock); 983 dfnp->fn_flags |= MF_MOUNTPOINT; 984 ASSERT(dfnp->fn_dirents == NULL); 985 mutex_exit(&dfnp->fn_lock); 986 success++; 987 } else { 988 /* 989 * Clear MF_MOUNTPOINT. 990 */ 991 mutex_enter(&dfnp->fn_lock); 992 if (dfnp->fn_flags & MF_MOUNTPOINT) { 993 AUTOFS_DPRINT((10, "autofs: clearing mountpoint " 994 "flag on %s.", dfnp->fn_name)); 995 ASSERT(dfnp->fn_dirents == NULL); 996 ASSERT(dfnp->fn_trigger == NULL); 997 } 998 dfnp->fn_flags &= ~MF_MOUNTPOINT; 999 mutex_exit(&dfnp->fn_lock); 1000 } 1001 1002 for (p = alp; p != NULL; p = p->next) { 1003 1004 vfs_t *vfsp; /* dummy argument */ 1005 vfs_t *mvfsp; 1006 1007 auto_mount = 0; 1008 1009 m = &p->action.action_list_entry_u.mounta; 1010 argsp = (struct autofs_args *)m->dataptr; 1011 ASSERT(strcmp(m->fstype, "autofs") == 0); 1012 /* 1013 * use the parent directory's timeout since it's the 1014 * one specified/inherited by automount. 1015 */ 1016 argsp->mount_to = dfnip->fi_mount_to; 1017 /* 1018 * The mountpoint is relative, and it is guaranteed to 1019 * begin with "." 1020 * 1021 */ 1022 ASSERT(m->dir[0] == '.'); 1023 if (m->dir[0] == '.' && m->dir[1] == '\0') { 1024 /* 1025 * mounting on the trigger node 1026 */ 1027 mvp = dvp; 1028 VN_HOLD(mvp); 1029 goto mount; 1030 } 1031 /* 1032 * ignore "./" in front of mountpoint 1033 */ 1034 ASSERT(m->dir[1] == '/'); 1035 mntpnt = m->dir + 2; 1036 1037 AUTOFS_DPRINT((10, "\tdfnip->fi_path=%s\n", dfnip->fi_path)); 1038 AUTOFS_DPRINT((10, "\tdfnip->fi_flags=%x\n", dfnip->fi_flags)); 1039 AUTOFS_DPRINT((10, "\tmntpnt=%s\n", mntpnt)); 1040 1041 if (dfnip->fi_flags & MF_DIRECT) { 1042 AUTOFS_DPRINT((10, "\tDIRECT\n")); 1043 (void) sprintf(buff, "%s/%s", dfnip->fi_path, 1044 mntpnt); 1045 } else { 1046 AUTOFS_DPRINT((10, "\tINDIRECT\n")); 1047 (void) sprintf(buff, "%s/%s/%s", 1048 dfnip->fi_path, 1049 dfnp->fn_name, mntpnt); 1050 } 1051 1052 if (vn_mountedvfs(dvp) == NULL) { 1053 /* 1054 * Daemon didn't mount anything on the root 1055 * We have to create the mountpoint if it 1056 * doesn't exist already 1057 * 1058 * We use the caller's credentials in case a 1059 * UID-match is required 1060 * (MF_THISUID_MATCH_RQD). 1061 */ 1062 rw_enter(&dfnp->fn_rwlock, RW_WRITER); 1063 error = auto_search(dfnp, mntpnt, &mfnp, cred); 1064 if (error == 0) { 1065 /* 1066 * AUTOFS mountpoint exists 1067 */ 1068 if (vn_mountedvfs(fntovn(mfnp)) != NULL) { 1069 cmn_err(CE_PANIC, 1070 "auto_perform_actions:" 1071 " mfnp=%p covered", 1072 (void *)mfnp); 1073 } 1074 } else { 1075 /* 1076 * Create AUTOFS mountpoint 1077 */ 1078 ASSERT((dfnp->fn_flags & MF_MOUNTPOINT) == 0); 1079 error = auto_enter(dfnp, mntpnt, &mfnp, cred); 1080 ASSERT(mfnp->fn_linkcnt == 1); 1081 mfnp->fn_linkcnt++; 1082 } 1083 if (!error) 1084 update_times = 1; 1085 rw_exit(&dfnp->fn_rwlock); 1086 ASSERT(error != EEXIST); 1087 if (!error) { 1088 /* 1089 * mfnp is already held. 1090 */ 1091 mvp = fntovn(mfnp); 1092 } else { 1093 auto_log(fngp->fng_verbose, fngp->fng_zoneid, 1094 CE_WARN, "autofs: mount of %s " 1095 "failed - can't create" 1096 " mountpoint.", buff); 1097 continue; 1098 } 1099 } else { 1100 /* 1101 * Find mountpoint in VFS mounted here. If not 1102 * found, fail the submount, though the overall 1103 * mount has succeeded since the root is 1104 * mounted. 1105 */ 1106 if (error = auto_getmntpnt(dvp, mntpnt, &mvp, 1107 kcred)) { 1108 auto_log(fngp->fng_verbose, 1109 fngp->fng_zoneid, 1110 CE_WARN, "autofs: mount of %s " 1111 "failed - mountpoint doesn't" 1112 " exist.", buff); 1113 continue; 1114 } 1115 if (mvp->v_type == VLNK) { 1116 auto_log(fngp->fng_verbose, 1117 fngp->fng_zoneid, 1118 CE_WARN, "autofs: %s symbolic " 1119 "link: not a valid mountpoint " 1120 "- mount failed", buff); 1121 VN_RELE(mvp); 1122 error = ENOENT; 1123 continue; 1124 } 1125 } 1126 mount: 1127 m->flags |= MS_SYSSPACE | MS_OPTIONSTR; 1128 1129 /* 1130 * Copy mounta struct here so we can substitute a 1131 * buffer that is large enough to hold the returned 1132 * option string, if that string is longer than the 1133 * input option string. 1134 * This can happen if there are default options enabled 1135 * that were not in the input option string. 1136 */ 1137 bcopy(m, &margs, sizeof (*m)); 1138 margs.optptr = kmem_alloc(MAX_MNTOPT_STR, KM_SLEEP); 1139 margs.optlen = MAX_MNTOPT_STR; 1140 (void) strcpy(margs.optptr, m->optptr); 1141 margs.dir = argsp->path; 1142 1143 /* 1144 * We use the zone's kcred because we don't want the 1145 * zone to be able to thus do something it wouldn't 1146 * normally be able to. 1147 */ 1148 error = domount(NULL, &margs, mvp, zcred, &vfsp); 1149 kmem_free(margs.optptr, MAX_MNTOPT_STR); 1150 if (error != 0) { 1151 auto_log(fngp->fng_verbose, fngp->fng_zoneid, 1152 CE_WARN, "autofs: domount of %s failed " 1153 "error=%d", buff, error); 1154 VN_RELE(mvp); 1155 continue; 1156 } 1157 VFS_RELE(vfsp); 1158 1159 /* 1160 * If mountpoint is an AUTOFS node, then I'm going to 1161 * flag it that the Filesystem mounted on top was 1162 * mounted in the kernel so that the unmount can be 1163 * done inside the kernel as well. 1164 * I don't care to flag non-AUTOFS mountpoints when an 1165 * AUTOFS in-kernel mount was done on top, because the 1166 * unmount routine already knows that such case was 1167 * done in the kernel. 1168 */ 1169 if (vfs_matchops(dvp->v_vfsp, 1170 vfs_getops(mvp->v_vfsp))) { 1171 mfnp = vntofn(mvp); 1172 mutex_enter(&mfnp->fn_lock); 1173 mfnp->fn_flags |= MF_IK_MOUNT; 1174 mutex_exit(&mfnp->fn_lock); 1175 } 1176 1177 (void) vn_vfswlock_wait(mvp); 1178 mvfsp = vn_mountedvfs(mvp); 1179 if (mvfsp != NULL) { 1180 vfs_lock_wait(mvfsp); 1181 vn_vfsunlock(mvp); 1182 error = VFS_ROOT(mvfsp, &newvp); 1183 vfs_unlock(mvfsp); 1184 if (error) { 1185 /* 1186 * We've dropped the locks, so let's 1187 * get the mounted vfs again in case 1188 * it changed. 1189 */ 1190 (void) vn_vfswlock_wait(mvp); 1191 mvfsp = vn_mountedvfs(mvp); 1192 if (mvfsp != NULL) { 1193 error = dounmount(mvfsp, 0, CRED()); 1194 if (error) { 1195 cmn_err(CE_WARN, 1196 "autofs: could" 1197 " not unmount" 1198 " vfs=%p", 1199 (void *)mvfsp); 1200 } 1201 } else 1202 vn_vfsunlock(mvp); 1203 VN_RELE(mvp); 1204 continue; 1205 } 1206 } else { 1207 vn_vfsunlock(mvp); 1208 VN_RELE(mvp); 1209 continue; 1210 } 1211 1212 auto_mount = vfs_matchops(dvp->v_vfsp, 1213 vfs_getops(newvp->v_vfsp)); 1214 newfnp = vntofn(newvp); 1215 newfnp->fn_parent = dfnp; 1216 1217 /* 1218 * At this time we want to save the AUTOFS filesystem 1219 * as a trigger node. (We only do this if the mount 1220 * occurred on a node different from the root. 1221 * We look at the trigger nodes during 1222 * the automatic unmounting to make sure we remove them 1223 * as a unit and remount them as a unit if the 1224 * filesystem mounted at the root could not be 1225 * unmounted. 1226 */ 1227 if (auto_mount && (error == 0) && (mvp != dvp)) { 1228 save_triggers++; 1229 /* 1230 * Add AUTOFS mount to hierarchy 1231 */ 1232 newfnp->fn_flags |= MF_TRIGGER; 1233 rw_enter(&newfnp->fn_rwlock, RW_WRITER); 1234 newfnp->fn_next = dfnp->fn_trigger; 1235 rw_exit(&newfnp->fn_rwlock); 1236 rw_enter(&dfnp->fn_rwlock, RW_WRITER); 1237 dfnp->fn_trigger = newfnp; 1238 rw_exit(&dfnp->fn_rwlock); 1239 /* 1240 * Don't VN_RELE(newvp) here since dfnp now 1241 * holds reference to it as its trigger node. 1242 */ 1243 AUTOFS_DPRINT((10, "\tadding trigger %s to %s\n", 1244 newfnp->fn_name, dfnp->fn_name)); 1245 AUTOFS_DPRINT((10, "\tfirst trigger is %s\n", 1246 dfnp->fn_trigger->fn_name)); 1247 if (newfnp->fn_next != NULL) 1248 AUTOFS_DPRINT((10, 1249 "\tnext trigger is %s\n", 1250 newfnp->fn_next->fn_name)); 1251 else 1252 AUTOFS_DPRINT((10, 1253 "\tno next trigger\n")); 1254 } else 1255 VN_RELE(newvp); 1256 1257 if (!error) 1258 success++; 1259 1260 if (update_times) { 1261 gethrestime(&now); 1262 dfnp->fn_atime = dfnp->fn_mtime = now; 1263 } 1264 1265 VN_RELE(mvp); 1266 } 1267 1268 if (save_triggers) { 1269 /* 1270 * Make sure the parent can't be freed while it has triggers. 1271 */ 1272 VN_HOLD(dvp); 1273 } 1274 1275 crfree(zcred); 1276 1277 done: 1278 /* 1279 * Return failure if daemon didn't mount anything, and all 1280 * kernel mounts attempted failed. 1281 */ 1282 error = success ? 0 : ENOENT; 1283 1284 if (alp != NULL) { 1285 if ((error == 0) && save_triggers) { 1286 /* 1287 * Save action_list information, so that we can use it 1288 * when it comes time to remount the trigger nodes 1289 * The action list is freed when the directory node 1290 * containing the reference to it is unmounted in 1291 * unmount_tree(). 1292 */ 1293 mutex_enter(&dfnp->fn_lock); 1294 ASSERT(dfnp->fn_alp == NULL); 1295 dfnp->fn_alp = alp; 1296 mutex_exit(&dfnp->fn_lock); 1297 } else { 1298 /* 1299 * free the action list now, 1300 */ 1301 xdr_free(xdr_action_list, (char *)alp); 1302 } 1303 } 1304 AUTOFS_DPRINT((5, "auto_perform_actions: error=%d\n", error)); 1305 return (error); 1306 } 1307 1308 fnnode_t * 1309 auto_makefnnode( 1310 vtype_t type, 1311 vfs_t *vfsp, 1312 char *name, 1313 cred_t *cred, 1314 struct autofs_globals *fngp) 1315 { 1316 fnnode_t *fnp; 1317 vnode_t *vp; 1318 char *tmpname; 1319 timestruc_t now; 1320 /* 1321 * autofs uses odd inode numbers 1322 * automountd uses even inode numbers 1323 * 1324 * To preserve the age-old semantics that inum+devid is unique across 1325 * the system, this variable must be global across zones. 1326 */ 1327 static ino_t nodeid = 3; 1328 1329 fnp = kmem_zalloc(sizeof (*fnp), KM_SLEEP); 1330 fnp->fn_vnode = vn_alloc(KM_SLEEP); 1331 1332 vp = fntovn(fnp); 1333 tmpname = kmem_alloc(strlen(name) + 1, KM_SLEEP); 1334 (void) strcpy(tmpname, name); 1335 fnp->fn_name = &tmpname[0]; 1336 fnp->fn_namelen = (int)strlen(tmpname) + 1; /* include '\0' */ 1337 fnp->fn_uid = crgetuid(cred); 1338 fnp->fn_gid = crgetgid(cred); 1339 /* 1340 * ".." is added in auto_enter and auto_mount. 1341 * "." is added in auto_mkdir and auto_mount. 1342 */ 1343 /* 1344 * Note that fn_size and fn_linkcnt are already 0 since 1345 * we used kmem_zalloc to allocated fnp 1346 */ 1347 fnp->fn_mode = AUTOFS_MODE; 1348 gethrestime(&now); 1349 fnp->fn_atime = fnp->fn_mtime = fnp->fn_ctime = now; 1350 fnp->fn_ref_time = now.tv_sec; 1351 mutex_enter(&autofs_nodeid_lock); 1352 fnp->fn_nodeid = nodeid; 1353 nodeid += 2; 1354 fnp->fn_globals = fngp; 1355 fngp->fng_fnnode_count++; 1356 mutex_exit(&autofs_nodeid_lock); 1357 vn_setops(vp, auto_vnodeops); 1358 vp->v_type = type; 1359 vp->v_data = (void *)fnp; 1360 vp->v_vfsp = vfsp; 1361 mutex_init(&fnp->fn_lock, NULL, MUTEX_DEFAULT, NULL); 1362 rw_init(&fnp->fn_rwlock, NULL, RW_DEFAULT, NULL); 1363 cv_init(&fnp->fn_cv_mount, NULL, CV_DEFAULT, NULL); 1364 vn_exists(vp); 1365 return (fnp); 1366 } 1367 1368 1369 void 1370 auto_freefnnode(fnnode_t *fnp) 1371 { 1372 vnode_t *vp = fntovn(fnp); 1373 1374 AUTOFS_DPRINT((4, "auto_freefnnode: fnp=%p\n", (void *)fnp)); 1375 1376 ASSERT(fnp->fn_linkcnt == 0); 1377 ASSERT(vp->v_count == 0); 1378 ASSERT(fnp->fn_dirents == NULL); 1379 ASSERT(fnp->fn_parent == NULL); 1380 1381 vn_invalid(vp); 1382 kmem_free(fnp->fn_name, fnp->fn_namelen); 1383 if (fnp->fn_symlink) { 1384 ASSERT(fnp->fn_flags & MF_THISUID_MATCH_RQD); 1385 kmem_free(fnp->fn_symlink, fnp->fn_symlinklen); 1386 } 1387 if (fnp->fn_cred) 1388 crfree(fnp->fn_cred); 1389 mutex_destroy(&fnp->fn_lock); 1390 rw_destroy(&fnp->fn_rwlock); 1391 cv_destroy(&fnp->fn_cv_mount); 1392 vn_free(vp); 1393 1394 mutex_enter(&autofs_nodeid_lock); 1395 fnp->fn_globals->fng_fnnode_count--; 1396 mutex_exit(&autofs_nodeid_lock); 1397 kmem_free(fnp, sizeof (*fnp)); 1398 } 1399 1400 void 1401 auto_disconnect( 1402 fnnode_t *dfnp, 1403 fnnode_t *fnp) 1404 { 1405 fnnode_t *tmp, **fnpp; 1406 vnode_t *vp = fntovn(fnp); 1407 timestruc_t now; 1408 1409 AUTOFS_DPRINT((4, 1410 "auto_disconnect: dfnp=%p fnp=%p linkcnt=%d\n v_count=%d", 1411 (void *)dfnp, (void *)fnp, fnp->fn_linkcnt, vp->v_count)); 1412 1413 ASSERT(RW_WRITE_HELD(&dfnp->fn_rwlock)); 1414 ASSERT(fnp->fn_linkcnt == 1); 1415 1416 if (vn_mountedvfs(vp) != NULL) { 1417 cmn_err(CE_PANIC, "auto_disconnect: vp %p mounted on", 1418 (void *)vp); 1419 } 1420 1421 /* 1422 * Decrement by 1 because we're removing the entry in dfnp. 1423 */ 1424 fnp->fn_linkcnt--; 1425 fnp->fn_size--; 1426 1427 /* 1428 * only changed while holding parent's (dfnp) rw_lock 1429 */ 1430 fnp->fn_parent = NULL; 1431 1432 fnpp = &dfnp->fn_dirents; 1433 for (;;) { 1434 tmp = *fnpp; 1435 if (tmp == NULL) { 1436 cmn_err(CE_PANIC, 1437 "auto_disconnect: %p not in %p dirent list", 1438 (void *)fnp, (void *)dfnp); 1439 } 1440 if (tmp == fnp) { 1441 *fnpp = tmp->fn_next; /* remove it from the list */ 1442 ASSERT(vp->v_count == 0); 1443 /* child had a pointer to parent ".." */ 1444 dfnp->fn_linkcnt--; 1445 dfnp->fn_size--; 1446 break; 1447 } 1448 fnpp = &tmp->fn_next; 1449 } 1450 1451 mutex_enter(&fnp->fn_lock); 1452 gethrestime(&now); 1453 fnp->fn_atime = fnp->fn_mtime = now; 1454 mutex_exit(&fnp->fn_lock); 1455 1456 AUTOFS_DPRINT((5, "auto_disconnect: done\n")); 1457 } 1458 1459 int 1460 auto_enter(fnnode_t *dfnp, char *name, fnnode_t **fnpp, cred_t *cred) 1461 { 1462 struct fnnode *cfnp, **spp; 1463 vnode_t *dvp = fntovn(dfnp); 1464 ushort_t offset = 0; 1465 ushort_t diff; 1466 1467 AUTOFS_DPRINT((4, "auto_enter: dfnp=%p, name=%s ", (void *)dfnp, name)); 1468 1469 ASSERT(RW_WRITE_HELD(&dfnp->fn_rwlock)); 1470 1471 cfnp = dfnp->fn_dirents; 1472 if (cfnp == NULL) { 1473 /* 1474 * offset = 0 for '.' and offset = 1 for '..' 1475 */ 1476 spp = &dfnp->fn_dirents; 1477 offset = 2; 1478 } 1479 1480 for (; cfnp; cfnp = cfnp->fn_next) { 1481 if (strcmp(cfnp->fn_name, name) == 0) { 1482 mutex_enter(&cfnp->fn_lock); 1483 if (cfnp->fn_flags & MF_THISUID_MATCH_RQD) { 1484 /* 1485 * "thisuser" kind of node, need to 1486 * match CREDs as well 1487 */ 1488 mutex_exit(&cfnp->fn_lock); 1489 if (crcmp(cfnp->fn_cred, cred) == 0) 1490 return (EEXIST); 1491 } else { 1492 mutex_exit(&cfnp->fn_lock); 1493 return (EEXIST); 1494 } 1495 } 1496 1497 if (cfnp->fn_next != NULL) { 1498 diff = (ushort_t) 1499 (cfnp->fn_next->fn_offset - cfnp->fn_offset); 1500 ASSERT(diff != 0); 1501 if (diff > 1 && offset == 0) { 1502 offset = (ushort_t)cfnp->fn_offset + 1; 1503 spp = &cfnp->fn_next; 1504 } 1505 } else if (offset == 0) { 1506 offset = (ushort_t)cfnp->fn_offset + 1; 1507 spp = &cfnp->fn_next; 1508 } 1509 } 1510 1511 *fnpp = auto_makefnnode(VDIR, dvp->v_vfsp, name, cred, 1512 dfnp->fn_globals); 1513 if (*fnpp == NULL) 1514 return (ENOMEM); 1515 1516 /* 1517 * I don't hold the mutex on fnpp because I created it, and 1518 * I'm already holding the writers lock for it's parent 1519 * directory, therefore nobody can reference it without me first 1520 * releasing the writers lock. 1521 */ 1522 (*fnpp)->fn_offset = offset; 1523 (*fnpp)->fn_next = *spp; 1524 *spp = *fnpp; 1525 (*fnpp)->fn_parent = dfnp; 1526 (*fnpp)->fn_linkcnt++; /* parent now holds reference to entry */ 1527 (*fnpp)->fn_size++; 1528 1529 /* 1530 * dfnp->fn_linkcnt and dfnp->fn_size protected by dfnp->rw_lock 1531 */ 1532 dfnp->fn_linkcnt++; /* child now holds reference to parent '..' */ 1533 dfnp->fn_size++; 1534 1535 dfnp->fn_ref_time = gethrestime_sec(); 1536 1537 AUTOFS_DPRINT((5, "*fnpp=%p\n", (void *)*fnpp)); 1538 return (0); 1539 } 1540 1541 int 1542 auto_search(fnnode_t *dfnp, char *name, fnnode_t **fnpp, cred_t *cred) 1543 { 1544 vnode_t *dvp; 1545 fnnode_t *p; 1546 int error = ENOENT, match = 0; 1547 1548 AUTOFS_DPRINT((4, "auto_search: dfnp=%p, name=%s...\n", 1549 (void *)dfnp, name)); 1550 1551 dvp = fntovn(dfnp); 1552 if (dvp->v_type != VDIR) { 1553 cmn_err(CE_PANIC, "auto_search: dvp=%p not a directory", 1554 (void *)dvp); 1555 } 1556 1557 ASSERT(RW_LOCK_HELD(&dfnp->fn_rwlock)); 1558 for (p = dfnp->fn_dirents; p != NULL; p = p->fn_next) { 1559 if (strcmp(p->fn_name, name) == 0) { 1560 mutex_enter(&p->fn_lock); 1561 if (p->fn_flags & MF_THISUID_MATCH_RQD) { 1562 /* 1563 * "thisuser" kind of node 1564 * Need to match CREDs as well 1565 */ 1566 mutex_exit(&p->fn_lock); 1567 match = crcmp(p->fn_cred, cred) == 0; 1568 } else { 1569 /* 1570 * No need to check CRED 1571 */ 1572 mutex_exit(&p->fn_lock); 1573 match = 1; 1574 } 1575 } 1576 if (match) { 1577 error = 0; 1578 if (fnpp) { 1579 *fnpp = p; 1580 VN_HOLD(fntovn(*fnpp)); 1581 } 1582 break; 1583 } 1584 } 1585 1586 AUTOFS_DPRINT((5, "auto_search: error=%d\n", error)); 1587 return (error); 1588 } 1589 1590 /* 1591 * If dvp is mounted on, get path's vnode in the mounted on 1592 * filesystem. Path is relative to dvp, ie "./path". 1593 * If successful, *mvp points to a the held mountpoint vnode. 1594 */ 1595 /* ARGSUSED */ 1596 static int 1597 auto_getmntpnt( 1598 vnode_t *dvp, 1599 char *path, 1600 vnode_t **mvpp, /* vnode for mountpoint */ 1601 cred_t *cred) 1602 { 1603 int error = 0; 1604 vnode_t *newvp; 1605 char namebuf[TYPICALMAXPATHLEN]; 1606 struct pathname lookpn; 1607 vfs_t *vfsp; 1608 1609 AUTOFS_DPRINT((4, "auto_getmntpnt: path=%s\n", path)); 1610 1611 if (error = vn_vfsrlock_wait(dvp)) 1612 return (error); 1613 1614 /* 1615 * Now that we have the vfswlock, check to see if dvp 1616 * is still mounted on. If not, then just bail out as 1617 * there is no need to remount the triggers since the 1618 * higher level mount point has gotten unmounted. 1619 */ 1620 vfsp = vn_mountedvfs(dvp); 1621 if (vfsp == NULL) { 1622 vn_vfsunlock(dvp); 1623 error = EBUSY; 1624 goto done; 1625 } 1626 /* 1627 * Since mounted on, lookup "path" in the new filesystem, 1628 * it is important that we do the filesystem jump here to 1629 * avoid lookuppn() calling auto_lookup on dvp and deadlock. 1630 */ 1631 error = VFS_ROOT(vfsp, &newvp); 1632 vn_vfsunlock(dvp); 1633 if (error) 1634 goto done; 1635 1636 /* 1637 * We do a VN_HOLD on newvp just in case the first call to 1638 * lookuppnvp() fails with ENAMETOOLONG. We should still have a 1639 * reference to this vnode for the second call to lookuppnvp(). 1640 */ 1641 VN_HOLD(newvp); 1642 1643 /* 1644 * Now create the pathname struct so we can make use of lookuppnvp, 1645 * and pn_getcomponent. 1646 * This code is similar to lookupname() in fs/lookup.c. 1647 */ 1648 error = pn_get_buf(path, UIO_SYSSPACE, &lookpn, 1649 namebuf, sizeof (namebuf)); 1650 if (error == 0) { 1651 error = lookuppnvp(&lookpn, NULL, NO_FOLLOW, NULLVPP, 1652 mvpp, rootdir, newvp, cred); 1653 } else 1654 VN_RELE(newvp); 1655 if (error == ENAMETOOLONG) { 1656 /* 1657 * This thread used a pathname > TYPICALMAXPATHLEN bytes long. 1658 * newvp is VN_RELE'd by this call to lookuppnvp. 1659 * 1660 * Using 'rootdir' in a zone's context is OK here: we already 1661 * ascertained that there are no '..'s in the path, and we're 1662 * not following symlinks. 1663 */ 1664 if ((error = pn_get(path, UIO_SYSSPACE, &lookpn)) == 0) { 1665 error = lookuppnvp(&lookpn, NULL, NO_FOLLOW, NULLVPP, 1666 mvpp, rootdir, newvp, cred); 1667 pn_free(&lookpn); 1668 } else 1669 VN_RELE(newvp); 1670 } else { 1671 /* 1672 * Need to release newvp here since we held it. 1673 */ 1674 VN_RELE(newvp); 1675 } 1676 1677 done: 1678 AUTOFS_DPRINT((5, "auto_getmntpnt: path=%s *mvpp=%p error=%d\n", 1679 path, (void *)*mvpp, error)); 1680 return (error); 1681 } 1682 1683 #define DEEPER(x) (((x)->fn_dirents != NULL) || \ 1684 (vn_mountedvfs(fntovn((x)))) != NULL) 1685 1686 /* 1687 * The caller, should have already VN_RELE'd its reference to the 1688 * root vnode of this filesystem. 1689 */ 1690 static int 1691 auto_inkernel_unmount(vfs_t *vfsp) 1692 { 1693 vnode_t *cvp = vfsp->vfs_vnodecovered; 1694 int error; 1695 1696 AUTOFS_DPRINT((4, 1697 "auto_inkernel_unmount: devid=%lx mntpnt(%p) count %u\n", 1698 vfsp->vfs_dev, (void *)cvp, cvp->v_count)); 1699 1700 ASSERT(vn_vfswlock_held(cvp)); 1701 1702 /* 1703 * Perform the unmount 1704 * The mountpoint has already been locked by the caller. 1705 */ 1706 error = dounmount(vfsp, 0, kcred); 1707 1708 AUTOFS_DPRINT((5, "auto_inkernel_unmount: exit count %u\n", 1709 cvp->v_count)); 1710 return (error); 1711 } 1712 1713 /* 1714 * unmounts trigger nodes in the kernel. 1715 */ 1716 static void 1717 unmount_triggers(fnnode_t *fnp, action_list **alp) 1718 { 1719 fnnode_t *tp, *next; 1720 int error = 0; 1721 vfs_t *vfsp; 1722 vnode_t *tvp; 1723 1724 AUTOFS_DPRINT((4, "unmount_triggers: fnp=%p\n", (void *)fnp)); 1725 ASSERT(RW_WRITE_HELD(&fnp->fn_rwlock)); 1726 1727 *alp = fnp->fn_alp; 1728 next = fnp->fn_trigger; 1729 while ((tp = next) != NULL) { 1730 tvp = fntovn(tp); 1731 ASSERT(tvp->v_count >= 2); 1732 next = tp->fn_next; 1733 /* 1734 * drop writer's lock since the unmount will end up 1735 * disconnecting this node from fnp and needs to acquire 1736 * the writer's lock again. 1737 * next has at least a reference count >= 2 since it's 1738 * a trigger node, therefore can not be accidentally freed 1739 * by a VN_RELE 1740 */ 1741 rw_exit(&fnp->fn_rwlock); 1742 1743 vfsp = tvp->v_vfsp; 1744 1745 /* 1746 * Its parent was holding a reference to it, since this 1747 * is a trigger vnode. 1748 */ 1749 VN_RELE(tvp); 1750 if (error = auto_inkernel_unmount(vfsp)) { 1751 cmn_err(CE_PANIC, "unmount_triggers: " 1752 "unmount of vp=%p failed error=%d", 1753 (void *)tvp, error); 1754 } 1755 /* 1756 * reacquire writer's lock 1757 */ 1758 rw_enter(&fnp->fn_rwlock, RW_WRITER); 1759 } 1760 1761 /* 1762 * We were holding a reference to our parent. Drop that. 1763 */ 1764 VN_RELE(fntovn(fnp)); 1765 fnp->fn_trigger = NULL; 1766 fnp->fn_alp = NULL; 1767 1768 AUTOFS_DPRINT((5, "unmount_triggers: finished\n")); 1769 } 1770 1771 /* 1772 * This routine locks the mountpoint of every trigger node if they're 1773 * not busy, or returns EBUSY if any node is busy. If a trigger node should 1774 * be unmounted first, then it sets nfnp to point to it, otherwise nfnp 1775 * points to NULL. 1776 */ 1777 static int 1778 triggers_busy(fnnode_t *fnp, fnnode_t **nfnp) 1779 { 1780 int error = 0, done; 1781 int lck_error = 0; 1782 fnnode_t *tp, *t1p; 1783 vfs_t *vfsp; 1784 1785 ASSERT(RW_WRITE_HELD(&fnp->fn_rwlock)); 1786 1787 *nfnp = NULL; 1788 for (tp = fnp->fn_trigger; tp != NULL; tp = tp->fn_next) { 1789 AUTOFS_DPRINT((10, "\ttrigger: %s\n", tp->fn_name)); 1790 vfsp = fntovn(tp)->v_vfsp; 1791 error = 0; 1792 /* 1793 * The vn_vfsunlock will be done in auto_inkernel_unmount. 1794 */ 1795 lck_error = vn_vfswlock(vfsp->vfs_vnodecovered); 1796 if (lck_error == 0) { 1797 mutex_enter(&tp->fn_lock); 1798 ASSERT((tp->fn_flags & MF_LOOKUP) == 0); 1799 if (tp->fn_flags & MF_INPROG) { 1800 /* 1801 * a mount is in progress 1802 */ 1803 error = EBUSY; 1804 } 1805 mutex_exit(&tp->fn_lock); 1806 } 1807 if (lck_error || error || DEEPER(tp) || 1808 ((fntovn(tp))->v_count) > 2) { 1809 /* 1810 * couldn't lock it because it's busy, 1811 * It is mounted on or has dirents? 1812 * If reference count is greater than two, then 1813 * somebody else is holding a reference to this vnode. 1814 * One reference is for the mountpoint, and the second 1815 * is for the trigger node. 1816 */ 1817 AUTOFS_DPRINT((10, "\ttrigger busy\n")); 1818 if ((lck_error == 0) && (error == 0)) { 1819 *nfnp = tp; 1820 /* 1821 * The matching VN_RELE is done in 1822 * unmount_tree(). 1823 */ 1824 VN_HOLD(fntovn(*nfnp)); 1825 } 1826 /* 1827 * Unlock previously locked mountpoints 1828 */ 1829 for (done = 0, t1p = fnp->fn_trigger; !done; 1830 t1p = t1p->fn_next) { 1831 /* 1832 * Unlock all nodes previously 1833 * locked. All nodes up to 'tp' 1834 * were successfully locked. If 'lck_err' is 1835 * set, then 'tp' was not locked, and thus 1836 * should not be unlocked. If 1837 * 'lck_err' is not set, then 'tp' was 1838 * successfully locked, and it should 1839 * be unlocked. 1840 */ 1841 if (t1p != tp || !lck_error) { 1842 vfsp = fntovn(t1p)->v_vfsp; 1843 vn_vfsunlock(vfsp->vfs_vnodecovered); 1844 } 1845 done = (t1p == tp); 1846 } 1847 error = EBUSY; 1848 break; 1849 } 1850 } 1851 1852 AUTOFS_DPRINT((4, "triggers_busy: error=%d\n", error)); 1853 return (error); 1854 } 1855 1856 /* 1857 * Unlock previously locked trigger nodes. 1858 */ 1859 static int 1860 triggers_unlock(fnnode_t *fnp) 1861 { 1862 fnnode_t *tp; 1863 vfs_t *vfsp; 1864 1865 ASSERT(RW_WRITE_HELD(&fnp->fn_rwlock)); 1866 1867 for (tp = fnp->fn_trigger; tp != NULL; tp = tp->fn_next) { 1868 AUTOFS_DPRINT((10, "\tunlock trigger: %s\n", tp->fn_name)); 1869 vfsp = fntovn(tp)->v_vfsp; 1870 vn_vfsunlock(vfsp->vfs_vnodecovered); 1871 } 1872 1873 return (0); 1874 } 1875 1876 /* 1877 * It is the caller's responsibility to grab the VVFSLOCK. 1878 * Releases the VVFSLOCK upon return. 1879 */ 1880 static int 1881 unmount_node(vnode_t *cvp, int force) 1882 { 1883 int error = 0; 1884 fnnode_t *cfnp; 1885 vfs_t *vfsp; 1886 umntrequest ul; 1887 fninfo_t *fnip; 1888 1889 AUTOFS_DPRINT((4, "\tunmount_node cvp=%p\n", (void *)cvp)); 1890 1891 ASSERT(vn_vfswlock_held(cvp)); 1892 cfnp = vntofn(cvp); 1893 vfsp = vn_mountedvfs(cvp); 1894 1895 if (force || cfnp->fn_flags & MF_IK_MOUNT) { 1896 /* 1897 * Mount was performed in the kernel, so 1898 * do an in-kernel unmount. auto_inkernel_unmount() 1899 * will vn_vfsunlock(cvp). 1900 */ 1901 error = auto_inkernel_unmount(vfsp); 1902 } else { 1903 zone_t *zone = NULL; 1904 refstr_t *mntpt, *resource; 1905 size_t mntoptslen; 1906 1907 /* 1908 * Get the mnttab information of the node 1909 * and ask the daemon to unmount it. 1910 */ 1911 bzero(&ul, sizeof (ul)); 1912 mntfs_getmntopts(vfsp, &ul.mntopts, &mntoptslen); 1913 if (ul.mntopts == NULL) { 1914 auto_log(cfnp->fn_globals->fng_verbose, 1915 cfnp->fn_globals->fng_zoneid, 1916 CE_WARN, "unmount_node: " 1917 "no memory"); 1918 vn_vfsunlock(cvp); 1919 error = ENOMEM; 1920 goto done; 1921 } 1922 if (mntoptslen > AUTOFS_MAXOPTSLEN) 1923 ul.mntopts[AUTOFS_MAXOPTSLEN - 1] = '\0'; 1924 1925 mntpt = vfs_getmntpoint(vfsp); 1926 ul.mntpnt = (char *)refstr_value(mntpt); 1927 resource = vfs_getresource(vfsp); 1928 ul.mntresource = (char *)refstr_value(resource); 1929 1930 fnip = vfstofni(cvp->v_vfsp); 1931 ul.isdirect = fnip->fi_flags & MF_DIRECT ? TRUE : FALSE; 1932 1933 /* 1934 * Since a zone'd automountd's view of the autofs mount points 1935 * differs from those in the kernel, we need to make sure we 1936 * give it consistent mount points. 1937 */ 1938 ASSERT(fnip->fi_zoneid == getzoneid()); 1939 zone = curproc->p_zone; 1940 1941 if (fnip->fi_zoneid != GLOBAL_ZONEID) { 1942 if (ZONE_PATH_VISIBLE(ul.mntpnt, zone)) { 1943 ul.mntpnt = 1944 ZONE_PATH_TRANSLATE(ul.mntpnt, zone); 1945 } 1946 if (ZONE_PATH_VISIBLE(ul.mntresource, zone)) { 1947 ul.mntresource = 1948 ZONE_PATH_TRANSLATE(ul.mntresource, zone); 1949 } 1950 } 1951 1952 ul.fstype = vfssw[vfsp->vfs_fstype].vsw_name; 1953 vn_vfsunlock(cvp); 1954 1955 error = auto_send_unmount_request(fnip, &ul, FALSE); 1956 kmem_free(ul.mntopts, mntoptslen); 1957 refstr_rele(mntpt); 1958 refstr_rele(resource); 1959 } 1960 1961 done: 1962 AUTOFS_DPRINT((5, "\tunmount_node cvp=%p error=%d\n", (void *)cvp, 1963 error)); 1964 return (error); 1965 } 1966 1967 /* 1968 * vp is the "root" of the AUTOFS filesystem. 1969 * return EBUSY if any thread is holding a reference to this vnode 1970 * other than us. 1971 */ 1972 static int 1973 check_auto_node(vnode_t *vp) 1974 { 1975 fnnode_t *fnp; 1976 int error = 0; 1977 /* 1978 * number of references to expect for 1979 * a non-busy vnode. 1980 */ 1981 uint_t count; 1982 1983 AUTOFS_DPRINT((4, "\tcheck_auto_node vp=%p ", (void *)vp)); 1984 fnp = vntofn(vp); 1985 ASSERT(fnp->fn_flags & MF_INPROG); 1986 ASSERT((fnp->fn_flags & MF_LOOKUP) == 0); 1987 1988 count = 1; /* we are holding a reference to vp */ 1989 if (fnp->fn_flags & MF_TRIGGER) { 1990 /* 1991 * parent holds a pointer to us (trigger) 1992 */ 1993 count++; 1994 } 1995 if (fnp->fn_trigger != NULL) { 1996 /* 1997 * The trigger nodes have a hold on us. 1998 */ 1999 count++; 2000 } 2001 mutex_enter(&vp->v_lock); 2002 if (vp->v_flag & VROOT) 2003 count++; 2004 ASSERT(vp->v_count > 0); 2005 AUTOFS_DPRINT((10, "\tcount=%u ", vp->v_count)); 2006 if (vp->v_count > count) 2007 error = EBUSY; 2008 mutex_exit(&vp->v_lock); 2009 2010 AUTOFS_DPRINT((5, "\tcheck_auto_node error=%d ", error)); 2011 return (error); 2012 } 2013 2014 /* 2015 * rootvp is the root of the AUTOFS filesystem. 2016 * If rootvp is busy (v_count > 1) returns EBUSY. 2017 * else removes every vnode under this tree. 2018 * ASSUMPTION: Assumes that the only node which can be busy is 2019 * the root vnode. This filesystem better be two levels deep only, 2020 * the root and its immediate subdirs. 2021 * The daemon will "AUTOFS direct-mount" only one level below the root. 2022 */ 2023 static int 2024 unmount_autofs(vnode_t *rootvp) 2025 { 2026 fnnode_t *fnp, *rootfnp, *nfnp; 2027 int error; 2028 2029 AUTOFS_DPRINT((4, "\tunmount_autofs rootvp=%p ", (void *)rootvp)); 2030 2031 error = check_auto_node(rootvp); 2032 if (error == 0) { 2033 /* 2034 * Remove all its immediate subdirectories. 2035 */ 2036 rootfnp = vntofn(rootvp); 2037 rw_enter(&rootfnp->fn_rwlock, RW_WRITER); 2038 nfnp = NULL; /* lint clean */ 2039 for (fnp = rootfnp->fn_dirents; fnp != NULL; fnp = nfnp) { 2040 ASSERT(fntovn(fnp)->v_count == 0); 2041 ASSERT(fnp->fn_dirents == NULL); 2042 ASSERT(fnp->fn_linkcnt == 2); 2043 fnp->fn_linkcnt--; 2044 auto_disconnect(rootfnp, fnp); 2045 nfnp = fnp->fn_next; 2046 auto_freefnnode(fnp); 2047 } 2048 rw_exit(&rootfnp->fn_rwlock); 2049 } 2050 AUTOFS_DPRINT((5, "\tunmount_autofs error=%d ", error)); 2051 return (error); 2052 } 2053 2054 /* 2055 * max number of unmount threads running 2056 */ 2057 static int autofs_unmount_threads = 5; 2058 2059 /* 2060 * XXX unmount_tree() is not suspend-safe within the scope of 2061 * the present model defined for cpr to suspend the system. Calls made 2062 * by the unmount_tree() that have been identified to be unsafe are 2063 * (1) RPC client handle setup and client calls to automountd which can 2064 * block deep down in the RPC library, (2) kmem_alloc() calls with the 2065 * KM_SLEEP flag which can block if memory is low, and (3) VFS_*() and 2066 * VOP_*() calls which can result in over the wire calls to servers. 2067 * The thread should be completely reevaluated to make it suspend-safe in 2068 * case of future updates to the cpr model. 2069 */ 2070 void 2071 unmount_tree(struct autofs_globals *fngp, int force) 2072 { 2073 vnode_t *vp, *newvp; 2074 vfs_t *vfsp; 2075 fnnode_t *fnp, *nfnp, *pfnp; 2076 action_list *alp; 2077 int error, ilocked_it = 0; 2078 fninfo_t *fnip; 2079 time_t ref_time; 2080 int autofs_busy_root, unmount_as_unit, unmount_done = 0; 2081 timestruc_t now; 2082 2083 callb_cpr_t cprinfo; 2084 kmutex_t unmount_tree_cpr_lock; 2085 2086 mutex_init(&unmount_tree_cpr_lock, NULL, MUTEX_DEFAULT, NULL); 2087 CALLB_CPR_INIT(&cprinfo, &unmount_tree_cpr_lock, callb_generic_cpr, 2088 "unmount_tree"); 2089 2090 /* 2091 * Got to release lock before attempting unmount in case 2092 * it hangs. 2093 */ 2094 rw_enter(&fngp->fng_rootfnnodep->fn_rwlock, RW_READER); 2095 if ((fnp = fngp->fng_rootfnnodep->fn_dirents) == NULL) { 2096 ASSERT(fngp->fng_fnnode_count == 1); 2097 /* 2098 * no autofs mounted, done. 2099 */ 2100 rw_exit(&fngp->fng_rootfnnodep->fn_rwlock); 2101 goto done; 2102 } 2103 VN_HOLD(fntovn(fnp)); 2104 rw_exit(&fngp->fng_rootfnnodep->fn_rwlock); 2105 2106 vp = fntovn(fnp); 2107 fnip = vfstofni(vp->v_vfsp); 2108 /* 2109 * autofssys() will be calling in from the global zone and doing 2110 * work on the behalf of the given zone, hence we can't always assert 2111 * that we have the right credentials, nor that the caller is always in 2112 * the correct zone. 2113 * 2114 * We do, however, know that if this is a "forced unmount" operation 2115 * (which autofssys() does), then we won't go down to the krpc layers, 2116 * so we don't need to fudge with the credentials. 2117 */ 2118 ASSERT(force || fnip->fi_zoneid == getzoneid()); 2119 if (!force && auto_null_request(fnip, FALSE) != 0) { 2120 /* 2121 * automountd not running in this zone, 2122 * don't attempt unmounting this round. 2123 */ 2124 VN_RELE(vp); 2125 goto done; 2126 } 2127 /* reference time for this unmount round */ 2128 ref_time = gethrestime_sec(); 2129 /* 2130 * If this an autofssys() call, we need to make sure we don't skip 2131 * nodes because we think we saw them recently. 2132 */ 2133 mutex_enter(&fnp->fn_lock); 2134 if (force && fnp->fn_unmount_ref_time >= ref_time) 2135 ref_time = fnp->fn_unmount_ref_time + 1; 2136 mutex_exit(&fnp->fn_lock); 2137 2138 AUTOFS_DPRINT((4, "unmount_tree (ID=%ld)\n", ref_time)); 2139 top: 2140 AUTOFS_DPRINT((10, "unmount_tree: %s\n", fnp->fn_name)); 2141 ASSERT(fnp); 2142 vp = fntovn(fnp); 2143 if (vp->v_type == VLNK) { 2144 /* 2145 * can't unmount symbolic links 2146 */ 2147 goto next; 2148 } 2149 fnip = vfstofni(vp->v_vfsp); 2150 ASSERT(vp->v_count > 0); 2151 error = 0; 2152 autofs_busy_root = unmount_as_unit = 0; 2153 alp = NULL; 2154 2155 ilocked_it = 0; 2156 mutex_enter(&fnp->fn_lock); 2157 if (fnp->fn_flags & (MF_INPROG | MF_LOOKUP)) { 2158 /* 2159 * Either a mount, lookup or another unmount of this 2160 * subtree is in progress, don't attempt to unmount at 2161 * this time. 2162 */ 2163 mutex_exit(&fnp->fn_lock); 2164 error = EBUSY; 2165 goto next; 2166 } 2167 if (fnp->fn_unmount_ref_time >= ref_time) { 2168 /* 2169 * Already been here, try next node. 2170 */ 2171 mutex_exit(&fnp->fn_lock); 2172 error = EBUSY; 2173 goto next; 2174 } 2175 fnp->fn_unmount_ref_time = ref_time; 2176 2177 /* 2178 * If forced operation ignore timeout values 2179 */ 2180 if (!force && fnp->fn_ref_time + fnip->fi_mount_to > 2181 gethrestime_sec()) { 2182 /* 2183 * Node has been referenced recently, try the 2184 * unmount of its children if any. 2185 */ 2186 mutex_exit(&fnp->fn_lock); 2187 AUTOFS_DPRINT((10, "fn_ref_time within range\n")); 2188 rw_enter(&fnp->fn_rwlock, RW_READER); 2189 if (fnp->fn_dirents) { 2190 /* 2191 * Has subdirectory, attempt their 2192 * unmount first 2193 */ 2194 nfnp = fnp->fn_dirents; 2195 VN_HOLD(fntovn(nfnp)); 2196 rw_exit(&fnp->fn_rwlock); 2197 2198 VN_RELE(vp); 2199 fnp = nfnp; 2200 goto top; 2201 } 2202 rw_exit(&fnp->fn_rwlock); 2203 /* 2204 * No children, try next node. 2205 */ 2206 error = EBUSY; 2207 goto next; 2208 } 2209 2210 AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG); 2211 fnp->fn_error = 0; 2212 mutex_exit(&fnp->fn_lock); 2213 ilocked_it = 1; 2214 2215 rw_enter(&fnp->fn_rwlock, RW_WRITER); 2216 if (fnp->fn_trigger != NULL) { 2217 unmount_as_unit = 1; 2218 if ((vn_mountedvfs(vp) == NULL) && (check_auto_node(vp))) { 2219 /* 2220 * AUTOFS mountpoint is busy, there's 2221 * no point trying to unmount. Fall through 2222 * to attempt to unmount subtrees rooted 2223 * at a possible trigger node, but remember 2224 * not to unmount this tree. 2225 */ 2226 autofs_busy_root = 1; 2227 } 2228 2229 if (triggers_busy(fnp, &nfnp)) { 2230 rw_exit(&fnp->fn_rwlock); 2231 if (nfnp == NULL) { 2232 error = EBUSY; 2233 goto next; 2234 } 2235 /* 2236 * nfnp is busy, try to unmount it first 2237 */ 2238 mutex_enter(&fnp->fn_lock); 2239 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG); 2240 mutex_exit(&fnp->fn_lock); 2241 VN_RELE(vp); 2242 ASSERT(fntovn(nfnp)->v_count > 1); 2243 fnp = nfnp; 2244 goto top; 2245 } 2246 2247 /* 2248 * At this point, we know all trigger nodes are locked, 2249 * and they're not busy or mounted on. 2250 */ 2251 2252 if (autofs_busy_root) { 2253 /* 2254 * Got to unlock the the trigger nodes since 2255 * I'm not really going to unmount the filesystem. 2256 */ 2257 (void) triggers_unlock(fnp); 2258 } else { 2259 /* 2260 * Attempt to unmount all the trigger nodes, 2261 * save the action_list in case we need to 2262 * remount them later. The action_list will be 2263 * freed later if there was no need to remount the 2264 * trigger nodes. 2265 */ 2266 unmount_triggers(fnp, &alp); 2267 } 2268 } 2269 rw_exit(&fnp->fn_rwlock); 2270 2271 if (autofs_busy_root) 2272 goto next; 2273 2274 (void) vn_vfswlock_wait(vp); 2275 2276 vfsp = vn_mountedvfs(vp); 2277 if (vfsp != NULL) { 2278 /* 2279 * Node is mounted on. 2280 */ 2281 AUTOFS_DPRINT((10, "\tNode is mounted on\n")); 2282 2283 /* 2284 * Deal with /xfn/host/jurassic alikes here... 2285 */ 2286 if (vfs_matchops(vfsp, vfs_getops(vp->v_vfsp))) { 2287 /* 2288 * If the filesystem mounted here is AUTOFS, and it 2289 * is busy, try to unmount the tree rooted on it 2290 * first. We know this call to VFS_ROOT is safe to 2291 * call while holding VVFSLOCK, since it resolves 2292 * to a call to auto_root(). 2293 */ 2294 AUTOFS_DPRINT((10, "\t\tAUTOFS mounted here\n")); 2295 if (VFS_ROOT(vfsp, &newvp)) { 2296 cmn_err(CE_PANIC, 2297 "unmount_tree: VFS_ROOT(vfs=%p) failed", 2298 (void *)vfsp); 2299 } 2300 nfnp = vntofn(newvp); 2301 if (DEEPER(nfnp)) { 2302 vn_vfsunlock(vp); 2303 mutex_enter(&fnp->fn_lock); 2304 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG); 2305 mutex_exit(&fnp->fn_lock); 2306 VN_RELE(vp); 2307 fnp = nfnp; 2308 goto top; 2309 } 2310 /* 2311 * Fall through to unmount this filesystem 2312 */ 2313 VN_RELE(newvp); 2314 } 2315 2316 /* 2317 * vn_vfsunlock(vp) is done inside unmount_node() 2318 */ 2319 error = unmount_node(vp, force); 2320 if (error == ECONNRESET) { 2321 AUTOFS_DPRINT((10, "\tConnection dropped\n")); 2322 if (vn_mountedvfs(vp) == NULL) { 2323 /* 2324 * The filesystem was unmounted before the 2325 * daemon died. Unfortunately we can not 2326 * determine whether all the cleanup work was 2327 * successfully finished (i.e. update mnttab, 2328 * or notify NFS server of the unmount). 2329 * We should not retry the operation since the 2330 * filesystem has already been unmounted, and 2331 * may have already been removed from mnttab, 2332 * in such case the devid/rdevid we send to 2333 * the daemon will not be matched. So we have 2334 * to be content with the partial unmount. 2335 * Since the mountpoint is no longer covered, we 2336 * clear the error condition. 2337 */ 2338 error = 0; 2339 auto_log(fngp->fng_verbose, fngp->fng_zoneid, 2340 CE_WARN, 2341 "unmount_tree: automountd connection " 2342 "dropped"); 2343 if (fnip->fi_flags & MF_DIRECT) { 2344 auto_log(fngp->fng_verbose, 2345 fngp->fng_zoneid, CE_WARN, 2346 "unmount_tree: " 2347 "%s successfully unmounted - " 2348 "do not remount triggers", 2349 fnip->fi_path); 2350 } else { 2351 auto_log(fngp->fng_verbose, 2352 fngp->fng_zoneid, CE_WARN, 2353 "unmount_tree: " 2354 "%s/%s successfully unmounted - " 2355 "do not remount triggers", 2356 fnip->fi_path, fnp->fn_name); 2357 } 2358 } 2359 } 2360 } else { 2361 vn_vfsunlock(vp); 2362 AUTOFS_DPRINT((10, "\tNode is AUTOFS\n")); 2363 if (unmount_as_unit) { 2364 AUTOFS_DPRINT((10, "\tunmount as unit\n")); 2365 error = unmount_autofs(vp); 2366 } else { 2367 AUTOFS_DPRINT((10, "\tunmount one at a time\n")); 2368 rw_enter(&fnp->fn_rwlock, RW_READER); 2369 if (fnp->fn_dirents != NULL) { 2370 /* 2371 * Has subdirectory, attempt their 2372 * unmount first 2373 */ 2374 nfnp = fnp->fn_dirents; 2375 VN_HOLD(fntovn(nfnp)); 2376 rw_exit(&fnp->fn_rwlock); 2377 2378 mutex_enter(&fnp->fn_lock); 2379 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG); 2380 mutex_exit(&fnp->fn_lock); 2381 VN_RELE(vp); 2382 fnp = nfnp; 2383 goto top; 2384 } 2385 rw_exit(&fnp->fn_rwlock); 2386 goto next; 2387 } 2388 } 2389 2390 if (error) { 2391 AUTOFS_DPRINT((10, "\tUnmount failed\n")); 2392 if (alp != NULL) { 2393 /* 2394 * Unmount failed, got to remount triggers. 2395 */ 2396 ASSERT((fnp->fn_flags & MF_THISUID_MATCH_RQD) == 0); 2397 error = auto_perform_actions(fnip, fnp, alp, 2398 CRED()); 2399 if (error) { 2400 auto_log(fngp->fng_verbose, 2401 fngp->fng_zoneid, CE_WARN, 2402 "autofs: can't remount " 2403 "triggers fnp=%p error=%d", (void *)fnp, 2404 error); 2405 error = 0; 2406 /* 2407 * The action list should have been 2408 * free'd by auto_perform_actions 2409 * since an error occured 2410 */ 2411 alp = NULL; 2412 2413 } 2414 } 2415 } else { 2416 /* 2417 * The unmount succeeded, which will cause this node to 2418 * be removed from its parent if its an indirect mount, 2419 * therefore update the parent's atime and mtime now. 2420 * I don't update them in auto_disconnect() because I 2421 * don't want atime and mtime changing every time a 2422 * lookup goes to the daemon and creates a new node. 2423 */ 2424 unmount_done = 1; 2425 if ((fnip->fi_flags & MF_DIRECT) == 0) { 2426 gethrestime(&now); 2427 if (fnp->fn_parent == fngp->fng_rootfnnodep) 2428 fnp->fn_atime = fnp->fn_mtime = now; 2429 else 2430 fnp->fn_parent->fn_atime = 2431 fnp->fn_parent->fn_mtime = now; 2432 } 2433 2434 /* 2435 * Free the action list here 2436 */ 2437 if (alp != NULL) { 2438 xdr_free(xdr_action_list, (char *)alp); 2439 alp = NULL; 2440 } 2441 } 2442 2443 fnp->fn_ref_time = gethrestime_sec(); 2444 2445 next: 2446 /* 2447 * Obtain parent's readers lock before grabbing 2448 * reference to next sibling. 2449 * XXX Note that nodes in the top level list (mounted 2450 * in user space not by the daemon in the kernel) parent is itself, 2451 * therefore grabbing the lock makes no sense, but doesn't 2452 * hurt either. 2453 */ 2454 pfnp = fnp->fn_parent; 2455 ASSERT(pfnp != NULL); 2456 rw_enter(&pfnp->fn_rwlock, RW_READER); 2457 if ((nfnp = fnp->fn_next) != NULL) 2458 VN_HOLD(fntovn(nfnp)); 2459 rw_exit(&pfnp->fn_rwlock); 2460 2461 if (ilocked_it) { 2462 mutex_enter(&fnp->fn_lock); 2463 if (unmount_done) { 2464 /* 2465 * Other threads may be waiting for this unmount to 2466 * finish. We must let it know that in order to 2467 * proceed, it must trigger the mount itself. 2468 */ 2469 fnp->fn_flags &= ~MF_IK_MOUNT; 2470 if (fnp->fn_flags & MF_WAITING) 2471 fnp->fn_error = EAGAIN; 2472 unmount_done = 0; 2473 } 2474 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG); 2475 mutex_exit(&fnp->fn_lock); 2476 ilocked_it = 0; 2477 } 2478 2479 if (nfnp != NULL) { 2480 VN_RELE(vp); 2481 fnp = nfnp; 2482 /* 2483 * Unmount next element 2484 */ 2485 goto top; 2486 } 2487 2488 /* 2489 * We don't want to unmount rootfnnodep, so the check is made here 2490 */ 2491 ASSERT(pfnp != fnp); 2492 if (pfnp != fngp->fng_rootfnnodep) { 2493 /* 2494 * Now attempt to unmount my parent 2495 */ 2496 VN_HOLD(fntovn(pfnp)); 2497 VN_RELE(vp); 2498 fnp = pfnp; 2499 2500 goto top; 2501 } 2502 2503 VN_RELE(vp); 2504 2505 /* 2506 * At this point we've walked the entire tree and attempted to unmount 2507 * as much as we can one level at a time. 2508 */ 2509 done: 2510 mutex_enter(&unmount_tree_cpr_lock); 2511 CALLB_CPR_EXIT(&cprinfo); 2512 mutex_destroy(&unmount_tree_cpr_lock); 2513 } 2514 2515 static void 2516 unmount_zone_tree(struct autofs_globals *fngp) 2517 { 2518 unmount_tree(fngp, 0); 2519 mutex_enter(&fngp->fng_unmount_threads_lock); 2520 fngp->fng_unmount_threads--; 2521 mutex_exit(&fngp->fng_unmount_threads_lock); 2522 2523 AUTOFS_DPRINT((5, "unmount_tree done. Thread exiting.\n")); 2524 2525 zthread_exit(); 2526 /* NOTREACHED */ 2527 } 2528 2529 static int autofs_unmount_thread_timer = 120; /* in seconds */ 2530 2531 void 2532 auto_do_unmount(struct autofs_globals *fngp) 2533 { 2534 callb_cpr_t cprinfo; 2535 clock_t timeleft; 2536 zone_t *zone = curproc->p_zone; 2537 2538 CALLB_CPR_INIT(&cprinfo, &fngp->fng_unmount_threads_lock, 2539 callb_generic_cpr, "auto_do_unmount"); 2540 2541 for (;;) { /* forever */ 2542 mutex_enter(&fngp->fng_unmount_threads_lock); 2543 CALLB_CPR_SAFE_BEGIN(&cprinfo); 2544 newthread: 2545 mutex_exit(&fngp->fng_unmount_threads_lock); 2546 timeleft = zone_status_timedwait(zone, lbolt + 2547 autofs_unmount_thread_timer * hz, ZONE_IS_SHUTTING_DOWN); 2548 mutex_enter(&fngp->fng_unmount_threads_lock); 2549 2550 if (timeleft != -1) { /* didn't time out */ 2551 ASSERT(zone_status_get(zone) >= ZONE_IS_SHUTTING_DOWN); 2552 /* 2553 * zone is exiting... don't create any new threads. 2554 * fng_unmount_threads_lock is released implicitly by 2555 * the below. 2556 */ 2557 CALLB_CPR_SAFE_END(&cprinfo, 2558 &fngp->fng_unmount_threads_lock); 2559 CALLB_CPR_EXIT(&cprinfo); 2560 zthread_exit(); 2561 /* NOTREACHED */ 2562 } 2563 if (fngp->fng_unmount_threads < autofs_unmount_threads) { 2564 fngp->fng_unmount_threads++; 2565 CALLB_CPR_SAFE_END(&cprinfo, 2566 &fngp->fng_unmount_threads_lock); 2567 mutex_exit(&fngp->fng_unmount_threads_lock); 2568 2569 (void) zthread_create(NULL, 0, unmount_zone_tree, fngp, 2570 0, minclsyspri); 2571 } else 2572 goto newthread; 2573 } 2574 /* NOTREACHED */ 2575 } 2576 2577 /* 2578 * Is nobrowse specified in option string? 2579 * opts should be a null ('\0') terminated string. 2580 * Returns non-zero if nobrowse has been specified. 2581 */ 2582 int 2583 auto_nobrowse_option(char *opts) 2584 { 2585 char *buf; 2586 char *p; 2587 char *t; 2588 int nobrowse = 0; 2589 int last_opt = 0; 2590 size_t len; 2591 2592 len = strlen(opts) + 1; 2593 p = buf = kmem_alloc(len, KM_SLEEP); 2594 (void) strcpy(buf, opts); 2595 do { 2596 if (t = strchr(p, ',')) 2597 *t++ = '\0'; 2598 else 2599 last_opt++; 2600 if (strcmp(p, MNTOPT_NOBROWSE) == 0) 2601 nobrowse = 1; 2602 else if (strcmp(p, MNTOPT_BROWSE) == 0) 2603 nobrowse = 0; 2604 p = t; 2605 } while (!last_opt); 2606 kmem_free(buf, len); 2607 2608 return (nobrowse); 2609 } 2610 2611 /* 2612 * used to log warnings only if automountd is running 2613 * with verbose mode set 2614 */ 2615 2616 void 2617 auto_log(int verbose, zoneid_t zoneid, int level, const char *fmt, ...) 2618 { 2619 va_list args; 2620 2621 if (verbose) { 2622 va_start(args, fmt); 2623 vzcmn_err(zoneid, level, fmt, args); 2624 va_end(args); 2625 } 2626 } 2627 2628 #ifdef DEBUG 2629 static int autofs_debug = 0; 2630 2631 /* 2632 * Utilities used by both client and server 2633 * Standard levels: 2634 * 0) no debugging 2635 * 1) hard failures 2636 * 2) soft failures 2637 * 3) current test software 2638 * 4) main procedure entry points 2639 * 5) main procedure exit points 2640 * 6) utility procedure entry points 2641 * 7) utility procedure exit points 2642 * 8) obscure procedure entry points 2643 * 9) obscure procedure exit points 2644 * 10) random stuff 2645 * 11) all <= 1 2646 * 12) all <= 2 2647 * 13) all <= 3 2648 * ... 2649 */ 2650 /* PRINTFLIKE2 */ 2651 void 2652 auto_dprint(int level, const char *fmt, ...) 2653 { 2654 va_list args; 2655 2656 if (autofs_debug == level || 2657 (autofs_debug > 10 && (autofs_debug - 10) >= level)) { 2658 va_start(args, fmt); 2659 (void) vprintf(fmt, args); 2660 va_end(args); 2661 } 2662 } 2663 #endif /* DEBUG */ 2664