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