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 (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <sys/param.h> 27 #include <sys/kmem.h> 28 #include <sys/errno.h> 29 #include <sys/proc.h> 30 #include <sys/disp.h> 31 #include <sys/vfs.h> 32 #include <sys/vnode.h> 33 #include <sys/pathname.h> 34 #include <sys/cred.h> 35 #include <sys/mount.h> 36 #include <sys/cmn_err.h> 37 #include <sys/debug.h> 38 #include <sys/systm.h> 39 #include <sys/dirent.h> 40 #include <fs/fs_subr.h> 41 #include <sys/fs/autofs.h> 42 #include <sys/callb.h> 43 #include <sys/sysmacros.h> 44 #include <sys/zone.h> 45 #include <sys/door.h> 46 #include <sys/fs/mntdata.h> 47 #include <nfs/mount.h> 48 #include <rpc/clnt.h> 49 #include <rpcsvc/autofs_prot.h> 50 #include <nfs/rnode.h> 51 #include <sys/utsname.h> 52 #include <sys/schedctl.h> 53 54 /* 55 * Autofs and Zones: 56 * 57 * Zones are delegated the responsibility of managing their own autofs mounts 58 * and maps. Each zone runs its own copy of automountd, with its own timeouts, 59 * and other logically "global" parameters. kRPC and virtualization in the 60 * loopback transport (tl) will prevent a zone from communicating with another 61 * zone's automountd. 62 * 63 * Each zone has its own "rootfnnode" and associated tree of auto nodes. 64 * 65 * Each zone also has its own set of "unmounter" kernel threads; these are 66 * created and run within the zone's context (ie, they are created via 67 * zthread_create()). 68 * 69 * Cross-zone mount triggers are disallowed. There is a check in 70 * auto_trigger_mount() to this effect; EPERM is returned to indicate that the 71 * mount is not owned by the caller. 72 * 73 * autofssys() enables a caller in the global zone to clean up in-kernel (as 74 * well as regular) autofs mounts via the unmount_tree() mechanism. This is 75 * routinely done when all mounts are removed as part of zone shutdown. 76 */ 77 #define TYPICALMAXPATHLEN 64 78 79 static kmutex_t autofs_nodeid_lock; 80 81 /* max number of unmount threads running */ 82 static int autofs_unmount_threads = 5; 83 static int autofs_unmount_thread_timer = 120; /* in seconds */ 84 85 static int auto_perform_link(fnnode_t *, struct linka *, cred_t *); 86 static int auto_perform_actions(fninfo_t *, fnnode_t *, 87 action_list *, cred_t *); 88 static int auto_getmntpnt(vnode_t *, char *, vnode_t **, cred_t *); 89 static int auto_lookup_request(fninfo_t *, char *, struct linka *, 90 bool_t, bool_t *, cred_t *); 91 static int auto_mount_request(fninfo_t *, char *, action_list **, cred_t *, 92 bool_t); 93 94 /* 95 * Clears the MF_INPROG flag, and wakes up those threads sleeping on 96 * fn_cv_mount if MF_WAITING is set. 97 */ 98 void 99 auto_unblock_others( 100 fnnode_t *fnp, 101 uint_t operation) /* either MF_INPROG or MF_LOOKUP */ 102 { 103 ASSERT(operation & (MF_INPROG | MF_LOOKUP)); 104 fnp->fn_flags &= ~operation; 105 if (fnp->fn_flags & MF_WAITING) { 106 fnp->fn_flags &= ~MF_WAITING; 107 cv_broadcast(&fnp->fn_cv_mount); 108 } 109 } 110 111 int 112 auto_wait4mount(fnnode_t *fnp) 113 { 114 int error; 115 k_sigset_t smask; 116 117 AUTOFS_DPRINT((4, "auto_wait4mount: fnp=%p\n", (void *)fnp)); 118 119 mutex_enter(&fnp->fn_lock); 120 while (fnp->fn_flags & (MF_INPROG | MF_LOOKUP)) { 121 /* 122 * There is a mount or a lookup in progress. 123 */ 124 fnp->fn_flags |= MF_WAITING; 125 sigintr(&smask, 1); 126 if (!cv_wait_sig(&fnp->fn_cv_mount, &fnp->fn_lock)) { 127 /* 128 * Decided not to wait for operation to 129 * finish after all. 130 */ 131 sigunintr(&smask); 132 mutex_exit(&fnp->fn_lock); 133 return (EINTR); 134 } 135 sigunintr(&smask); 136 } 137 error = fnp->fn_error; 138 139 if (error == EINTR) { 140 /* 141 * The thread doing the mount got interrupted, we need to 142 * try again, by returning EAGAIN. 143 */ 144 error = EAGAIN; 145 } 146 mutex_exit(&fnp->fn_lock); 147 148 AUTOFS_DPRINT((5, "auto_wait4mount: fnp=%p error=%d\n", (void *)fnp, 149 error)); 150 return (error); 151 } 152 153 int 154 auto_lookup_aux(fnnode_t *fnp, char *name, cred_t *cred) 155 { 156 struct fninfo *fnip; 157 struct linka link; 158 bool_t mountreq = FALSE; 159 int error = 0; 160 161 fnip = vfstofni(fntovn(fnp)->v_vfsp); 162 bzero(&link, sizeof (link)); 163 error = auto_lookup_request(fnip, name, &link, TRUE, &mountreq, cred); 164 if (!error) { 165 if (link.link != NULL || link.link != '\0') { 166 /* 167 * This node should be a symlink 168 */ 169 error = auto_perform_link(fnp, &link, cred); 170 } else if (mountreq) { 171 /* 172 * The automount daemon is requesting a mount, 173 * implying this entry must be a wildcard match and 174 * therefore in need of verification that the entry 175 * exists on the server. 176 */ 177 mutex_enter(&fnp->fn_lock); 178 AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG); 179 fnp->fn_error = 0; 180 181 /* 182 * Unblock other lookup requests on this node, 183 * this is needed to let the lookup generated by 184 * the mount call to complete. The caveat is 185 * other lookups on this node can also get by, 186 * i.e., another lookup on this node that occurs 187 * while this lookup is attempting the mount 188 * would return a positive result no matter what. 189 * Therefore two lookups on the this node could 190 * potentially get disparate results. 191 */ 192 AUTOFS_UNBLOCK_OTHERS(fnp, MF_LOOKUP); 193 mutex_exit(&fnp->fn_lock); 194 /* 195 * auto_new_mount_thread fires up a new thread which 196 * calls automountd finishing up the work 197 */ 198 auto_new_mount_thread(fnp, name, cred); 199 200 /* 201 * At this point, we are simply another thread 202 * waiting for the mount to complete 203 */ 204 error = auto_wait4mount(fnp); 205 if (error == AUTOFS_SHUTDOWN) 206 error = ENOENT; 207 } 208 } 209 210 if (link.link) 211 kmem_free(link.link, strlen(link.link) + 1); 212 if (link.dir) 213 kmem_free(link.dir, strlen(link.dir) + 1); 214 mutex_enter(&fnp->fn_lock); 215 fnp->fn_error = error; 216 217 /* 218 * Notify threads waiting for lookup/mount that 219 * it's done. 220 */ 221 if (mountreq) { 222 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG); 223 } else { 224 AUTOFS_UNBLOCK_OTHERS(fnp, MF_LOOKUP); 225 } 226 mutex_exit(&fnp->fn_lock); 227 return (error); 228 } 229 230 /* 231 * Starting point for thread to handle mount requests with automountd. 232 * XXX auto_mount_thread() is not suspend-safe within the scope of 233 * the present model defined for cpr to suspend the system. Calls 234 * made by the auto_mount_thread() that have been identified to be unsafe 235 * are (1) RPC client handle setup and client calls to automountd which 236 * can block deep down in the RPC library, (2) kmem_alloc() calls with the 237 * KM_SLEEP flag which can block if memory is low, and (3) VFS_*(), and 238 * lookuppnvp() calls which can result in over the wire calls to servers. 239 * The thread should be completely reevaluated to make it suspend-safe in 240 * case of future updates to the cpr model. 241 */ 242 static void 243 auto_mount_thread(struct autofs_callargs *argsp) 244 { 245 struct fninfo *fnip; 246 fnnode_t *fnp; 247 vnode_t *vp; 248 char *name; 249 size_t namelen; 250 cred_t *cred; 251 action_list *alp = NULL; 252 int error; 253 callb_cpr_t cprinfo; 254 kmutex_t auto_mount_thread_cpr_lock; 255 256 mutex_init(&auto_mount_thread_cpr_lock, NULL, MUTEX_DEFAULT, NULL); 257 CALLB_CPR_INIT(&cprinfo, &auto_mount_thread_cpr_lock, 258 callb_generic_cpr, "auto_mount_thread"); 259 260 fnp = argsp->fnc_fnp; 261 vp = fntovn(fnp); 262 fnip = vfstofni(vp->v_vfsp); 263 name = argsp->fnc_name; 264 cred = argsp->fnc_cred; 265 ASSERT(crgetzoneid(argsp->fnc_cred) == fnip->fi_zoneid); 266 267 error = auto_mount_request(fnip, name, &alp, cred, TRUE); 268 if (!error) 269 error = auto_perform_actions(fnip, fnp, alp, cred); 270 mutex_enter(&fnp->fn_lock); 271 fnp->fn_error = error; 272 273 /* 274 * Notify threads waiting for mount that 275 * it's done. 276 */ 277 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG); 278 mutex_exit(&fnp->fn_lock); 279 280 VN_RELE(vp); 281 crfree(argsp->fnc_cred); 282 namelen = strlen(argsp->fnc_name) + 1; 283 kmem_free(argsp->fnc_name, namelen); 284 kmem_free(argsp, sizeof (*argsp)); 285 286 mutex_enter(&auto_mount_thread_cpr_lock); 287 CALLB_CPR_EXIT(&cprinfo); 288 mutex_destroy(&auto_mount_thread_cpr_lock); 289 zthread_exit(); 290 /* NOTREACHED */ 291 } 292 293 static int autofs_thr_success = 0; 294 295 /* 296 * Creates new thread which calls auto_mount_thread which does 297 * the bulk of the work calling automountd, via 'auto_perform_actions'. 298 */ 299 void 300 auto_new_mount_thread(fnnode_t *fnp, char *name, cred_t *cred) 301 { 302 struct autofs_callargs *argsp; 303 304 argsp = kmem_alloc(sizeof (*argsp), KM_SLEEP); 305 VN_HOLD(fntovn(fnp)); 306 argsp->fnc_fnp = fnp; 307 argsp->fnc_name = kmem_alloc(strlen(name) + 1, KM_SLEEP); 308 (void) strcpy(argsp->fnc_name, name); 309 argsp->fnc_origin = curthread; 310 crhold(cred); 311 argsp->fnc_cred = cred; 312 313 (void) zthread_create(NULL, 0, auto_mount_thread, argsp, 0, 314 minclsyspri); 315 autofs_thr_success++; 316 } 317 318 #define DOOR_BUF_ALIGN (1024*1024) 319 #define DOOR_BUF_MULTIPLIER 3 320 #define DOOR_BUF_DEFAULT_SZ (DOOR_BUF_MULTIPLIER * DOOR_BUF_ALIGN) 321 int doorbuf_defsz = DOOR_BUF_DEFAULT_SZ; 322 323 /*ARGSUSED*/ 324 int 325 auto_calldaemon( 326 zoneid_t zoneid, 327 int which, 328 xdrproc_t xarg_func, 329 void *argsp, 330 xdrproc_t xresp_func, 331 void *resp, 332 int reslen, 333 bool_t hard) /* retry forever? */ 334 { 335 int retry; 336 int error = 0; 337 k_sigset_t smask; 338 door_arg_t door_args; 339 door_handle_t dh; 340 XDR xdrarg; 341 XDR xdrres; 342 struct autofs_globals *fngp = NULL; 343 void *orp = NULL; 344 int orl; 345 int rlen = 0; /* MUST be initialized */ 346 autofs_door_args_t *xdr_argsp; 347 int xdr_len = 0; 348 int printed_not_running_msg = 0; 349 klwp_t *lwp = ttolwp(curthread); 350 351 /* 352 * We know that the current thread is doing work on 353 * behalf of its own zone, so it's ok to use 354 * curproc->p_zone. 355 */ 356 ASSERT(zoneid == getzoneid()); 357 if (zone_status_get(curproc->p_zone) >= ZONE_IS_SHUTTING_DOWN) { 358 /* 359 * There's no point in trying to talk to 360 * automountd. Plus, zone_shutdown() is 361 * waiting for us. 362 */ 363 return (ECONNREFUSED); 364 } 365 366 do { 367 retry = 0; 368 mutex_enter(&autofs_minor_lock); 369 fngp = zone_getspecific(autofs_key, curproc->p_zone); 370 mutex_exit(&autofs_minor_lock); 371 if (fngp == NULL) { 372 if (hard) { 373 AUTOFS_DPRINT((5, 374 "auto_calldaemon: "\ 375 "failed to get door handle\n")); 376 if (!printed_not_running_msg) { 377 printed_not_running_msg = 1; 378 zprintf(zoneid, "automountd not "\ 379 "running, retrying\n"); 380 } 381 delay(hz); 382 retry = 1; 383 } else { 384 /* 385 * There is no global data so no door. 386 * There's no point in attempting to talk 387 * to automountd if we can't get the door 388 * handle. 389 */ 390 return (ECONNREFUSED); 391 } 392 } 393 } while (retry); 394 395 if (printed_not_running_msg) { 396 fngp->fng_printed_not_running_msg = printed_not_running_msg; 397 } 398 399 ASSERT(fngp != NULL); 400 401 if (argsp != NULL && (xdr_len = xdr_sizeof(xarg_func, argsp)) == 0) 402 return (EINVAL); 403 xdr_argsp = kmem_zalloc(xdr_len + sizeof (*xdr_argsp), KM_SLEEP); 404 xdr_argsp->xdr_len = xdr_len; 405 xdr_argsp->cmd = which; 406 407 if (argsp) { 408 xdrmem_create(&xdrarg, (char *)&xdr_argsp->xdr_arg, 409 xdr_argsp->xdr_len, XDR_ENCODE); 410 411 if (!(*xarg_func)(&xdrarg, argsp)) { 412 kmem_free(xdr_argsp, xdr_len + sizeof (*xdr_argsp)); 413 return (EINVAL); 414 } 415 } 416 417 /* 418 * We're saving off the original pointer and length due to the 419 * possibility that the results buffer returned by the door 420 * upcall can be different then what we passed in. This is because 421 * the door will allocate new memory if the results buffer passed 422 * in isn't large enough to hold what we need to send back. 423 * In this case we need to free the memory originally allocated 424 * for that buffer. 425 */ 426 if (resp) 427 rlen = xdr_sizeof(xresp_func, resp); 428 orl = (rlen == 0) ? doorbuf_defsz : MAX(rlen, doorbuf_defsz); 429 orp = kmem_zalloc(orl, KM_SLEEP); 430 431 do { 432 retry = 0; 433 mutex_enter(&fngp->fng_autofs_daemon_lock); 434 dh = fngp->fng_autofs_daemon_dh; 435 if (dh) 436 door_ki_hold(dh); 437 mutex_exit(&fngp->fng_autofs_daemon_lock); 438 439 if (dh == NULL) { 440 if (orp) 441 kmem_free(orp, orl); 442 kmem_free(xdr_argsp, xdr_len + sizeof (*xdr_argsp)); 443 return (ENOENT); 444 } 445 door_args.data_ptr = (char *)xdr_argsp; 446 door_args.data_size = sizeof (*xdr_argsp) + xdr_argsp->xdr_len; 447 door_args.desc_ptr = NULL; 448 door_args.desc_num = 0; 449 door_args.rbuf = orp ? (char *)orp : NULL; 450 door_args.rsize = orl; 451 452 sigintr(&smask, 1); 453 error = 454 door_ki_upcall_limited(dh, &door_args, NULL, SIZE_MAX, 0); 455 sigunintr(&smask); 456 457 door_ki_rele(dh); 458 459 /* 460 * Handle daemon errors 461 */ 462 if (!error) { 463 /* 464 * Upcall successful. Let's check for soft errors 465 * from the daemon. We only recover from overflow 466 * type scenarios. Any other errors, we return to 467 * the caller. 468 */ 469 autofs_door_res_t *adr = 470 (autofs_door_res_t *)door_args.rbuf; 471 472 if (door_args.rbuf != NULL) { 473 int nl; 474 475 switch (error = adr->res_status) { 476 case 0: /* no error; continue */ 477 break; 478 479 case EOVERFLOW: 480 /* 481 * orig landing buf not big enough. 482 * xdr_len in XDR_BYTES_PER_UNIT 483 */ 484 if ((nl = adr->xdr_len) > 0 && 485 (btopr(nl) < freemem/64)) { 486 if (orp) 487 kmem_free(orp, orl); 488 orp = kmem_zalloc(nl, KM_SLEEP); 489 orl = nl; 490 retry = 1; 491 break; 492 } 493 /*FALLTHROUGH*/ 494 495 default: 496 kmem_free(xdr_argsp, 497 xdr_len + sizeof (*xdr_argsp)); 498 if (orp) 499 kmem_free(orp, orl); 500 return (error); 501 } 502 } 503 continue; 504 } 505 506 /* 507 * no daemon errors; now process door/comm errors (if any) 508 */ 509 switch (error) { 510 case EINTR: 511 /* 512 * interrupts should be handled properly by the 513 * door upcall. If the door doesn't handle the 514 * interupt completely then we need to bail out. 515 */ 516 if (lwp && (ISSIG(curthread, 517 JUSTLOOKING) || MUSTRETURN(curproc, curthread))) { 518 if (ISSIG(curthread, FORREAL) || 519 lwp->lwp_sysabort || 520 MUSTRETURN(curproc, curthread)) { 521 lwp->lwp_sysabort = 0; 522 return (EINTR); 523 } 524 } 525 /* 526 * We may have gotten EINTR for other reasons 527 * like the door being revoked on us. Instead 528 * of trying to extract this out of the door 529 * handle, sleep and try again, if still 530 * revoked we will get EBADF next time 531 * through. 532 * 533 * If we have a pending cancellation and we don't 534 * have cancellation disabled, we will get EINTR 535 * forever, no matter how many times we retry, 536 * so just get out now if this is the case. 537 */ 538 if (schedctl_cancel_pending()) 539 break; 540 /* FALLTHROUGH */ 541 case EAGAIN: /* process may be forking */ 542 /* 543 * Back off for a bit 544 */ 545 delay(hz); 546 retry = 1; 547 break; 548 case EBADF: /* Invalid door */ 549 case EINVAL: /* Not a door, wrong target */ 550 /* 551 * A fatal door error, if our failing door 552 * handle is the current door handle, clean 553 * up our state. 554 */ 555 mutex_enter(&fngp->fng_autofs_daemon_lock); 556 if (dh == fngp->fng_autofs_daemon_dh) { 557 door_ki_rele(fngp->fng_autofs_daemon_dh); 558 fngp->fng_autofs_daemon_dh = NULL; 559 } 560 mutex_exit(&fngp->fng_autofs_daemon_lock); 561 AUTOFS_DPRINT((5, "auto_calldaemon error=%d\n", error)); 562 if (hard) { 563 if (!fngp->fng_printed_not_running_msg) { 564 fngp->fng_printed_not_running_msg = 1; 565 zprintf(zoneid, "automountd not " 566 "running, retrying\n"); 567 } 568 delay(hz); 569 retry = 1; 570 break; 571 } else { 572 error = ECONNREFUSED; 573 kmem_free(xdr_argsp, 574 xdr_len + sizeof (*xdr_argsp)); 575 if (orp) 576 kmem_free(orp, orl); 577 return (error); 578 } 579 default: /* Unknown must be fatal */ 580 error = ENOENT; 581 kmem_free(xdr_argsp, xdr_len + sizeof (*xdr_argsp)); 582 if (orp) 583 kmem_free(orp, orl); 584 return (error); 585 } 586 } while (retry); 587 588 if (fngp->fng_printed_not_running_msg == 1) { 589 fngp->fng_printed_not_running_msg = 0; 590 zprintf(zoneid, "automountd OK\n"); 591 } 592 593 if (orp && orl) { 594 autofs_door_res_t *door_resp; 595 door_resp = (autofs_door_res_t *)door_args.rbuf; 596 597 if ((void *)door_args.rbuf != orp) 598 kmem_free(orp, orl); 599 600 xdrmem_create(&xdrres, (char *)&door_resp->xdr_res, 601 door_resp->xdr_len, XDR_DECODE); 602 603 if (!((*xresp_func)(&xdrres, resp))) 604 error = EINVAL; 605 kmem_free(door_args.rbuf, door_args.rsize); 606 } 607 kmem_free(xdr_argsp, xdr_len + sizeof (*xdr_argsp)); 608 return (error); 609 } 610 611 static int 612 auto_null_request(zoneid_t zoneid, bool_t hard) 613 { 614 int error; 615 616 AUTOFS_DPRINT((4, "\tauto_null_request\n")); 617 618 error = auto_calldaemon(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. 1840 */ 1841 static boolean_t 1842 triggers_busy(fnnode_t *fnp) 1843 { 1844 int done; 1845 int lck_error = 0; 1846 fnnode_t *tp, *t1p; 1847 vfs_t *vfsp; 1848 1849 ASSERT(RW_WRITE_HELD(&fnp->fn_rwlock)); 1850 1851 for (tp = fnp->fn_trigger; tp != NULL; tp = tp->fn_next) { 1852 AUTOFS_DPRINT((10, "\ttrigger: %s\n", tp->fn_name)); 1853 /* MF_LOOKUP should never be set on trigger nodes */ 1854 ASSERT((tp->fn_flags & MF_LOOKUP) == 0); 1855 vfsp = fntovn(tp)->v_vfsp; 1856 1857 /* 1858 * The vn_vfsunlock will be done in auto_inkernel_unmount. 1859 */ 1860 lck_error = vn_vfswlock(vfsp->vfs_vnodecovered); 1861 1862 if (lck_error != 0 || (tp->fn_flags & MF_INPROG) || 1863 DEEPER(tp) || ((fntovn(tp))->v_count) > 2) { 1864 /* 1865 * couldn't lock it because it's busy, 1866 * It is mounted on or has dirents? 1867 * If reference count is greater than two, then 1868 * somebody else is holding a reference to this vnode. 1869 * One reference is for the mountpoint, and the second 1870 * is for the trigger node. 1871 */ 1872 AUTOFS_DPRINT((10, "\ttrigger busy\n")); 1873 1874 /* 1875 * Unlock previously locked mountpoints 1876 */ 1877 for (done = 0, t1p = fnp->fn_trigger; !done; 1878 t1p = t1p->fn_next) { 1879 /* 1880 * Unlock all nodes previously 1881 * locked. All nodes up to 'tp' 1882 * were successfully locked. If 'lck_err' is 1883 * set, then 'tp' was not locked, and thus 1884 * should not be unlocked. If 1885 * 'lck_err' is not set, then 'tp' was 1886 * successfully locked, and it should 1887 * be unlocked. 1888 */ 1889 if (t1p != tp || !lck_error) { 1890 vfsp = fntovn(t1p)->v_vfsp; 1891 vn_vfsunlock(vfsp->vfs_vnodecovered); 1892 } 1893 done = (t1p == tp); 1894 } 1895 return (B_TRUE); 1896 } 1897 } 1898 1899 return (B_FALSE); 1900 } 1901 1902 /* 1903 * It is the caller's responsibility to grab the VVFSLOCK. 1904 * Releases the VVFSLOCK upon return. 1905 */ 1906 static int 1907 unmount_node(vnode_t *cvp, int force) 1908 { 1909 int error = 0; 1910 fnnode_t *cfnp; 1911 vfs_t *vfsp; 1912 umntrequest ul; 1913 fninfo_t *fnip; 1914 1915 AUTOFS_DPRINT((4, "\tunmount_node cvp=%p\n", (void *)cvp)); 1916 1917 ASSERT(vn_vfswlock_held(cvp)); 1918 cfnp = vntofn(cvp); 1919 vfsp = vn_mountedvfs(cvp); 1920 1921 if (force || cfnp->fn_flags & MF_IK_MOUNT) { 1922 /* 1923 * Mount was performed in the kernel, so 1924 * do an in-kernel unmount. auto_inkernel_unmount() 1925 * will vn_vfsunlock(cvp). 1926 */ 1927 error = auto_inkernel_unmount(vfsp); 1928 } else { 1929 zone_t *zone = NULL; 1930 refstr_t *mntpt, *resource; 1931 size_t mntoptslen; 1932 1933 /* 1934 * Get the mnttab information of the node 1935 * and ask the daemon to unmount it. 1936 */ 1937 bzero(&ul, sizeof (ul)); 1938 mntfs_getmntopts(vfsp, &ul.mntopts, &mntoptslen); 1939 if (ul.mntopts == NULL) { 1940 auto_log(cfnp->fn_globals->fng_verbose, 1941 cfnp->fn_globals->fng_zoneid, CE_WARN, 1942 "unmount_node: no memory"); 1943 vn_vfsunlock(cvp); 1944 error = ENOMEM; 1945 goto done; 1946 } 1947 if (mntoptslen > AUTOFS_MAXOPTSLEN) 1948 ul.mntopts[AUTOFS_MAXOPTSLEN - 1] = '\0'; 1949 1950 mntpt = vfs_getmntpoint(vfsp); 1951 ul.mntpnt = (char *)refstr_value(mntpt); 1952 resource = vfs_getresource(vfsp); 1953 ul.mntresource = (char *)refstr_value(resource); 1954 1955 fnip = vfstofni(cvp->v_vfsp); 1956 ul.isdirect = fnip->fi_flags & MF_DIRECT ? TRUE : FALSE; 1957 1958 /* 1959 * Since a zone'd automountd's view of the autofs mount points 1960 * differs from those in the kernel, we need to make sure we 1961 * give it consistent mount points. 1962 */ 1963 ASSERT(fnip->fi_zoneid == getzoneid()); 1964 zone = curproc->p_zone; 1965 1966 if (fnip->fi_zoneid != GLOBAL_ZONEID) { 1967 if (ZONE_PATH_VISIBLE(ul.mntpnt, zone)) { 1968 ul.mntpnt = 1969 ZONE_PATH_TRANSLATE(ul.mntpnt, zone); 1970 } 1971 if (ZONE_PATH_VISIBLE(ul.mntresource, zone)) { 1972 ul.mntresource = 1973 ZONE_PATH_TRANSLATE(ul.mntresource, zone); 1974 } 1975 } 1976 1977 ul.fstype = vfssw[vfsp->vfs_fstype].vsw_name; 1978 vn_vfsunlock(cvp); 1979 1980 error = auto_send_unmount_request(fnip, &ul, FALSE); 1981 kmem_free(ul.mntopts, mntoptslen); 1982 refstr_rele(mntpt); 1983 refstr_rele(resource); 1984 } 1985 1986 done: 1987 AUTOFS_DPRINT((5, "\tunmount_node cvp=%p error=%d\n", (void *)cvp, 1988 error)); 1989 return (error); 1990 } 1991 1992 /* 1993 * return EBUSY if any thread is holding a reference to this vnode 1994 * other than us. Result of this function cannot be relied on, since 1995 * it doesn't follow proper locking rules (i.e. vp->v_vfsmountedhere 1996 * and fnp->fn_trigger can change throughout this function). However 1997 * it's good enough for rough estimation. 1998 */ 1999 static int 2000 check_auto_node(vnode_t *vp) 2001 { 2002 fnnode_t *fnp; 2003 int error = 0; 2004 /* 2005 * number of references to expect for 2006 * a non-busy vnode. 2007 */ 2008 uint_t count; 2009 2010 AUTOFS_DPRINT((4, "\tcheck_auto_node vp=%p ", (void *)vp)); 2011 fnp = vntofn(vp); 2012 2013 count = 1; /* we are holding a reference to vp */ 2014 if (fnp->fn_flags & MF_TRIGGER) { 2015 /* 2016 * parent holds a pointer to us (trigger) 2017 */ 2018 count++; 2019 } 2020 if (fnp->fn_trigger != NULL) { 2021 /* 2022 * The trigger nodes have a hold on us. 2023 */ 2024 count++; 2025 } 2026 if (vn_ismntpt(vp)) { 2027 /* 2028 * File system is mounted on us. 2029 */ 2030 count++; 2031 } 2032 mutex_enter(&vp->v_lock); 2033 ASSERT(vp->v_count > 0); 2034 if (vp->v_flag & VROOT) 2035 count++; 2036 AUTOFS_DPRINT((10, "\tcount=%u ", vp->v_count)); 2037 if (vp->v_count > count) 2038 error = EBUSY; 2039 mutex_exit(&vp->v_lock); 2040 2041 AUTOFS_DPRINT((5, "\tcheck_auto_node error=%d ", error)); 2042 return (error); 2043 } 2044 2045 /* 2046 * rootvp is the root of the AUTOFS filesystem. 2047 * If rootvp is busy (v_count > 1) returns EBUSY. 2048 * else removes every vnode under this tree. 2049 * ASSUMPTION: Assumes that the only node which can be busy is 2050 * the root vnode. This filesystem better be two levels deep only, 2051 * the root and its immediate subdirs. 2052 * The daemon will "AUTOFS direct-mount" only one level below the root. 2053 */ 2054 static void 2055 unmount_autofs(vnode_t *rootvp) 2056 { 2057 fnnode_t *fnp, *rootfnp, *nfnp; 2058 2059 AUTOFS_DPRINT((4, "\tunmount_autofs rootvp=%p ", (void *)rootvp)); 2060 2061 /* 2062 * Remove all its immediate subdirectories. 2063 */ 2064 rootfnp = vntofn(rootvp); 2065 rw_enter(&rootfnp->fn_rwlock, RW_WRITER); 2066 for (fnp = rootfnp->fn_dirents; fnp != NULL; fnp = nfnp) { 2067 ASSERT(fntovn(fnp)->v_count == 0); 2068 ASSERT(fnp->fn_dirents == NULL); 2069 ASSERT(fnp->fn_linkcnt == 2); 2070 fnp->fn_linkcnt--; 2071 auto_disconnect(rootfnp, fnp); 2072 nfnp = fnp->fn_next; 2073 auto_freefnnode(fnp); 2074 } 2075 rw_exit(&rootfnp->fn_rwlock); 2076 } 2077 2078 /* 2079 * If a node matches all unmount criteria, do: 2080 * destroy subordinate trigger node(s) if there is any 2081 * unmount filesystem mounted on top of the node if there is any 2082 * 2083 * Function should be called with locked fnp's mutex. The mutex is 2084 * unlocked before return from function. 2085 */ 2086 static int 2087 try_unmount_node(fnnode_t *fnp, boolean_t force) 2088 { 2089 boolean_t trigger_unmount = B_FALSE; 2090 action_list *alp = NULL; 2091 vnode_t *vp; 2092 int error = 0; 2093 fninfo_t *fnip; 2094 vfs_t *vfsp; 2095 struct autofs_globals *fngp; 2096 2097 AUTOFS_DPRINT((10, "\ttry_unmount_node: processing node %p\n", 2098 (void *)fnp)); 2099 2100 ASSERT(MUTEX_HELD(&fnp->fn_lock)); 2101 2102 fngp = fnp->fn_globals; 2103 vp = fntovn(fnp); 2104 fnip = vfstofni(vp->v_vfsp); 2105 2106 /* 2107 * If either a mount, lookup or another unmount of this subtree is in 2108 * progress, don't attempt to unmount at this time. 2109 */ 2110 if (fnp->fn_flags & (MF_INPROG | MF_LOOKUP)) { 2111 mutex_exit(&fnp->fn_lock); 2112 return (EBUSY); 2113 } 2114 2115 /* 2116 * Bail out if someone else is holding reference to this vnode. 2117 * This check isn't just an optimization (someone is probably 2118 * just about to trigger mount). It is necessary to prevent a deadlock 2119 * in domount() called from auto_perform_actions() if unmount of 2120 * trigger parent fails. domount() calls lookupname() to resolve 2121 * special in mount arguments. Special is set to a map name in case 2122 * of autofs triggers (i.e. auto_ws.sun.com). Thus if current 2123 * working directory is set to currently processed node, lookupname() 2124 * calls into autofs vnops in order to resolve special, which deadlocks 2125 * the process. 2126 * 2127 * Note: This should be fixed. Autofs shouldn't pass the map name 2128 * in special and avoid useless lookup with potentially disasterous 2129 * consequence. 2130 */ 2131 if (check_auto_node(vp) == EBUSY) { 2132 mutex_exit(&fnp->fn_lock); 2133 return (EBUSY); 2134 } 2135 2136 /* 2137 * If not forced operation, back out if node has been referenced 2138 * recently. 2139 */ 2140 if (!force && 2141 fnp->fn_ref_time + fnip->fi_mount_to > gethrestime_sec()) { 2142 mutex_exit(&fnp->fn_lock); 2143 return (EBUSY); 2144 } 2145 2146 /* block mounts/unmounts on the node */ 2147 AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG); 2148 fnp->fn_error = 0; 2149 mutex_exit(&fnp->fn_lock); 2150 2151 /* unmount next level triggers if there are any */ 2152 rw_enter(&fnp->fn_rwlock, RW_WRITER); 2153 if (fnp->fn_trigger != NULL) { 2154 trigger_unmount = B_TRUE; 2155 2156 if (triggers_busy(fnp)) { 2157 rw_exit(&fnp->fn_rwlock); 2158 mutex_enter(&fnp->fn_lock); 2159 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG); 2160 mutex_exit(&fnp->fn_lock); 2161 return (EBUSY); 2162 } 2163 2164 /* 2165 * At this point, we know all trigger nodes are locked, 2166 * and they're not busy or mounted on. 2167 * 2168 * Attempt to unmount all trigger nodes, save the 2169 * action_list in case we need to remount them later. 2170 * The action_list will be freed later if there was no 2171 * need to remount the trigger nodes. 2172 */ 2173 unmount_triggers(fnp, &alp); 2174 } 2175 rw_exit(&fnp->fn_rwlock); 2176 2177 (void) vn_vfswlock_wait(vp); 2178 2179 vfsp = vn_mountedvfs(vp); 2180 if (vfsp != NULL) { 2181 /* vn_vfsunlock(vp) is done inside unmount_node() */ 2182 error = unmount_node(vp, force); 2183 if (error == ECONNRESET) { 2184 if (vn_mountedvfs(vp) == NULL) { 2185 /* 2186 * The filesystem was unmounted before the 2187 * daemon died. Unfortunately we can not 2188 * determine whether all the cleanup work was 2189 * successfully finished (i.e. update mnttab, 2190 * or notify NFS server of the unmount). 2191 * We should not retry the operation since the 2192 * filesystem has already been unmounted, and 2193 * may have already been removed from mnttab, 2194 * in such case the devid/rdevid we send to 2195 * the daemon will not be matched. So we have 2196 * to be content with the partial unmount. 2197 * Since the mountpoint is no longer covered, we 2198 * clear the error condition. 2199 */ 2200 error = 0; 2201 auto_log(fngp->fng_verbose, fngp->fng_zoneid, 2202 CE_WARN, "autofs: automountd " 2203 "connection dropped when unmounting %s/%s", 2204 fnip->fi_path, (fnip->fi_flags & MF_DIRECT) 2205 ? "" : fnp->fn_name); 2206 } 2207 } 2208 } else { 2209 vn_vfsunlock(vp); 2210 /* Destroy all dirents of fnp if we unmounted its triggers */ 2211 if (trigger_unmount) 2212 unmount_autofs(vp); 2213 } 2214 2215 /* If unmount failed, we got to remount triggers */ 2216 if (error != 0) { 2217 if (trigger_unmount) { 2218 int ret; 2219 2220 ASSERT((fnp->fn_flags & MF_THISUID_MATCH_RQD) == 0); 2221 2222 /* 2223 * The action list was free'd by auto_perform_actions 2224 */ 2225 ret = auto_perform_actions(fnip, fnp, alp, CRED()); 2226 if (ret != 0) { 2227 auto_log(fngp->fng_verbose, fngp->fng_zoneid, 2228 CE_WARN, "autofs: can't remount triggers " 2229 "fnp=%p error=%d", (void *)fnp, ret); 2230 } 2231 } 2232 mutex_enter(&fnp->fn_lock); 2233 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG); 2234 mutex_exit(&fnp->fn_lock); 2235 } else { 2236 /* Free the action list here */ 2237 if (trigger_unmount) 2238 xdr_free(xdr_action_list, (char *)alp); 2239 2240 /* 2241 * Other threads may be waiting for this unmount to 2242 * finish. We must let it know that in order to 2243 * proceed, it must trigger the mount itself. 2244 */ 2245 mutex_enter(&fnp->fn_lock); 2246 fnp->fn_flags &= ~MF_IK_MOUNT; 2247 if (fnp->fn_flags & MF_WAITING) 2248 fnp->fn_error = EAGAIN; 2249 AUTOFS_UNBLOCK_OTHERS(fnp, MF_INPROG); 2250 mutex_exit(&fnp->fn_lock); 2251 } 2252 2253 return (error); 2254 } 2255 2256 /* 2257 * This is an implementation of depth-first search in a tree rooted by 2258 * start_fnp and composed from fnnodes. Links between tree levels are 2259 * fn_dirents, fn_trigger in fnnode_t and v_mountedvfs in vnode_t (if 2260 * mounted vfs is autofs). The algorithm keeps track of visited nodes 2261 * by means of a timestamp (fn_unmount_ref_time). 2262 * 2263 * Upon top-down traversal of the tree we apply following locking scheme: 2264 * lock fn_rwlock of current node 2265 * grab reference to child's vnode (VN_HOLD) 2266 * unlock fn_rwlock 2267 * free reference to current vnode (VN_RELE) 2268 * Similar locking scheme is used for down-top and left-right traversal. 2269 * 2270 * Algorithm examines the most down-left node in tree, which hasn't been 2271 * visited yet. From this follows that nodes are processed in bottom-up 2272 * fashion. 2273 * 2274 * Function returns either zero if unmount of root node was successful 2275 * or error code (mostly EBUSY). 2276 */ 2277 int 2278 unmount_subtree(fnnode_t *rootfnp, boolean_t force) 2279 { 2280 fnnode_t *currfnp; /* currently examined node in the tree */ 2281 fnnode_t *lastfnp; /* previously processed node */ 2282 fnnode_t *nextfnp; /* next examined node in the tree */ 2283 vnode_t *curvp; 2284 vnode_t *newvp; 2285 vfs_t *vfsp; 2286 time_t timestamp; 2287 2288 ASSERT(fntovn(rootfnp)->v_type != VLNK); 2289 AUTOFS_DPRINT((10, "unmount_subtree: root=%p (%s)\n", (void *)rootfnp, 2290 rootfnp->fn_name)); 2291 2292 /* 2293 * Timestamp, which visited nodes are marked with, to distinguish them 2294 * from unvisited nodes. 2295 */ 2296 timestamp = gethrestime_sec(); 2297 currfnp = lastfnp = rootfnp; 2298 2299 /* Loop until we examine all nodes in the tree */ 2300 mutex_enter(&currfnp->fn_lock); 2301 while (currfnp != rootfnp || rootfnp->fn_unmount_ref_time < timestamp) { 2302 curvp = fntovn(currfnp); 2303 AUTOFS_DPRINT((10, "\tunmount_subtree: entering node %p (%s)\n", 2304 (void *)currfnp, currfnp->fn_name)); 2305 2306 /* 2307 * New candidate for processing must have been already visited, 2308 * by us because we want to process tree nodes in bottom-up 2309 * order. 2310 */ 2311 if (currfnp->fn_unmount_ref_time == timestamp && 2312 currfnp != lastfnp) { 2313 (void) try_unmount_node(currfnp, force); 2314 lastfnp = currfnp; 2315 mutex_enter(&currfnp->fn_lock); 2316 /* 2317 * Fall through to next if-branch to pick 2318 * sibling or parent of this node. 2319 */ 2320 } 2321 2322 /* 2323 * If this node has been already visited, it means that it's 2324 * dead end and we need to pick sibling or parent as next node. 2325 */ 2326 if (currfnp->fn_unmount_ref_time >= timestamp || 2327 curvp->v_type == VLNK) { 2328 mutex_exit(&currfnp->fn_lock); 2329 /* 2330 * Obtain parent's readers lock before grabbing 2331 * reference to sibling. 2332 */ 2333 rw_enter(&currfnp->fn_parent->fn_rwlock, RW_READER); 2334 if ((nextfnp = currfnp->fn_next) != NULL) { 2335 VN_HOLD(fntovn(nextfnp)); 2336 rw_exit(&currfnp->fn_parent->fn_rwlock); 2337 VN_RELE(curvp); 2338 currfnp = nextfnp; 2339 mutex_enter(&currfnp->fn_lock); 2340 continue; 2341 } 2342 rw_exit(&currfnp->fn_parent->fn_rwlock); 2343 2344 /* 2345 * All descendants and siblings were visited. Perform 2346 * bottom-up move. 2347 */ 2348 nextfnp = currfnp->fn_parent; 2349 VN_HOLD(fntovn(nextfnp)); 2350 VN_RELE(curvp); 2351 currfnp = nextfnp; 2352 mutex_enter(&currfnp->fn_lock); 2353 continue; 2354 } 2355 2356 /* 2357 * Mark node as visited. Note that the timestamp could have 2358 * been updated by somebody else in the meantime. 2359 */ 2360 if (currfnp->fn_unmount_ref_time < timestamp) 2361 currfnp->fn_unmount_ref_time = timestamp; 2362 2363 /* 2364 * Don't descent below nodes, which are being unmounted/mounted. 2365 * 2366 * We need to hold both locks at once: fn_lock because we need 2367 * to read MF_INPROG and fn_rwlock to prevent anybody from 2368 * modifying fn_trigger until its used to traverse triggers 2369 * below. 2370 * 2371 * Acquire fn_rwlock in non-blocking mode to avoid deadlock. 2372 * If it can't be acquired, then acquire locks in correct 2373 * order. 2374 */ 2375 if (!rw_tryenter(&currfnp->fn_rwlock, RW_READER)) { 2376 mutex_exit(&currfnp->fn_lock); 2377 rw_enter(&currfnp->fn_rwlock, RW_READER); 2378 mutex_enter(&currfnp->fn_lock); 2379 } 2380 if (currfnp->fn_flags & MF_INPROG) { 2381 rw_exit(&currfnp->fn_rwlock); 2382 continue; 2383 } 2384 mutex_exit(&currfnp->fn_lock); 2385 2386 /* 2387 * Examine descendants in this order: triggers, dirents, autofs 2388 * mounts. 2389 */ 2390 2391 if ((nextfnp = currfnp->fn_trigger) != NULL) { 2392 VN_HOLD(fntovn(nextfnp)); 2393 rw_exit(&currfnp->fn_rwlock); 2394 VN_RELE(curvp); 2395 currfnp = nextfnp; 2396 mutex_enter(&currfnp->fn_lock); 2397 continue; 2398 } 2399 2400 if ((nextfnp = currfnp->fn_dirents) != NULL) { 2401 VN_HOLD(fntovn(nextfnp)); 2402 rw_exit(&currfnp->fn_rwlock); 2403 VN_RELE(curvp); 2404 currfnp = nextfnp; 2405 mutex_enter(&currfnp->fn_lock); 2406 continue; 2407 } 2408 rw_exit(&currfnp->fn_rwlock); 2409 2410 (void) vn_vfswlock_wait(curvp); 2411 vfsp = vn_mountedvfs(curvp); 2412 if (vfsp != NULL && 2413 vfs_matchops(vfsp, vfs_getops(curvp->v_vfsp))) { 2414 /* 2415 * Deal with /xfn/host/jurassic alikes here... 2416 * 2417 * We know this call to VFS_ROOT is safe to call while 2418 * holding VVFSLOCK, since it resolves to a call to 2419 * auto_root(). 2420 */ 2421 if (VFS_ROOT(vfsp, &newvp)) { 2422 cmn_err(CE_PANIC, 2423 "autofs: VFS_ROOT(vfs=%p) failed", 2424 (void *)vfsp); 2425 } 2426 vn_vfsunlock(curvp); 2427 VN_RELE(curvp); 2428 currfnp = vntofn(newvp); 2429 mutex_enter(&currfnp->fn_lock); 2430 continue; 2431 } 2432 vn_vfsunlock(curvp); 2433 mutex_enter(&currfnp->fn_lock); 2434 } 2435 2436 /* 2437 * Now we deal with the root node (currfnp's mutex is unlocked 2438 * in try_unmount_node()). 2439 */ 2440 return (try_unmount_node(currfnp, force)); 2441 } 2442 2443 /* 2444 * XXX unmount_tree() is not suspend-safe within the scope of 2445 * the present model defined for cpr to suspend the system. Calls made 2446 * by the unmount_tree() that have been identified to be unsafe are 2447 * (1) RPC client handle setup and client calls to automountd which can 2448 * block deep down in the RPC library, (2) kmem_alloc() calls with the 2449 * KM_SLEEP flag which can block if memory is low, and (3) VFS_*() and 2450 * VOP_*() calls which can result in over the wire calls to servers. 2451 * The thread should be completely reevaluated to make it suspend-safe in 2452 * case of future updates to the cpr model. 2453 */ 2454 void 2455 unmount_tree(struct autofs_globals *fngp, boolean_t force) 2456 { 2457 callb_cpr_t cprinfo; 2458 kmutex_t unmount_tree_cpr_lock; 2459 fnnode_t *root, *fnp, *next; 2460 2461 mutex_init(&unmount_tree_cpr_lock, NULL, MUTEX_DEFAULT, NULL); 2462 CALLB_CPR_INIT(&cprinfo, &unmount_tree_cpr_lock, callb_generic_cpr, 2463 "unmount_tree"); 2464 2465 /* 2466 * autofssys() will be calling in from the global zone and doing 2467 * work on the behalf of the given zone, hence we can't always 2468 * assert that we have the right credentials, nor that the 2469 * caller is always in the correct zone. 2470 * 2471 * We do, however, know that if this is a "forced unmount" 2472 * operation (which autofssys() does), then we won't go down to 2473 * the krpc layers, so we don't need to fudge with the 2474 * credentials. 2475 */ 2476 ASSERT(force || fngp->fng_zoneid == getzoneid()); 2477 2478 /* 2479 * If automountd is not running in this zone, 2480 * don't attempt unmounting this round. 2481 */ 2482 if (force || auto_null_request(fngp->fng_zoneid, FALSE) == 0) { 2483 /* 2484 * Iterate over top level autofs filesystems and call 2485 * unmount_subtree() for each of them. 2486 */ 2487 root = fngp->fng_rootfnnodep; 2488 rw_enter(&root->fn_rwlock, RW_READER); 2489 for (fnp = root->fn_dirents; fnp != NULL; fnp = next) { 2490 VN_HOLD(fntovn(fnp)); 2491 rw_exit(&root->fn_rwlock); 2492 (void) unmount_subtree(fnp, force); 2493 rw_enter(&root->fn_rwlock, RW_READER); 2494 next = fnp->fn_next; 2495 VN_RELE(fntovn(fnp)); 2496 } 2497 rw_exit(&root->fn_rwlock); 2498 } 2499 2500 mutex_enter(&unmount_tree_cpr_lock); 2501 CALLB_CPR_EXIT(&cprinfo); 2502 mutex_destroy(&unmount_tree_cpr_lock); 2503 } 2504 2505 static void 2506 unmount_zone_tree(struct autofs_globals *fngp) 2507 { 2508 AUTOFS_DPRINT((5, "unmount_zone_tree started. Thread created.\n")); 2509 2510 unmount_tree(fngp, B_FALSE); 2511 mutex_enter(&fngp->fng_unmount_threads_lock); 2512 fngp->fng_unmount_threads--; 2513 mutex_exit(&fngp->fng_unmount_threads_lock); 2514 2515 AUTOFS_DPRINT((5, "unmount_zone_tree done. Thread exiting.\n")); 2516 2517 zthread_exit(); 2518 /* NOTREACHED */ 2519 } 2520 2521 void 2522 auto_do_unmount(struct autofs_globals *fngp) 2523 { 2524 callb_cpr_t cprinfo; 2525 clock_t timeleft; 2526 zone_t *zone = curproc->p_zone; 2527 2528 CALLB_CPR_INIT(&cprinfo, &fngp->fng_unmount_threads_lock, 2529 callb_generic_cpr, "auto_do_unmount"); 2530 2531 for (;;) { /* forever */ 2532 mutex_enter(&fngp->fng_unmount_threads_lock); 2533 CALLB_CPR_SAFE_BEGIN(&cprinfo); 2534 newthread: 2535 mutex_exit(&fngp->fng_unmount_threads_lock); 2536 timeleft = zone_status_timedwait(zone, ddi_get_lbolt() + 2537 autofs_unmount_thread_timer * hz, ZONE_IS_SHUTTING_DOWN); 2538 mutex_enter(&fngp->fng_unmount_threads_lock); 2539 2540 if (timeleft != -1) { /* didn't time out */ 2541 ASSERT(zone_status_get(zone) >= ZONE_IS_SHUTTING_DOWN); 2542 /* 2543 * zone is exiting... don't create any new threads. 2544 * fng_unmount_threads_lock is released implicitly by 2545 * the below. 2546 */ 2547 CALLB_CPR_SAFE_END(&cprinfo, 2548 &fngp->fng_unmount_threads_lock); 2549 CALLB_CPR_EXIT(&cprinfo); 2550 zthread_exit(); 2551 /* NOTREACHED */ 2552 } 2553 if (fngp->fng_unmount_threads < autofs_unmount_threads) { 2554 fngp->fng_unmount_threads++; 2555 CALLB_CPR_SAFE_END(&cprinfo, 2556 &fngp->fng_unmount_threads_lock); 2557 mutex_exit(&fngp->fng_unmount_threads_lock); 2558 2559 (void) zthread_create(NULL, 0, unmount_zone_tree, fngp, 2560 0, minclsyspri); 2561 } else 2562 goto newthread; 2563 } 2564 /* NOTREACHED */ 2565 } 2566 2567 /* 2568 * Is nobrowse specified in option string? 2569 * opts should be a null ('\0') terminated string. 2570 * Returns non-zero if nobrowse has been specified. 2571 */ 2572 int 2573 auto_nobrowse_option(char *opts) 2574 { 2575 char *buf; 2576 char *p; 2577 char *t; 2578 int nobrowse = 0; 2579 int last_opt = 0; 2580 size_t len; 2581 2582 len = strlen(opts) + 1; 2583 p = buf = kmem_alloc(len, KM_SLEEP); 2584 (void) strcpy(buf, opts); 2585 do { 2586 if (t = strchr(p, ',')) 2587 *t++ = '\0'; 2588 else 2589 last_opt++; 2590 if (strcmp(p, MNTOPT_NOBROWSE) == 0) 2591 nobrowse = 1; 2592 else if (strcmp(p, MNTOPT_BROWSE) == 0) 2593 nobrowse = 0; 2594 p = t; 2595 } while (!last_opt); 2596 kmem_free(buf, len); 2597 2598 return (nobrowse); 2599 } 2600 2601 /* 2602 * used to log warnings only if automountd is running 2603 * with verbose mode set 2604 */ 2605 2606 void 2607 auto_log(int verbose, zoneid_t zoneid, int level, const char *fmt, ...) 2608 { 2609 va_list args; 2610 2611 if (verbose) { 2612 va_start(args, fmt); 2613 vzcmn_err(zoneid, level, fmt, args); 2614 va_end(args); 2615 } 2616 } 2617 2618 #ifdef DEBUG 2619 static int autofs_debug = 0; 2620 2621 /* 2622 * Utilities used by both client and server 2623 * Standard levels: 2624 * 0) no debugging 2625 * 1) hard failures 2626 * 2) soft failures 2627 * 3) current test software 2628 * 4) main procedure entry points 2629 * 5) main procedure exit points 2630 * 6) utility procedure entry points 2631 * 7) utility procedure exit points 2632 * 8) obscure procedure entry points 2633 * 9) obscure procedure exit points 2634 * 10) random stuff 2635 * 11) all <= 1 2636 * 12) all <= 2 2637 * 13) all <= 3 2638 * ... 2639 */ 2640 /* PRINTFLIKE2 */ 2641 void 2642 auto_dprint(int level, const char *fmt, ...) 2643 { 2644 va_list args; 2645 2646 if (autofs_debug == level || 2647 (autofs_debug > 10 && (autofs_debug - 10) >= level)) { 2648 va_start(args, fmt); 2649 (void) vprintf(fmt, args); 2650 va_end(args); 2651 } 2652 } 2653 #endif /* DEBUG */ 2654