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