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