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/systm.h> 30 #include <sys/errno.h> 31 #include <sys/proc.h> 32 #include <sys/vnode.h> 33 #include <sys/vfs.h> 34 #include <sys/vfs_opreg.h> 35 #include <sys/uio.h> 36 #include <sys/cred.h> 37 #include <sys/pathname.h> 38 #include <sys/dirent.h> 39 #include <sys/debug.h> 40 #include <sys/sysmacros.h> 41 #include <sys/tiuser.h> 42 #include <sys/cmn_err.h> 43 #include <sys/stat.h> 44 #include <sys/mode.h> 45 #include <sys/policy.h> 46 #include <rpc/types.h> 47 #include <rpc/auth.h> 48 #include <rpc/clnt.h> 49 #include <sys/fs/autofs.h> 50 #include <rpcsvc/autofs_prot.h> 51 #include <fs/fs_subr.h> 52 53 /* 54 * Vnode ops for autofs 55 */ 56 static int auto_open(vnode_t **, int, cred_t *); 57 static int auto_close(vnode_t *, int, int, offset_t, cred_t *); 58 static int auto_getattr(vnode_t *, vattr_t *, int, cred_t *); 59 static int auto_setattr(vnode_t *, vattr_t *, int, cred_t *, 60 caller_context_t *); 61 static int auto_access(vnode_t *, int, int, cred_t *); 62 static int auto_lookup(vnode_t *, char *, vnode_t **, 63 pathname_t *, int, vnode_t *, cred_t *); 64 static int auto_create(vnode_t *, char *, vattr_t *, vcexcl_t, 65 int, vnode_t **, cred_t *, int); 66 static int auto_remove(vnode_t *, char *, cred_t *); 67 static int auto_link(vnode_t *, vnode_t *, char *, cred_t *); 68 static int auto_rename(vnode_t *, char *, vnode_t *, char *, cred_t *); 69 static int auto_mkdir(vnode_t *, char *, vattr_t *, vnode_t **, cred_t *); 70 static int auto_rmdir(vnode_t *, char *, vnode_t *, cred_t *); 71 static int auto_readdir(vnode_t *, uio_t *, cred_t *, int *); 72 static int auto_symlink(vnode_t *, char *, vattr_t *, char *, cred_t *); 73 static int auto_readlink(vnode_t *, struct uio *, cred_t *); 74 static int auto_fsync(vnode_t *, int, cred_t *); 75 static void auto_inactive(vnode_t *, cred_t *); 76 static int auto_rwlock(vnode_t *, int, caller_context_t *); 77 static void auto_rwunlock(vnode_t *vp, int, caller_context_t *); 78 static int auto_seek(vnode_t *vp, offset_t, offset_t *); 79 80 static int auto_trigger_mount(vnode_t *, cred_t *, vnode_t **); 81 82 vnodeops_t *auto_vnodeops; 83 84 const fs_operation_def_t auto_vnodeops_template[] = { 85 VOPNAME_OPEN, { .vop_open = auto_open }, 86 VOPNAME_CLOSE, { .vop_close = auto_close }, 87 VOPNAME_GETATTR, { .vop_getattr = auto_getattr }, 88 VOPNAME_SETATTR, { .vop_setattr = auto_setattr }, 89 VOPNAME_ACCESS, { .vop_access = auto_access }, 90 VOPNAME_LOOKUP, { .vop_lookup = auto_lookup }, 91 VOPNAME_CREATE, { .vop_create = auto_create }, 92 VOPNAME_REMOVE, { .vop_remove = auto_remove }, 93 VOPNAME_LINK, { .vop_link = auto_link }, 94 VOPNAME_RENAME, { .vop_rename = auto_rename }, 95 VOPNAME_MKDIR, { .vop_mkdir = auto_mkdir }, 96 VOPNAME_RMDIR, { .vop_rmdir = auto_rmdir }, 97 VOPNAME_READDIR, { .vop_readdir = auto_readdir }, 98 VOPNAME_SYMLINK, { .vop_symlink = auto_symlink }, 99 VOPNAME_READLINK, { .vop_readlink = auto_readlink }, 100 VOPNAME_FSYNC, { .vop_fsync = auto_fsync }, 101 VOPNAME_INACTIVE, { .vop_inactive = auto_inactive }, 102 VOPNAME_RWLOCK, { .vop_rwlock = auto_rwlock }, 103 VOPNAME_RWUNLOCK, { .vop_rwunlock = auto_rwunlock }, 104 VOPNAME_SEEK, { .vop_seek = auto_seek }, 105 VOPNAME_FRLOCK, { .error = fs_error }, 106 VOPNAME_DISPOSE, { .error = fs_error }, 107 VOPNAME_SHRLOCK, { .error = fs_error }, 108 VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support }, 109 NULL, NULL 110 }; 111 112 113 114 /* ARGSUSED */ 115 static int 116 auto_open(vnode_t **vpp, int flag, cred_t *cred) 117 { 118 vnode_t *newvp; 119 int error; 120 121 AUTOFS_DPRINT((4, "auto_open: *vpp=%p\n", (void *)*vpp)); 122 123 error = auto_trigger_mount(*vpp, cred, &newvp); 124 if (error) 125 goto done; 126 127 if (newvp != NULL) { 128 /* 129 * Node is now mounted on. 130 */ 131 VN_RELE(*vpp); 132 *vpp = newvp; 133 error = VOP_ACCESS(*vpp, VREAD, 0, cred); 134 if (!error) 135 error = VOP_OPEN(vpp, flag, cred); 136 } 137 138 done: 139 AUTOFS_DPRINT((5, "auto_open: *vpp=%p error=%d\n", (void *)*vpp, 140 error)); 141 return (error); 142 } 143 144 /* ARGSUSED */ 145 static int 146 auto_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cred) 147 { 148 return (0); 149 } 150 151 static int 152 auto_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cred) 153 { 154 fnnode_t *fnp = vntofn(vp); 155 vnode_t *newvp; 156 vfs_t *vfsp; 157 int error; 158 159 AUTOFS_DPRINT((4, "auto_getattr vp %p\n", (void *)vp)); 160 161 if (flags & ATTR_TRIGGER) { 162 /* 163 * Pre-trigger the mount 164 */ 165 error = auto_trigger_mount(vp, cred, &newvp); 166 if (error) 167 return (error); 168 169 if (newvp == NULL) 170 goto defattr; 171 172 if (error = vn_vfsrlock_wait(vp)) 173 return (error); 174 175 vfsp = newvp->v_vfsp; 176 } else { 177 /* 178 * Recursive auto_getattr/mount; go to the vfsp == NULL 179 * case. 180 */ 181 if (vn_vfswlock_held(vp)) 182 goto defattr; 183 184 if (error = vn_vfsrlock_wait(vp)) 185 return (error); 186 187 vfsp = vn_mountedvfs(vp); 188 } 189 190 if (vfsp != NULL) { 191 /* 192 * Node is mounted on. 193 */ 194 error = VFS_ROOT(vfsp, &newvp); 195 vn_vfsunlock(vp); 196 if (error) 197 return (error); 198 mutex_enter(&fnp->fn_lock); 199 if (fnp->fn_seen == newvp && fnp->fn_thread == curthread) { 200 /* 201 * Recursive auto_getattr(); just release newvp and drop 202 * into the vfsp == NULL case. 203 */ 204 mutex_exit(&fnp->fn_lock); 205 VN_RELE(newvp); 206 } else { 207 while (fnp->fn_thread && fnp->fn_thread != curthread) { 208 fnp->fn_flags |= MF_ATTR_WAIT; 209 cv_wait(&fnp->fn_cv_mount, &fnp->fn_lock); 210 } 211 fnp->fn_thread = curthread; 212 fnp->fn_seen = newvp; 213 mutex_exit(&fnp->fn_lock); 214 error = VOP_GETATTR(newvp, vap, flags, cred); 215 VN_RELE(newvp); 216 mutex_enter(&fnp->fn_lock); 217 fnp->fn_seen = 0; 218 fnp->fn_thread = 0; 219 if (fnp->fn_flags & MF_ATTR_WAIT) { 220 fnp->fn_flags &= ~MF_ATTR_WAIT; 221 cv_broadcast(&fnp->fn_cv_mount); 222 } 223 mutex_exit(&fnp->fn_lock); 224 return (error); 225 } 226 } else { 227 vn_vfsunlock(vp); 228 } 229 230 defattr: 231 ASSERT(vp->v_type == VDIR || vp->v_type == VLNK); 232 vap->va_uid = 0; 233 vap->va_gid = 0; 234 vap->va_nlink = fnp->fn_linkcnt; 235 vap->va_nodeid = (u_longlong_t)fnp->fn_nodeid; 236 vap->va_size = fnp->fn_size; 237 vap->va_atime = fnp->fn_atime; 238 vap->va_mtime = fnp->fn_mtime; 239 vap->va_ctime = fnp->fn_ctime; 240 vap->va_type = vp->v_type; 241 vap->va_mode = fnp->fn_mode; 242 vap->va_fsid = vp->v_vfsp->vfs_dev; 243 vap->va_rdev = 0; 244 vap->va_blksize = MAXBSIZE; 245 vap->va_nblocks = (fsblkcnt64_t)btod(vap->va_size); 246 vap->va_seq = 0; 247 248 return (0); 249 } 250 251 /*ARGSUSED4*/ 252 static int 253 auto_setattr( 254 vnode_t *vp, 255 struct vattr *vap, 256 int flags, 257 cred_t *cred, 258 caller_context_t *ct) 259 { 260 vnode_t *newvp; 261 int error; 262 263 AUTOFS_DPRINT((4, "auto_setattr vp %p\n", (void *)vp)); 264 265 if (error = auto_trigger_mount(vp, cred, &newvp)) 266 goto done; 267 268 if (newvp != NULL) { 269 /* 270 * Node is mounted on. 271 */ 272 if (vn_is_readonly(newvp)) 273 error = EROFS; 274 else 275 error = VOP_SETATTR(newvp, vap, flags, cred, NULL); 276 VN_RELE(newvp); 277 } else 278 error = ENOSYS; 279 280 done: 281 AUTOFS_DPRINT((5, "auto_setattr: error=%d\n", error)); 282 return (error); 283 } 284 285 /* ARGSUSED */ 286 static int 287 auto_access(vnode_t *vp, int mode, int flags, cred_t *cred) 288 { 289 fnnode_t *fnp = vntofn(vp); 290 vnode_t *newvp; 291 int error; 292 293 AUTOFS_DPRINT((4, "auto_access: vp=%p\n", (void *)vp)); 294 295 if (error = auto_trigger_mount(vp, cred, &newvp)) 296 goto done; 297 298 if (newvp != NULL) { 299 /* 300 * Node is mounted on. 301 */ 302 error = VOP_ACCESS(newvp, mode, 0, cred); 303 VN_RELE(newvp); 304 } else { 305 int shift = 0; 306 307 /* 308 * really interested in the autofs node, check the 309 * access on it 310 */ 311 ASSERT(error == 0); 312 if (crgetuid(cred) != fnp->fn_uid) { 313 shift += 3; 314 if (groupmember(fnp->fn_gid, cred) == 0) 315 shift += 3; 316 } 317 mode &= ~(fnp->fn_mode << shift); 318 if (mode != 0) 319 error = secpolicy_vnode_access(cred, vp, fnp->fn_uid, 320 mode); 321 } 322 323 done: 324 AUTOFS_DPRINT((5, "auto_access: error=%d\n", error)); 325 return (error); 326 } 327 328 static int 329 auto_lookup( 330 vnode_t *dvp, 331 char *nm, 332 vnode_t **vpp, 333 pathname_t *pnp, 334 int flags, 335 vnode_t *rdir, 336 cred_t *cred) 337 { 338 int error = 0; 339 vnode_t *newvp = NULL; 340 vfs_t *vfsp; 341 fninfo_t *dfnip; 342 fnnode_t *dfnp = NULL; 343 fnnode_t *fnp = NULL; 344 char *searchnm; 345 int operation; /* either AUTOFS_LOOKUP or AUTOFS_MOUNT */ 346 347 dfnip = vfstofni(dvp->v_vfsp); 348 AUTOFS_DPRINT((3, "auto_lookup: dvp=%p (%s) name=%s\n", 349 (void *)dvp, dfnip->fi_map, nm)); 350 351 if (nm[0] == 0) { 352 VN_HOLD(dvp); 353 *vpp = dvp; 354 return (0); 355 } 356 357 if (error = VOP_ACCESS(dvp, VEXEC, 0, cred)) 358 return (error); 359 360 if (nm[0] == '.' && nm[1] == 0) { 361 VN_HOLD(dvp); 362 *vpp = dvp; 363 return (0); 364 } 365 366 if (nm[0] == '.' && nm[1] == '.' && nm[2] == 0) { 367 fnnode_t *pdfnp; 368 369 pdfnp = (vntofn(dvp))->fn_parent; 370 ASSERT(pdfnp != NULL); 371 372 /* 373 * Since it is legitimate to have the VROOT flag set for the 374 * subdirectories of the indirect map in autofs filesystem, 375 * rootfnnodep is checked against fnnode of dvp instead of 376 * just checking whether VROOT flag is set in dvp 377 */ 378 379 if (pdfnp == pdfnp->fn_globals->fng_rootfnnodep) { 380 vnode_t *vp; 381 382 vfs_rlock_wait(dvp->v_vfsp); 383 if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) { 384 vfs_unlock(dvp->v_vfsp); 385 return (EIO); 386 } 387 vp = dvp->v_vfsp->vfs_vnodecovered; 388 VN_HOLD(vp); 389 vfs_unlock(dvp->v_vfsp); 390 error = VOP_LOOKUP(vp, nm, vpp, pnp, flags, rdir, cred); 391 VN_RELE(vp); 392 return (error); 393 } else { 394 *vpp = fntovn(pdfnp); 395 VN_HOLD(*vpp); 396 return (0); 397 } 398 } 399 400 top: 401 dfnp = vntofn(dvp); 402 searchnm = nm; 403 operation = 0; 404 405 ASSERT(vn_matchops(dvp, auto_vnodeops)); 406 407 AUTOFS_DPRINT((3, "auto_lookup: dvp=%p dfnp=%p\n", (void *)dvp, 408 (void *)dfnp)); 409 410 /* 411 * If a lookup or mount of this node is in progress, wait for it 412 * to finish, and return whatever result it got. 413 */ 414 mutex_enter(&dfnp->fn_lock); 415 if (dfnp->fn_flags & (MF_LOOKUP | MF_INPROG)) { 416 mutex_exit(&dfnp->fn_lock); 417 error = auto_wait4mount(dfnp); 418 if (error == AUTOFS_SHUTDOWN) 419 error = ENOENT; 420 if (error == EAGAIN) 421 goto top; 422 if (error) 423 return (error); 424 } else 425 mutex_exit(&dfnp->fn_lock); 426 427 428 error = vn_vfsrlock_wait(dvp); 429 if (error) 430 return (error); 431 vfsp = vn_mountedvfs(dvp); 432 if (vfsp != NULL) { 433 error = VFS_ROOT(vfsp, &newvp); 434 vn_vfsunlock(dvp); 435 if (!error) { 436 error = VOP_LOOKUP(newvp, nm, vpp, pnp, 437 flags, rdir, cred); 438 VN_RELE(newvp); 439 } 440 return (error); 441 } 442 vn_vfsunlock(dvp); 443 444 rw_enter(&dfnp->fn_rwlock, RW_READER); 445 error = auto_search(dfnp, nm, &fnp, cred); 446 if (error) { 447 if (dfnip->fi_flags & MF_DIRECT) { 448 /* 449 * direct map. 450 */ 451 if (dfnp->fn_dirents) { 452 /* 453 * Mount previously triggered. 454 * 'nm' not found 455 */ 456 error = ENOENT; 457 } else { 458 /* 459 * I need to contact the daemon to trigger 460 * the mount. 'dfnp' will be the mountpoint. 461 */ 462 operation = AUTOFS_MOUNT; 463 VN_HOLD(fntovn(dfnp)); 464 fnp = dfnp; 465 error = 0; 466 } 467 } else if (dvp == dfnip->fi_rootvp) { 468 /* 469 * 'dfnp' is the root of the indirect AUTOFS. 470 */ 471 if (rw_tryupgrade(&dfnp->fn_rwlock) == 0) { 472 /* 473 * Could not acquire writer lock, release 474 * reader, and wait until available. We 475 * need to search for 'nm' again, since we 476 * had to release the lock before reacquiring 477 * it. 478 */ 479 rw_exit(&dfnp->fn_rwlock); 480 rw_enter(&dfnp->fn_rwlock, RW_WRITER); 481 error = auto_search(dfnp, nm, &fnp, cred); 482 } 483 484 ASSERT(RW_WRITE_HELD(&dfnp->fn_rwlock)); 485 if (error) { 486 /* 487 * create node being looked-up and request 488 * mount on it. 489 */ 490 error = auto_enter(dfnp, nm, &fnp, kcred); 491 if (!error) 492 operation = AUTOFS_LOOKUP; 493 } 494 } else if ((dfnp->fn_dirents == NULL) && 495 ((dvp->v_flag & VROOT) == 0) && 496 ((fntovn(dfnp->fn_parent))->v_flag & VROOT)) { 497 /* 498 * dfnp is the actual 'mountpoint' of indirect map, 499 * it is the equivalent of a direct mount, 500 * ie, /home/'user1' 501 */ 502 operation = AUTOFS_MOUNT; 503 VN_HOLD(fntovn(dfnp)); 504 fnp = dfnp; 505 error = 0; 506 searchnm = dfnp->fn_name; 507 } 508 } 509 510 if (error == EAGAIN) { 511 rw_exit(&dfnp->fn_rwlock); 512 goto top; 513 } 514 if (error) { 515 rw_exit(&dfnp->fn_rwlock); 516 return (error); 517 } 518 519 /* 520 * We now have the actual fnnode we're interested in. 521 * The 'MF_LOOKUP' indicates another thread is currently 522 * performing a daemon lookup of this node, therefore we 523 * wait for its completion. 524 * The 'MF_INPROG' indicates another thread is currently 525 * performing a daemon mount of this node, we wait for it 526 * to be done if we are performing a MOUNT. We don't 527 * wait for it if we are performing a LOOKUP. 528 * We can release the reader/writer lock as soon as we acquire 529 * the mutex, since the state of the lock can only change by 530 * first acquiring the mutex. 531 */ 532 mutex_enter(&fnp->fn_lock); 533 rw_exit(&dfnp->fn_rwlock); 534 if ((fnp->fn_flags & MF_LOOKUP) || 535 ((operation == AUTOFS_MOUNT) && (fnp->fn_flags & MF_INPROG))) { 536 mutex_exit(&fnp->fn_lock); 537 error = auto_wait4mount(fnp); 538 VN_RELE(fntovn(fnp)); 539 if (error == AUTOFS_SHUTDOWN) 540 error = ENOENT; 541 if (error && error != EAGAIN) 542 return (error); 543 goto top; 544 } 545 546 if (operation == 0) { 547 /* 548 * got the fnnode, check for any errors 549 * on the previous operation on that node. 550 */ 551 error = fnp->fn_error; 552 if ((error == EINTR) || (error == EAGAIN)) { 553 /* 554 * previous operation on this node was 555 * not completed, do a lookup now. 556 */ 557 operation = AUTOFS_LOOKUP; 558 } else { 559 /* 560 * previous operation completed. Return 561 * a pointer to the node only if there was 562 * no error. 563 */ 564 mutex_exit(&fnp->fn_lock); 565 if (!error) 566 *vpp = fntovn(fnp); 567 else 568 VN_RELE(fntovn(fnp)); 569 return (error); 570 } 571 } 572 573 /* 574 * Since I got to this point, it means I'm the one 575 * responsible for triggering the mount/look-up of this node. 576 */ 577 switch (operation) { 578 case AUTOFS_LOOKUP: 579 AUTOFS_BLOCK_OTHERS(fnp, MF_LOOKUP); 580 fnp->fn_error = 0; 581 mutex_exit(&fnp->fn_lock); 582 error = auto_lookup_aux(fnp, searchnm, cred); 583 if (!error) { 584 /* 585 * Return this vnode 586 */ 587 *vpp = fntovn(fnp); 588 } else { 589 /* 590 * release our reference to this vnode 591 * and return error 592 */ 593 VN_RELE(fntovn(fnp)); 594 } 595 break; 596 case AUTOFS_MOUNT: 597 AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG); 598 fnp->fn_error = 0; 599 mutex_exit(&fnp->fn_lock); 600 /* 601 * auto_new_mount_thread fires up a new thread which 602 * calls automountd finishing up the work 603 */ 604 auto_new_mount_thread(fnp, searchnm, cred); 605 606 /* 607 * At this point, we are simply another thread 608 * waiting for the mount to complete 609 */ 610 error = auto_wait4mount(fnp); 611 if (error == AUTOFS_SHUTDOWN) 612 error = ENOENT; 613 614 /* 615 * now release our reference to this vnode 616 */ 617 VN_RELE(fntovn(fnp)); 618 if (!error) 619 goto top; 620 break; 621 default: 622 auto_log(dfnp->fn_globals->fng_verbose, 623 dfnp->fn_globals->fng_zoneid, CE_WARN, 624 "auto_lookup: unknown operation %d", 625 operation); 626 } 627 628 AUTOFS_DPRINT((5, "auto_lookup: name=%s *vpp=%p return=%d\n", 629 nm, (void *)*vpp, error)); 630 631 return (error); 632 } 633 634 static int 635 auto_create( 636 vnode_t *dvp, 637 char *nm, 638 vattr_t *va, 639 vcexcl_t excl, 640 int mode, 641 vnode_t **vpp, 642 cred_t *cred, 643 int flag) 644 { 645 vnode_t *newvp; 646 int error; 647 648 AUTOFS_DPRINT((4, "auto_create dvp %p nm %s\n", (void *)dvp, nm)); 649 650 if (error = auto_trigger_mount(dvp, cred, &newvp)) 651 goto done; 652 653 if (newvp != NULL) { 654 /* 655 * Node is now mounted on. 656 */ 657 if (vn_is_readonly(newvp)) 658 error = EROFS; 659 else 660 error = VOP_CREATE(newvp, nm, va, excl, 661 mode, vpp, cred, flag); 662 VN_RELE(newvp); 663 } else 664 error = ENOSYS; 665 666 done: 667 AUTOFS_DPRINT((5, "auto_create: error=%d\n", error)); 668 return (error); 669 } 670 671 static int 672 auto_remove(vnode_t *dvp, char *nm, cred_t *cred) 673 { 674 vnode_t *newvp; 675 int error; 676 677 AUTOFS_DPRINT((4, "auto_remove dvp %p nm %s\n", (void *)dvp, nm)); 678 679 if (error = auto_trigger_mount(dvp, cred, &newvp)) 680 goto done; 681 682 if (newvp != NULL) { 683 /* 684 * Node is now mounted on. 685 */ 686 if (vn_is_readonly(newvp)) 687 error = EROFS; 688 else 689 error = VOP_REMOVE(newvp, nm, cred); 690 VN_RELE(newvp); 691 } else 692 error = ENOSYS; 693 694 done: 695 AUTOFS_DPRINT((5, "auto_remove: error=%d\n", error)); 696 return (error); 697 } 698 699 static int 700 auto_link(vnode_t *tdvp, vnode_t *svp, char *nm, cred_t *cred) 701 { 702 vnode_t *newvp; 703 int error; 704 705 AUTOFS_DPRINT((4, "auto_link tdvp %p svp %p nm %s\n", (void *)tdvp, 706 (void *)svp, nm)); 707 708 if (error = auto_trigger_mount(tdvp, cred, &newvp)) 709 goto done; 710 711 if (newvp == NULL) { 712 /* 713 * an autonode can not be a link to another node 714 */ 715 error = ENOSYS; 716 goto done; 717 } 718 719 if (vn_is_readonly(newvp)) { 720 error = EROFS; 721 VN_RELE(newvp); 722 goto done; 723 } 724 725 if (vn_matchops(svp, auto_vnodeops)) { 726 /* 727 * source vp can't be an autonode 728 */ 729 error = ENOSYS; 730 VN_RELE(newvp); 731 goto done; 732 } 733 734 error = VOP_LINK(newvp, svp, nm, cred); 735 VN_RELE(newvp); 736 737 done: 738 AUTOFS_DPRINT((5, "auto_link error=%d\n", error)); 739 return (error); 740 } 741 742 static int 743 auto_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr) 744 { 745 vnode_t *o_newvp, *n_newvp; 746 int error; 747 748 AUTOFS_DPRINT((4, "auto_rename odvp %p onm %s to ndvp %p nnm %s\n", 749 (void *)odvp, onm, (void *)ndvp, nnm)); 750 751 /* 752 * we know odvp is an autonode, otherwise this function 753 * could not have ever been called. 754 */ 755 ASSERT(vn_matchops(odvp, auto_vnodeops)); 756 757 if (error = auto_trigger_mount(odvp, cr, &o_newvp)) 758 goto done; 759 760 if (o_newvp == NULL) { 761 /* 762 * can't rename an autonode 763 */ 764 error = ENOSYS; 765 goto done; 766 } 767 768 if (vn_matchops(ndvp, auto_vnodeops)) { 769 /* 770 * directory is AUTOFS, need to trigger the 771 * mount of the real filesystem. 772 */ 773 if (error = auto_trigger_mount(ndvp, cr, &n_newvp)) { 774 VN_RELE(o_newvp); 775 goto done; 776 } 777 778 if (n_newvp == NULL) { 779 /* 780 * target can't be an autonode 781 */ 782 error = ENOSYS; 783 VN_RELE(o_newvp); 784 goto done; 785 } 786 } else { 787 /* 788 * destination directory mount had been 789 * triggered prior to the call to this function. 790 */ 791 n_newvp = ndvp; 792 } 793 794 ASSERT(!vn_matchops(n_newvp, auto_vnodeops)); 795 796 if (vn_is_readonly(n_newvp)) { 797 error = EROFS; 798 VN_RELE(o_newvp); 799 if (n_newvp != ndvp) 800 VN_RELE(n_newvp); 801 goto done; 802 } 803 804 error = VOP_RENAME(o_newvp, onm, n_newvp, nnm, cr); 805 VN_RELE(o_newvp); 806 if (n_newvp != ndvp) 807 VN_RELE(n_newvp); 808 809 done: 810 AUTOFS_DPRINT((5, "auto_rename error=%d\n", error)); 811 return (error); 812 } 813 814 static int 815 auto_mkdir(vnode_t *dvp, char *nm, vattr_t *va, vnode_t **vpp, cred_t *cred) 816 { 817 vnode_t *newvp; 818 int error; 819 820 AUTOFS_DPRINT((4, "auto_mkdir dvp %p nm %s\n", (void *)dvp, nm)); 821 822 if (error = auto_trigger_mount(dvp, cred, &newvp)) 823 goto done; 824 825 if (newvp != NULL) { 826 /* 827 * Node is now mounted on. 828 */ 829 if (vn_is_readonly(newvp)) 830 error = EROFS; 831 else 832 error = VOP_MKDIR(newvp, nm, va, vpp, cred); 833 VN_RELE(newvp); 834 } else 835 error = ENOSYS; 836 837 done: 838 AUTOFS_DPRINT((5, "auto_mkdir: error=%d\n", error)); 839 return (error); 840 } 841 842 static int 843 auto_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cred) 844 { 845 vnode_t *newvp; 846 int error; 847 848 AUTOFS_DPRINT((4, "auto_rmdir: vp=%p nm=%s\n", (void *)dvp, nm)); 849 850 if (error = auto_trigger_mount(dvp, cred, &newvp)) 851 goto done; 852 853 if (newvp != NULL) { 854 /* 855 * Node is now mounted on. 856 */ 857 if (vn_is_readonly(newvp)) 858 error = EROFS; 859 else 860 error = VOP_RMDIR(newvp, nm, cdir, cred); 861 VN_RELE(newvp); 862 } else 863 error = ENOSYS; 864 865 done: 866 AUTOFS_DPRINT((5, "auto_rmdir: error=%d\n", error)); 867 return (error); 868 } 869 870 static int autofs_nobrowse = 0; 871 872 #ifdef nextdp 873 #undef nextdp 874 #endif 875 #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen)) 876 877 static int 878 auto_readdir(vnode_t *vp, uio_t *uiop, cred_t *cred, int *eofp) 879 { 880 struct autofs_rddirargs rda; 881 autofs_rddirres rd; 882 fnnode_t *fnp = vntofn(vp); 883 fnnode_t *cfnp, *nfnp; 884 dirent64_t *dp; 885 ulong_t offset; 886 ulong_t outcount = 0, count = 0; 887 size_t namelen; 888 ulong_t alloc_count; 889 void *outbuf = NULL; 890 fninfo_t *fnip = vfstofni(vp->v_vfsp); 891 struct iovec *iovp; 892 int error = 0; 893 int reached_max = 0; 894 int myeof = 0; 895 int this_reclen; 896 struct autofs_globals *fngp = vntofn(fnip->fi_rootvp)->fn_globals; 897 898 AUTOFS_DPRINT((4, "auto_readdir vp=%p offset=%lld\n", 899 (void *)vp, uiop->uio_loffset)); 900 901 if (eofp != NULL) 902 *eofp = 0; 903 904 if (uiop->uio_iovcnt != 1) 905 return (EINVAL); 906 907 iovp = uiop->uio_iov; 908 alloc_count = iovp->iov_len; 909 910 gethrestime(&fnp->fn_atime); 911 fnp->fn_ref_time = fnp->fn_atime.tv_sec; 912 913 dp = outbuf = kmem_zalloc(alloc_count, KM_SLEEP); 914 915 /* 916 * Held when getdents calls VOP_RWLOCK.... 917 */ 918 ASSERT(RW_READ_HELD(&fnp->fn_rwlock)); 919 if (uiop->uio_offset >= AUTOFS_DAEMONCOOKIE) { 920 again: 921 /* 922 * Do readdir of daemon contents only 923 * Drop readers lock and reacquire after reply. 924 */ 925 rw_exit(&fnp->fn_rwlock); 926 bzero(&rd, sizeof (struct autofs_rddirres)); 927 count = 0; 928 rda.rda_map = fnip->fi_map; 929 rda.rda_offset = (uint_t)uiop->uio_offset; 930 rd.rd_rddir.rddir_entries = dp; 931 rda.rda_count = rd.rd_rddir.rddir_size = (uint_t)alloc_count; 932 rda.uid = crgetuid(cred); 933 934 error = auto_calldaemon(fngp->fng_zoneid, 935 AUTOFS_READDIR, 936 xdr_autofs_rddirargs, 937 &rda, 938 xdr_autofs_rddirres, 939 (void *)&rd, 940 sizeof (autofs_rddirres), 941 TRUE); 942 943 /* 944 * reacquire previously dropped lock 945 */ 946 rw_enter(&fnp->fn_rwlock, RW_READER); 947 948 if (!error) { 949 error = rd.rd_status; 950 dp = rd.rd_rddir.rddir_entries; 951 } 952 953 if (error) { 954 if (error == AUTOFS_SHUTDOWN) { 955 /* 956 * treat as empty directory 957 */ 958 error = 0; 959 myeof = 1; 960 if (eofp) 961 *eofp = 1; 962 } 963 goto done; 964 } 965 if (rd.rd_rddir.rddir_size) { 966 dirent64_t *odp = dp; /* next in output buffer */ 967 dirent64_t *cdp = dp; /* current examined entry */ 968 969 /* 970 * Check for duplicates here 971 */ 972 do { 973 this_reclen = cdp->d_reclen; 974 if (auto_search(fnp, cdp->d_name, 975 NULL, cred)) { 976 /* 977 * entry not found in kernel list, 978 * include it in readdir output. 979 * 980 * If we are skipping entries. then 981 * we need to copy this entry to the 982 * correct position in the buffer 983 * to be copied out. 984 */ 985 if (cdp != odp) 986 bcopy(cdp, odp, 987 (size_t)this_reclen); 988 odp = nextdp(odp); 989 outcount += this_reclen; 990 } else { 991 /* 992 * Entry was found in the kernel 993 * list. If it is the first entry 994 * in this buffer, then just skip it 995 */ 996 if (odp == dp) { 997 dp = nextdp(dp); 998 odp = dp; 999 } 1000 } 1001 count += this_reclen; 1002 cdp = (struct dirent64 *) 1003 ((char *)cdp + this_reclen); 1004 } while (count < rd.rd_rddir.rddir_size); 1005 1006 if (outcount) 1007 error = uiomove(dp, outcount, UIO_READ, uiop); 1008 uiop->uio_offset = rd.rd_rddir.rddir_offset; 1009 } else { 1010 if (rd.rd_rddir.rddir_eof == 0) { 1011 /* 1012 * alloc_count not large enough for one 1013 * directory entry 1014 */ 1015 error = EINVAL; 1016 } 1017 } 1018 if (rd.rd_rddir.rddir_eof && !error) { 1019 myeof = 1; 1020 if (eofp) 1021 *eofp = 1; 1022 } 1023 if (!error && !myeof && outcount == 0) { 1024 /* 1025 * call daemon with new cookie, all previous 1026 * elements happened to be duplicates 1027 */ 1028 dp = outbuf; 1029 goto again; 1030 } 1031 goto done; 1032 } 1033 1034 if (uiop->uio_offset == 0) { 1035 /* 1036 * first time: so fudge the . and .. 1037 */ 1038 this_reclen = DIRENT64_RECLEN(1); 1039 if (alloc_count < this_reclen) { 1040 error = EINVAL; 1041 goto done; 1042 } 1043 dp->d_ino = (ino64_t)fnp->fn_nodeid; 1044 dp->d_off = (off64_t)1; 1045 dp->d_reclen = (ushort_t)this_reclen; 1046 1047 /* use strncpy(9f) to zero out uninitialized bytes */ 1048 1049 (void) strncpy(dp->d_name, ".", 1050 DIRENT64_NAMELEN(this_reclen)); 1051 outcount += dp->d_reclen; 1052 dp = nextdp(dp); 1053 1054 this_reclen = DIRENT64_RECLEN(2); 1055 if (alloc_count < outcount + this_reclen) { 1056 error = EINVAL; 1057 goto done; 1058 } 1059 dp->d_reclen = (ushort_t)this_reclen; 1060 dp->d_ino = (ino64_t)fnp->fn_parent->fn_nodeid; 1061 dp->d_off = (off64_t)2; 1062 1063 /* use strncpy(9f) to zero out uninitialized bytes */ 1064 1065 (void) strncpy(dp->d_name, "..", 1066 DIRENT64_NAMELEN(this_reclen)); 1067 outcount += dp->d_reclen; 1068 dp = nextdp(dp); 1069 } 1070 1071 offset = 2; 1072 cfnp = fnp->fn_dirents; 1073 while (cfnp != NULL) { 1074 nfnp = cfnp->fn_next; 1075 offset = cfnp->fn_offset; 1076 if ((offset >= uiop->uio_offset) && 1077 (!(cfnp->fn_flags & MF_LOOKUP))) { 1078 int reclen; 1079 1080 /* 1081 * include node only if its offset is greater or 1082 * equal to the one required and it is not in 1083 * transient state (not being looked-up) 1084 */ 1085 namelen = strlen(cfnp->fn_name); 1086 reclen = (int)DIRENT64_RECLEN(namelen); 1087 if (outcount + reclen > alloc_count) { 1088 reached_max = 1; 1089 break; 1090 } 1091 dp->d_reclen = (ushort_t)reclen; 1092 dp->d_ino = (ino64_t)cfnp->fn_nodeid; 1093 if (nfnp != NULL) { 1094 /* 1095 * get the offset of the next element 1096 */ 1097 dp->d_off = (off64_t)nfnp->fn_offset; 1098 } else { 1099 /* 1100 * This is the last element, make 1101 * offset one plus the current 1102 */ 1103 dp->d_off = (off64_t)cfnp->fn_offset + 1; 1104 } 1105 1106 /* use strncpy(9f) to zero out uninitialized bytes */ 1107 1108 (void) strncpy(dp->d_name, cfnp->fn_name, 1109 DIRENT64_NAMELEN(reclen)); 1110 outcount += dp->d_reclen; 1111 dp = nextdp(dp); 1112 } 1113 cfnp = nfnp; 1114 } 1115 1116 if (outcount) 1117 error = uiomove(outbuf, outcount, UIO_READ, uiop); 1118 1119 if (!error) { 1120 if (reached_max) { 1121 /* 1122 * This entry did not get added to the buffer on this, 1123 * call. We need to add it on the next call therefore 1124 * set uio_offset to this entry's offset. If there 1125 * wasn't enough space for one dirent, return EINVAL. 1126 */ 1127 uiop->uio_offset = offset; 1128 if (outcount == 0) 1129 error = EINVAL; 1130 } else if (autofs_nobrowse || 1131 auto_nobrowse_option(fnip->fi_opts) || 1132 (fnip->fi_flags & MF_DIRECT) || 1133 (fnp->fn_trigger != NULL) || 1134 (((vp->v_flag & VROOT) == 0) && 1135 ((fntovn(fnp->fn_parent))->v_flag & VROOT) && 1136 (fnp->fn_dirents == NULL))) { 1137 /* 1138 * done reading directory entries 1139 */ 1140 uiop->uio_offset = offset + 1; 1141 if (eofp) 1142 *eofp = 1; 1143 } else { 1144 /* 1145 * Need to get the rest of the entries from the daemon. 1146 */ 1147 uiop->uio_offset = AUTOFS_DAEMONCOOKIE; 1148 } 1149 } 1150 1151 done: 1152 kmem_free(outbuf, alloc_count); 1153 AUTOFS_DPRINT((5, "auto_readdir vp=%p offset=%lld eof=%d\n", 1154 (void *)vp, uiop->uio_loffset, myeof)); 1155 return (error); 1156 } 1157 1158 static int 1159 auto_symlink( 1160 vnode_t *dvp, 1161 char *lnknm, /* new entry */ 1162 vattr_t *tva, 1163 char *tnm, /* existing entry */ 1164 cred_t *cred) 1165 { 1166 vnode_t *newvp; 1167 int error; 1168 1169 AUTOFS_DPRINT((4, "auto_symlink: dvp=%p lnknm=%s tnm=%s\n", 1170 (void *)dvp, lnknm, tnm)); 1171 1172 if (error = auto_trigger_mount(dvp, cred, &newvp)) 1173 goto done; 1174 1175 if (newvp != NULL) { 1176 /* 1177 * Node is mounted on. 1178 */ 1179 if (vn_is_readonly(newvp)) 1180 error = EROFS; 1181 else 1182 error = VOP_SYMLINK(newvp, lnknm, tva, tnm, cred); 1183 VN_RELE(newvp); 1184 } else 1185 error = ENOSYS; 1186 1187 done: 1188 AUTOFS_DPRINT((5, "auto_symlink: error=%d\n", error)); 1189 return (error); 1190 } 1191 1192 /* ARGSUSED */ 1193 static int 1194 auto_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr) 1195 { 1196 fnnode_t *fnp = vntofn(vp); 1197 int error; 1198 timestruc_t now; 1199 1200 AUTOFS_DPRINT((4, "auto_readlink: vp=%p\n", (void *)vp)); 1201 1202 gethrestime(&now); 1203 fnp->fn_ref_time = now.tv_sec; 1204 1205 if (vp->v_type != VLNK) 1206 error = EINVAL; 1207 else { 1208 ASSERT(!(fnp->fn_flags & (MF_INPROG | MF_LOOKUP))); 1209 fnp->fn_atime = now; 1210 error = uiomove(fnp->fn_symlink, MIN(fnp->fn_symlinklen, 1211 uiop->uio_resid), UIO_READ, uiop); 1212 } 1213 1214 AUTOFS_DPRINT((5, "auto_readlink: error=%d\n", error)); 1215 return (error); 1216 } 1217 1218 /* ARGSUSED */ 1219 static int 1220 auto_fsync(vnode_t *cp, int syncflag, cred_t *cred) 1221 { 1222 return (0); 1223 } 1224 1225 /* ARGSUSED */ 1226 static void 1227 auto_inactive(vnode_t *vp, cred_t *cred) 1228 { 1229 fnnode_t *fnp = vntofn(vp); 1230 fnnode_t *dfnp = fnp->fn_parent; 1231 int count; 1232 1233 AUTOFS_DPRINT((4, "auto_inactive: vp=%p v_count=%u fn_link=%d\n", 1234 (void *)vp, vp->v_count, fnp->fn_linkcnt)); 1235 1236 /* 1237 * The rwlock should not be already held by this thread. 1238 * The assert relies on the fact that the owner field is cleared 1239 * when the lock is released. 1240 */ 1241 ASSERT(dfnp != NULL); 1242 ASSERT(rw_owner(&dfnp->fn_rwlock) != curthread); 1243 rw_enter(&dfnp->fn_rwlock, RW_WRITER); 1244 mutex_enter(&vp->v_lock); 1245 ASSERT(vp->v_count > 0); 1246 count = --vp->v_count; 1247 mutex_exit(&vp->v_lock); 1248 if (count == 0) { 1249 /* 1250 * Free only if node has no subdirectories. 1251 */ 1252 if (fnp->fn_linkcnt == 1) { 1253 auto_disconnect(dfnp, fnp); 1254 rw_exit(&dfnp->fn_rwlock); 1255 auto_freefnnode(fnp); 1256 AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p freed\n", 1257 (void *)vp)); 1258 return; 1259 } 1260 } 1261 rw_exit(&dfnp->fn_rwlock); 1262 1263 AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p v_count=%u fn_link=%d\n", 1264 (void *)vp, vp->v_count, fnp->fn_linkcnt)); 1265 } 1266 1267 /* ARGSUSED2 */ 1268 static int 1269 auto_rwlock(vnode_t *vp, int write_lock, caller_context_t *ct) 1270 { 1271 fnnode_t *fnp = vntofn(vp); 1272 if (write_lock) 1273 rw_enter(&fnp->fn_rwlock, RW_WRITER); 1274 else 1275 rw_enter(&fnp->fn_rwlock, RW_READER); 1276 return (write_lock); 1277 } 1278 1279 /* ARGSUSED */ 1280 static void 1281 auto_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ct) 1282 { 1283 fnnode_t *fnp = vntofn(vp); 1284 rw_exit(&fnp->fn_rwlock); 1285 } 1286 1287 1288 /* ARGSUSED */ 1289 static int 1290 auto_seek(struct vnode *vp, offset_t ooff, offset_t *noffp) 1291 { 1292 /* 1293 * Return 0 unconditionally, since we expect 1294 * a VDIR all the time 1295 */ 1296 return (0); 1297 } 1298 1299 /* 1300 * Triggers the mount if needed. If the mount has been triggered by 1301 * another thread, it will wait for its return status, and return it. 1302 * Whether the mount is triggered by this thread, another thread, or 1303 * if the vnode was already covered, '*newvp' is a 1304 * VN_HELD vnode pointing to the root of the filesystem covering 'vp'. 1305 * If the node is not mounted on, and should not be mounted on, '*newvp' 1306 * will be NULL. 1307 * The calling routine may use '*newvp' to do the filesystem jump. 1308 */ 1309 static int 1310 auto_trigger_mount(vnode_t *vp, cred_t *cred, vnode_t **newvp) 1311 { 1312 fnnode_t *fnp = vntofn(vp); 1313 fninfo_t *fnip = vfstofni(vp->v_vfsp); 1314 vnode_t *dvp; 1315 vfs_t *vfsp; 1316 int delayed_ind; 1317 char name[AUTOFS_MAXPATHLEN]; 1318 int error; 1319 1320 AUTOFS_DPRINT((4, "auto_trigger_mount: vp=%p\n", (void *)vp)); 1321 1322 *newvp = NULL; 1323 1324 /* 1325 * Cross-zone mount triggering is disallowed. 1326 */ 1327 if (fnip->fi_zoneid != getzoneid()) 1328 return (EPERM); /* Not owner of mount */ 1329 1330 retry: 1331 error = 0; 1332 delayed_ind = 0; 1333 mutex_enter(&fnp->fn_lock); 1334 while (fnp->fn_flags & (MF_LOOKUP | MF_INPROG)) { 1335 /* 1336 * Mount or lookup in progress, 1337 * wait for it before proceeding. 1338 */ 1339 mutex_exit(&fnp->fn_lock); 1340 error = auto_wait4mount(fnp); 1341 if (error == AUTOFS_SHUTDOWN) { 1342 error = 0; 1343 goto done; 1344 } 1345 if (error && error != EAGAIN) 1346 goto done; 1347 error = 0; 1348 mutex_enter(&fnp->fn_lock); 1349 } 1350 1351 /* 1352 * If the vfslock can't be acquired for the first time. 1353 * drop the fn_lock and retry next time in blocking mode. 1354 */ 1355 if (vn_vfswlock(vp)) { 1356 /* 1357 * Lock held by another thread. 1358 * Perform blocking by dropping the 1359 * fn_lock. 1360 */ 1361 mutex_exit(&fnp->fn_lock); 1362 error = vn_vfswlock_wait(vp); 1363 if (error) 1364 goto done; 1365 /* 1366 * Because fn_lock wasn't held, the state 1367 * of the trigger node might have changed. 1368 * Need to run through the checks on trigger 1369 * node again. 1370 */ 1371 vn_vfsunlock(vp); 1372 goto retry; 1373 } 1374 1375 vfsp = vn_mountedvfs(vp); 1376 if (vfsp != NULL) { 1377 mutex_exit(&fnp->fn_lock); 1378 error = VFS_ROOT(vfsp, newvp); 1379 vn_vfsunlock(vp); 1380 goto done; 1381 } else { 1382 vn_vfsunlock(vp); 1383 if ((fnp->fn_flags & MF_MOUNTPOINT) && 1384 fnp->fn_trigger != NULL) { 1385 ASSERT(fnp->fn_dirents == NULL); 1386 /* 1387 * The filesystem that used to sit here has been 1388 * forcibly unmounted. 1389 */ 1390 mutex_exit(&fnp->fn_lock); 1391 error = EIO; 1392 goto done; 1393 } 1394 } 1395 1396 ASSERT(vp->v_type == VDIR); 1397 dvp = fntovn(fnp->fn_parent); 1398 1399 if ((fnp->fn_dirents == NULL) && 1400 ((fnip->fi_flags & MF_DIRECT) == 0) && 1401 ((vp->v_flag & VROOT) == 0) && 1402 (dvp->v_flag & VROOT)) { 1403 /* 1404 * If the parent of this node is the root of an indirect 1405 * AUTOFS filesystem, this node is remountable. 1406 */ 1407 delayed_ind = 1; 1408 } 1409 1410 if (delayed_ind || 1411 ((fnip->fi_flags & MF_DIRECT) && (fnp->fn_dirents == NULL))) { 1412 /* 1413 * Trigger mount since: 1414 * direct mountpoint with no subdirs or 1415 * delayed indirect. 1416 */ 1417 AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG); 1418 fnp->fn_error = 0; 1419 mutex_exit(&fnp->fn_lock); 1420 if (delayed_ind) 1421 (void) strcpy(name, fnp->fn_name); 1422 else 1423 (void) strcpy(name, "."); 1424 fnp->fn_ref_time = gethrestime_sec(); 1425 auto_new_mount_thread(fnp, name, cred); 1426 /* 1427 * At this point we're simply another thread waiting 1428 * for the mount to finish. 1429 */ 1430 error = auto_wait4mount(fnp); 1431 if (error == EAGAIN) 1432 goto retry; 1433 if (error == AUTOFS_SHUTDOWN) { 1434 error = 0; 1435 goto done; 1436 } 1437 if (error == 0) { 1438 if (error = vn_vfsrlock_wait(vp)) 1439 goto done; 1440 /* Reacquire after dropping locks */ 1441 vfsp = vn_mountedvfs(vp); 1442 if (vfsp != NULL) { 1443 error = VFS_ROOT(vfsp, newvp); 1444 vn_vfsunlock(vp); 1445 } else { 1446 vn_vfsunlock(vp); 1447 goto retry; 1448 } 1449 } 1450 } else 1451 mutex_exit(&fnp->fn_lock); 1452 1453 done: 1454 AUTOFS_DPRINT((5, "auto_trigger_mount: error=%d\n", error)); 1455 return (error); 1456 } 1457