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