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