2 * Copyright (c) 2019 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/vnode_internal.h>
34 #include <sys/kauth.h>
35 #include <sys/mount_internal.h>
36 #include <sys/fcntl.h>
37 #include <sys/unistd.h>
38 #include <sys/malloc.h>
39 #include <vfs/vfs_support.h>
41 #include <libkern/OSAtomic.h>
44 #include <security/mac_framework.h>
49 static int routefs_init(__unused
struct vfsconf
*vfsp
);
50 static int routefs_mount(struct mount
*mp
, __unused vnode_t devvp
, __unused user_addr_t data
, vfs_context_t ctx
);
51 static int routefs_start(__unused
struct mount
*mp
, __unused
int flags
, __unused vfs_context_t ctx
);
52 static int routefs_unmount( struct mount
*mp
, int mntflags
, __unused vfs_context_t ctx
);
53 static int routefs_root(struct mount
*mp
, struct vnode
**vpp
, __unused vfs_context_t ctx
);
54 static int routefs_statfs( struct mount
*mp
, struct vfsstatfs
*sbp
, __unused vfs_context_t ctx
);
55 static int routefs_vfs_getattr(__unused mount_t mp
, struct vfs_attr
*fsap
, __unused vfs_context_t ctx
);
56 static int routefs_sync(__unused
struct mount
*mp
, __unused
int waitfor
, __unused vfs_context_t ctx
);
57 static int routefs_vget(__unused
struct mount
*mp
, __unused ino64_t ino
, __unused
struct vnode
**vpp
, __unused vfs_context_t ctx
);
58 static int routefs_fhtovp(__unused
struct mount
*mp
, __unused
int fhlen
, __unused
unsigned char *fhp
, __unused
struct vnode
**vpp
, __unused vfs_context_t ctx
);
59 static int routefs_vptofh(__unused
struct vnode
*vp
, __unused
int *fhlenp
, __unused
unsigned char *fhp
, __unused vfs_context_t ctx
);
60 static int routefs_sysctl(__unused
int *name
, __unused u_int namelen
, __unused user_addr_t oldp
,
61 __unused
size_t *oldlenp
, __unused user_addr_t newp
,
62 __unused
size_t newlen
, __unused vfs_context_t ctx
);
63 static int routefserr_lookup(__unused
struct vnop_lookup_args
* args
);
65 static int routefserr_setlabel(__unused
struct vnop_setlabel_args
* args
);
68 lck_grp_t
* routefs_lck_grp
;
69 lck_grp_attr_t
* routefs_lck_grp_attr
;
70 lck_attr_t
* routefs_lck_attr
;
71 lck_mtx_t routefs_mutex
;
73 #define ROUTEFS_LOCK() lck_mtx_lock(&routefs_mutex)
74 #define ROUTEFS_UNLOCK() lck_mtx_unlock(&routefs_mutex)
75 static int _lock_inited
= 0;
76 static boolean_t _fs_alreadyMounted
= FALSE
; /* atleast a mount of this filesystem is present */
79 routefs_init(__unused
struct vfsconf
*vfsp
)
81 routefs_lck_grp_attr
= lck_grp_attr_alloc_init();
82 routefs_lck_grp
= lck_grp_alloc_init("routefs_lock", routefs_lck_grp_attr
);
83 routefs_lck_attr
= lck_attr_alloc_init();
84 lck_mtx_init(&routefs_mutex
, routefs_lck_grp
, routefs_lck_attr
);
91 routefs_mount(struct mount
*mp
, __unused vnode_t devvp
, user_addr_t data
, vfs_context_t ctx
)
93 struct routefs_mount
*routefs_mp_p
= NULL
; /* routefs specific mount info */
95 struct routefs_args
* rargs
= (struct routefs_args
*)data
;
98 * If they just want to update, we don't need to do anything.
100 if (mp
->mnt_flag
& MNT_UPDATE
) {
105 /* check for root mount only */
106 if ((error
= proc_suser(current_proc())) != 0) {
110 if (vfs_iskernelmount(mp
) == FALSE
) {
115 if (_fs_alreadyMounted
== TRUE
) {
116 /* if a filesystem is mounted, it needs to be unmounted prior to mount again */
121 /* Advisory locking should be handled at the VFS layer */
122 vfs_setlocklocal(mp
);
125 * Well, it's not an update, it's a real mount request.
127 * HERE we should check to see if we are already mounted here.
130 MALLOC(routefs_mp_p
, struct routefs_mount
*, sizeof(struct routefs_mount
),
132 if (routefs_mp_p
== NULL
) {
135 bzero(routefs_mp_p
, sizeof(*routefs_mp_p
));
137 routefs_mp_p
->route_mount
= mp
;
139 if (rargs
->route_rvp
== NULLVP
) {
144 strlcpy(routefs_mp_p
->route_path
, rargs
->route_path
, MAXPATHLEN
);
145 routefs_mp_p
->route_rvp
= rargs
->route_rvp
;
146 routefs_mp_p
->route_vpvid
= vnode_vid(rargs
->route_rvp
);
148 if (vnode_ref(routefs_mp_p
->route_rvp
) != 0) {
154 * Fill out some fields
156 __IGNORE_WCASTALIGN(mp
->mnt_data
= (qaddr_t
)routefs_mp_p
);
157 mp
->mnt_vfsstat
.f_fsid
.val
[0] = (int32_t)VM_KERNEL_ADDRHASH(routefs_mp_p
);
158 mp
->mnt_vfsstat
.f_fsid
.val
[1] = vfs_typenum(mp
);
159 mp
->mnt_flag
|= MNT_LOCAL
;
162 * Copy in the name of the directory the filesystem
163 * is to be mounted on.
164 * And we clear the remainder of the character strings
168 bzero(mp
->mnt_vfsstat
.f_mntfromname
, MAXPATHLEN
);
169 bcopy("routefs", mp
->mnt_vfsstat
.f_mntfromname
, 5);
170 (void)routefs_statfs(mp
, &mp
->mnt_vfsstat
, ctx
);
171 _fs_alreadyMounted
= TRUE
; /* yep, fs is in play now */
175 if (routefs_mp_p
!= NULL
) {
176 FREE(routefs_mp_p
, M_TEMP
);
184 routefs_start(__unused
struct mount
*mp
, __unused
int flags
, __unused vfs_context_t ctx
)
190 * Unmount the filesystem described by mp.
193 routefs_unmount( struct mount
*mp
, int mntflags
, __unused vfs_context_t ctx
)
195 struct routefs_mount
*routefs_mp_p
= (struct routefs_mount
*)mp
->mnt_data
;
200 /* check for root unmount only */
201 if ((error
= proc_suser(current_proc())) != 0) {
205 if (mntflags
& MNT_FORCE
) {
209 /* giveup the ioref of vnode, no longer need it */
210 if (routefs_mp_p
->route_rvp
!= NULLVP
) {
211 if (vnode_getwithref(routefs_mp_p
->route_rvp
) == 0) {
212 vnode_rele(routefs_mp_p
->route_rvp
);
213 vnode_put(routefs_mp_p
->route_rvp
);
214 routefs_mp_p
->route_rvp
= NULLVP
;
217 /* no vnodes, ignore any errors */
218 (void)vflush(mp
, NULLVP
, flags
);
219 FREE(routefs_mp_p
, M_TEMP
);
220 mp
->mnt_data
= (qaddr_t
)0;
221 mp
->mnt_flag
&= ~MNT_LOCAL
;
222 _fs_alreadyMounted
= FALSE
; /* unmounted the fs, only one allowed at a time */
226 /* return the address of the root vnode in *vpp */
228 routefs_root(struct mount
*mp
, struct vnode
**vpp
, __unused vfs_context_t ctx
)
230 struct routefs_mount
*routefs_mp_p
= (struct routefs_mount
*)(mp
->mnt_data
);
233 /* check for nullvp incase its being rolled */
234 if (routefs_mp_p
->route_rvp
== NULLVP
) {
236 if (routefs_mp_p
->route_rvp
== NULLVP
) {
243 if (vnode_getwithvid(routefs_mp_p
->route_rvp
, routefs_mp_p
->route_vpvid
) != 0) {
244 /* only one in the path., since no vnodes with this, you can hold across this call */
246 if (vnode_getwithref(routefs_mp_p
->route_rvp
) == 0) {
247 vnode_rele(routefs_mp_p
->route_rvp
);
248 vnode_put(routefs_mp_p
->route_rvp
);
249 routefs_mp_p
->route_rvp
= NULLVP
;
250 routefs_mp_p
->route_vpvid
= -1;
251 error
= vnode_lookup(routefs_mp_p
->route_path
, FREAD
| O_DIRECTORY
, &routefs_mp_p
->route_rvp
, ctx
);
253 routefs_mp_p
->route_vpvid
= vnode_vid(routefs_mp_p
->route_rvp
);
264 *vpp
= routefs_mp_p
->route_rvp
;
270 routefs_statfs( struct mount
*mp
, struct vfsstatfs
*sbp
, __unused vfs_context_t ctx
)
272 struct routefs_mount
*routefs_mp_p
= (struct routefs_mount
*)mp
->mnt_data
;
275 * Fill in the stat block.
277 //sbp->f_type = mp->mnt_vfsstat.f_type;
278 sbp
->f_flags
= 0; /* XXX */
281 sbp
->f_blocks
= (sizeof(struct routefs_mount
) + sbp
->f_bsize
) / sbp
->f_bsize
;
286 sbp
->f_fsid
.val
[0] = (int32_t)VM_KERNEL_ADDRHASH(routefs_mp_p
);
287 sbp
->f_fsid
.val
[1] = vfs_typenum(mp
);
293 routefs_vfs_getattr(__unused mount_t mp
, struct vfs_attr
*fsap
, __unused vfs_context_t ctx
)
295 VFSATTR_RETURN(fsap
, f_objcount
, 1);
296 VFSATTR_RETURN(fsap
, f_maxobjcount
, 1);
297 VFSATTR_RETURN(fsap
, f_bsize
, 512);
298 VFSATTR_RETURN(fsap
, f_iosize
, 512);
299 if (VFSATTR_IS_ACTIVE(fsap
, f_blocks
) || VFSATTR_IS_ACTIVE(fsap
, f_bused
)) {
300 fsap
->f_blocks
= (sizeof(struct routefs_mount
) + fsap
->f_bsize
) / fsap
->f_bsize
;
301 fsap
->f_bused
= fsap
->f_blocks
;
302 VFSATTR_SET_SUPPORTED(fsap
, f_blocks
);
303 VFSATTR_SET_SUPPORTED(fsap
, f_bused
);
305 VFSATTR_RETURN(fsap
, f_bfree
, 0);
306 VFSATTR_RETURN(fsap
, f_bavail
, 0);
307 VFSATTR_RETURN(fsap
, f_files
, 0);
308 VFSATTR_RETURN(fsap
, f_ffree
, 0);
309 VFSATTR_RETURN(fsap
, f_fssubtype
, 0);
311 if (VFSATTR_IS_ACTIVE(fsap
, f_capabilities
)) {
312 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_FORMAT
] =
313 VOL_CAP_FMT_SYMBOLICLINKS
|
314 VOL_CAP_FMT_HARDLINKS
|
315 VOL_CAP_FMT_NO_ROOT_TIMES
|
316 VOL_CAP_FMT_CASE_SENSITIVE
|
317 VOL_CAP_FMT_CASE_PRESERVING
|
318 VOL_CAP_FMT_FAST_STATFS
|
319 VOL_CAP_FMT_2TB_FILESIZE
|
320 VOL_CAP_FMT_HIDDEN_FILES
;
321 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_INTERFACES
] =
322 VOL_CAP_INT_ATTRLIST
;
323 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED1
] = 0;
324 fsap
->f_capabilities
.capabilities
[VOL_CAPABILITIES_RESERVED2
] = 0;
326 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_FORMAT
] =
327 VOL_CAP_FMT_PERSISTENTOBJECTIDS
|
328 VOL_CAP_FMT_SYMBOLICLINKS
|
329 VOL_CAP_FMT_HARDLINKS
|
330 VOL_CAP_FMT_JOURNAL
|
331 VOL_CAP_FMT_JOURNAL_ACTIVE
|
332 VOL_CAP_FMT_NO_ROOT_TIMES
|
333 VOL_CAP_FMT_SPARSE_FILES
|
334 VOL_CAP_FMT_ZERO_RUNS
|
335 VOL_CAP_FMT_CASE_SENSITIVE
|
336 VOL_CAP_FMT_CASE_PRESERVING
|
337 VOL_CAP_FMT_FAST_STATFS
|
338 VOL_CAP_FMT_2TB_FILESIZE
|
339 VOL_CAP_FMT_OPENDENYMODES
|
340 VOL_CAP_FMT_HIDDEN_FILES
|
341 VOL_CAP_FMT_PATH_FROM_ID
|
342 VOL_CAP_FMT_NO_VOLUME_SIZES
;
343 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_INTERFACES
] =
344 VOL_CAP_INT_SEARCHFS
|
345 VOL_CAP_INT_ATTRLIST
|
346 VOL_CAP_INT_NFSEXPORT
|
347 VOL_CAP_INT_READDIRATTR
|
348 VOL_CAP_INT_EXCHANGEDATA
|
349 VOL_CAP_INT_COPYFILE
|
350 VOL_CAP_INT_ALLOCATE
|
351 VOL_CAP_INT_VOL_RENAME
|
352 VOL_CAP_INT_ADVLOCK
|
354 VOL_CAP_INT_EXTENDED_SECURITY
|
355 VOL_CAP_INT_USERACCESS
|
356 VOL_CAP_INT_MANLOCK
|
357 VOL_CAP_INT_EXTENDED_ATTR
|
358 VOL_CAP_INT_NAMEDSTREAMS
;
359 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED1
] = 0;
360 fsap
->f_capabilities
.valid
[VOL_CAPABILITIES_RESERVED2
] = 0;
362 VFSATTR_SET_SUPPORTED(fsap
, f_capabilities
);
365 if (VFSATTR_IS_ACTIVE(fsap
, f_attributes
)) {
366 fsap
->f_attributes
.validattr
.commonattr
=
367 ATTR_CMN_NAME
| ATTR_CMN_DEVID
| ATTR_CMN_FSID
|
368 ATTR_CMN_OBJTYPE
| ATTR_CMN_OBJTAG
| ATTR_CMN_OBJID
|
370 ATTR_CMN_MODTIME
| ATTR_CMN_CHGTIME
| ATTR_CMN_ACCTIME
|
371 ATTR_CMN_OWNERID
| ATTR_CMN_GRPID
| ATTR_CMN_ACCESSMASK
|
372 ATTR_CMN_FLAGS
| ATTR_CMN_USERACCESS
| ATTR_CMN_FILEID
;
373 fsap
->f_attributes
.validattr
.volattr
=
374 ATTR_VOL_FSTYPE
| ATTR_VOL_SIZE
| ATTR_VOL_SPACEFREE
|
375 ATTR_VOL_SPACEAVAIL
| ATTR_VOL_MINALLOCATION
|
376 ATTR_VOL_OBJCOUNT
| ATTR_VOL_MAXOBJCOUNT
|
377 ATTR_VOL_MOUNTPOINT
| ATTR_VOL_MOUNTFLAGS
|
378 ATTR_VOL_MOUNTEDDEVICE
| ATTR_VOL_CAPABILITIES
|
380 fsap
->f_attributes
.validattr
.dirattr
=
381 ATTR_DIR_LINKCOUNT
| ATTR_DIR_MOUNTSTATUS
;
382 fsap
->f_attributes
.validattr
.fileattr
=
383 ATTR_FILE_LINKCOUNT
| ATTR_FILE_TOTALSIZE
|
384 ATTR_FILE_IOBLOCKSIZE
| ATTR_FILE_DEVTYPE
|
385 ATTR_FILE_DATALENGTH
;
386 fsap
->f_attributes
.validattr
.forkattr
= 0;
388 fsap
->f_attributes
.nativeattr
.commonattr
=
389 ATTR_CMN_NAME
| ATTR_CMN_DEVID
| ATTR_CMN_FSID
|
390 ATTR_CMN_OBJTYPE
| ATTR_CMN_OBJTAG
| ATTR_CMN_OBJID
|
392 ATTR_CMN_MODTIME
| ATTR_CMN_CHGTIME
| ATTR_CMN_ACCTIME
|
393 ATTR_CMN_OWNERID
| ATTR_CMN_GRPID
| ATTR_CMN_ACCESSMASK
|
394 ATTR_CMN_FLAGS
| ATTR_CMN_USERACCESS
| ATTR_CMN_FILEID
;
395 fsap
->f_attributes
.nativeattr
.volattr
=
396 ATTR_VOL_FSTYPE
| ATTR_VOL_SIZE
| ATTR_VOL_SPACEFREE
|
397 ATTR_VOL_SPACEAVAIL
| ATTR_VOL_MINALLOCATION
|
398 ATTR_VOL_OBJCOUNT
| ATTR_VOL_MAXOBJCOUNT
|
399 ATTR_VOL_MOUNTPOINT
| ATTR_VOL_MOUNTFLAGS
|
400 ATTR_VOL_MOUNTEDDEVICE
| ATTR_VOL_CAPABILITIES
|
402 fsap
->f_attributes
.nativeattr
.dirattr
=
403 ATTR_DIR_MOUNTSTATUS
;
404 fsap
->f_attributes
.nativeattr
.fileattr
=
405 ATTR_FILE_LINKCOUNT
| ATTR_FILE_TOTALSIZE
|
406 ATTR_FILE_IOBLOCKSIZE
| ATTR_FILE_DEVTYPE
|
407 ATTR_FILE_DATALENGTH
;
408 fsap
->f_attributes
.nativeattr
.forkattr
= 0;
410 VFSATTR_SET_SUPPORTED(fsap
, f_attributes
);
417 routefs_sync(__unused
struct mount
*mp
, __unused
int waitfor
, __unused vfs_context_t ctx
)
424 routefs_vget(__unused
struct mount
*mp
, __unused ino64_t ino
, __unused
struct vnode
**vpp
, __unused vfs_context_t ctx
)
430 routefs_fhtovp(__unused
struct mount
*mp
, __unused
int fhlen
, __unused
unsigned char *fhp
, __unused
struct vnode
**vpp
, __unused vfs_context_t ctx
)
437 routefs_vptofh(__unused
struct vnode
*vp
, __unused
int *fhlenp
, __unused
unsigned char *fhp
, __unused vfs_context_t ctx
)
443 routefs_sysctl(__unused
int *name
, __unused u_int namelen
, __unused user_addr_t oldp
,
444 __unused
size_t *oldlenp
, __unused user_addr_t newp
,
445 __unused
size_t newlen
, __unused vfs_context_t ctx
)
450 #include <sys/namei.h>
451 #define MOBILE_DIR_PATH "/private/var/mobile"
453 * Function: routefs_kernel_mount
455 * Mount routefs at the given mount point from within the kernel.
458 routefs_kernel_mount(char * routepath
)
461 vfs_context_t ctx
= vfs_context_kernel();
462 char fsname
[] = "routefs";
463 struct routefs_args args
;
464 char mounthere
[] = MOBILE_DIR_PATH
; /* !const because of internal casting */
466 bzero(&args
, sizeof(struct routefs_args
));
467 strlcpy(args
.route_path
, routepath
, MAXPATHLEN
);
468 error
= vnode_lookup(args
.route_path
, FREAD
| O_DIRECTORY
, &args
.route_rvp
, ctx
);
473 if (!vnode_isdir(args
.route_rvp
)) {
478 error
= kernel_mount(fsname
, NULLVP
, NULLVP
, mounthere
, &args
, 0, MNT_DONTBROWSE
, KERNEL_MOUNT_NOAUTH
, ctx
);
484 if (args
.route_rvp
!= NULLVP
) {
485 (void) vnode_put(args
.route_rvp
);
490 const struct vfsops routefs_vfsops
= {
491 .vfs_mount
= routefs_mount
,
492 .vfs_start
= routefs_start
,
493 .vfs_unmount
= routefs_unmount
,
494 .vfs_root
= routefs_root
,
495 .vfs_getattr
= routefs_vfs_getattr
,
496 .vfs_sync
= routefs_sync
,
497 .vfs_vget
= routefs_vget
,
498 .vfs_fhtovp
= routefs_fhtovp
,
499 .vfs_vptofh
= routefs_vptofh
,
500 .vfs_init
= routefs_init
,
501 .vfs_sysctl
= routefs_sysctl
,
502 // There are other VFS ops that we do not support
506 routefserr_lookup(__unused
struct vnop_lookup_args
* args
)
512 routefserr_setlabel(__unused
struct vnop_setlabel_args
* args
)
517 #define VOPFUNC int (*)(void *)
519 /* The following ops are used by directories and symlinks */
520 int(**routefs_vnodeop_p
)(void *);
521 static const struct vnodeopv_entry_desc routefs_vnodeop_entries
[] = {
522 { .opve_op
= &vnop_default_desc
, .opve_impl
= (VOPFUNC
)vn_default_error
},
523 { .opve_op
= &vnop_lookup_desc
, .opve_impl
= (VOPFUNC
)routefserr_lookup
}, /* lookup */
524 { .opve_op
= &vnop_create_desc
, .opve_impl
= (VOPFUNC
)err_create
}, /* create */
525 { .opve_op
= &vnop_whiteout_desc
, .opve_impl
= (VOPFUNC
)err_whiteout
}, /* whiteout */
526 { .opve_op
= &vnop_mknod_desc
, .opve_impl
= (VOPFUNC
)err_mknod
}, /* mknod */
527 { .opve_op
= &vnop_open_desc
, .opve_impl
= (VOPFUNC
)err_open
}, /* open */
528 { .opve_op
= &vnop_close_desc
, .opve_impl
= (VOPFUNC
)err_close
}, /* close */
529 { .opve_op
= &vnop_getattr_desc
, .opve_impl
= (VOPFUNC
)err_getattr
}, /* getattr */
530 { .opve_op
= &vnop_setattr_desc
, .opve_impl
= (VOPFUNC
)err_setattr
}, /* setattr */
531 { .opve_op
= &vnop_read_desc
, .opve_impl
= (VOPFUNC
)err_read
}, /* read */
532 { .opve_op
= &vnop_write_desc
, .opve_impl
= (VOPFUNC
)err_write
}, /* write */
533 { .opve_op
= &vnop_ioctl_desc
, .opve_impl
= (VOPFUNC
)err_ioctl
}, /* ioctl */
534 { .opve_op
= &vnop_select_desc
, .opve_impl
= (VOPFUNC
)err_select
}, /* select */
535 { .opve_op
= &vnop_revoke_desc
, .opve_impl
= (VOPFUNC
)err_revoke
}, /* revoke */
536 { .opve_op
= &vnop_mmap_desc
, .opve_impl
= (VOPFUNC
)err_mmap
}, /* mmap */
537 { .opve_op
= &vnop_fsync_desc
, .opve_impl
= (VOPFUNC
)nop_fsync
}, /* fsync */
538 { .opve_op
= &vnop_remove_desc
, .opve_impl
= (VOPFUNC
)err_remove
}, /* remove */
539 { .opve_op
= &vnop_link_desc
, .opve_impl
= (VOPFUNC
)err_link
}, /* link */
540 { .opve_op
= &vnop_rename_desc
, .opve_impl
= (VOPFUNC
)err_rename
}, /* rename */
541 { .opve_op
= &vnop_mkdir_desc
, .opve_impl
= (VOPFUNC
)err_mkdir
}, /* mkdir */
542 { .opve_op
= &vnop_rmdir_desc
, .opve_impl
= (VOPFUNC
)err_rmdir
}, /* rmdir */
543 { .opve_op
= &vnop_symlink_desc
, .opve_impl
= (VOPFUNC
)err_symlink
}, /* symlink */
544 { .opve_op
= &vnop_readdir_desc
, .opve_impl
= (VOPFUNC
)err_readdir
}, /* readdir */
545 { .opve_op
= &vnop_readlink_desc
, .opve_impl
= (VOPFUNC
)err_readlink
}, /* readlink */
546 { .opve_op
= &vnop_inactive_desc
, .opve_impl
= (VOPFUNC
)err_inactive
}, /* inactive */
547 { .opve_op
= &vnop_reclaim_desc
, .opve_impl
= (VOPFUNC
)err_reclaim
}, /* reclaim */
548 { .opve_op
= &vnop_strategy_desc
, .opve_impl
= (VOPFUNC
)err_strategy
}, /* strategy */
549 { .opve_op
= &vnop_pathconf_desc
, .opve_impl
= (VOPFUNC
)err_pathconf
}, /* pathconf */
550 { .opve_op
= &vnop_advlock_desc
, .opve_impl
= (VOPFUNC
)err_advlock
}, /* advlock */
551 { .opve_op
= &vnop_bwrite_desc
, .opve_impl
= (VOPFUNC
)err_bwrite
},
552 { .opve_op
= &vnop_pagein_desc
, .opve_impl
= (VOPFUNC
)err_pagein
}, /* Pagein */
553 { .opve_op
= &vnop_pageout_desc
, .opve_impl
= (VOPFUNC
)err_pageout
}, /* Pageout */
554 { .opve_op
= &vnop_copyfile_desc
, .opve_impl
= (VOPFUNC
)err_copyfile
}, /* Copyfile */
555 { .opve_op
= &vnop_blktooff_desc
, .opve_impl
= (VOPFUNC
)err_blktooff
}, /* blktooff */
556 { .opve_op
= &vnop_offtoblk_desc
, .opve_impl
= (VOPFUNC
)err_offtoblk
}, /* offtoblk */
557 { .opve_op
= &vnop_blockmap_desc
, .opve_impl
= (VOPFUNC
)err_blockmap
}, /* blockmap */
559 { .opve_op
= &vnop_setlabel_desc
, .opve_impl
= (VOPFUNC
)routefserr_setlabel
}, /* setlabel */
561 { .opve_op
= (struct vnodeop_desc
*)NULL
, .opve_impl
= (int (*)(void *))NULL
}
564 const struct vnodeopv_desc routefs_vnodeop_opv_desc
=
565 { .opv_desc_vector_p
= &routefs_vnodeop_p
, .opv_desc_ops
= routefs_vnodeop_entries
};