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
xva_init(xvattr_t * xvap)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 *
xva_getxoptattr(xvattr_t * xvap)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
vn_rdwr(enum uio_rw rw,struct vnode * vp,caddr_t base,ssize_t len,offset_t offset,enum uio_seg seg,int ioflag,rlim64_t ulimit,cred_t * cr,ssize_t * residp)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
vn_rele(vnode_t * vp)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
vn_compare(vnode_t * vp1,vnode_t * vp2)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
vn_vfswlock_wait(vnode_t * vp)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
vn_vfsrlock_wait(vnode_t * vp)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
vn_vfswlock(vnode_t * vp)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
vn_vfsrlock(vnode_t * vp)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
vn_vfsunlock(vnode_t * vp)511 vn_vfsunlock(vnode_t *vp)
512 {
513
514 rw_exit(&vfsentry_ve_lock);
515 }
516
517 int
vn_vfswlock_held(vnode_t * vp)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
vn_make_ops(const char * name,const fs_operation_def_t * templ,vnodeops_t ** actual)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
vn_freevnodeops(vnodeops_t * vnops)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
vn_cache_constructor(void * buf,void * cdrarg,int kmflags)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
vn_cache_destructor(void * buf,void * cdrarg)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
vn_create_cache(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
vn_destroy_cache(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
vn_recycle(vnode_t * vp)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
vn_reinit(vnode_t * vp)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 *
vn_alloc(int kmflag)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
vn_free(vnode_t * vp)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
vn_reclaim(vnode_t * vp)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
vn_idle(vnode_t * vp)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
vn_exists(vnode_t * vp)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
vn_invalid(vnode_t * vp)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
vn_is_readonly(vnode_t * vp)793 vn_is_readonly(vnode_t *vp)
794 {
795 return (vp->v_vfsp->vfs_flag & VFS_RDONLY);
796 }
797
798 int
vn_has_flocks(vnode_t * vp)799 vn_has_flocks(vnode_t *vp)
800 {
801 ASSERT(vp->v_filocks == NULL);
802 return (0);
803 }
804
805 int
vn_has_mandatory_locks(vnode_t * vp,int mode)806 vn_has_mandatory_locks(vnode_t *vp, int mode)
807 {
808 ASSERT(vp->v_filocks == NULL);
809 return (0);
810 }
811
812 int
vn_has_cached_data(vnode_t * vp)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
vn_ismntpt(vnode_t * vp)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 *
vn_mountedvfs(vnode_t * vp)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
vn_in_dnlc(vnode_t * vp)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
vn_has_other_opens(vnode_t * vp,v_mode_t mode)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
vn_is_opened(vnode_t * vp,v_mode_t mode)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
vn_is_mapped(vnode_t * vp,v_mode_t mode)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
vn_setops(vnode_t * vp,vnodeops_t * vnodeops)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 *
vn_getops(vnode_t * vp)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
vn_matchops(vnode_t * vp,vnodeops_t * vnodeops)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
vn_updatepath(vnode_t * pvp,vnode_t * vp,const char * name)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
fop_open(vnode_t ** vpp,int mode,cred_t * cr,caller_context_t * ct)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
fop_close(vnode_t * vp,int flag,int count,offset_t offset,cred_t * cr,caller_context_t * ct)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
fop_read(vnode_t * vp,uio_t * uiop,int ioflag,cred_t * cr,caller_context_t * ct)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
fop_write(vnode_t * vp,uio_t * uiop,int ioflag,cred_t * cr,caller_context_t * ct)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
fop_ioctl(vnode_t * vp,int cmd,intptr_t arg,int flag,cred_t * cr,int * rvalp,caller_context_t * ct)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
fop_setfl(vnode_t * vp,int oflags,int nflags,cred_t * cr,caller_context_t * ct)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
fop_getattr(vnode_t * vp,vattr_t * vap,int flags,cred_t * cr,caller_context_t * ct)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
fop_setattr(vnode_t * vp,vattr_t * vap,int flags,cred_t * cr,caller_context_t * ct)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
fop_access(vnode_t * vp,int mode,int flags,cred_t * cr,caller_context_t * ct)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
fop_lookup(vnode_t * dvp,char * nm,vnode_t ** vpp,pathname_t * pnp,int flags,vnode_t * rdir,cred_t * cr,caller_context_t * ct,int * deflags,pathname_t * ppnp)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
fop_create(vnode_t * dvp,char * name,vattr_t * vap,vcexcl_t excl,int mode,vnode_t ** vpp,cred_t * cr,int flags,caller_context_t * ct,vsecattr_t * vsecp)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
fop_remove(vnode_t * dvp,char * nm,cred_t * cr,caller_context_t * ct,int flags)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
fop_link(vnode_t * tdvp,vnode_t * svp,char * tnm,cred_t * cr,caller_context_t * ct,int flags)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
fop_rename(vnode_t * sdvp,char * snm,vnode_t * tdvp,char * tnm,cred_t * cr,caller_context_t * ct,int flags)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
fop_mkdir(vnode_t * dvp,char * dirname,vattr_t * vap,vnode_t ** vpp,cred_t * cr,caller_context_t * ct,int flags,vsecattr_t * vsecp)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
fop_rmdir(vnode_t * dvp,char * nm,vnode_t * cdir,cred_t * cr,caller_context_t * ct,int flags)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
fop_readdir(vnode_t * vp,uio_t * uiop,cred_t * cr,int * eofp,caller_context_t * ct,int flags)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
fop_symlink(vnode_t * dvp,char * linkname,vattr_t * vap,char * target,cred_t * cr,caller_context_t * ct,int flags)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
fop_readlink(vnode_t * vp,uio_t * uiop,cred_t * cr,caller_context_t * ct)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
fop_fsync(vnode_t * vp,int syncflag,cred_t * cr,caller_context_t * ct)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
fop_inactive(vnode_t * vp,cred_t * cr,caller_context_t * ct)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
fop_fid(vnode_t * vp,fid_t * fidp,caller_context_t * ct)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
fop_rwlock(vnode_t * vp,int write_lock,caller_context_t * ct)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
fop_rwunlock(vnode_t * vp,int write_lock,caller_context_t * ct)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
fop_seek(vnode_t * vp,offset_t ooff,offset_t * noffp,caller_context_t * ct)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
fop_cmp(vnode_t * vp1,vnode_t * vp2,caller_context_t * ct)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
fop_frlock(vnode_t * vp,int cmd,flock64_t * bfp,int flag,offset_t offset,struct flk_callback * flk_cbp,cred_t * cr,caller_context_t * ct)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
fop_space(vnode_t * vp,int cmd,flock64_t * bfp,int flag,offset_t offset,cred_t * cr,caller_context_t * ct)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
fop_realvp(vnode_t * vp,vnode_t ** vpp,caller_context_t * ct)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
fop_getpage(vnode_t * vp,offset_t off,size_t len,uint_t * protp,page_t ** plarr,size_t plsz,struct seg * seg,caddr_t addr,enum seg_rw rw,cred_t * cr,caller_context_t * ct)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
fop_putpage(vnode_t * vp,offset_t off,size_t len,int flags,cred_t * cr,caller_context_t * ct)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
fop_map(vnode_t * vp,offset_t off,struct as * as,caddr_t * addrp,size_t len,uchar_t prot,uchar_t maxprot,uint_t flags,cred_t * cr,caller_context_t * ct)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
fop_addmap(vnode_t * vp,offset_t off,struct as * as,caddr_t addr,size_t len,uchar_t prot,uchar_t maxprot,uint_t flags,cred_t * cr,caller_context_t * ct)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
fop_delmap(vnode_t * vp,offset_t off,struct as * as,caddr_t addr,size_t len,uint_t prot,uint_t maxprot,uint_t flags,cred_t * cr,caller_context_t * ct)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
fop_poll(vnode_t * vp,short events,int anyyet,short * reventsp,struct pollhead ** phpp,caller_context_t * ct)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
fop_dump(vnode_t * vp,caddr_t addr,offset_t lbdn,offset_t dblks,caller_context_t * ct)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
fop_pathconf(vnode_t * vp,int cmd,ulong_t * valp,cred_t * cr,caller_context_t * ct)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
fop_pageio(vnode_t * vp,struct page * pp,u_offset_t io_off,size_t io_len,int flags,cred_t * cr,caller_context_t * ct)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
fop_dumpctl(vnode_t * vp,int action,offset_t * blkp,caller_context_t * ct)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
fop_dispose(vnode_t * vp,page_t * pp,int flag,int dn,cred_t * cr,caller_context_t * ct)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
fop_setsecattr(vnode_t * vp,vsecattr_t * vsap,int flag,cred_t * cr,caller_context_t * ct)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
fop_getsecattr(vnode_t * vp,vsecattr_t * vsap,int flag,cred_t * cr,caller_context_t * ct)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
fop_shrlock(vnode_t * vp,int cmd,struct shrlock * shr,int flag,cred_t * cr,caller_context_t * ct)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
fop_vnevent(vnode_t * vp,vnevent_t vnevent,vnode_t * dvp,char * fnm,caller_context_t * ct)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
fs_reparse_mark(char * target,vattr_t * vap,xvattr_t * xvattr)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
vn_is_reparse(vnode_t * vp,cred_t * cr,caller_context_t * ct)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