2 * Copyright (c) 2000-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@
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
30 * Copyright (c) 1992, 1993
31 * The Regents of the University of California. All rights reserved.
33 * This code is derived from software donated to Berkeley by
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed by the University of
47 * California, Berkeley and its contributors.
48 * 4. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * @(#)fdesc_vnops.c 8.17 (Berkeley) 5/22/95
72 #include <sys/param.h>
73 #include <sys/systm.h>
74 #include <sys/types.h>
76 #include <sys/proc_internal.h>
77 #include <sys/kernel.h> /* boottime */
78 #include <sys/resourcevar.h>
79 #include <sys/filedesc.h>
80 #include <sys/kauth.h>
81 #include <sys/vnode_internal.h>
82 #include <sys/malloc.h>
83 #include <sys/file_internal.h>
85 #include <sys/mount_internal.h>
86 #include <sys/namei.h>
87 #include <sys/dirent.h>
89 #include <sys/socketvar.h>
91 #include <sys/uio_internal.h>
92 #include <vfs/vfs_support.h>
93 #include <pexpert/pexpert.h>
94 #include <miscfs/devfs/fdesc.h>
95 #include <miscfs/devfs/devfs.h>
96 #include <miscfs/devfs/devfsdefs.h>
99 #define FDL_LOCKED 0x02
100 static int fdcache_lock
;
103 #if (FD_STDIN != FD_STDOUT - 1) || (FD_STDOUT != FD_STDERR - 1)
104 FD_STDIN
, FD_STDOUT
, FD_STDERR must be a sequence n
, n
+ 1, n
+ 2
109 #define FD_NHASH(ix) \
110 (&fdhashtbl[(ix) & fdhash])
111 LIST_HEAD(fdhashhead
, fdescnode
) * fdhashtbl
;
114 static int fdesc_attr(int fd
, struct vnode_attr
*vap
, vfs_context_t a_context
);
116 static LCK_GRP_DECLARE(fdesc_lckgrp
, "fdesc");
117 static LCK_MTX_DECLARE(fdesc_mtx
, &fdesc_lckgrp
);
122 lck_mtx_lock(&fdesc_mtx
);
128 lck_mtx_unlock(&fdesc_mtx
);
133 * Initialise cache headers, create the devfs node
139 devnode_t
*rootdir
= dev_root
->de_dnp
;
140 devdirent_t
*direntp
;
142 /* XXX Make sure you have the right path... */
143 fdhashtbl
= hashinit(NFDCACHE
, M_CACHE
, &fdhash
);
146 dev_add_entry("fd", rootdir
, DEV_DEVFD
, NULL
, NULL
, NULL
, &direntp
);
147 devfs_fdesc_makelinks();
154 * Called during early startup, no need to synchronize
157 devfs_fdesc_makelinks()
160 devdirent_t
*stdin_ent
= NULL
, *stdout_ent
= NULL
, *stderr_ent
= NULL
;
161 devnode_t
*root_devnode
= dev_root
->de_dnp
;
163 /* We do this ugliness to get around some "const" warnings */
165 char out
[] = "stdout";
166 char err
[] = "stderr";
167 char zero
[] = "fd/0";
171 if ((error
= devfs_make_symlink(root_devnode
, in
, 0555, zero
, &stdin_ent
))) {
172 printf("Couldn't make stdin, err %d.\n", error
);
176 if ((error
= devfs_make_symlink(root_devnode
, out
, 0555, one
, &stdout_ent
))) {
177 printf("Couldn't make stdout, err %d.\n", error
);
181 if ((error
= devfs_make_symlink(root_devnode
, err
, 0555, two
, &stderr_ent
))) {
182 printf("Couldn't make stderr, err %d.\n", error
);
190 dev_free_name(stdin_ent
);
193 dev_free_name(stdout_ent
);
196 dev_free_name(stderr_ent
);
203 fdesc_allocvp(fdntype ftype
, int ix
, struct mount
*mp
, struct vnode
**vpp
, enum vtype vtype
, int fdno
)
205 struct fdhashhead
*fc
;
206 struct fdescnode
*fd
;
209 struct vnode_fsparam vfsp
;
215 for (fd
= fc
->lh_first
; fd
!= 0; fd
= fd
->fd_hash
.le_next
) {
216 if (fd
->fd_ix
== ix
&& vnode_mount(fd
->fd_vnode
) == mp
) {
217 vid
= vnode_vid(fd
->fd_vnode
);
220 if (vnode_getwithvid(fd
->fd_vnode
, vid
)) {
226 (*vpp
)->v_type
= (uint16_t)vtype
;
232 /* Only one thread can add to the hash at a time */
233 if (fdcache_lock
& FDL_LOCKED
) {
234 fdcache_lock
|= FDL_WANT
;
235 msleep((caddr_t
) &fdcache_lock
, &fdesc_mtx
, PINOD
, "fdesc_allocvp", NULL
);
239 fdcache_lock
|= FDL_LOCKED
;
242 MALLOC(fd
, void *, sizeof(struct fdescnode
), M_TEMP
, M_WAITOK
);
245 vfsp
.vnfs_vtype
= vtype
;
246 vfsp
.vnfs_str
= "fdesc";
247 vfsp
.vnfs_dvp
= NULL
;
248 vfsp
.vnfs_fsnode
= fd
;
249 vfsp
.vnfs_cnp
= NULL
;
250 vfsp
.vnfs_vops
= fdesc_vnodeop_p
;
252 vfsp
.vnfs_filesize
= 0;
253 vfsp
.vnfs_flags
= VNFS_NOCACHE
| VNFS_CANTCACHE
;
254 vfsp
.vnfs_marksystem
= 0;
255 vfsp
.vnfs_markroot
= 0;
257 error
= vnode_create(VNCREATE_FLAVOR
, VCREATESIZE
, &vfsp
, vpp
);
264 (*vpp
)->v_tag
= VT_FDESC
;
274 LIST_INSERT_HEAD(fc
, fd
, fd_hash
);
276 /* Hold the lock when we get here */
277 fdcache_lock
&= ~FDL_LOCKED
;
279 if (fdcache_lock
& FDL_WANT
) {
280 fdcache_lock
&= ~FDL_WANT
;
281 wakeup((caddr_t
) &fdcache_lock
);
290 * vp is the current namei directory
291 * ndp is the name to locate in that directory...
293 * This vnop should only be called on the special directory /dev/fd.
296 devfs_devfd_lookup(struct vnop_lookup_args
*ap
)
298 struct vnode
**vpp
= ap
->a_vpp
;
299 struct vnode
*dvp
= ap
->a_dvp
;
300 struct componentname
*cnp
= ap
->a_cnp
;
301 char *pname
= cnp
->cn_nameptr
;
302 struct proc
*p
= vfs_context_proc(ap
->a_context
);
303 int numfiles
= p
->p_fd
->fd_nfiles
;
308 if (cnp
->cn_namelen
== 1 && *pname
== '.') {
311 if ((error
= vnode_get(dvp
))) {
318 while (*pname
>= '0' && *pname
<= '9') {
319 fd
= 10 * fd
+ *pname
++ - '0';
320 if (fd
>= numfiles
) {
325 if (*pname
!= '\0') {
330 if (fd
< 0 || fd
>= numfiles
||
331 *fdfile(p
, fd
) == NULL
||
332 (*fdflags(p
, fd
) & UF_RESERVED
)) {
337 error
= fdesc_allocvp(Fdesc
, FD_DESC
+ fd
, dvp
->v_mount
, &fvp
, VNON
, fd
);
350 fdesc_open(struct vnop_open_args
*ap
)
352 struct vnode
*vp
= ap
->a_vp
;
353 thread_t thr
= vfs_context_thread(ap
->a_context
);
361 uu
= get_bsdthread_info(thr
);
363 switch (VTOFDESC(vp
)->fd_type
) {
366 * XXX Kludge: set uu->uu_dupfd to contain the value of the
367 * the file descriptor being sought for duplication. The error
368 * return ensures that the vnode for this device will be
369 * released by vn_open. Open will detect this special error and
370 * take the actions in dupfdopen. Other callers of vn_open or
371 * vnop_open will simply report the error.
373 uu
->uu_dupfd
= VTOFDESC(vp
)->fd_fd
; /* XXX */
377 panic("Invalid type for fdesc node!");
385 fdesc_attr(int fd
, struct vnode_attr
*vap
, vfs_context_t a_context
)
388 struct proc
*p
= vfs_context_proc(a_context
);
392 if ((error
= fp_lookup(p
, fd
, &fp
, 0))) {
395 switch (FILEGLOB_DTYPE(fp
->fp_glob
)) {
397 if ((error
= vnode_getwithref((struct vnode
*) fp
->fp_glob
->fg_data
)) != 0) {
400 if ((error
= vnode_authorize((struct vnode
*)fp
->fp_glob
->fg_data
,
402 KAUTH_VNODE_READ_ATTRIBUTES
| KAUTH_VNODE_READ_SECURITY
,
404 error
= vnode_getattr((struct vnode
*)fp
->fp_glob
->fg_data
, vap
, a_context
);
406 if (error
== 0 && vap
->va_type
== VDIR
) {
408 * directories can cause loops in the namespace,
409 * so turn off the 'x' bits to avoid trouble.
411 * XXX ACLs break this, of course
413 vap
->va_mode
&= ~((VEXEC
) | (VEXEC
>> 3) | (VEXEC
>> 6));
415 (void)vnode_put((struct vnode
*) fp
->fp_glob
->fg_data
);
421 if (FILEGLOB_DTYPE(fp
->fp_glob
) == DTYPE_SOCKET
) {
422 error
= soo_stat((struct socket
*)fp
->fp_glob
->fg_data
, (void *)&stb
, 0);
425 error
= pipe_stat((struct pipe
*)fp
->fp_glob
->fg_data
, (void *)&stb
, 0);
428 if (FILEGLOB_DTYPE(fp
->fp_glob
) == DTYPE_SOCKET
) {
429 VATTR_RETURN(vap
, va_type
, VSOCK
);
431 VATTR_RETURN(vap
, va_type
, VFIFO
);
434 VATTR_RETURN(vap
, va_mode
, stb
.st_mode
);
435 VATTR_RETURN(vap
, va_nlink
, stb
.st_nlink
);
436 VATTR_RETURN(vap
, va_uid
, stb
.st_uid
);
437 VATTR_RETURN(vap
, va_gid
, stb
.st_gid
);
438 VATTR_RETURN(vap
, va_fsid
, stb
.st_dev
);
439 VATTR_RETURN(vap
, va_fileid
, stb
.st_ino
);
440 VATTR_RETURN(vap
, va_data_size
, stb
.st_size
);
441 VATTR_RETURN(vap
, va_access_time
, stb
.st_atimespec
);
442 VATTR_RETURN(vap
, va_modify_time
, stb
.st_mtimespec
);
443 VATTR_RETURN(vap
, va_change_time
, stb
.st_ctimespec
);
444 VATTR_RETURN(vap
, va_gen
, stb
.st_gen
);
445 VATTR_RETURN(vap
, va_flags
, stb
.st_flags
);
446 VATTR_RETURN(vap
, va_rdev
, stb
.st_rdev
);
447 VATTR_RETURN(vap
, va_total_alloc
, stb
.st_blocks
* stb
.st_blksize
);
448 VATTR_RETURN(vap
, va_acl
, NULL
);
456 fp_drop(p
, fd
, fp
, 0);
461 fdesc_getattr(struct vnop_getattr_args
*ap
)
463 struct vnode
*vp
= ap
->a_vp
;
464 struct vnode_attr
*vap
= ap
->a_vap
;
468 switch (VTOFDESC(vp
)->fd_type
) {
470 fd
= VTOFDESC(vp
)->fd_fd
;
471 error
= fdesc_attr(fd
, vap
, ap
->a_context
);
475 panic("Invalid type for an fdesc node!\n");
480 * Yes, we do this without locking, but this value is always just
484 vp
->v_type
= (uint16_t)vap
->va_type
;
486 /* We need an inactive to reset type to VNON */
487 vnode_setneedinactive(vp
);
494 fdesc_setattr(struct vnop_setattr_args
*ap
)
499 struct proc
* p
= vfs_context_proc(ap
->a_context
);
502 * Can't mess with the root vnode
504 switch (VTOFDESC(ap
->a_vp
)->fd_type
) {
508 panic("Invalid type for an fdesc node!\n");
512 fd
= VTOFDESC(ap
->a_vp
)->fd_fd
;
513 if ((error
= fp_lookup(vfs_context_proc(ap
->a_context
), fd
, &fp
, 0))) {
518 * Can setattr the underlying vnode, but not sockets!
520 switch (FILEGLOB_DTYPE(fp
->fp_glob
)) {
523 if ((error
= vnode_getwithref((struct vnode
*) fp
->fp_glob
->fg_data
)) != 0) {
526 error
= vnode_setattr((struct vnode
*) fp
->fp_glob
->fg_data
, ap
->a_vap
, ap
->a_context
);
527 (void)vnode_put((struct vnode
*) fp
->fp_glob
->fg_data
);
541 fp_drop(p
, fd
, fp
, 0);
548 * static struct dirtmp {
549 * u_int32_t d_fileno;
554 * { FD_DEVFD, UIO_MX, 2, "fd" },
555 * { FD_STDIN, UIO_MX, 5, "stdin" },
556 * { FD_STDOUT, UIO_MX, 6, "stdout" },
557 * { FD_STDERR, UIO_MX, 6, "stderr" },
562 /* Only called on /dev/fd */
564 devfs_devfd_readdir(struct vnop_readdir_args
*ap
)
566 struct uio
*uio
= ap
->a_uio
;
567 struct proc
*p
= current_proc();
572 * We don't allow exporting fdesc mounts, and currently local
573 * requests do not need cookies.
575 if (ap
->a_flags
& (VNODE_READDIR_EXTENDED
| VNODE_READDIR_REQSEEKOFF
)) {
580 * There needs to be space for at least one entry.
582 if (uio_resid(uio
) < UIO_MX
) {
586 i
= uio
->uio_offset
/ UIO_MX
;
588 while (uio_resid(uio
) >= UIO_MX
) {
589 if (i
>= p
->p_fd
->fd_nfiles
|| i
< 0) {
593 if (*fdfile(p
, i
) != NULL
&& !(*fdflags(p
, i
) & UF_RESERVED
)) {
595 struct dirent
*dp
= &d
;
597 bzero((caddr_t
) dp
, UIO_MX
);
599 dp
->d_namlen
= (__uint8_t
)scnprintf(dp
->d_name
, sizeof(dp
->d_name
),
601 dp
->d_reclen
= UIO_MX
;
602 dp
->d_type
= DT_UNKNOWN
;
603 dp
->d_fileno
= (ino_t
)i
+ FD_STDIN
;
605 * And ship to userland
607 error
= uiomove((caddr_t
) dp
, UIO_MX
, uio
);
615 uio
->uio_offset
= i
* UIO_MX
;
620 fdesc_read(__unused
struct vnop_read_args
*ap
)
626 fdesc_write(__unused
struct vnop_write_args
*ap
)
632 fdesc_ioctl(__unused
struct vnop_ioctl_args
*ap
)
638 fdesc_select(__unused
struct vnop_select_args
*ap
)
644 fdesc_inactive(struct vnop_inactive_args
*ap
)
646 struct vnode
*vp
= ap
->a_vp
;
649 * Clear out the v_type field to avoid
650 * nasty things happening in vgone().
658 fdesc_reclaim(struct vnop_reclaim_args
*ap
)
660 struct vnode
*vp
= ap
->a_vp
;
661 struct fdescnode
*fd
= VTOFDESC(vp
);
665 LIST_REMOVE(fd
, fd_hash
);
666 FREE(vp
->v_data
, M_TEMP
);
675 * Return POSIX pathconf information applicable to special devices.
678 fdesc_pathconf(struct vnop_pathconf_args
*ap
)
680 switch (ap
->a_name
) {
682 *ap
->a_retval
= LINK_MAX
;
685 *ap
->a_retval
= MAX_CANON
;
688 *ap
->a_retval
= MAX_INPUT
;
691 *ap
->a_retval
= PIPE_BUF
;
693 case _PC_CHOWN_RESTRICTED
:
694 *ap
->a_retval
= 200112; /* _POSIX_CHOWN_RESTRICTED */
697 *ap
->a_retval
= _POSIX_VDISABLE
;
706 * /dev/fd "should never get here" operation
715 #define VOPFUNC int (*)(void *)
717 #define fdesc_create (int (*) (struct vnop_create_args *))eopnotsupp
718 #define fdesc_mknod (int (*) (struct vnop_mknod_args *))eopnotsupp
719 #define fdesc_close (int (*) (struct vnop_close_args *))nullop
720 #define fdesc_access (int (*) (struct vnop_access_args *))nullop
721 #define fdesc_mmap (int (*) (struct vnop_mmap_args *))eopnotsupp
722 #define fdesc_revoke nop_revoke
723 #define fdesc_fsync (int (*) (struct vnop_fsync_args *))nullop
724 #define fdesc_remove (int (*) (struct vnop_remove_args *))eopnotsupp
725 #define fdesc_link (int (*) (struct vnop_link_args *))eopnotsupp
726 #define fdesc_rename (int (*) (struct vnop_rename_args *))eopnotsupp
727 #define fdesc_mkdir (int (*) (struct vnop_mkdir_args *))eopnotsupp
728 #define fdesc_rmdir (int (*) (struct vnop_rmdir_args *))eopnotsupp
729 #define fdesc_symlink (int (*) (struct vnop_symlink_args *))eopnotsupp
730 #define fdesc_strategy (int (*) (struct vnop_strategy_args *))fdesc_badop
731 #define fdesc_advlock (int (*) (struct vnop_advlock_args *))eopnotsupp
732 #define fdesc_bwrite (int (*) (struct vnop_bwrite_args *))eopnotsupp
733 #define fdesc_blktooff (int (*) (struct vnop_blktooff_args *))eopnotsupp
734 #define fdesc_offtoblk (int (*) (struct vnop_offtoblk_args *))eopnotsupp
735 #define fdesc_blockmap (int (*) (struct vnop_blockmap_args *))eopnotsupp
737 int(**fdesc_vnodeop_p
)(void *);
738 const struct vnodeopv_entry_desc devfs_fdesc_vnodeop_entries
[] = {
739 { .opve_op
= &vnop_default_desc
, .opve_impl
= (VOPFUNC
)vn_default_error
},
740 { .opve_op
= &vnop_lookup_desc
, .opve_impl
= (VOPFUNC
)vn_default_error
}, /* lookup */
741 { .opve_op
= &vnop_create_desc
, .opve_impl
= (VOPFUNC
)fdesc_create
}, /* create */
742 { .opve_op
= &vnop_mknod_desc
, .opve_impl
= (VOPFUNC
)fdesc_mknod
}, /* mknod */
743 { .opve_op
= &vnop_open_desc
, .opve_impl
= (VOPFUNC
)fdesc_open
}, /* open */
744 { .opve_op
= &vnop_close_desc
, .opve_impl
= (VOPFUNC
)fdesc_close
}, /* close */
745 { .opve_op
= &vnop_access_desc
, .opve_impl
= (VOPFUNC
)fdesc_access
}, /* access */
746 { .opve_op
= &vnop_getattr_desc
, .opve_impl
= (VOPFUNC
)fdesc_getattr
}, /* getattr */
747 { .opve_op
= &vnop_setattr_desc
, .opve_impl
= (VOPFUNC
)fdesc_setattr
}, /* setattr */
748 { .opve_op
= &vnop_read_desc
, .opve_impl
= (VOPFUNC
)fdesc_read
}, /* read */
749 { .opve_op
= &vnop_write_desc
, .opve_impl
= (VOPFUNC
)fdesc_write
}, /* write */
750 { .opve_op
= &vnop_ioctl_desc
, .opve_impl
= (VOPFUNC
)fdesc_ioctl
}, /* ioctl */
751 { .opve_op
= &vnop_select_desc
, .opve_impl
= (VOPFUNC
)fdesc_select
}, /* select */
752 { .opve_op
= &vnop_revoke_desc
, .opve_impl
= (VOPFUNC
)fdesc_revoke
}, /* revoke */
753 { .opve_op
= &vnop_mmap_desc
, .opve_impl
= (VOPFUNC
)fdesc_mmap
}, /* mmap */
754 { .opve_op
= &vnop_fsync_desc
, .opve_impl
= (VOPFUNC
)fdesc_fsync
}, /* fsync */
755 { .opve_op
= &vnop_remove_desc
, .opve_impl
= (VOPFUNC
)fdesc_remove
}, /* remove */
756 { .opve_op
= &vnop_link_desc
, .opve_impl
= (VOPFUNC
)fdesc_link
}, /* link */
757 { .opve_op
= &vnop_rename_desc
, .opve_impl
= (VOPFUNC
)fdesc_rename
}, /* rename */
758 { .opve_op
= &vnop_mkdir_desc
, .opve_impl
= (VOPFUNC
)fdesc_mkdir
}, /* mkdir */
759 { .opve_op
= &vnop_rmdir_desc
, .opve_impl
= (VOPFUNC
)fdesc_rmdir
}, /* rmdir */
760 { .opve_op
= &vnop_symlink_desc
, .opve_impl
= (VOPFUNC
)fdesc_symlink
}, /* symlink */
761 { .opve_op
= &vnop_readdir_desc
, .opve_impl
= (VOPFUNC
)vn_default_error
},/* readdir */
762 { .opve_op
= &vnop_readlink_desc
, .opve_impl
= (VOPFUNC
)err_readlink
}, /* readlink */
763 { .opve_op
= &vnop_inactive_desc
, .opve_impl
= (VOPFUNC
)fdesc_inactive
},/* inactive */
764 { .opve_op
= &vnop_reclaim_desc
, .opve_impl
= (VOPFUNC
)fdesc_reclaim
}, /* reclaim */
765 { .opve_op
= &vnop_strategy_desc
, .opve_impl
= (VOPFUNC
)fdesc_strategy
}, /* strategy */
766 { .opve_op
= &vnop_pathconf_desc
, .opve_impl
= (VOPFUNC
)fdesc_pathconf
}, /* pathconf */
767 { .opve_op
= &vnop_advlock_desc
, .opve_impl
= (VOPFUNC
)fdesc_advlock
}, /* advlock */
768 { .opve_op
= &vnop_bwrite_desc
, .opve_impl
= (VOPFUNC
)fdesc_bwrite
}, /* bwrite */
769 { .opve_op
= &vnop_pagein_desc
, .opve_impl
= (VOPFUNC
)err_pagein
}, /* pagein */
770 { .opve_op
= &vnop_pageout_desc
, .opve_impl
= (VOPFUNC
)err_pageout
}, /* pageout */
771 { .opve_op
= &vnop_copyfile_desc
, .opve_impl
= (VOPFUNC
)err_copyfile
}, /* Copyfile */
772 { .opve_op
= &vnop_blktooff_desc
, .opve_impl
= (VOPFUNC
)fdesc_blktooff
}, /* blktooff */
773 { .opve_op
= &vnop_blktooff_desc
, .opve_impl
= (VOPFUNC
)fdesc_offtoblk
}, /* offtoblk */
774 { .opve_op
= &vnop_blockmap_desc
, .opve_impl
= (VOPFUNC
)fdesc_blockmap
}, /* blockmap */
775 { .opve_op
= (struct vnodeop_desc
*)NULL
, .opve_impl
= (VOPFUNC
)NULL
}
778 const struct vnodeopv_desc devfs_fdesc_vnodeop_opv_desc
=
779 { .opv_desc_vector_p
= &fdesc_vnodeop_p
, .opv_desc_ops
= devfs_fdesc_vnodeop_entries
};