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