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