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