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_vfsrlock_wait(vp)) 166 return (error); 167 168 vfsp = vn_mountedvfs(vp); 169 if (vfsp != NULL) { 170 /* 171 * Node is mounted on. 172 */ 173 error = VFS_ROOT(vfsp, &newvp); 174 vn_vfsunlock(vp); 175 if (error) 176 return (error); 177 mutex_enter(&fnp->fn_lock); 178 if (fnp->fn_seen == newvp && fnp->fn_thread == curthread) { 179 /* 180 * Recursive auto_getattr(); just release newvp and drop 181 * into the vfsp == NULL case. 182 */ 183 mutex_exit(&fnp->fn_lock); 184 VN_RELE(newvp); 185 } else { 186 while (fnp->fn_thread && fnp->fn_thread != curthread) { 187 fnp->fn_flags |= MF_ATTR_WAIT; 188 cv_wait(&fnp->fn_cv_mount, &fnp->fn_lock); 189 } 190 fnp->fn_thread = curthread; 191 fnp->fn_seen = newvp; 192 mutex_exit(&fnp->fn_lock); 193 error = VOP_GETATTR(newvp, vap, flags, cred); 194 VN_RELE(newvp); 195 mutex_enter(&fnp->fn_lock); 196 fnp->fn_seen = 0; 197 fnp->fn_thread = 0; 198 if (fnp->fn_flags & MF_ATTR_WAIT) { 199 fnp->fn_flags &= ~MF_ATTR_WAIT; 200 cv_broadcast(&fnp->fn_cv_mount); 201 } 202 mutex_exit(&fnp->fn_lock); 203 return (error); 204 } 205 } else { 206 vn_vfsunlock(vp); 207 } 208 209 defattr: 210 ASSERT(vp->v_type == VDIR || vp->v_type == VLNK); 211 vap->va_uid = 0; 212 vap->va_gid = 0; 213 vap->va_nlink = fnp->fn_linkcnt; 214 vap->va_nodeid = (u_longlong_t)fnp->fn_nodeid; 215 vap->va_size = fnp->fn_size; 216 vap->va_atime = fnp->fn_atime; 217 vap->va_mtime = fnp->fn_mtime; 218 vap->va_ctime = fnp->fn_ctime; 219 vap->va_type = vp->v_type; 220 vap->va_mode = fnp->fn_mode; 221 vap->va_fsid = vp->v_vfsp->vfs_dev; 222 vap->va_rdev = 0; 223 vap->va_blksize = MAXBSIZE; 224 vap->va_nblocks = (fsblkcnt64_t)btod(vap->va_size); 225 vap->va_seq = 0; 226 227 return (0); 228 } 229 230 /*ARGSUSED4*/ 231 static int 232 auto_setattr( 233 vnode_t *vp, 234 struct vattr *vap, 235 int flags, 236 cred_t *cred, 237 caller_context_t *ct) 238 { 239 vnode_t *newvp; 240 int error; 241 242 AUTOFS_DPRINT((4, "auto_setattr vp %p\n", (void *)vp)); 243 244 if (error = auto_trigger_mount(vp, cred, &newvp)) 245 goto done; 246 247 if (newvp != NULL) { 248 /* 249 * Node is mounted on. 250 */ 251 if (vn_is_readonly(newvp)) 252 error = EROFS; 253 else 254 error = VOP_SETATTR(newvp, vap, flags, cred, NULL); 255 VN_RELE(newvp); 256 } else 257 error = ENOSYS; 258 259 done: 260 AUTOFS_DPRINT((5, "auto_setattr: error=%d\n", error)); 261 return (error); 262 } 263 264 /* ARGSUSED */ 265 static int 266 auto_access(vnode_t *vp, int mode, int flags, cred_t *cred) 267 { 268 fnnode_t *fnp = vntofn(vp); 269 vnode_t *newvp; 270 int error; 271 272 AUTOFS_DPRINT((4, "auto_access: vp=%p\n", (void *)vp)); 273 274 if (error = auto_trigger_mount(vp, cred, &newvp)) 275 goto done; 276 277 if (newvp != NULL) { 278 /* 279 * Node is mounted on. 280 */ 281 error = VOP_ACCESS(newvp, mode, 0, cred); 282 VN_RELE(newvp); 283 } else { 284 int shift = 0; 285 286 /* 287 * really interested in the autofs node, check the 288 * access on it 289 */ 290 ASSERT(error == 0); 291 if (crgetuid(cred) != fnp->fn_uid) { 292 shift += 3; 293 if (groupmember(fnp->fn_gid, cred) == 0) 294 shift += 3; 295 } 296 mode &= ~(fnp->fn_mode << shift); 297 if (mode != 0) 298 error = secpolicy_vnode_access(cred, vp, fnp->fn_uid, 299 mode); 300 } 301 302 done: 303 AUTOFS_DPRINT((5, "auto_access: error=%d\n", error)); 304 return (error); 305 } 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, CE_WARN, "auto_lookup: unknown " 603 "operation %d", operation); 604 } 605 606 AUTOFS_DPRINT((5, "auto_lookup: name=%s *vpp=%p return=%d\n", 607 nm, (void *)*vpp, error)); 608 609 return (error); 610 } 611 612 static int 613 auto_create( 614 vnode_t *dvp, 615 char *nm, 616 vattr_t *va, 617 vcexcl_t excl, 618 int mode, 619 vnode_t **vpp, 620 cred_t *cred, 621 int flag) 622 { 623 vnode_t *newvp; 624 int error; 625 626 AUTOFS_DPRINT((4, "auto_create dvp %p nm %s\n", (void *)dvp, nm)); 627 628 if (error = auto_trigger_mount(dvp, cred, &newvp)) 629 goto done; 630 631 if (newvp != NULL) { 632 /* 633 * Node is now mounted on. 634 */ 635 if (vn_is_readonly(newvp)) 636 error = EROFS; 637 else 638 error = VOP_CREATE(newvp, nm, va, excl, 639 mode, vpp, cred, flag); 640 VN_RELE(newvp); 641 } else 642 error = ENOSYS; 643 644 done: 645 AUTOFS_DPRINT((5, "auto_create: error=%d\n", error)); 646 return (error); 647 } 648 649 static int 650 auto_remove(vnode_t *dvp, char *nm, cred_t *cred) 651 { 652 vnode_t *newvp; 653 int error; 654 655 AUTOFS_DPRINT((4, "auto_remove dvp %p nm %s\n", (void *)dvp, nm)); 656 657 if (error = auto_trigger_mount(dvp, cred, &newvp)) 658 goto done; 659 660 if (newvp != NULL) { 661 /* 662 * Node is now mounted on. 663 */ 664 if (vn_is_readonly(newvp)) 665 error = EROFS; 666 else 667 error = VOP_REMOVE(newvp, nm, cred); 668 VN_RELE(newvp); 669 } else 670 error = ENOSYS; 671 672 done: 673 AUTOFS_DPRINT((5, "auto_remove: error=%d\n", error)); 674 return (error); 675 } 676 677 static int 678 auto_link(vnode_t *tdvp, vnode_t *svp, char *nm, cred_t *cred) 679 { 680 vnode_t *newvp; 681 int error; 682 683 AUTOFS_DPRINT((4, "auto_link tdvp %p svp %p nm %s\n", (void *)tdvp, 684 (void *)svp, nm)); 685 686 if (error = auto_trigger_mount(tdvp, cred, &newvp)) 687 goto done; 688 689 if (newvp == NULL) { 690 /* 691 * an autonode can not be a link to another node 692 */ 693 error = ENOSYS; 694 goto done; 695 } 696 697 if (vn_is_readonly(newvp)) { 698 error = EROFS; 699 VN_RELE(newvp); 700 goto done; 701 } 702 703 if (vn_matchops(svp, auto_vnodeops)) { 704 /* 705 * source vp can't be an autonode 706 */ 707 error = ENOSYS; 708 VN_RELE(newvp); 709 goto done; 710 } 711 712 error = VOP_LINK(newvp, svp, nm, cred); 713 VN_RELE(newvp); 714 715 done: 716 AUTOFS_DPRINT((5, "auto_link error=%d\n", error)); 717 return (error); 718 } 719 720 static int 721 auto_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr) 722 { 723 vnode_t *o_newvp, *n_newvp; 724 int error; 725 726 AUTOFS_DPRINT((4, "auto_rename odvp %p onm %s to ndvp %p nnm %s\n", 727 (void *)odvp, onm, (void *)ndvp, nnm)); 728 729 /* 730 * we know odvp is an autonode, otherwise this function 731 * could not have ever been called. 732 */ 733 ASSERT(vn_matchops(odvp, auto_vnodeops)); 734 735 if (error = auto_trigger_mount(odvp, cr, &o_newvp)) 736 goto done; 737 738 if (o_newvp == NULL) { 739 /* 740 * can't rename an autonode 741 */ 742 error = ENOSYS; 743 goto done; 744 } 745 746 if (vn_matchops(ndvp, auto_vnodeops)) { 747 /* 748 * directory is AUTOFS, need to trigger the 749 * mount of the real filesystem. 750 */ 751 if (error = auto_trigger_mount(ndvp, cr, &n_newvp)) { 752 VN_RELE(o_newvp); 753 goto done; 754 } 755 756 if (n_newvp == NULL) { 757 /* 758 * target can't be an autonode 759 */ 760 error = ENOSYS; 761 VN_RELE(o_newvp); 762 goto done; 763 } 764 } else { 765 /* 766 * destination directory mount had been 767 * triggered prior to the call to this function. 768 */ 769 n_newvp = ndvp; 770 } 771 772 ASSERT(!vn_matchops(n_newvp, auto_vnodeops)); 773 774 if (vn_is_readonly(n_newvp)) { 775 error = EROFS; 776 VN_RELE(o_newvp); 777 if (n_newvp != ndvp) 778 VN_RELE(n_newvp); 779 goto done; 780 } 781 782 error = VOP_RENAME(o_newvp, onm, n_newvp, nnm, cr); 783 VN_RELE(o_newvp); 784 if (n_newvp != ndvp) 785 VN_RELE(n_newvp); 786 787 done: 788 AUTOFS_DPRINT((5, "auto_rename error=%d\n", error)); 789 return (error); 790 } 791 792 static int 793 auto_mkdir(vnode_t *dvp, char *nm, vattr_t *va, vnode_t **vpp, cred_t *cred) 794 { 795 vnode_t *newvp; 796 int error; 797 798 AUTOFS_DPRINT((4, "auto_mkdir dvp %p nm %s\n", (void *)dvp, nm)); 799 800 if (error = auto_trigger_mount(dvp, cred, &newvp)) 801 goto done; 802 803 if (newvp != NULL) { 804 /* 805 * Node is now mounted on. 806 */ 807 if (vn_is_readonly(newvp)) 808 error = EROFS; 809 else 810 error = VOP_MKDIR(newvp, nm, va, vpp, cred); 811 VN_RELE(newvp); 812 } else 813 error = ENOSYS; 814 815 done: 816 AUTOFS_DPRINT((5, "auto_mkdir: error=%d\n", error)); 817 return (error); 818 } 819 820 static int 821 auto_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cred) 822 { 823 vnode_t *newvp; 824 int error; 825 826 AUTOFS_DPRINT((4, "auto_rmdir: vp=%p nm=%s\n", (void *)dvp, nm)); 827 828 if (error = auto_trigger_mount(dvp, cred, &newvp)) 829 goto done; 830 831 if (newvp != NULL) { 832 /* 833 * Node is now mounted on. 834 */ 835 if (vn_is_readonly(newvp)) 836 error = EROFS; 837 else 838 error = VOP_RMDIR(newvp, nm, cdir, cred); 839 VN_RELE(newvp); 840 } else 841 error = ENOSYS; 842 843 done: 844 AUTOFS_DPRINT((5, "auto_rmdir: error=%d\n", error)); 845 return (error); 846 } 847 848 static int autofs_nobrowse = 0; 849 850 #ifdef nextdp 851 #undef nextdp 852 #endif 853 #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen)) 854 855 static int 856 auto_readdir(vnode_t *vp, uio_t *uiop, cred_t *cred, int *eofp) 857 { 858 struct autofs_rddirargs rda; 859 struct autofs_rddirres rd; 860 fnnode_t *fnp = vntofn(vp); 861 fnnode_t *cfnp, *nfnp; 862 dirent64_t *dp; 863 ulong_t offset; 864 ulong_t outcount = 0, count = 0; 865 size_t namelen; 866 ulong_t alloc_count; 867 void *outbuf; 868 fninfo_t *fnip = vfstofni(vp->v_vfsp); 869 struct iovec *iovp; 870 int error = 0; 871 int reached_max = 0; 872 int myeof = 0; 873 int this_reclen; 874 875 AUTOFS_DPRINT((4, "auto_readdir vp=%p offset=%lld\n", 876 (void *)vp, uiop->uio_loffset)); 877 878 if (eofp != NULL) 879 *eofp = 0; 880 881 iovp = uiop->uio_iov; 882 alloc_count = iovp->iov_len; 883 884 if (uiop->uio_iovcnt != 1) 885 return (EINVAL); 886 887 gethrestime(&fnp->fn_atime); 888 fnp->fn_ref_time = fnp->fn_atime.tv_sec; 889 890 dp = outbuf = kmem_alloc(alloc_count, KM_SLEEP); 891 892 /* 893 * Held when getdents calls VOP_RWLOCK.... 894 */ 895 ASSERT(RW_READ_HELD(&fnp->fn_rwlock)); 896 if (uiop->uio_offset >= AUTOFS_DAEMONCOOKIE) { 897 again: 898 /* 899 * Do readdir of daemon contents only 900 * Drop readers lock and reacquire after reply. 901 */ 902 rw_exit(&fnp->fn_rwlock); 903 904 count = 0; 905 rda.rda_map = fnip->fi_map; 906 rda.rda_offset = (uint_t)uiop->uio_offset; 907 rd.rd_rddir.rddir_entries = dp; 908 rda.rda_count = rd.rd_rddir.rddir_size = (uint_t)alloc_count; 909 error = auto_calldaemon(fnip, AUTOFS_READDIR, 910 xdr_autofs_rddirargs, &rda, 911 xdr_autofs_rddirres, &rd, 912 cred, TRUE); 913 /* 914 * reacquire previously dropped lock 915 */ 916 rw_enter(&fnp->fn_rwlock, RW_READER); 917 918 if (!error) 919 error = rd.rd_status; 920 if (error) { 921 if (error == AUTOFS_SHUTDOWN) { 922 /* 923 * treat as empty directory 924 */ 925 error = 0; 926 myeof = 1; 927 if (eofp) 928 *eofp = 1; 929 } 930 goto done; 931 } 932 933 if (rd.rd_rddir.rddir_size) { 934 dirent64_t *odp = dp; /* next in output buffer */ 935 dirent64_t *cdp = dp; /* current examined entry */ 936 937 /* 938 * Check for duplicates here 939 */ 940 do { 941 this_reclen = cdp->d_reclen; 942 if (auto_search(fnp, cdp->d_name, NULL, cred)) { 943 /* 944 * entry not found in kernel list, 945 * include it in readdir output. 946 * 947 * If we are skipping entries. then 948 * we need to copy this entry to the 949 * correct position in the buffer 950 * to be copied out. 951 */ 952 if (cdp != odp) 953 bcopy(cdp, odp, 954 (size_t)this_reclen); 955 odp = nextdp(odp); 956 outcount += this_reclen; 957 } else { 958 /* 959 * Entry was found in the kernel 960 * list. If it is the first entry 961 * in this buffer, then just skip it 962 */ 963 if (odp == dp) { 964 dp = nextdp(dp); 965 odp = dp; 966 } 967 } 968 count += this_reclen; 969 cdp = (struct dirent64 *) 970 ((char *)cdp + this_reclen); 971 } while (count < rd.rd_rddir.rddir_size); 972 973 if (outcount) 974 error = uiomove(dp, outcount, UIO_READ, uiop); 975 uiop->uio_offset = rd.rd_rddir.rddir_offset; 976 } else { 977 if (rd.rd_rddir.rddir_eof == 0) { 978 /* 979 * alloc_count not large enough for one 980 * directory entry 981 */ 982 error = EINVAL; 983 } 984 } 985 if (rd.rd_rddir.rddir_eof && !error) { 986 myeof = 1; 987 if (eofp) 988 *eofp = 1; 989 } 990 if (!error && !myeof && outcount == 0) { 991 /* 992 * call daemon with new cookie, all previous 993 * elements happened to be duplicates 994 */ 995 dp = outbuf; 996 goto again; 997 } 998 goto done; 999 } 1000 1001 if (uiop->uio_offset == 0) { 1002 /* 1003 * first time: so fudge the . and .. 1004 */ 1005 this_reclen = DIRENT64_RECLEN(1); 1006 if (alloc_count < this_reclen) { 1007 error = EINVAL; 1008 goto done; 1009 } 1010 dp->d_ino = (ino64_t)fnp->fn_nodeid; 1011 dp->d_off = (off64_t)1; 1012 dp->d_reclen = (ushort_t)this_reclen; 1013 1014 /* use strncpy(9f) to zero out uninitialized bytes */ 1015 1016 (void) strncpy(dp->d_name, ".", 1017 DIRENT64_NAMELEN(this_reclen)); 1018 outcount += dp->d_reclen; 1019 dp = nextdp(dp); 1020 1021 this_reclen = DIRENT64_RECLEN(2); 1022 if (alloc_count < outcount + this_reclen) { 1023 error = EINVAL; 1024 goto done; 1025 } 1026 dp->d_reclen = (ushort_t)this_reclen; 1027 dp->d_ino = (ino64_t)fnp->fn_parent->fn_nodeid; 1028 dp->d_off = (off64_t)2; 1029 1030 /* use strncpy(9f) to zero out uninitialized bytes */ 1031 1032 (void) strncpy(dp->d_name, "..", 1033 DIRENT64_NAMELEN(this_reclen)); 1034 outcount += dp->d_reclen; 1035 dp = nextdp(dp); 1036 } 1037 1038 offset = 2; 1039 cfnp = fnp->fn_dirents; 1040 while (cfnp != NULL) { 1041 nfnp = cfnp->fn_next; 1042 offset = cfnp->fn_offset; 1043 if ((offset >= uiop->uio_offset) && 1044 (!(cfnp->fn_flags & MF_LOOKUP))) { 1045 int reclen; 1046 1047 /* 1048 * include node only if its offset is greater or 1049 * equal to the one required and it is not in 1050 * transient state (not being looked-up) 1051 */ 1052 namelen = strlen(cfnp->fn_name); 1053 reclen = (int)DIRENT64_RECLEN(namelen); 1054 if (outcount + reclen > alloc_count) { 1055 reached_max = 1; 1056 break; 1057 } 1058 dp->d_reclen = (ushort_t)reclen; 1059 dp->d_ino = (ino64_t)cfnp->fn_nodeid; 1060 if (nfnp != NULL) { 1061 /* 1062 * get the offset of the next element 1063 */ 1064 dp->d_off = (off64_t)nfnp->fn_offset; 1065 } else { 1066 /* 1067 * This is the last element, make 1068 * offset one plus the current 1069 */ 1070 dp->d_off = (off64_t)cfnp->fn_offset + 1; 1071 } 1072 1073 /* use strncpy(9f) to zero out uninitialized bytes */ 1074 1075 (void) strncpy(dp->d_name, cfnp->fn_name, 1076 DIRENT64_NAMELEN(reclen)); 1077 outcount += dp->d_reclen; 1078 dp = nextdp(dp); 1079 } 1080 cfnp = nfnp; 1081 } 1082 1083 if (outcount) 1084 error = uiomove(outbuf, outcount, UIO_READ, uiop); 1085 if (!error) { 1086 if (reached_max) { 1087 /* 1088 * This entry did not get added to the buffer on this, 1089 * call. We need to add it on the next call therefore 1090 * set uio_offset to this entry's offset. If there 1091 * wasn't enough space for one dirent, return EINVAL. 1092 */ 1093 uiop->uio_offset = offset; 1094 if (outcount == 0) 1095 error = EINVAL; 1096 } else if (autofs_nobrowse || 1097 auto_nobrowse_option(fnip->fi_opts) || 1098 (fnip->fi_flags & MF_DIRECT) || (fnp->fn_trigger != NULL) || 1099 (((vp->v_flag & VROOT) == 0) && 1100 ((fntovn(fnp->fn_parent))->v_flag & VROOT) && 1101 (fnp->fn_dirents == NULL))) { 1102 /* 1103 * done reading directory entries 1104 */ 1105 uiop->uio_offset = offset + 1; 1106 if (eofp) 1107 *eofp = 1; 1108 } else { 1109 /* 1110 * Need to get the rest of the entries from the daemon. 1111 */ 1112 uiop->uio_offset = AUTOFS_DAEMONCOOKIE; 1113 } 1114 } 1115 1116 done: 1117 kmem_free(outbuf, alloc_count); 1118 AUTOFS_DPRINT((5, "auto_readdir vp=%p offset=%lld eof=%d\n", 1119 (void *)vp, uiop->uio_loffset, myeof)); 1120 return (error); 1121 } 1122 1123 static int 1124 auto_symlink( 1125 vnode_t *dvp, 1126 char *lnknm, /* new entry */ 1127 vattr_t *tva, 1128 char *tnm, /* existing entry */ 1129 cred_t *cred) 1130 { 1131 vnode_t *newvp; 1132 int error; 1133 1134 AUTOFS_DPRINT((4, "auto_symlink: dvp=%p lnknm=%s tnm=%s\n", 1135 (void *)dvp, lnknm, tnm)); 1136 1137 if (error = auto_trigger_mount(dvp, cred, &newvp)) 1138 goto done; 1139 1140 if (newvp != NULL) { 1141 /* 1142 * Node is mounted on. 1143 */ 1144 if (vn_is_readonly(newvp)) 1145 error = EROFS; 1146 else 1147 error = VOP_SYMLINK(newvp, lnknm, tva, tnm, cred); 1148 VN_RELE(newvp); 1149 } else 1150 error = ENOSYS; 1151 1152 done: 1153 AUTOFS_DPRINT((5, "auto_symlink: error=%d\n", error)); 1154 return (error); 1155 } 1156 1157 /* ARGSUSED */ 1158 static int 1159 auto_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr) 1160 { 1161 fnnode_t *fnp = vntofn(vp); 1162 int error; 1163 timestruc_t now; 1164 1165 AUTOFS_DPRINT((4, "auto_readlink: vp=%p\n", (void *)vp)); 1166 1167 gethrestime(&now); 1168 fnp->fn_ref_time = now.tv_sec; 1169 1170 if (vp->v_type != VLNK) 1171 error = EINVAL; 1172 else { 1173 ASSERT(!(fnp->fn_flags & (MF_INPROG | MF_LOOKUP))); 1174 fnp->fn_atime = now; 1175 error = uiomove(fnp->fn_symlink, MIN(fnp->fn_symlinklen, 1176 uiop->uio_resid), UIO_READ, uiop); 1177 } 1178 1179 AUTOFS_DPRINT((5, "auto_readlink: error=%d\n", error)); 1180 return (error); 1181 } 1182 1183 /* ARGSUSED */ 1184 static int 1185 auto_fsync(vnode_t *cp, int syncflag, cred_t *cred) 1186 { 1187 return (0); 1188 } 1189 1190 /* ARGSUSED */ 1191 static void 1192 auto_inactive(vnode_t *vp, cred_t *cred) 1193 { 1194 fnnode_t *fnp = vntofn(vp); 1195 fnnode_t *dfnp = fnp->fn_parent; 1196 int count; 1197 1198 AUTOFS_DPRINT((4, "auto_inactive: vp=%p v_count=%u fn_link=%d\n", 1199 (void *)vp, vp->v_count, fnp->fn_linkcnt)); 1200 1201 /* 1202 * The rwlock should not be already held by this thread. 1203 * The assert relies on the fact that the owner field is cleared 1204 * when the lock is released. 1205 */ 1206 ASSERT(dfnp != NULL); 1207 ASSERT(rw_owner(&dfnp->fn_rwlock) != curthread); 1208 rw_enter(&dfnp->fn_rwlock, RW_WRITER); 1209 mutex_enter(&vp->v_lock); 1210 ASSERT(vp->v_count > 0); 1211 count = --vp->v_count; 1212 mutex_exit(&vp->v_lock); 1213 if (count == 0) { 1214 /* 1215 * Free only if node has no subdirectories. 1216 */ 1217 if (fnp->fn_linkcnt == 1) { 1218 auto_disconnect(dfnp, fnp); 1219 rw_exit(&dfnp->fn_rwlock); 1220 auto_freefnnode(fnp); 1221 AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p freed\n", 1222 (void *)vp)); 1223 return; 1224 } 1225 } 1226 rw_exit(&dfnp->fn_rwlock); 1227 1228 AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p v_count=%u fn_link=%d\n", 1229 (void *)vp, vp->v_count, fnp->fn_linkcnt)); 1230 } 1231 1232 /* ARGSUSED2 */ 1233 static int 1234 auto_rwlock(vnode_t *vp, int write_lock, caller_context_t *ct) 1235 { 1236 fnnode_t *fnp = vntofn(vp); 1237 if (write_lock) 1238 rw_enter(&fnp->fn_rwlock, RW_WRITER); 1239 else 1240 rw_enter(&fnp->fn_rwlock, RW_READER); 1241 return (write_lock); 1242 } 1243 1244 /* ARGSUSED */ 1245 static void 1246 auto_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ct) 1247 { 1248 fnnode_t *fnp = vntofn(vp); 1249 rw_exit(&fnp->fn_rwlock); 1250 } 1251 1252 1253 /* ARGSUSED */ 1254 static int 1255 auto_seek(struct vnode *vp, offset_t ooff, offset_t *noffp) 1256 { 1257 /* 1258 * Return 0 unconditionally, since we expect 1259 * a VDIR all the time 1260 */ 1261 return (0); 1262 } 1263 1264 /* 1265 * Triggers the mount if needed. If the mount has been triggered by 1266 * another thread, it will wait for its return status, and return it. 1267 * Whether the mount is triggered by this thread, another thread, or 1268 * if the vnode was already covered, '*newvp' is a 1269 * VN_HELD vnode pointing to the root of the filesystem covering 'vp'. 1270 * If the node is not mounted on, and should not be mounted on, '*newvp' 1271 * will be NULL. 1272 * The calling routine may use '*newvp' to do the filesystem jump. 1273 */ 1274 static int 1275 auto_trigger_mount(vnode_t *vp, cred_t *cred, vnode_t **newvp) 1276 { 1277 fnnode_t *fnp = vntofn(vp); 1278 fninfo_t *fnip = vfstofni(vp->v_vfsp); 1279 vnode_t *dvp; 1280 vfs_t *vfsp; 1281 int delayed_ind; 1282 char name[AUTOFS_MAXPATHLEN]; 1283 int error; 1284 1285 AUTOFS_DPRINT((4, "auto_trigger_mount: vp=%p\n", (void *)vp)); 1286 1287 *newvp = NULL; 1288 1289 /* 1290 * Cross-zone mount triggering is disallowed. 1291 */ 1292 if (fnip->fi_zoneid != getzoneid()) 1293 return (EPERM); /* Not owner of mount */ 1294 1295 retry: 1296 error = 0; 1297 delayed_ind = 0; 1298 mutex_enter(&fnp->fn_lock); 1299 while (fnp->fn_flags & (MF_LOOKUP | MF_INPROG)) { 1300 /* 1301 * Mount or lookup in progress, 1302 * wait for it before proceeding. 1303 */ 1304 mutex_exit(&fnp->fn_lock); 1305 error = auto_wait4mount(fnp); 1306 if (error == AUTOFS_SHUTDOWN) { 1307 error = 0; 1308 goto done; 1309 } 1310 if (error && error != EAGAIN) 1311 goto done; 1312 error = 0; 1313 mutex_enter(&fnp->fn_lock); 1314 } 1315 1316 /* 1317 * If the vfslock can't be acquired for the first time. 1318 * drop the fn_lock and retry next time in blocking mode. 1319 */ 1320 if (vn_vfswlock(vp)) { 1321 /* 1322 * Lock held by another thread. 1323 * Perform blocking by dropping the 1324 * fn_lock. 1325 */ 1326 mutex_exit(&fnp->fn_lock); 1327 error = vn_vfswlock_wait(vp); 1328 if (error) 1329 goto done; 1330 /* 1331 * Because fn_lock wasn't held, the state 1332 * of the trigger node might have changed. 1333 * Need to run through the checks on trigger 1334 * node again. 1335 */ 1336 vn_vfsunlock(vp); 1337 goto retry; 1338 } 1339 1340 vfsp = vn_mountedvfs(vp); 1341 if (vfsp != NULL) { 1342 mutex_exit(&fnp->fn_lock); 1343 error = VFS_ROOT(vfsp, newvp); 1344 vn_vfsunlock(vp); 1345 goto done; 1346 } else { 1347 vn_vfsunlock(vp); 1348 if ((fnp->fn_flags & MF_MOUNTPOINT) && 1349 fnp->fn_trigger != NULL) { 1350 ASSERT(fnp->fn_dirents == NULL); 1351 /* 1352 * The filesystem that used to sit here has been 1353 * forcibly unmounted. 1354 */ 1355 mutex_exit(&fnp->fn_lock); 1356 error = EIO; 1357 goto done; 1358 } 1359 } 1360 1361 ASSERT(vp->v_type == VDIR); 1362 dvp = fntovn(fnp->fn_parent); 1363 1364 if ((fnp->fn_dirents == NULL) && 1365 ((fnip->fi_flags & MF_DIRECT) == 0) && 1366 ((vp->v_flag & VROOT) == 0) && 1367 (dvp->v_flag & VROOT)) { 1368 /* 1369 * If the parent of this node is the root of an indirect 1370 * AUTOFS filesystem, this node is remountable. 1371 */ 1372 delayed_ind = 1; 1373 } 1374 1375 if (delayed_ind || 1376 ((fnip->fi_flags & MF_DIRECT) && (fnp->fn_dirents == NULL))) { 1377 /* 1378 * Trigger mount since: 1379 * direct mountpoint with no subdirs or 1380 * delayed indirect. 1381 */ 1382 AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG); 1383 fnp->fn_error = 0; 1384 mutex_exit(&fnp->fn_lock); 1385 if (delayed_ind) 1386 (void) strcpy(name, fnp->fn_name); 1387 else 1388 (void) strcpy(name, "."); 1389 fnp->fn_ref_time = gethrestime_sec(); 1390 auto_new_mount_thread(fnp, name, cred); 1391 /* 1392 * At this point we're simply another thread waiting 1393 * for the mount to finish. 1394 */ 1395 error = auto_wait4mount(fnp); 1396 if (error == EAGAIN) 1397 goto retry; 1398 if (error == AUTOFS_SHUTDOWN) { 1399 error = 0; 1400 goto done; 1401 } 1402 if (error == 0) { 1403 if (error = vn_vfsrlock_wait(vp)) 1404 goto done; 1405 /* Reacquire after dropping locks */ 1406 vfsp = vn_mountedvfs(vp); 1407 if (vfsp != NULL) { 1408 error = VFS_ROOT(vfsp, newvp); 1409 vn_vfsunlock(vp); 1410 } else { 1411 vn_vfsunlock(vp); 1412 goto retry; 1413 } 1414 } 1415 } else 1416 mutex_exit(&fnp->fn_lock); 1417 1418 done: 1419 AUTOFS_DPRINT((5, "auto_trigger_mount: error=%d\n", error)); 1420 return (error); 1421 } 1422