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 /*
  23  * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2017, Joyent, Inc.
  25  * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
  26  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  27  */
  28 
  29 /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
  30 /*        All Rights Reserved   */
  31 
  32 /*
  33  * University Copyright- Copyright (c) 1982, 1986, 1988
  34  * The Regents of the University of California
  35  * All Rights Reserved
  36  *
  37  * University Acknowledgment- Portions of this document are derived from
  38  * software developed by the University of California, Berkeley, and its
  39  * contributors.
  40  */
  41 
  42 /*
  43  * This file contains those functions from fs/vnode.c that can be
  44  * used with relatively little change.  Functions that differ
  45  * significantly from that are in other files.
  46  */
  47 
  48 #include <sys/types.h>
  49 #include <sys/param.h>
  50 #include <sys/t_lock.h>
  51 #include <sys/errno.h>
  52 #include <sys/cred.h>
  53 #include <sys/user.h>
  54 #include <sys/uio.h>
  55 #include <sys/file.h>
  56 #include <sys/pathname.h>
  57 #include <sys/vfs.h>
  58 #include <sys/vfs_opreg.h>
  59 #include <sys/vnode.h>
  60 #include <sys/rwstlock.h>
  61 #include <sys/fem.h>
  62 #include <sys/stat.h>
  63 #include <sys/mode.h>
  64 #include <sys/conf.h>
  65 #include <sys/sysmacros.h>
  66 #include <sys/cmn_err.h>
  67 #include <sys/systm.h>
  68 #include <sys/kmem.h>
  69 #include <sys/atomic.h>
  70 #include <sys/debug.h>
  71 #include <sys/acl.h>
  72 #include <sys/nbmlock.h>
  73 #include <sys/fcntl.h>
  74 #include <sys/time.h>
  75 #include <fs/fs_subr.h>
  76 #include <fs/fs_reparse.h>
  77 
  78 #include <libfksmbfs.h>
  79 
  80 /* Determine if this vnode is a file that is read-only */
  81 #define ISROFILE(vp)    \
  82         ((vp)->v_type != VCHR && (vp)->v_type != VBLK && \
  83             (vp)->v_type != VFIFO && vn_is_readonly(vp))
  84 
  85 #define VOPSTATS_UPDATE(vp, counter) ((void)vp)
  86 #define VOPSTATS_UPDATE_IO(vp, counter, bytecounter, bytesval) \
  87         ((void)vp, (void)bytesval)
  88 #define VOPXID_MAP_CR(vp, cr)   ((void)vp)
  89 
  90 /*
  91  * Excerpts from fs/vnode.c
  92  */
  93 
  94 /* Global used for empty/invalid v_path */
  95 char *vn_vpath_empty = "";
  96 
  97 static int fs_reparse_mark(char *target, vattr_t *vap, xvattr_t *xvattr);
  98 
  99 /*
 100  * Convert stat(2) formats to vnode types and vice versa.  (Knows about
 101  * numerical order of S_IFMT and vnode types.)
 102  */
 103 enum vtype iftovt_tab[] = {
 104         VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
 105         VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VNON
 106 };
 107 
 108 ushort_t vttoif_tab[] = {
 109         0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFIFO,
 110         S_IFDOOR, 0, S_IFSOCK, S_IFPORT, 0
 111 };
 112 
 113 /*
 114  * The system vnode cache.
 115  */
 116 
 117 kmem_cache_t *vn_cache;
 118 
 119 
 120 /*
 121  * Vnode operations vector.
 122  */
 123 
 124 static const fs_operation_trans_def_t vn_ops_table[] = {
 125         VOPNAME_OPEN, offsetof(struct vnodeops, vop_open),
 126             fs_nosys, fs_nosys,
 127 
 128         VOPNAME_CLOSE, offsetof(struct vnodeops, vop_close),
 129             fs_nosys, fs_nosys,
 130 
 131         VOPNAME_READ, offsetof(struct vnodeops, vop_read),
 132             fs_nosys, fs_nosys,
 133 
 134         VOPNAME_WRITE, offsetof(struct vnodeops, vop_write),
 135             fs_nosys, fs_nosys,
 136 
 137         VOPNAME_IOCTL, offsetof(struct vnodeops, vop_ioctl),
 138             fs_nosys, fs_nosys,
 139 
 140         VOPNAME_SETFL, offsetof(struct vnodeops, vop_setfl),
 141             fs_setfl, fs_nosys,
 142 
 143         VOPNAME_GETATTR, offsetof(struct vnodeops, vop_getattr),
 144             fs_nosys, fs_nosys,
 145 
 146         VOPNAME_SETATTR, offsetof(struct vnodeops, vop_setattr),
 147             fs_nosys, fs_nosys,
 148 
 149         VOPNAME_ACCESS, offsetof(struct vnodeops, vop_access),
 150             fs_nosys, fs_nosys,
 151 
 152         VOPNAME_LOOKUP, offsetof(struct vnodeops, vop_lookup),
 153             fs_nosys, fs_nosys,
 154 
 155         VOPNAME_CREATE, offsetof(struct vnodeops, vop_create),
 156             fs_nosys, fs_nosys,
 157 
 158         VOPNAME_REMOVE, offsetof(struct vnodeops, vop_remove),
 159             fs_nosys, fs_nosys,
 160 
 161         VOPNAME_LINK, offsetof(struct vnodeops, vop_link),
 162             fs_nosys, fs_nosys,
 163 
 164         VOPNAME_RENAME, offsetof(struct vnodeops, vop_rename),
 165             fs_nosys, fs_nosys,
 166 
 167         VOPNAME_MKDIR, offsetof(struct vnodeops, vop_mkdir),
 168             fs_nosys, fs_nosys,
 169 
 170         VOPNAME_RMDIR, offsetof(struct vnodeops, vop_rmdir),
 171             fs_nosys, fs_nosys,
 172 
 173         VOPNAME_READDIR, offsetof(struct vnodeops, vop_readdir),
 174             fs_nosys, fs_nosys,
 175 
 176         VOPNAME_SYMLINK, offsetof(struct vnodeops, vop_symlink),
 177             fs_nosys, fs_nosys,
 178 
 179         VOPNAME_READLINK, offsetof(struct vnodeops, vop_readlink),
 180             fs_nosys, fs_nosys,
 181 
 182         VOPNAME_FSYNC, offsetof(struct vnodeops, vop_fsync),
 183             fs_nosys, fs_nosys,
 184 
 185         VOPNAME_INACTIVE, offsetof(struct vnodeops, vop_inactive),
 186             fs_nosys, fs_nosys,
 187 
 188         VOPNAME_FID, offsetof(struct vnodeops, vop_fid),
 189             fs_nosys, fs_nosys,
 190 
 191         VOPNAME_RWLOCK, offsetof(struct vnodeops, vop_rwlock),
 192             fs_rwlock, fs_rwlock,
 193 
 194         VOPNAME_RWUNLOCK, offsetof(struct vnodeops, vop_rwunlock),
 195             (fs_generic_func_p) fs_rwunlock,
 196             (fs_generic_func_p) fs_rwunlock,    /* no errors allowed */
 197 
 198         VOPNAME_SEEK, offsetof(struct vnodeops, vop_seek),
 199             fs_nosys, fs_nosys,
 200 
 201         VOPNAME_CMP, offsetof(struct vnodeops, vop_cmp),
 202             fs_cmp, fs_cmp,             /* no errors allowed */
 203 
 204         VOPNAME_FRLOCK, offsetof(struct vnodeops, vop_frlock),
 205             fs_frlock, fs_nosys,
 206 
 207         VOPNAME_SPACE, offsetof(struct vnodeops, vop_space),
 208             fs_nosys, fs_nosys,
 209 
 210         VOPNAME_REALVP, offsetof(struct vnodeops, vop_realvp),
 211             fs_nosys, fs_nosys,
 212 
 213         VOPNAME_GETPAGE, offsetof(struct vnodeops, vop_getpage),
 214             fs_nosys, fs_nosys,
 215 
 216         VOPNAME_PUTPAGE, offsetof(struct vnodeops, vop_putpage),
 217             fs_nosys, fs_nosys,
 218 
 219         VOPNAME_MAP, offsetof(struct vnodeops, vop_map),
 220             (fs_generic_func_p) fs_nosys_map,
 221             (fs_generic_func_p) fs_nosys_map,
 222 
 223         VOPNAME_ADDMAP, offsetof(struct vnodeops, vop_addmap),
 224             (fs_generic_func_p) fs_nosys_addmap,
 225             (fs_generic_func_p) fs_nosys_addmap,
 226 
 227         VOPNAME_DELMAP, offsetof(struct vnodeops, vop_delmap),
 228             fs_nosys, fs_nosys,
 229 
 230         VOPNAME_POLL, offsetof(struct vnodeops, vop_poll),
 231             (fs_generic_func_p) fs_poll, (fs_generic_func_p) fs_nosys_poll,
 232 
 233         VOPNAME_DUMP, offsetof(struct vnodeops, vop_dump),
 234             fs_nosys, fs_nosys,
 235 
 236         VOPNAME_PATHCONF, offsetof(struct vnodeops, vop_pathconf),
 237             fs_pathconf, fs_nosys,
 238 
 239         VOPNAME_PAGEIO, offsetof(struct vnodeops, vop_pageio),
 240             fs_nosys, fs_nosys,
 241 
 242         VOPNAME_DUMPCTL, offsetof(struct vnodeops, vop_dumpctl),
 243             fs_nosys, fs_nosys,
 244 
 245         VOPNAME_DISPOSE, offsetof(struct vnodeops, vop_dispose),
 246             (fs_generic_func_p) fs_dispose,
 247             (fs_generic_func_p) fs_nodispose,
 248 
 249         VOPNAME_SETSECATTR, offsetof(struct vnodeops, vop_setsecattr),
 250             fs_nosys, fs_nosys,
 251 
 252         VOPNAME_GETSECATTR, offsetof(struct vnodeops, vop_getsecattr),
 253             fs_fab_acl, fs_nosys,
 254 
 255         VOPNAME_SHRLOCK, offsetof(struct vnodeops, vop_shrlock),
 256             fs_shrlock, fs_nosys,
 257 
 258         VOPNAME_VNEVENT, offsetof(struct vnodeops, vop_vnevent),
 259             (fs_generic_func_p) fs_vnevent_nosupport,
 260             (fs_generic_func_p) fs_vnevent_nosupport,
 261 
 262         VOPNAME_REQZCBUF, offsetof(struct vnodeops, vop_reqzcbuf),
 263             fs_nosys, fs_nosys,
 264 
 265         VOPNAME_RETZCBUF, offsetof(struct vnodeops, vop_retzcbuf),
 266             fs_nosys, fs_nosys,
 267 
 268         NULL, 0, NULL, NULL
 269 };
 270 
 271 /* Extensible attribute (xva) routines. */
 272 
 273 /*
 274  * Zero out the structure, set the size of the requested/returned bitmaps,
 275  * set AT_XVATTR in the embedded vattr_t's va_mask, and set up the pointer
 276  * to the returned attributes array.
 277  */
 278 void
 279 xva_init(xvattr_t *xvap)
 280 {
 281         bzero(xvap, sizeof (xvattr_t));
 282         xvap->xva_mapsize = XVA_MAPSIZE;
 283         xvap->xva_magic = XVA_MAGIC;
 284         xvap->xva_vattr.va_mask = AT_XVATTR;
 285         xvap->xva_rtnattrmapp = &(xvap->xva_rtnattrmap)[0];
 286 }
 287 
 288 /*
 289  * If AT_XVATTR is set, returns a pointer to the embedded xoptattr_t
 290  * structure.  Otherwise, returns NULL.
 291  */
 292 xoptattr_t *
 293 xva_getxoptattr(xvattr_t *xvap)
 294 {
 295         xoptattr_t *xoap = NULL;
 296         if (xvap->xva_vattr.va_mask & AT_XVATTR)
 297                 xoap = &xvap->xva_xoptattrs;
 298         return (xoap);
 299 }
 300 
 301 // vska_compar
 302 // create_vopstats_template
 303 // new_vskstat
 304 // vopstats_startup
 305 // initialize_vopstats
 306 // get_fstype_vopstats
 307 // get_vskstat_anchor
 308 // teardown_vopstats
 309 
 310 /*
 311  * Read or write a vnode.  Called from kernel code.
 312  */
 313 int
 314 vn_rdwr(
 315         enum uio_rw rw,
 316         struct vnode *vp,
 317         caddr_t base,
 318         ssize_t len,
 319         offset_t offset,
 320         enum uio_seg seg,
 321         int ioflag,
 322         rlim64_t ulimit,        /* meaningful only if rw is UIO_WRITE */
 323         cred_t *cr,
 324         ssize_t *residp)
 325 {
 326         struct uio uio;
 327         struct iovec iov;
 328         int error;
 329         int in_crit = 0;
 330 
 331         if (rw == UIO_WRITE && ISROFILE(vp))
 332                 return (EROFS);
 333 
 334         if (len < 0)
 335                 return (EIO);
 336 
 337         VOPXID_MAP_CR(vp, cr);
 338 
 339         iov.iov_base = base;
 340         iov.iov_len = len;
 341         uio.uio_iov = &iov;
 342         uio.uio_iovcnt = 1;
 343         uio.uio_loffset = offset;
 344         uio.uio_segflg = (short)seg;
 345         uio.uio_resid = len;
 346         uio.uio_llimit = ulimit;
 347 
 348         /*
 349          * We have to enter the critical region before calling VOP_RWLOCK
 350          * to avoid a deadlock with ufs.
 351          */
 352         if (nbl_need_check(vp)) {
 353                 int svmand;
 354 
 355                 nbl_start_crit(vp, RW_READER);
 356                 in_crit = 1;
 357                 error = nbl_svmand(vp, cr, &svmand);
 358                 if (error != 0)
 359                         goto done;
 360                 if (nbl_conflict(vp, rw == UIO_WRITE ? NBL_WRITE : NBL_READ,
 361                     uio.uio_offset, uio.uio_resid, svmand, NULL)) {
 362                         error = EACCES;
 363                         goto done;
 364                 }
 365         }
 366 
 367         (void) VOP_RWLOCK(vp,
 368             rw == UIO_WRITE ? V_WRITELOCK_TRUE : V_WRITELOCK_FALSE, NULL);
 369         if (rw == UIO_WRITE) {
 370                 uio.uio_fmode = FWRITE;
 371                 uio.uio_extflg = UIO_COPY_DEFAULT;
 372                 error = VOP_WRITE(vp, &uio, ioflag, cr, NULL);
 373         } else {
 374                 uio.uio_fmode = FREAD;
 375                 uio.uio_extflg = UIO_COPY_CACHED;
 376                 error = VOP_READ(vp, &uio, ioflag, cr, NULL);
 377         }
 378         VOP_RWUNLOCK(vp,
 379             rw == UIO_WRITE ? V_WRITELOCK_TRUE : V_WRITELOCK_FALSE, NULL);
 380         if (residp)
 381                 *residp = uio.uio_resid;
 382         else if (uio.uio_resid)
 383                 error = EIO;
 384 
 385 done:
 386         if (in_crit)
 387                 nbl_end_crit(vp);
 388         return (error);
 389 }
 390 
 391 /*
 392  * Incremend the hold on a vnode
 393  * (Real kernel uses a macro)
 394  */
 395 void
 396 vn_hold(struct vnode *vp)
 397 {
 398         mutex_enter(&vp->v_lock);
 399         (vp)->v_count++;
 400         mutex_exit(&vp->v_lock);
 401 }
 402 
 403 /*
 404  * Release a vnode.  Call VOP_INACTIVE on last reference or
 405  * decrement reference count...
 406  */
 407 void
 408 vn_rele(vnode_t *vp)
 409 {
 410         VERIFY(vp->v_count > 0);
 411         mutex_enter(&vp->v_lock);
 412         if (vp->v_count == 1) {
 413                 mutex_exit(&vp->v_lock);
 414                 VOP_INACTIVE(vp, CRED(), NULL);
 415                 return;
 416         }
 417         VN_RELE_LOCKED(vp);
 418         mutex_exit(&vp->v_lock);
 419 }
 420 
 421 // vn_rele_dnlc
 422 // vn_rele_stream
 423 // vn_rele_inactive
 424 // vn_rele_async
 425 // vn_open, vn_openat
 426 // vn_open_upgrade
 427 // vn_open_downgrade
 428 // vn_create, vn_createat
 429 // vn_link, vn_linkat
 430 // vn_rename, vn_renameat
 431 // vn_remove, vn_removeat
 432 
 433 
 434 /*
 435  * Utility function to compare equality of vnodes.
 436  * Compare the underlying real vnodes, if there are underlying vnodes.
 437  * This is a more thorough comparison than the VN_CMP() macro provides.
 438  */
 439 int
 440 vn_compare(vnode_t *vp1, vnode_t *vp2)
 441 {
 442         vnode_t *realvp;
 443 
 444         if (vp1 != NULL && VOP_REALVP(vp1, &realvp, NULL) == 0)
 445                 vp1 = realvp;
 446         if (vp2 != NULL && VOP_REALVP(vp2, &realvp, NULL) == 0)
 447                 vp2 = realvp;
 448         return (VN_CMP(vp1, vp2));
 449 }
 450 
 451 // vn_vfslocks_buckets
 452 // vn_vfslocks_getlock
 453 // vn_vfslocks_rele
 454 
 455 static krwlock_t vfsentry_ve_lock;
 456 
 457 /*
 458  * vn_vfswlock_wait is used to implement a lock which is logically a
 459  * writers lock protecting the v_vfsmountedhere field.
 460  * vn_vfswlock_wait has been modified to be similar to vn_vfswlock,
 461  * except that it blocks to acquire the lock VVFSLOCK.
 462  *
 463  * traverse() and routines re-implementing part of traverse (e.g. autofs)
 464  * need to hold this lock. mount(), vn_rename(), vn_remove() and so on
 465  * need the non-blocking version of the writers lock i.e. vn_vfswlock
 466  */
 467 int
 468 vn_vfswlock_wait(vnode_t *vp)
 469 {
 470 
 471         ASSERT(vp != NULL);
 472 
 473         rw_enter(&vfsentry_ve_lock, RW_WRITER);
 474 
 475         return (0);
 476 }
 477 
 478 int
 479 vn_vfsrlock_wait(vnode_t *vp)
 480 {
 481 
 482         ASSERT(vp != NULL);
 483 
 484         rw_enter(&vfsentry_ve_lock, RW_READER);
 485 
 486         return (0);
 487 }
 488 
 489 /*
 490  * vn_vfswlock is used to implement a lock which is logically a writers lock
 491  * protecting the v_vfsmountedhere field.
 492  */
 493 int
 494 vn_vfswlock(vnode_t *vp)
 495 {
 496 
 497         if (vp == NULL)
 498                 return (EBUSY);
 499 
 500         if (rw_tryenter(&vfsentry_ve_lock, RW_WRITER))
 501                 return (0);
 502 
 503         return (EBUSY);
 504 }
 505 
 506 int
 507 vn_vfsrlock(vnode_t *vp)
 508 {
 509 
 510         if (vp == NULL)
 511                 return (EBUSY);
 512 
 513         if (rw_tryenter(&vfsentry_ve_lock, RW_READER))
 514                 return (0);
 515 
 516         return (EBUSY);
 517 }
 518 
 519 void
 520 vn_vfsunlock(vnode_t *vp)
 521 {
 522 
 523         rw_exit(&vfsentry_ve_lock);
 524 }
 525 
 526 int
 527 vn_vfswlock_held(vnode_t *vp)
 528 {
 529         int held;
 530 
 531         ASSERT(vp != NULL);
 532 
 533         held = rw_write_held(&vfsentry_ve_lock);
 534 
 535         return (held);
 536 }
 537 
 538 
 539 int
 540 vn_make_ops(
 541         const char *name,                       /* Name of file system */
 542         const fs_operation_def_t *templ,        /* Operation specification */
 543         vnodeops_t **actual)                    /* Return the vnodeops */
 544 {
 545         int unused_ops;
 546         int error;
 547 
 548         *actual = (vnodeops_t *)kmem_alloc(sizeof (vnodeops_t), KM_SLEEP);
 549 
 550         (*actual)->vnop_name = name;
 551 
 552         error = fs_build_vector(*actual, &unused_ops, vn_ops_table, templ);
 553         if (error) {
 554                 kmem_free(*actual, sizeof (vnodeops_t));
 555         }
 556 
 557 #if DEBUG
 558         if (unused_ops != 0)
 559                 cmn_err(CE_WARN, "vn_make_ops: %s: %d operations supplied "
 560                     "but not used", name, unused_ops);
 561 #endif
 562 
 563         return (error);
 564 }
 565 
 566 /*
 567  * Free the vnodeops created as a result of vn_make_ops()
 568  */
 569 void
 570 vn_freevnodeops(vnodeops_t *vnops)
 571 {
 572         kmem_free(vnops, sizeof (vnodeops_t));
 573 }
 574 
 575 /*
 576  * Vnode cache.
 577  */
 578 
 579 /* ARGSUSED */
 580 static int
 581 vn_cache_constructor(void *buf, void *cdrarg, int kmflags)
 582 {
 583         struct vnode *vp = buf;
 584 
 585         bzero(vp, sizeof (*vp));
 586         mutex_init(&vp->v_lock, NULL, MUTEX_DEFAULT, NULL);
 587         rw_init(&vp->v_nbllock, NULL, RW_DEFAULT, NULL);
 588         vp->v_path = vn_vpath_empty;
 589         vp->v_fd = -1;
 590         vp->v_st_dev = NODEV;
 591 
 592         return (0);
 593 }
 594 
 595 /* ARGSUSED */
 596 static void
 597 vn_cache_destructor(void *buf, void *cdrarg)
 598 {
 599         struct vnode *vp;
 600 
 601         vp = buf;
 602 
 603         rw_destroy(&vp->v_nbllock);
 604         mutex_destroy(&vp->v_lock);
 605 }
 606 
 607 void
 608 vn_create_cache(void)
 609 {
 610         vn_cache = kmem_cache_create("vn_cache", sizeof (struct vnode),
 611             VNODE_ALIGN, vn_cache_constructor, vn_cache_destructor, NULL, NULL,
 612             NULL, 0);
 613 }
 614 
 615 void
 616 vn_destroy_cache(void)
 617 {
 618         kmem_cache_destroy(vn_cache);
 619 }
 620 
 621 /*
 622  * Used by file systems when fs-specific nodes (e.g., ufs inodes) are
 623  * cached by the file system and vnodes remain associated.
 624  */
 625 void
 626 vn_recycle(vnode_t *vp)
 627 {
 628         VERIFY(vp->v_path != NULL);
 629 
 630         /*
 631          * XXX - This really belongs in vn_reinit(), but we have some issues
 632          * with the counts.  Best to have it here for clean initialization.
 633          */
 634         vp->v_rdcnt = 0;
 635         vp->v_wrcnt = 0;
 636 
 637         /*
 638          * If FEM was in use...
 639          */
 640 
 641         if (vp->v_path != vn_vpath_empty) {
 642                 kmem_free(vp->v_path, strlen(vp->v_path) + 1);
 643                 vp->v_path = vn_vpath_empty;
 644         }
 645         // vsd_free(vp);
 646 }
 647 
 648 /*
 649  * Used to reset the vnode fields including those that are directly accessible
 650  * as well as those which require an accessor function.
 651  */
 652 void
 653 vn_reinit(vnode_t *vp)
 654 {
 655         vp->v_count = 1;
 656         // vp->v_count_dnlc = 0;
 657         vp->v_vfsp = NULL;
 658         vp->v_stream = NULL;
 659         vp->v_vfsmountedhere = NULL;
 660         vp->v_flag = 0;
 661         vp->v_type = VNON;
 662         vp->v_rdev = NODEV;
 663 
 664         vp->v_xattrdir = NULL;
 665 
 666         /*
 667          * In a few specific instances, vn_reinit() is used to initialize
 668          * locally defined vnode_t instances.  Lacking the construction offered
 669          * by vn_alloc(), these vnodes require v_path initialization.
 670          */
 671         if (vp->v_path == NULL) {
 672                 vp->v_path = vn_vpath_empty;
 673         }
 674 
 675         /* Handles v_femhead, v_path, and the r/w/map counts */
 676         vn_recycle(vp);
 677 }
 678 
 679 vnode_t *
 680 vn_alloc(int kmflag)
 681 {
 682         vnode_t *vp;
 683 
 684         vp = kmem_cache_alloc(vn_cache, kmflag);
 685 
 686         if (vp != NULL) {
 687                 // vp->v_femhead = NULL; /* Must be done before vn_reinit() */
 688                 // vp->v_fopdata = NULL;
 689                 vn_reinit(vp);
 690         }
 691 
 692         return (vp);
 693 }
 694 
 695 void
 696 vn_free(vnode_t *vp)
 697 {
 698         extern vnode_t *rootdir;
 699         ASSERT(vp != rootdir);
 700 
 701         /*
 702          * Some file systems call vn_free() with v_count of zero,
 703          * some with v_count of 1.  In any case, the value should
 704          * never be anything else.
 705          */
 706         ASSERT((vp->v_count == 0) || (vp->v_count == 1));
 707         VERIFY(vp->v_path != NULL);
 708         if (vp->v_path != vn_vpath_empty) {
 709                 kmem_free(vp->v_path, strlen(vp->v_path) + 1);
 710                 vp->v_path = vn_vpath_empty;
 711         }
 712 
 713         /* If FEM was in use... */
 714 
 715         // vsd_free(vp);
 716         kmem_cache_free(vn_cache, vp);
 717 }
 718 
 719 /*
 720  * vnode status changes, should define better states than 1, 0.
 721  */
 722 void
 723 vn_reclaim(vnode_t *vp)
 724 {
 725         vfs_t   *vfsp = vp->v_vfsp;
 726 
 727         if (vfsp == NULL ||
 728             vfsp->vfs_implp == NULL || vfsp->vfs_femhead == NULL) {
 729                 return;
 730         }
 731         (void) VFS_VNSTATE(vfsp, vp, VNTRANS_RECLAIMED);
 732 }
 733 
 734 void
 735 vn_idle(vnode_t *vp)
 736 {
 737         vfs_t   *vfsp = vp->v_vfsp;
 738 
 739         if (vfsp == NULL ||
 740             vfsp->vfs_implp == NULL || vfsp->vfs_femhead == NULL) {
 741                 return;
 742         }
 743         (void) VFS_VNSTATE(vfsp, vp, VNTRANS_IDLED);
 744 }
 745 void
 746 vn_exists(vnode_t *vp)
 747 {
 748         vfs_t   *vfsp = vp->v_vfsp;
 749 
 750         if (vfsp == NULL ||
 751             vfsp->vfs_implp == NULL || vfsp->vfs_femhead == NULL) {
 752                 return;
 753         }
 754         (void) VFS_VNSTATE(vfsp, vp, VNTRANS_EXISTS);
 755 }
 756 
 757 void
 758 vn_invalid(vnode_t *vp)
 759 {
 760 }
 761 
 762 /* Vnode event notification */
 763 // vnevent_support()
 764 // vnevent_...
 765 
 766 /*
 767  * Vnode accessors.
 768  */
 769 
 770 int
 771 vn_is_readonly(vnode_t *vp)
 772 {
 773         return (vp->v_vfsp->vfs_flag & VFS_RDONLY);
 774 }
 775 
 776 int
 777 vn_has_flocks(vnode_t *vp)
 778 {
 779         return (0);
 780 }
 781 
 782 int
 783 vn_has_mandatory_locks(vnode_t *vp, int mode)
 784 {
 785         return (0);
 786 }
 787 
 788 int
 789 vn_has_cached_data(vnode_t *vp)
 790 {
 791         return (0);
 792 }
 793 
 794 // vn_can_change_zones
 795 
 796 /*
 797  * Return nonzero if the vnode is a mount point, zero if not.
 798  */
 799 int
 800 vn_ismntpt(vnode_t *vp)
 801 {
 802         return (vp->v_vfsmountedhere != NULL);
 803 }
 804 
 805 /* Retrieve the vfs (if any) mounted on this vnode */
 806 vfs_t *
 807 vn_mountedvfs(vnode_t *vp)
 808 {
 809         return (vp->v_vfsmountedhere);
 810 }
 811 
 812 /*
 813  * Return nonzero if the vnode is referenced by the dnlc, zero if not.
 814  * (no DNLC here)
 815  */
 816 int
 817 vn_in_dnlc(vnode_t *vp)
 818 {
 819         return (0);
 820 }
 821 
 822 
 823 /*
 824  * vn_has_other_opens() checks whether a particular file is opened by more than
 825  * just the caller and whether the open is for read and/or write.
 826  * This routine is for calling after the caller has already called VOP_OPEN()
 827  * and the caller wishes to know if they are the only one with it open for
 828  * the mode(s) specified.
 829  *
 830  * Vnode counts are only kept on regular files (v_type=VREG).
 831  */
 832 int
 833 vn_has_other_opens(
 834         vnode_t *vp,
 835         v_mode_t mode)
 836 {
 837 
 838         ASSERT(vp != NULL);
 839 
 840         switch (mode) {
 841         case V_WRITE:
 842                 if (vp->v_wrcnt > 1)
 843                         return (V_TRUE);
 844                 break;
 845         case V_RDORWR:
 846                 if ((vp->v_rdcnt > 1) || (vp->v_wrcnt > 1))
 847                         return (V_TRUE);
 848                 break;
 849         case V_RDANDWR:
 850                 if ((vp->v_rdcnt > 1) && (vp->v_wrcnt > 1))
 851                         return (V_TRUE);
 852                 break;
 853         case V_READ:
 854                 if (vp->v_rdcnt > 1)
 855                         return (V_TRUE);
 856                 break;
 857         }
 858 
 859         return (V_FALSE);
 860 }
 861 
 862 /*
 863  * vn_is_opened() checks whether a particular file is opened and
 864  * whether the open is for read and/or write.
 865  *
 866  * Vnode counts are only kept on regular files (v_type=VREG).
 867  */
 868 int
 869 vn_is_opened(
 870         vnode_t *vp,
 871         v_mode_t mode)
 872 {
 873 
 874         ASSERT(vp != NULL);
 875 
 876         switch (mode) {
 877         case V_WRITE:
 878                 if (vp->v_wrcnt)
 879                         return (V_TRUE);
 880                 break;
 881         case V_RDANDWR:
 882                 if (vp->v_rdcnt && vp->v_wrcnt)
 883                         return (V_TRUE);
 884                 break;
 885         case V_RDORWR:
 886                 if (vp->v_rdcnt || vp->v_wrcnt)
 887                         return (V_TRUE);
 888                 break;
 889         case V_READ:
 890                 if (vp->v_rdcnt)
 891                         return (V_TRUE);
 892                 break;
 893         }
 894 
 895         return (V_FALSE);
 896 }
 897 
 898 /*
 899  * vn_is_mapped() checks whether a particular file is mapped and whether
 900  * the file is mapped read and/or write.  (no mmap here)
 901  */
 902 int
 903 vn_is_mapped(
 904         vnode_t *vp,
 905         v_mode_t mode)
 906 {
 907         return (V_FALSE);
 908 }
 909 
 910 /*
 911  * Set the operations vector for a vnode.
 912  */
 913 void
 914 vn_setops(vnode_t *vp, vnodeops_t *vnodeops)
 915 {
 916 
 917         ASSERT(vp != NULL);
 918         ASSERT(vnodeops != NULL);
 919 
 920         vp->v_op = vnodeops;
 921 }
 922 
 923 /*
 924  * Retrieve the operations vector for a vnode
 925  */
 926 vnodeops_t *
 927 vn_getops(vnode_t *vp)
 928 {
 929 
 930         ASSERT(vp != NULL);
 931 
 932         return (vp->v_op);
 933 }
 934 
 935 /*
 936  * Returns non-zero (1) if the vnodeops matches that of the vnode.
 937  * Returns zero (0) if not.
 938  */
 939 int
 940 vn_matchops(vnode_t *vp, vnodeops_t *vnodeops)
 941 {
 942         return (vn_getops(vp) == vnodeops);
 943 }
 944 
 945 // vn_matchopval
 946 // fs_new_caller_id
 947 
 948 // vn_clearpath
 949 // vn_setpath_common
 950 
 951 /* ARGSUSED */
 952 void
 953 vn_updatepath(vnode_t *pvp, vnode_t *vp, const char *name)
 954 {
 955 }
 956 
 957 // vn_setpath...
 958 // vn_renamepath
 959 // vn_copypath
 960 
 961 // vn_vmpss_usepageio
 962 
 963 /* VOP_XXX() macros call the corresponding fop_xxx() function */
 964 
 965 int
 966 fop_open(
 967         vnode_t **vpp,
 968         int mode,
 969         cred_t *cr,
 970         caller_context_t *ct)
 971 {
 972         int ret;
 973         vnode_t *vp = *vpp;
 974 
 975         VN_HOLD(vp);
 976         /*
 977          * Adding to the vnode counts before calling open
 978          * avoids the need for a mutex...
 979          */
 980         if ((*vpp)->v_type == VREG) {
 981                 if (mode & FREAD)
 982                         atomic_inc_32(&(*vpp)->v_rdcnt);
 983                 if (mode & FWRITE)
 984                         atomic_inc_32(&(*vpp)->v_wrcnt);
 985         }
 986 
 987         VOPXID_MAP_CR(vp, cr);
 988 
 989         ret = (*(*(vpp))->v_op->vop_open)(vpp, mode, cr, ct);
 990 
 991         if (ret) {
 992                 /*
 993                  * Use the saved vp just in case the vnode ptr got trashed
 994                  * by the error.
 995                  */
 996                 VOPSTATS_UPDATE(vp, open);
 997                 if ((vp->v_type == VREG) && (mode & FREAD))
 998                         atomic_dec_32(&vp->v_rdcnt);
 999                 if ((vp->v_type == VREG) && (mode & FWRITE))
1000                         atomic_dec_32(&vp->v_wrcnt);
1001         } else {
1002                 /*
1003                  * Some filesystems will return a different vnode,
1004                  * but the same path was still used to open it.
1005                  * So if we do change the vnode and need to
1006                  * copy over the path, do so here, rather than special
1007                  * casing each filesystem. Adjust the vnode counts to
1008                  * reflect the vnode switch.
1009                  */
1010                 VOPSTATS_UPDATE(*vpp, open);
1011                 if (*vpp != vp && *vpp != NULL) {
1012                         // vn_copypath(vp, *vpp);
1013                         if (((*vpp)->v_type == VREG) && (mode & FREAD))
1014                                 atomic_inc_32(&(*vpp)->v_rdcnt);
1015                         if ((vp->v_type == VREG) && (mode & FREAD))
1016                                 atomic_dec_32(&vp->v_rdcnt);
1017                         if (((*vpp)->v_type == VREG) && (mode & FWRITE))
1018                                 atomic_inc_32(&(*vpp)->v_wrcnt);
1019                         if ((vp->v_type == VREG) && (mode & FWRITE))
1020                                 atomic_dec_32(&vp->v_wrcnt);
1021                 }
1022         }
1023         VN_RELE(vp);
1024         return (ret);
1025 }
1026 
1027 int
1028 fop_close(
1029         vnode_t *vp,
1030         int flag,
1031         int count,
1032         offset_t offset,
1033         cred_t *cr,
1034         caller_context_t *ct)
1035 {
1036         int err;
1037 
1038         VOPXID_MAP_CR(vp, cr);
1039 
1040         err = (*(vp)->v_op->vop_close)(vp, flag, count, offset, cr, ct);
1041         VOPSTATS_UPDATE(vp, close);
1042         /*
1043          * Check passed in count to handle possible dups. Vnode counts are only
1044          * kept on regular files
1045          */
1046         if ((vp->v_type == VREG) && (count == 1))  {
1047                 if (flag & FREAD) {
1048                         ASSERT(vp->v_rdcnt > 0);
1049                         atomic_dec_32(&vp->v_rdcnt);
1050                 }
1051                 if (flag & FWRITE) {
1052                         ASSERT(vp->v_wrcnt > 0);
1053                         atomic_dec_32(&vp->v_wrcnt);
1054                 }
1055         }
1056         return (err);
1057 }
1058 
1059 int
1060 fop_read(
1061         vnode_t *vp,
1062         uio_t *uiop,
1063         int ioflag,
1064         cred_t *cr,
1065         caller_context_t *ct)
1066 {
1067         int     err;
1068         ssize_t resid_start = uiop->uio_resid;
1069 
1070         VOPXID_MAP_CR(vp, cr);
1071 
1072         err = (*(vp)->v_op->vop_read)(vp, uiop, ioflag, cr, ct);
1073         VOPSTATS_UPDATE_IO(vp, read,
1074             read_bytes, (resid_start - uiop->uio_resid));
1075         return (err);
1076 }
1077 
1078 int
1079 fop_write(
1080         vnode_t *vp,
1081         uio_t *uiop,
1082         int ioflag,
1083         cred_t *cr,
1084         caller_context_t *ct)
1085 {
1086         int     err;
1087         ssize_t resid_start = uiop->uio_resid;
1088 
1089         VOPXID_MAP_CR(vp, cr);
1090 
1091         err = (*(vp)->v_op->vop_write)(vp, uiop, ioflag, cr, ct);
1092         VOPSTATS_UPDATE_IO(vp, write,
1093             write_bytes, (resid_start - uiop->uio_resid));
1094         return (err);
1095 }
1096 
1097 int
1098 fop_ioctl(
1099         vnode_t *vp,
1100         int cmd,
1101         intptr_t arg,
1102         int flag,
1103         cred_t *cr,
1104         int *rvalp,
1105         caller_context_t *ct)
1106 {
1107         int     err;
1108 
1109         VOPXID_MAP_CR(vp, cr);
1110 
1111         err = (*(vp)->v_op->vop_ioctl)(vp, cmd, arg, flag, cr, rvalp, ct);
1112         VOPSTATS_UPDATE(vp, ioctl);
1113         return (err);
1114 }
1115 
1116 int
1117 fop_setfl(
1118         vnode_t *vp,
1119         int oflags,
1120         int nflags,
1121         cred_t *cr,
1122         caller_context_t *ct)
1123 {
1124         int     err;
1125 
1126         VOPXID_MAP_CR(vp, cr);
1127 
1128         err = (*(vp)->v_op->vop_setfl)(vp, oflags, nflags, cr, ct);
1129         VOPSTATS_UPDATE(vp, setfl);
1130         return (err);
1131 }
1132 
1133 int
1134 fop_getattr(
1135         vnode_t *vp,
1136         vattr_t *vap,
1137         int flags,
1138         cred_t *cr,
1139         caller_context_t *ct)
1140 {
1141         int     err;
1142 
1143         VOPXID_MAP_CR(vp, cr);
1144 
1145         /*
1146          * If this file system doesn't understand the xvattr extensions
1147          * then turn off the xvattr bit.
1148          */
1149         if (vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) == 0) {
1150                 vap->va_mask &= ~AT_XVATTR;
1151         }
1152 
1153         /*
1154          * We're only allowed to skip the ACL check iff we used a 32 bit
1155          * ACE mask with VOP_ACCESS() to determine permissions.
1156          */
1157         if ((flags & ATTR_NOACLCHECK) &&
1158             vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
1159                 return (EINVAL);
1160         }
1161         err = (*(vp)->v_op->vop_getattr)(vp, vap, flags, cr, ct);
1162         VOPSTATS_UPDATE(vp, getattr);
1163         return (err);
1164 }
1165 
1166 int
1167 fop_setattr(
1168         vnode_t *vp,
1169         vattr_t *vap,
1170         int flags,
1171         cred_t *cr,
1172         caller_context_t *ct)
1173 {
1174         int     err;
1175 
1176         VOPXID_MAP_CR(vp, cr);
1177 
1178         /*
1179          * If this file system doesn't understand the xvattr extensions
1180          * then turn off the xvattr bit.
1181          */
1182         if (vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) == 0) {
1183                 vap->va_mask &= ~AT_XVATTR;
1184         }
1185 
1186         /*
1187          * We're only allowed to skip the ACL check iff we used a 32 bit
1188          * ACE mask with VOP_ACCESS() to determine permissions.
1189          */
1190         if ((flags & ATTR_NOACLCHECK) &&
1191             vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
1192                 return (EINVAL);
1193         }
1194         err = (*(vp)->v_op->vop_setattr)(vp, vap, flags, cr, ct);
1195         VOPSTATS_UPDATE(vp, setattr);
1196         return (err);
1197 }
1198 
1199 int
1200 fop_access(
1201         vnode_t *vp,
1202         int mode,
1203         int flags,
1204         cred_t *cr,
1205         caller_context_t *ct)
1206 {
1207         int     err;
1208 
1209         if ((flags & V_ACE_MASK) &&
1210             vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
1211                 return (EINVAL);
1212         }
1213 
1214         VOPXID_MAP_CR(vp, cr);
1215 
1216         err = (*(vp)->v_op->vop_access)(vp, mode, flags, cr, ct);
1217         VOPSTATS_UPDATE(vp, access);
1218         return (err);
1219 }
1220 
1221 int
1222 fop_lookup(
1223         vnode_t *dvp,
1224         char *nm,
1225         vnode_t **vpp,
1226         pathname_t *pnp,
1227         int flags,
1228         vnode_t *rdir,
1229         cred_t *cr,
1230         caller_context_t *ct,
1231         int *deflags,           /* Returned per-dirent flags */
1232         pathname_t *ppnp)       /* Returned case-preserved name in directory */
1233 {
1234         int ret;
1235 
1236         /*
1237          * If this file system doesn't support case-insensitive access
1238          * and said access is requested, fail quickly.  It is required
1239          * that if the vfs supports case-insensitive lookup, it also
1240          * supports extended dirent flags.
1241          */
1242         if (flags & FIGNORECASE &&
1243             (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
1244             vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
1245                 return (EINVAL);
1246 
1247         VOPXID_MAP_CR(dvp, cr);
1248 
1249         /*
1250          * The real vnode.c would call xattr_dir_lookup here,
1251          * which inserts the special "System Attribute" files:
1252          * (SUNWattr_rw, SUNWattr_ro) into the xattr list.
1253          * Here the main focus is on testing xattr support,
1254          * so the system attribute stuff is ommitted.
1255          */
1256 #if 0
1257         if ((flags & LOOKUP_XATTR) && (flags & LOOKUP_HAVE_SYSATTR_DIR) == 0) {
1258                 // Don't need xattr support in libfksmbfs.
1259                 // ret = xattr_dir_lookup(dvp, vpp, flags, cr);
1260                 ret = EINVAL;
1261         } else
1262 #endif
1263         {
1264                 ret = (*(dvp)->v_op->vop_lookup)
1265                     (dvp, nm, vpp, pnp, flags, rdir, cr, ct, deflags, ppnp);
1266         }
1267         if (ret == 0 && *vpp) {
1268                 VOPSTATS_UPDATE(*vpp, lookup);
1269                 vn_updatepath(dvp, *vpp, nm);
1270         }
1271 
1272         return (ret);
1273 }
1274 
1275 int
1276 fop_create(
1277         vnode_t *dvp,
1278         char *name,
1279         vattr_t *vap,
1280         vcexcl_t excl,
1281         int mode,
1282         vnode_t **vpp,
1283         cred_t *cr,
1284         int flags,
1285         caller_context_t *ct,
1286         vsecattr_t *vsecp)      /* ACL to set during create */
1287 {
1288         int ret;
1289 
1290         if (vsecp != NULL &&
1291             vfs_has_feature(dvp->v_vfsp, VFSFT_ACLONCREATE) == 0) {
1292                 return (EINVAL);
1293         }
1294         /*
1295          * If this file system doesn't support case-insensitive access
1296          * and said access is requested, fail quickly.
1297          */
1298         if (flags & FIGNORECASE &&
1299             (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
1300             vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
1301                 return (EINVAL);
1302 
1303         VOPXID_MAP_CR(dvp, cr);
1304 
1305         ret = (*(dvp)->v_op->vop_create)
1306             (dvp, name, vap, excl, mode, vpp, cr, flags, ct, vsecp);
1307         if (ret == 0 && *vpp) {
1308                 VOPSTATS_UPDATE(*vpp, create);
1309                 vn_updatepath(dvp, *vpp, name);
1310         }
1311 
1312         return (ret);
1313 }
1314 
1315 int
1316 fop_remove(
1317         vnode_t *dvp,
1318         char *nm,
1319         cred_t *cr,
1320         caller_context_t *ct,
1321         int flags)
1322 {
1323         int     err;
1324 
1325         /*
1326          * If this file system doesn't support case-insensitive access
1327          * and said access is requested, fail quickly.
1328          */
1329         if (flags & FIGNORECASE &&
1330             (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
1331             vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
1332                 return (EINVAL);
1333 
1334         VOPXID_MAP_CR(dvp, cr);
1335 
1336         err = (*(dvp)->v_op->vop_remove)(dvp, nm, cr, ct, flags);
1337         VOPSTATS_UPDATE(dvp, remove);
1338         return (err);
1339 }
1340 
1341 int
1342 fop_link(
1343         vnode_t *tdvp,
1344         vnode_t *svp,
1345         char *tnm,
1346         cred_t *cr,
1347         caller_context_t *ct,
1348         int flags)
1349 {
1350         int     err;
1351 
1352         /*
1353          * If the target file system doesn't support case-insensitive access
1354          * and said access is requested, fail quickly.
1355          */
1356         if (flags & FIGNORECASE &&
1357             (vfs_has_feature(tdvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
1358             vfs_has_feature(tdvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
1359                 return (EINVAL);
1360 
1361         VOPXID_MAP_CR(tdvp, cr);
1362 
1363         err = (*(tdvp)->v_op->vop_link)(tdvp, svp, tnm, cr, ct, flags);
1364         VOPSTATS_UPDATE(tdvp, link);
1365         return (err);
1366 }
1367 
1368 int
1369 fop_rename(
1370         vnode_t *sdvp,
1371         char *snm,
1372         vnode_t *tdvp,
1373         char *tnm,
1374         cred_t *cr,
1375         caller_context_t *ct,
1376         int flags)
1377 {
1378         int     err;
1379 
1380         /*
1381          * If the file system involved does not support
1382          * case-insensitive access and said access is requested, fail
1383          * quickly.
1384          */
1385         if (flags & FIGNORECASE &&
1386             ((vfs_has_feature(sdvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
1387             vfs_has_feature(sdvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0)))
1388                 return (EINVAL);
1389 
1390         VOPXID_MAP_CR(tdvp, cr);
1391 
1392         err = (*(sdvp)->v_op->vop_rename)(sdvp, snm, tdvp, tnm, cr, ct, flags);
1393         VOPSTATS_UPDATE(sdvp, rename);
1394         return (err);
1395 }
1396 
1397 int
1398 fop_mkdir(
1399         vnode_t *dvp,
1400         char *dirname,
1401         vattr_t *vap,
1402         vnode_t **vpp,
1403         cred_t *cr,
1404         caller_context_t *ct,
1405         int flags,
1406         vsecattr_t *vsecp)      /* ACL to set during create */
1407 {
1408         int ret;
1409 
1410         if (vsecp != NULL &&
1411             vfs_has_feature(dvp->v_vfsp, VFSFT_ACLONCREATE) == 0) {
1412                 return (EINVAL);
1413         }
1414         /*
1415          * If this file system doesn't support case-insensitive access
1416          * and said access is requested, fail quickly.
1417          */
1418         if (flags & FIGNORECASE &&
1419             (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
1420             vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
1421                 return (EINVAL);
1422 
1423         VOPXID_MAP_CR(dvp, cr);
1424 
1425         ret = (*(dvp)->v_op->vop_mkdir)
1426             (dvp, dirname, vap, vpp, cr, ct, flags, vsecp);
1427         if (ret == 0 && *vpp) {
1428                 VOPSTATS_UPDATE(*vpp, mkdir);
1429                 vn_updatepath(dvp, *vpp, dirname);
1430         }
1431 
1432         return (ret);
1433 }
1434 
1435 int
1436 fop_rmdir(
1437         vnode_t *dvp,
1438         char *nm,
1439         vnode_t *cdir,
1440         cred_t *cr,
1441         caller_context_t *ct,
1442         int flags)
1443 {
1444         int     err;
1445 
1446         /*
1447          * If this file system doesn't support case-insensitive access
1448          * and said access is requested, fail quickly.
1449          */
1450         if (flags & FIGNORECASE &&
1451             (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
1452             vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
1453                 return (EINVAL);
1454 
1455         VOPXID_MAP_CR(dvp, cr);
1456 
1457         err = (*(dvp)->v_op->vop_rmdir)(dvp, nm, cdir, cr, ct, flags);
1458         VOPSTATS_UPDATE(dvp, rmdir);
1459         return (err);
1460 }
1461 
1462 int
1463 fop_readdir(
1464         vnode_t *vp,
1465         uio_t *uiop,
1466         cred_t *cr,
1467         int *eofp,
1468         caller_context_t *ct,
1469         int flags)
1470 {
1471         int     err;
1472         ssize_t resid_start = uiop->uio_resid;
1473 
1474         /*
1475          * If this file system doesn't support retrieving directory
1476          * entry flags and said access is requested, fail quickly.
1477          */
1478         if (flags & V_RDDIR_ENTFLAGS &&
1479             vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS) == 0)
1480                 return (EINVAL);
1481 
1482         VOPXID_MAP_CR(vp, cr);
1483 
1484         err = (*(vp)->v_op->vop_readdir)(vp, uiop, cr, eofp, ct, flags);
1485         VOPSTATS_UPDATE_IO(vp, readdir,
1486             readdir_bytes, (resid_start - uiop->uio_resid));
1487         return (err);
1488 }
1489 
1490 int
1491 fop_symlink(
1492         vnode_t *dvp,
1493         char *linkname,
1494         vattr_t *vap,
1495         char *target,
1496         cred_t *cr,
1497         caller_context_t *ct,
1498         int flags)
1499 {
1500         int     err;
1501         xvattr_t xvattr;
1502 
1503         /*
1504          * If this file system doesn't support case-insensitive access
1505          * and said access is requested, fail quickly.
1506          */
1507         if (flags & FIGNORECASE &&
1508             (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
1509             vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
1510                 return (EINVAL);
1511 
1512         VOPXID_MAP_CR(dvp, cr);
1513 
1514         /* check for reparse point */
1515         if ((vfs_has_feature(dvp->v_vfsp, VFSFT_REPARSE)) &&
1516             (strncmp(target, FS_REPARSE_TAG_STR,
1517             strlen(FS_REPARSE_TAG_STR)) == 0)) {
1518                 if (!fs_reparse_mark(target, vap, &xvattr))
1519                         vap = (vattr_t *)&xvattr;
1520         }
1521 
1522         err = (*(dvp)->v_op->vop_symlink)
1523             (dvp, linkname, vap, target, cr, ct, flags);
1524         VOPSTATS_UPDATE(dvp, symlink);
1525         return (err);
1526 }
1527 
1528 int
1529 fop_readlink(
1530         vnode_t *vp,
1531         uio_t *uiop,
1532         cred_t *cr,
1533         caller_context_t *ct)
1534 {
1535         int     err;
1536 
1537         VOPXID_MAP_CR(vp, cr);
1538 
1539         err = (*(vp)->v_op->vop_readlink)(vp, uiop, cr, ct);
1540         VOPSTATS_UPDATE(vp, readlink);
1541         return (err);
1542 }
1543 
1544 int
1545 fop_fsync(
1546         vnode_t *vp,
1547         int syncflag,
1548         cred_t *cr,
1549         caller_context_t *ct)
1550 {
1551         int     err;
1552 
1553         VOPXID_MAP_CR(vp, cr);
1554 
1555         err = (*(vp)->v_op->vop_fsync)(vp, syncflag, cr, ct);
1556         VOPSTATS_UPDATE(vp, fsync);
1557         return (err);
1558 }
1559 
1560 void
1561 fop_inactive(
1562         vnode_t *vp,
1563         cred_t *cr,
1564         caller_context_t *ct)
1565 {
1566         /* Need to update stats before vop call since we may lose the vnode */
1567         VOPSTATS_UPDATE(vp, inactive);
1568 
1569         VOPXID_MAP_CR(vp, cr);
1570 
1571         (*(vp)->v_op->vop_inactive)(vp, cr, ct);
1572 }
1573 
1574 int
1575 fop_fid(
1576         vnode_t *vp,
1577         fid_t *fidp,
1578         caller_context_t *ct)
1579 {
1580         int     err;
1581 
1582         err = (*(vp)->v_op->vop_fid)(vp, fidp, ct);
1583         VOPSTATS_UPDATE(vp, fid);
1584         return (err);
1585 }
1586 
1587 int
1588 fop_rwlock(
1589         vnode_t *vp,
1590         int write_lock,
1591         caller_context_t *ct)
1592 {
1593         int     ret;
1594 
1595         ret = ((*(vp)->v_op->vop_rwlock)(vp, write_lock, ct));
1596         VOPSTATS_UPDATE(vp, rwlock);
1597         return (ret);
1598 }
1599 
1600 void
1601 fop_rwunlock(
1602         vnode_t *vp,
1603         int write_lock,
1604         caller_context_t *ct)
1605 {
1606         (*(vp)->v_op->vop_rwunlock)(vp, write_lock, ct);
1607         VOPSTATS_UPDATE(vp, rwunlock);
1608 }
1609 
1610 int
1611 fop_seek(
1612         vnode_t *vp,
1613         offset_t ooff,
1614         offset_t *noffp,
1615         caller_context_t *ct)
1616 {
1617         int     err;
1618 
1619         err = (*(vp)->v_op->vop_seek)(vp, ooff, noffp, ct);
1620         VOPSTATS_UPDATE(vp, seek);
1621         return (err);
1622 }
1623 
1624 int
1625 fop_cmp(
1626         vnode_t *vp1,
1627         vnode_t *vp2,
1628         caller_context_t *ct)
1629 {
1630         int     err;
1631 
1632         err = (*(vp1)->v_op->vop_cmp)(vp1, vp2, ct);
1633         VOPSTATS_UPDATE(vp1, cmp);
1634         return (err);
1635 }
1636 
1637 int
1638 fop_frlock(
1639         vnode_t *vp,
1640         int cmd,
1641         flock64_t *bfp,
1642         int flag,
1643         offset_t offset,
1644         struct flk_callback *flk_cbp,
1645         cred_t *cr,
1646         caller_context_t *ct)
1647 {
1648         int     err;
1649 
1650         VOPXID_MAP_CR(vp, cr);
1651 
1652         err = (*(vp)->v_op->vop_frlock)
1653             (vp, cmd, bfp, flag, offset, flk_cbp, cr, ct);
1654         VOPSTATS_UPDATE(vp, frlock);
1655         return (err);
1656 }
1657 
1658 int
1659 fop_space(
1660         vnode_t *vp,
1661         int cmd,
1662         flock64_t *bfp,
1663         int flag,
1664         offset_t offset,
1665         cred_t *cr,
1666         caller_context_t *ct)
1667 {
1668         int     err;
1669 
1670         VOPXID_MAP_CR(vp, cr);
1671 
1672         err = (*(vp)->v_op->vop_space)(vp, cmd, bfp, flag, offset, cr, ct);
1673         VOPSTATS_UPDATE(vp, space);
1674         return (err);
1675 }
1676 
1677 int
1678 fop_realvp(
1679         vnode_t *vp,
1680         vnode_t **vpp,
1681         caller_context_t *ct)
1682 {
1683         int     err;
1684 
1685         err = (*(vp)->v_op->vop_realvp)(vp, vpp, ct);
1686         VOPSTATS_UPDATE(vp, realvp);
1687         return (err);
1688 }
1689 
1690 int
1691 fop_getpage(
1692         vnode_t *vp,
1693         offset_t off,
1694         size_t len,
1695         uint_t *protp,
1696         page_t **plarr,
1697         size_t plsz,
1698         struct seg *seg,
1699         caddr_t addr,
1700         enum seg_rw rw,
1701         cred_t *cr,
1702         caller_context_t *ct)
1703 {
1704         int     err;
1705 
1706         VOPXID_MAP_CR(vp, cr);
1707 
1708         err = (*(vp)->v_op->vop_getpage)
1709             (vp, off, len, protp, plarr, plsz, seg, addr, rw, cr, ct);
1710         VOPSTATS_UPDATE(vp, getpage);
1711         return (err);
1712 }
1713 
1714 int
1715 fop_putpage(
1716         vnode_t *vp,
1717         offset_t off,
1718         size_t len,
1719         int flags,
1720         cred_t *cr,
1721         caller_context_t *ct)
1722 {
1723         int     err;
1724 
1725         VOPXID_MAP_CR(vp, cr);
1726 
1727         err = (*(vp)->v_op->vop_putpage)(vp, off, len, flags, cr, ct);
1728         VOPSTATS_UPDATE(vp, putpage);
1729         return (err);
1730 }
1731 
1732 int
1733 fop_map(
1734         vnode_t *vp,
1735         offset_t off,
1736         struct as *as,
1737         caddr_t *addrp,
1738         size_t len,
1739         uchar_t prot,
1740         uchar_t maxprot,
1741         uint_t flags,
1742         cred_t *cr,
1743         caller_context_t *ct)
1744 {
1745         int     err;
1746 
1747         VOPXID_MAP_CR(vp, cr);
1748 
1749         err = (*(vp)->v_op->vop_map)
1750             (vp, off, as, addrp, len, prot, maxprot, flags, cr, ct);
1751         VOPSTATS_UPDATE(vp, map);
1752         return (err);
1753 }
1754 
1755 int
1756 fop_addmap(
1757         vnode_t *vp,
1758         offset_t off,
1759         struct as *as,
1760         caddr_t addr,
1761         size_t len,
1762         uchar_t prot,
1763         uchar_t maxprot,
1764         uint_t flags,
1765         cred_t *cr,
1766         caller_context_t *ct)
1767 {
1768         int error;
1769 
1770         VOPXID_MAP_CR(vp, cr);
1771 
1772         error = (*(vp)->v_op->vop_addmap)
1773             (vp, off, as, addr, len, prot, maxprot, flags, cr, ct);
1774 
1775         VOPSTATS_UPDATE(vp, addmap);
1776         return (error);
1777 }
1778 
1779 int
1780 fop_delmap(
1781         vnode_t *vp,
1782         offset_t off,
1783         struct as *as,
1784         caddr_t addr,
1785         size_t len,
1786         uint_t prot,
1787         uint_t maxprot,
1788         uint_t flags,
1789         cred_t *cr,
1790         caller_context_t *ct)
1791 {
1792         int error;
1793 
1794         VOPXID_MAP_CR(vp, cr);
1795 
1796         error = (*(vp)->v_op->vop_delmap)
1797             (vp, off, as, addr, len, prot, maxprot, flags, cr, ct);
1798 
1799         VOPSTATS_UPDATE(vp, delmap);
1800         return (error);
1801 }
1802 
1803 
1804 int
1805 fop_poll(
1806         vnode_t *vp,
1807         short events,
1808         int anyyet,
1809         short *reventsp,
1810         struct pollhead **phpp,
1811         caller_context_t *ct)
1812 {
1813         int     err;
1814 
1815         err = (*(vp)->v_op->vop_poll)(vp, events, anyyet, reventsp, phpp, ct);
1816         VOPSTATS_UPDATE(vp, poll);
1817         return (err);
1818 }
1819 
1820 int
1821 fop_dump(
1822         vnode_t *vp,
1823         caddr_t addr,
1824         offset_t lbdn,
1825         offset_t dblks,
1826         caller_context_t *ct)
1827 {
1828         int     err;
1829 
1830         /* ensure lbdn and dblks can be passed safely to bdev_dump */
1831         if ((lbdn != (daddr_t)lbdn) || (dblks != (int)dblks))
1832                 return (EIO);
1833 
1834         err = (*(vp)->v_op->vop_dump)(vp, addr, lbdn, dblks, ct);
1835         VOPSTATS_UPDATE(vp, dump);
1836         return (err);
1837 }
1838 
1839 int
1840 fop_pathconf(
1841         vnode_t *vp,
1842         int cmd,
1843         ulong_t *valp,
1844         cred_t *cr,
1845         caller_context_t *ct)
1846 {
1847         int     err;
1848 
1849         VOPXID_MAP_CR(vp, cr);
1850 
1851         err = (*(vp)->v_op->vop_pathconf)(vp, cmd, valp, cr, ct);
1852         VOPSTATS_UPDATE(vp, pathconf);
1853         return (err);
1854 }
1855 
1856 int
1857 fop_pageio(
1858         vnode_t *vp,
1859         struct page *pp,
1860         u_offset_t io_off,
1861         size_t io_len,
1862         int flags,
1863         cred_t *cr,
1864         caller_context_t *ct)
1865 {
1866         int     err;
1867 
1868         VOPXID_MAP_CR(vp, cr);
1869 
1870         err = (*(vp)->v_op->vop_pageio)(vp, pp, io_off, io_len, flags, cr, ct);
1871         VOPSTATS_UPDATE(vp, pageio);
1872         return (err);
1873 }
1874 
1875 int
1876 fop_dumpctl(
1877         vnode_t *vp,
1878         int action,
1879         offset_t *blkp,
1880         caller_context_t *ct)
1881 {
1882         int     err;
1883         err = (*(vp)->v_op->vop_dumpctl)(vp, action, blkp, ct);
1884         VOPSTATS_UPDATE(vp, dumpctl);
1885         return (err);
1886 }
1887 
1888 void
1889 fop_dispose(
1890         vnode_t *vp,
1891         page_t *pp,
1892         int flag,
1893         int dn,
1894         cred_t *cr,
1895         caller_context_t *ct)
1896 {
1897         /* Must do stats first since it's possible to lose the vnode */
1898         VOPSTATS_UPDATE(vp, dispose);
1899 
1900         VOPXID_MAP_CR(vp, cr);
1901 
1902         (*(vp)->v_op->vop_dispose)(vp, pp, flag, dn, cr, ct);
1903 }
1904 
1905 int
1906 fop_setsecattr(
1907         vnode_t *vp,
1908         vsecattr_t *vsap,
1909         int flag,
1910         cred_t *cr,
1911         caller_context_t *ct)
1912 {
1913         int     err;
1914 
1915         VOPXID_MAP_CR(vp, cr);
1916 
1917         /*
1918          * We're only allowed to skip the ACL check iff we used a 32 bit
1919          * ACE mask with VOP_ACCESS() to determine permissions.
1920          */
1921         if ((flag & ATTR_NOACLCHECK) &&
1922             vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
1923                 return (EINVAL);
1924         }
1925         err = (*(vp)->v_op->vop_setsecattr) (vp, vsap, flag, cr, ct);
1926         VOPSTATS_UPDATE(vp, setsecattr);
1927         return (err);
1928 }
1929 
1930 int
1931 fop_getsecattr(
1932         vnode_t *vp,
1933         vsecattr_t *vsap,
1934         int flag,
1935         cred_t *cr,
1936         caller_context_t *ct)
1937 {
1938         int     err;
1939 
1940         /*
1941          * We're only allowed to skip the ACL check iff we used a 32 bit
1942          * ACE mask with VOP_ACCESS() to determine permissions.
1943          */
1944         if ((flag & ATTR_NOACLCHECK) &&
1945             vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
1946                 return (EINVAL);
1947         }
1948 
1949         VOPXID_MAP_CR(vp, cr);
1950 
1951         err = (*(vp)->v_op->vop_getsecattr) (vp, vsap, flag, cr, ct);
1952         VOPSTATS_UPDATE(vp, getsecattr);
1953         return (err);
1954 }
1955 
1956 int
1957 fop_shrlock(
1958         vnode_t *vp,
1959         int cmd,
1960         struct shrlock *shr,
1961         int flag,
1962         cred_t *cr,
1963         caller_context_t *ct)
1964 {
1965         int     err;
1966 
1967         VOPXID_MAP_CR(vp, cr);
1968 
1969         err = (*(vp)->v_op->vop_shrlock)(vp, cmd, shr, flag, cr, ct);
1970         VOPSTATS_UPDATE(vp, shrlock);
1971         return (err);
1972 }
1973 
1974 int
1975 fop_vnevent(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *fnm,
1976     caller_context_t *ct)
1977 {
1978         int     err;
1979 
1980         err = (*(vp)->v_op->vop_vnevent)(vp, vnevent, dvp, fnm, ct);
1981         VOPSTATS_UPDATE(vp, vnevent);
1982         return (err);
1983 }
1984 
1985 // fop_reqzcbuf
1986 // fop_retzcbuf
1987 
1988 // vsd_defaultdestructor
1989 // vsd_create, vsd_destroy
1990 // vsd_get, vsd_set
1991 // vsd_free, vsd_realloc
1992 
1993 static int
1994 fs_reparse_mark(char *target, vattr_t *vap, xvattr_t *xvattr)
1995 {
1996         return (-1);
1997 }
1998 
1999 /*
2000  * Function to check whether a symlink is a reparse point.
2001  * Return B_TRUE if it is a reparse point, else return B_FALSE
2002  */
2003 boolean_t
2004 vn_is_reparse(vnode_t *vp, cred_t *cr, caller_context_t *ct)
2005 {
2006         xvattr_t xvattr;
2007         xoptattr_t *xoap;
2008 
2009         if ((vp->v_type != VLNK) ||
2010             !(vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR)))
2011                 return (B_FALSE);
2012 
2013         xva_init(&xvattr);
2014         xoap = xva_getxoptattr(&xvattr);
2015         ASSERT(xoap);
2016         XVA_SET_REQ(&xvattr, XAT_REPARSE);
2017 
2018         if (VOP_GETATTR(vp, &xvattr.xva_vattr, 0, cr, ct))
2019                 return (B_FALSE);
2020 
2021         if ((!(xvattr.xva_vattr.va_mask & AT_XVATTR)) ||
2022             (!(XVA_ISSET_RTN(&xvattr, XAT_REPARSE))))
2023                 return (B_FALSE);
2024 
2025         return (xoap->xoa_reparse ? B_TRUE : B_FALSE);
2026 }