2 * Copyright (c) 2019 Tomohiro Kusumi <tkusumi@netbsd.org>
3 * Copyright (c) 2019 The DragonFly Project
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/fcntl.h>
31 #include <sys/dirent.h>
33 #include <sys/mountctl.h>
34 #include <vm/vm_pager.h>
35 #include <vm/vnode_pager.h>
38 fuse_set_attr(struct fuse_node
*fnp
, struct fuse_attr
*fat
)
40 struct vattr
*vap
= &fnp
->attr
;
45 vap
->va_type
= IFTOVT(fat
->mode
);
46 vap
->va_size
= fat
->size
;
47 vap
->va_bytes
= fat
->blocks
* S_BLKSIZE
;
48 vap
->va_mode
= fat
->mode
& ~S_IFMT
;
49 if (!fat
->nlink
) /* XXX .fuse_hidden* has 0 link */
52 vap
->va_nlink
= fat
->nlink
;
53 vap
->va_uid
= fat
->uid
;
54 vap
->va_gid
= fat
->gid
;
55 vap
->va_fsid
= fnp
->fmp
->mp
->mnt_stat
.f_fsid
.val
[0];
56 vap
->va_fileid
= fat
->ino
;
57 vap
->va_blocksize
= FUSE_BLKSIZE
;
58 vap
->va_rmajor
= VNOVAL
;
59 vap
->va_rminor
= VNOVAL
;
60 vap
->va_atime
.tv_sec
= fat
->atime
;
61 vap
->va_atime
.tv_nsec
= fat
->atimensec
;
62 vap
->va_mtime
.tv_sec
= fat
->mtime
;
63 vap
->va_mtime
.tv_nsec
= fat
->mtimensec
;
64 vap
->va_ctime
.tv_sec
= fat
->ctime
;
65 vap
->va_ctime
.tv_nsec
= fat
->ctimensec
;
70 KKASSERT(vap
->va_type
== fnp
->type
);
72 if (fnp
->nlink
!= vap
->va_nlink
) {
73 fuse_dbg("ino=%ju update nlink %d -> %ju\n",
74 fnp
->ino
, fnp
->nlink
, vap
->va_nlink
);
75 fnp
->nlink
= vap
->va_nlink
;
78 if (fnp
->vp
->v_object
&& fnp
->size
!= vap
->va_size
)
79 error
= fuse_node_truncate(fnp
, fnp
->size
, vap
->va_size
);
85 fuse_vop_access(struct vop_access_args
*ap
)
87 struct vnode
*vp
= ap
->a_vp
;
88 mode_t mode
= ap
->a_mode
;
89 struct fuse_mount
*fmp
= VFSTOFUSE(vp
->v_mount
);
91 struct fuse_access_in
*fai
;
95 if (fuse_test_dead(fmp
))
98 if (fuse_test_nosys(fmp
, FUSE_ACCESS
))
101 switch (vp
->v_type
) {
105 if ((mode
& VWRITE
) && (vp
->v_mount
->mnt_flag
& MNT_RDONLY
))
125 fip
= fuse_ipc_get(fmp
, sizeof(*fai
));
126 fai
= fuse_ipc_fill(fip
, FUSE_ACCESS
, VTOI(vp
)->ino
, ap
->a_cred
);
129 error
= fuse_ipc_tx(fip
);
133 if (error
== ENOTCONN
&& (vp
->v_flag
& VROOT
))
144 fuse_vop_open(struct vop_open_args
*ap
)
146 struct vnode
*vp
= ap
->a_vp
;
147 struct fuse_mount
*fmp
= VFSTOFUSE(vp
->v_mount
);
148 struct fuse_node
*fnp
= VTOI(vp
);
149 struct fuse_ipc
*fip
;
150 struct fuse_open_in
*foi
;
151 struct fuse_open_out
*foo
;
154 if (fuse_test_dead(fmp
))
157 if (fuse_test_nosys(fmp
, FUSE_OPEN
))
160 if (vp
->v_type
== VDIR
)
165 fip
= fuse_ipc_get(fmp
, sizeof(*foi
));
166 foi
= fuse_ipc_fill(fip
, op
, fnp
->ino
, ap
->a_cred
);
167 foi
->flags
= OFLAGS(ap
->a_mode
);
168 fuse_dbg("flags=%X\n", foi
->flags
);
169 if (foi
->flags
& O_CREAT
) {
170 fuse_dbg("drop O_CREAT\n");
171 foi
->flags
&= ~O_CREAT
;
174 error
= fuse_ipc_tx(fip
);
179 foo
= fuse_out_data(fip
);
180 if (foo
->open_flags
& FOPEN_DIRECT_IO
)
182 else if (foo
->open_flags
& FOPEN_KEEP_CACHE
)
184 else if (foo
->open_flags
& FOPEN_NONSEEKABLE
)
186 else if (foo
->open_flags
& FOPEN_CACHE_DIR
)
190 fuse_get_nfh(VTOI(vp
), foo
->fh
);
193 fuse_get_fh(ap
->a_fp
, foo
->fh
);
195 /* see #if0'd code in fuse_vop_setattr() */
196 if (!ap
->a_fp
->private_data
)
197 fuse_get_fh(ap
->a_fp
, foo
->fh
);
199 uint64_t *fhp
= ap
->a_fp
->private_data
;
207 return vop_stdopen(ap
);
211 fuse_vop_close(struct vop_close_args
*ap
)
213 struct vnode
*vp
= ap
->a_vp
;
214 struct fuse_mount
*fmp
= VFSTOFUSE(vp
->v_mount
);
215 struct fuse_node
*fnp
= VTOI(vp
);
216 struct fuse_ipc
*fip
;
217 struct fuse_release_in
*fri
;
220 if (fuse_test_dead(fmp
))
223 if (fuse_test_nosys(fmp
, FUSE_RELEASE
) ||
224 fuse_test_nosys(fmp
, FUSE_RELEASEDIR
))
227 if (vp
->v_type
== VDIR
)
228 op
= FUSE_RELEASEDIR
;
232 fip
= fuse_ipc_get(fmp
, sizeof(*fri
));
233 fri
= fuse_ipc_fill(fip
, op
, fnp
->ino
, NULL
);
236 //fri->release_flags = ...;
237 //fri->lock_owner = ...;
238 fri
->fh
= fuse_nfh(VTOI(vp
));
240 fri
->fh
= fuse_fh(ap
->a_fp
);
242 error
= fuse_ipc_tx(fip
);
249 fuse_put_nfh(VTOI(vp
));
251 fuse_put_fh(ap
->a_fp
);
253 return vop_stdclose(ap
);
257 fuse_vop_fsync(struct vop_fsync_args
*ap
)
259 struct vnode
*vp
= ap
->a_vp
;
260 struct fuse_mount
*fmp
= VFSTOFUSE(vp
->v_mount
);
261 struct fuse_ipc
*fip
;
262 struct fuse_fsync_in
*fsi
;
265 if (fuse_test_dead(fmp
))
268 if (fuse_test_nosys(fmp
, FUSE_FSYNC
))
271 if (vp
->v_type
== VDIR
)
276 fip
= fuse_ipc_get(fmp
, sizeof(*fsi
));
277 fsi
= fuse_ipc_fill(fip
, op
, VTOI(vp
)->ino
, NULL
);
278 fsi
->fh
= fuse_nfh(VTOI(vp
));
280 fsi
->fh
= fuse_fh(ap
->a_fp
);
281 fsi
->fsync_flags
= 1; /* datasync */
283 error
= fuse_ipc_tx(fip
);
288 vn_syncer_remove(vp
, 1);
289 vfsync(ap
->a_vp
, ap
->a_waitfor
, 1, NULL
, NULL
);
296 fuse_vop_getattr(struct vop_getattr_args
*ap
)
298 struct vnode
*vp
= ap
->a_vp
;
299 struct vattr
*vap
= ap
->a_vap
;
300 struct fuse_mount
*fmp
= VFSTOFUSE(vp
->v_mount
);
301 struct fuse_node
*fnp
= VTOI(vp
);
302 struct fuse_ipc
*fip
;
303 struct fuse_getattr_in
*fgi
;
304 struct fuse_attr_out
*fao
;
307 if (fuse_test_dead(fmp
))
310 if (fuse_test_nosys(fmp
, FUSE_GETATTR
))
313 fip
= fuse_ipc_get(fmp
, sizeof(*fgi
));
314 fgi
= fuse_ipc_fill(fip
, FUSE_GETATTR
, fnp
->ino
, NULL
);
316 /* this may be called before open when fh is 0 */
317 fgi
->getattr_flags
|= FUSE_GETATTR_FH
;
318 fgi
->fh
= fuse_nfh(fnp
);
320 fgi
->fh
= fuse_fh(ap
->a_fp
);
322 error
= fuse_ipc_tx(fip
);
326 if (error
== ENOTCONN
&& (vp
->v_flag
& VROOT
)) {
327 memset(vap
, 0, sizeof(*vap
));
328 vap
->va_type
= vp
->v_type
;
334 fao
= fuse_out_data(fip
);
335 mtx_lock(&fnp
->node_lock
);
336 fuse_set_attr(fnp
, &fao
->attr
);
337 memcpy(vap
, &fnp
->attr
, sizeof(*vap
));
340 //fao->attr_valid_nsec;
341 mtx_unlock(&fnp
->node_lock
);
345 if (vap
->va_type
!= vp
->v_type
)
352 fuse_vop_setattr(struct vop_setattr_args
*ap
)
354 struct vnode
*vp
= ap
->a_vp
;
355 struct vattr
*vap
= ap
->a_vap
;
356 struct fuse_mount
*fmp
= VFSTOFUSE(vp
->v_mount
);
357 struct fuse_node
*fnp
= VTOI(vp
);
358 struct fuse_ipc
*fip
;
359 struct fuse_setattr_in
*fsi
, arg
;
360 struct fuse_attr_out
*fao
;
364 if (fuse_test_dead(fmp
))
367 if (fuse_test_nosys(fmp
, FUSE_SETATTR
))
370 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
373 memset(&arg
, 0, sizeof(arg
));
374 mtx_lock(&fnp
->node_lock
);
376 if (!error
&& (vap
->va_flags
!= VNOVAL
)) {
377 mtx_unlock(&fnp
->node_lock
);
378 kflags
|= NOTE_ATTRIB
;
379 return EOPNOTSUPP
; /* XXX */
382 if (!error
&& (vap
->va_size
!= VNOVAL
)) {
383 if (vp
->v_type
== VDIR
) {
384 mtx_unlock(&fnp
->node_lock
);
387 if (vp
->v_type
== VREG
&&
388 (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)) {
389 mtx_unlock(&fnp
->node_lock
);
392 arg
.size
= vap
->va_size
;
393 arg
.valid
|= FATTR_SIZE
;
394 if (vap
->va_size
> fnp
->size
)
395 kflags
|= NOTE_WRITE
| NOTE_EXTEND
;
397 kflags
|= NOTE_WRITE
;
400 if (!error
&& (vap
->va_uid
!= (uid_t
)VNOVAL
||
401 vap
->va_gid
!= (gid_t
)VNOVAL
)) {
403 error
= vop_helper_chown(vp
, vap
->va_uid
, vap
->va_gid
,
404 ap
->a_cred
, &arg
.uid
, &arg
.gid
, &mode
);
405 arg
.valid
|= FATTR_UID
;
406 arg
.valid
|= FATTR_GID
;
407 kflags
|= NOTE_ATTRIB
;
410 if (!error
&& (vap
->va_mode
!= (mode_t
)VNOVAL
)) {
411 error
= vop_helper_chmod(vp
, vap
->va_mode
, ap
->a_cred
,
412 vap
->va_uid
, vap
->va_gid
, (mode_t
*)&arg
.mode
);
413 arg
.valid
|= FATTR_MODE
;
414 kflags
|= NOTE_ATTRIB
;
417 if (!error
&& (vap
->va_atime
.tv_sec
!= VNOVAL
&&
418 vap
->va_atime
.tv_nsec
!= VNOVAL
)) {
419 arg
.atime
= vap
->va_atime
.tv_sec
;
420 arg
.atimensec
= vap
->va_atime
.tv_nsec
;
421 arg
.valid
|= FATTR_ATIME
;
422 kflags
|= NOTE_ATTRIB
;
425 if (!error
&& (vap
->va_mtime
.tv_sec
!= VNOVAL
&&
426 vap
->va_mtime
.tv_nsec
!= VNOVAL
)) {
427 arg
.mtime
= vap
->va_mtime
.tv_sec
;
428 arg
.mtimensec
= vap
->va_mtime
.tv_nsec
;
429 arg
.valid
|= FATTR_MTIME
;
430 kflags
|= NOTE_ATTRIB
;
433 if (!error
&& (vap
->va_ctime
.tv_sec
!= VNOVAL
&&
434 vap
->va_ctime
.tv_nsec
!= VNOVAL
)) {
435 arg
.ctime
= vap
->va_ctime
.tv_sec
;
436 arg
.ctimensec
= vap
->va_ctime
.tv_nsec
;
437 arg
.valid
|= FATTR_CTIME
;
438 kflags
|= NOTE_ATTRIB
;
441 mtx_unlock(&fnp
->node_lock
);
448 fip
= fuse_ipc_get(fmp
, sizeof(*fsi
));
449 fsi
= fuse_ipc_fill(fip
, FUSE_SETATTR
, fnp
->ino
, ap
->a_cred
);
450 memcpy(fsi
, &arg
, sizeof(arg
));
452 fsi
->valid
|= FATTR_FH
;
453 fsi
->fh
= fuse_nfh(fnp
);
455 /* vn_open() may call VOP_SETATTR_FP() prior to VOP_OPEN(). */
456 if (!ap
->a_fp
->private_data
)
457 fuse_get_fh(ap
->a_fp
, 0); /* XXX */
458 fsi
->fh
= fuse_fh(ap
->a_fp
);
461 error
= fuse_ipc_tx(fip
);
465 fao
= fuse_out_data(fip
);
466 if (IFTOVT(fao
->attr
.mode
) != vp
->v_type
) {
470 mtx_lock(&fnp
->node_lock
);
471 fuse_set_attr(fnp
, &fao
->attr
);
474 //fao->attr_valid_nsec;
475 mtx_unlock(&fnp
->node_lock
);
478 fuse_knote(vp
, kflags
);
484 fuse_vop_nresolve(struct vop_nresolve_args
*ap
)
486 struct vnode
*dvp
= ap
->a_dvp
;
488 struct namecache
*ncp
= ap
->a_nch
->ncp
;
489 struct fuse_mount
*fmp
= VFSTOFUSE(dvp
->v_mount
);
490 struct fuse_node
*dfnp
= VTOI(dvp
);
491 struct fuse_ipc
*fip
;
492 struct fuse_entry_out
*feo
;
498 if (fuse_test_dead(fmp
))
501 if (fuse_test_nosys(fmp
, FUSE_LOOKUP
))
504 fip
= fuse_ipc_get(fmp
, ncp
->nc_nlen
+ 1);
505 p
= fuse_ipc_fill(fip
, FUSE_LOOKUP
, dfnp
->ino
, ap
->a_cred
);
507 memcpy(p
, ncp
->nc_name
, ncp
->nc_nlen
);
508 p
[ncp
->nc_nlen
] = '\0';
509 strlcpy(tmp
, p
, sizeof(tmp
));
511 error
= fuse_ipc_tx(fip
);
512 if (error
== ENOENT
) {
513 cache_setvp(ap
->a_nch
, NULL
);
514 fuse_dbg("lookup \"%s\" ENOENT\n", tmp
);
517 fuse_dbg("lookup \"%s\" error=%d\n", tmp
, error
);
521 feo
= fuse_out_data(fip
);
522 fuse_dbg("lookup \"%s\" ino=%ju/%ju\n", p
, feo
->nodeid
, feo
->attr
.ino
);
524 mode
= feo
->attr
.mode
;
527 else if (S_ISDIR(mode
))
529 else if (S_ISBLK(mode
))
531 else if (S_ISCHR(mode
))
533 else if (S_ISLNK(mode
))
535 else if (S_ISSOCK(mode
))
537 else if (S_ISFIFO(mode
))
542 error
= fuse_alloc_node(dfnp
, feo
->nodeid
, p
, strlen(p
), vtyp
, &vp
);
548 KKASSERT(vn_islocked(vp
));
551 cache_setvp(ap
->a_nch
, vp
);
558 //feo->entry_valid_nsec;
559 //feo->attr_valid_nsec;
567 fuse_vop_nlink(struct vop_nlink_args
*ap
)
569 struct vnode
*dvp
= ap
->a_dvp
;
570 struct vnode
*vp
= ap
->a_vp
;
571 struct namecache
*ncp
= ap
->a_nch
->ncp
;
572 struct fuse_mount
*fmp
= VFSTOFUSE(vp
->v_mount
);
573 struct fuse_node
*dfnp
= VTOI(dvp
);
574 struct fuse_node
*fnp
= VTOI(vp
);
575 struct fuse_dent
*fep
;
576 struct fuse_ipc
*fip
;
577 struct fuse_link_in
*fli
;
578 struct fuse_entry_out
*feo
;
582 if (fuse_test_dead(fmp
))
585 if (fuse_test_nosys(fmp
, FUSE_LINK
))
588 if (vp
->v_type
== VDIR
)
590 if (dvp
->v_mount
!= vp
->v_mount
)
592 if (fnp
->nlink
>= LINK_MAX
)
595 fip
= fuse_ipc_get(fmp
, sizeof(fli
) + ncp
->nc_nlen
+ 1);
596 fli
= fuse_ipc_fill(fip
, FUSE_LINK
, dfnp
->ino
, ap
->a_cred
);
597 fli
->oldnodeid
= fnp
->ino
;
599 p
= (char*)(fli
+ 1);
600 memcpy(p
, ncp
->nc_name
, ncp
->nc_nlen
);
601 p
[ncp
->nc_nlen
] = '\0';
603 error
= fuse_ipc_tx(fip
);
607 feo
= fuse_out_data(fip
);
608 if (IFTOVT(feo
->attr
.mode
) != vp
->v_type
) {
613 mtx_lock(&dfnp
->node_lock
);
614 mtx_lock(&fnp
->node_lock
);
615 fuse_dent_new(fnp
, p
, strlen(p
), &fep
);
616 fuse_dent_attach(dfnp
, fep
);
617 fuse_set_attr(fnp
, &feo
->attr
);
618 mtx_unlock(&fnp
->node_lock
);
619 mtx_unlock(&dfnp
->node_lock
);
621 cache_setunresolved(ap
->a_nch
);
622 cache_setvp(ap
->a_nch
, vp
);
623 fuse_knote(dvp
, NOTE_WRITE
);
624 fuse_knote(vp
, NOTE_LINK
);
631 //feo->entry_valid_nsec;
632 //feo->attr_valid_nsec;
640 fuse_vop_ncreate(struct vop_ncreate_args
*ap
)
642 struct vnode
*dvp
= ap
->a_dvp
;
644 struct namecache
*ncp
= ap
->a_nch
->ncp
;
645 struct fuse_mount
*fmp
= VFSTOFUSE(dvp
->v_mount
);
646 struct fuse_node
*dfnp
= VTOI(dvp
);
647 struct fuse_node
*fnp
;
648 struct fuse_ipc
*fip
;
649 struct fuse_create_in
*fci
;
650 struct fuse_entry_out
*feo
;
651 struct fuse_open_out
*foo
;
656 if (fuse_test_dead(fmp
))
659 if (fuse_test_nosys(fmp
, FUSE_CREATE
))
662 fip
= fuse_ipc_get(fmp
, sizeof(*fci
) + ncp
->nc_nlen
+ 1);
663 fci
= fuse_ipc_fill(fip
, FUSE_CREATE
, dfnp
->ino
, ap
->a_cred
);
664 fci
->flags
= OFLAGS(ap
->a_vap
->va_fuseflags
);
665 fci
->mode
= MAKEIMODE(ap
->a_vap
->va_type
, ap
->a_vap
->va_mode
);
668 fuse_dbg("flags=%X mode=%X\n", fci
->flags
, fci
->mode
);
670 p
= (char*)(fci
+ 1);
671 memcpy(p
, ncp
->nc_name
, ncp
->nc_nlen
);
672 p
[ncp
->nc_nlen
] = '\0';
674 error
= fuse_ipc_tx(fip
);
678 feo
= fuse_out_data(fip
);
679 foo
= (struct fuse_open_out
*)(feo
+ 1);
680 vtyp
= IFTOVT(feo
->attr
.mode
);
681 if (vtyp
!= VREG
&& vtyp
!= VSOCK
) {
686 error
= fuse_alloc_node(dfnp
, feo
->nodeid
, p
, strlen(p
), VREG
, &vp
);
692 KKASSERT(vn_islocked(vp
));
695 mtx_lock(&fnp
->node_lock
);
696 fuse_set_attr(fnp
, &feo
->attr
);
697 mtx_unlock(&fnp
->node_lock
);
699 cache_setunresolved(ap
->a_nch
);
700 cache_setvp(ap
->a_nch
, vp
);
702 fuse_knote(dvp
, NOTE_WRITE
);
708 //feo->entry_valid_nsec;
709 //feo->attr_valid_nsec;
719 fuse_vop_nmknod(struct vop_nmknod_args
*ap
)
721 struct vnode
*dvp
= ap
->a_dvp
;
723 struct namecache
*ncp
= ap
->a_nch
->ncp
;
724 struct fuse_mount
*fmp
= VFSTOFUSE(dvp
->v_mount
);
725 struct fuse_node
*dfnp
= VTOI(dvp
);
726 struct fuse_node
*fnp
;
727 struct fuse_ipc
*fip
;
728 struct fuse_mknod_in
*fmi
;
729 struct fuse_entry_out
*feo
;
734 if (fuse_test_dead(fmp
))
737 if (fuse_test_nosys(fmp
, FUSE_MKNOD
))
740 fip
= fuse_ipc_get(fmp
, sizeof(*fmi
) + ncp
->nc_nlen
+ 1);
741 fmi
= fuse_ipc_fill(fip
, FUSE_MKNOD
, dfnp
->ino
, ap
->a_cred
);
742 fmi
->mode
= MAKEIMODE(ap
->a_vap
->va_type
, ap
->a_vap
->va_mode
);
747 p
= (char*)(fmi
+ 1);
748 memcpy(p
, ncp
->nc_name
, ncp
->nc_nlen
);
749 p
[ncp
->nc_nlen
] = '\0';
751 error
= fuse_ipc_tx(fip
);
755 feo
= fuse_out_data(fip
);
756 vtyp
= IFTOVT(feo
->attr
.mode
);
757 if (vtyp
!= VBLK
&& vtyp
!= VCHR
&& vtyp
!= VFIFO
) {
762 error
= fuse_alloc_node(dfnp
, feo
->nodeid
, p
, strlen(p
),
763 ap
->a_vap
->va_type
, &vp
);
769 KKASSERT(vn_islocked(vp
));
772 mtx_lock(&fnp
->node_lock
);
773 fuse_set_attr(fnp
, &feo
->attr
);
774 mtx_unlock(&fnp
->node_lock
);
776 cache_setunresolved(ap
->a_nch
);
777 cache_setvp(ap
->a_nch
, vp
);
779 fuse_knote(dvp
, NOTE_WRITE
);
785 //feo->entry_valid_nsec;
786 //feo->attr_valid_nsec;
794 fuse_vop_nremove(struct vop_nremove_args
*ap
)
796 struct vnode
*dvp
= ap
->a_dvp
;
798 struct namecache
*ncp
= ap
->a_nch
->ncp
;
799 struct fuse_mount
*fmp
= VFSTOFUSE(dvp
->v_mount
);
800 struct fuse_node
*dfnp
= VTOI(dvp
);
801 struct fuse_node
*fnp
;
802 struct fuse_dent
*fep
;
803 struct fuse_ipc
*fip
;
807 if (fuse_test_dead(fmp
))
810 if (fuse_test_nosys(fmp
, FUSE_UNLINK
))
813 error
= cache_vget(ap
->a_nch
, ap
->a_cred
, LK_SHARED
, &vp
);
814 KKASSERT(vp
->v_mount
== dvp
->v_mount
);
815 KKASSERT(!error
); /* from tmpfs */
818 fip
= fuse_ipc_get(fmp
, ncp
->nc_nlen
+ 1);
819 p
= fuse_ipc_fill(fip
, FUSE_UNLINK
, dfnp
->ino
, ap
->a_cred
);
821 memcpy(p
, ncp
->nc_name
, ncp
->nc_nlen
);
822 p
[ncp
->nc_nlen
] = '\0';
824 error
= fuse_ipc_tx(fip
);
831 mtx_lock(&dfnp
->node_lock
);
832 mtx_lock(&fnp
->node_lock
);
833 error
= fuse_dent_find(dfnp
, p
, strlen(p
), &fep
);
834 if (error
== ENOENT
) {
835 mtx_unlock(&fnp
->node_lock
);
836 mtx_unlock(&dfnp
->node_lock
);
841 fuse_dent_detach(dfnp
, fep
);
843 mtx_unlock(&fnp
->node_lock
);
844 mtx_unlock(&dfnp
->node_lock
);
846 cache_unlink(ap
->a_nch
);
847 fuse_knote(dvp
, NOTE_WRITE
);
848 fuse_knote(vp
, NOTE_DELETE
);
857 fuse_vop_nmkdir(struct vop_nmkdir_args
*ap
)
859 struct vnode
*dvp
= ap
->a_dvp
;
861 struct namecache
*ncp
= ap
->a_nch
->ncp
;
862 struct fuse_mount
*fmp
= VFSTOFUSE(dvp
->v_mount
);
863 struct fuse_node
*dfnp
= VTOI(dvp
);
864 struct fuse_node
*fnp
;
865 struct fuse_ipc
*fip
;
866 struct fuse_mkdir_in
*fmi
;
867 struct fuse_entry_out
*feo
;
871 if (fuse_test_dead(fmp
))
874 if (fuse_test_nosys(fmp
, FUSE_MKDIR
))
877 fip
= fuse_ipc_get(fmp
, sizeof(*fmi
) + ncp
->nc_nlen
+ 1);
878 fmi
= fuse_ipc_fill(fip
, FUSE_MKDIR
, dfnp
->ino
, ap
->a_cred
);
879 fmi
->mode
= MAKEIMODE(ap
->a_vap
->va_type
, ap
->a_vap
->va_mode
);
881 p
= (char*)(fmi
+ 1);
882 memcpy(p
, ncp
->nc_name
, ncp
->nc_nlen
);
883 p
[ncp
->nc_nlen
] = '\0';
885 error
= fuse_ipc_tx(fip
);
889 feo
= fuse_out_data(fip
);
890 if (IFTOVT(feo
->attr
.mode
) != VDIR
) {
895 error
= fuse_alloc_node(dfnp
, feo
->nodeid
, p
, strlen(p
), VDIR
, &vp
);
901 KKASSERT(vn_islocked(vp
));
904 mtx_lock(&fnp
->node_lock
);
905 fuse_set_attr(fnp
, &feo
->attr
);
906 mtx_unlock(&fnp
->node_lock
);
908 cache_setunresolved(ap
->a_nch
);
909 cache_setvp(ap
->a_nch
, vp
);
911 fuse_knote(dvp
, NOTE_WRITE
| NOTE_LINK
);
917 //feo->entry_valid_nsec;
918 //feo->attr_valid_nsec;
926 fuse_vop_nrmdir(struct vop_nrmdir_args
*ap
)
928 struct vnode
*dvp
= ap
->a_dvp
;
930 struct namecache
*ncp
= ap
->a_nch
->ncp
;
931 struct fuse_mount
*fmp
= VFSTOFUSE(dvp
->v_mount
);
932 struct fuse_node
*dfnp
= VTOI(dvp
);
933 struct fuse_node
*fnp
;
934 struct fuse_dent
*fep
;
935 struct fuse_ipc
*fip
;
939 if (fuse_test_dead(fmp
))
942 if (fuse_test_nosys(fmp
, FUSE_RMDIR
))
945 error
= cache_vget(ap
->a_nch
, ap
->a_cred
, LK_SHARED
, &vp
);
946 KKASSERT(vp
->v_mount
== dvp
->v_mount
);
947 KKASSERT(!error
); /* from tmpfs */
950 fip
= fuse_ipc_get(fmp
, ncp
->nc_nlen
+ 1);
951 p
= fuse_ipc_fill(fip
, FUSE_RMDIR
, dfnp
->ino
, ap
->a_cred
);
953 memcpy(p
, ncp
->nc_name
, ncp
->nc_nlen
);
954 p
[ncp
->nc_nlen
] = '\0';
956 error
= fuse_ipc_tx(fip
);
963 mtx_lock(&dfnp
->node_lock
);
964 mtx_lock(&fnp
->node_lock
);
965 error
= fuse_dent_find(dfnp
, p
, strlen(p
), &fep
);
966 if (error
== ENOENT
) {
967 mtx_unlock(&fnp
->node_lock
);
968 mtx_unlock(&dfnp
->node_lock
);
973 fuse_dent_detach(dfnp
, fep
);
975 mtx_unlock(&fnp
->node_lock
);
976 mtx_unlock(&dfnp
->node_lock
);
978 cache_unlink(ap
->a_nch
);
979 fuse_knote(dvp
, NOTE_WRITE
| NOTE_LINK
);
988 fuse_vop_pathconf(struct vop_pathconf_args
*ap
)
990 switch (ap
->a_name
) {
991 case _PC_FILESIZEBITS
:
998 return vop_stdpathconf(ap
);
1005 fuse_vop_readdir(struct vop_readdir_args
*ap
)
1007 struct vnode
*vp
= ap
->a_vp
;
1008 struct uio
*uio
= ap
->a_uio
;
1009 struct fuse_mount
*fmp
= VFSTOFUSE(vp
->v_mount
);
1010 struct fuse_ipc
*fip
;
1011 struct fuse_read_in
*fri
;
1014 off_t cur_offset
= 0;
1017 if (fuse_test_dead(fmp
))
1020 if (fuse_test_nosys(fmp
, FUSE_READDIR
))
1023 fip
= fuse_ipc_get(fmp
, sizeof(*fri
));
1024 fri
= fuse_ipc_fill(fip
, FUSE_READDIR
, VTOI(vp
)->ino
, ap
->a_cred
);
1025 fri
->fh
= fuse_nfh(VTOI(vp
));
1027 fri
->fh
= fuse_fh(ap
->a_fp
);
1030 * XXX This needs to be large enough to read all entries at once.
1031 * FUSE filesystems typically just opendir/readdir and return entries.
1033 fri
->size
= FUSE_BLKSIZE
* 10;
1035 //fri->read_flags = ...;
1036 //fri->lock_owner = ...;
1039 error
= fuse_ipc_tx(fip
);
1043 buf
= fuse_out_data(fip
);
1044 len
= fuse_out_data_size(fip
);
1047 const struct fuse_dirent
*fde
;
1050 fuse_dbg("uio_offset=%ju uio_resid=%ju\n",
1051 uio
->uio_offset
, uio
->uio_resid
);
1053 if (len
< FUSE_NAME_OFFSET
) {
1058 if (uio
->uio_resid
< FUSE_NAME_OFFSET
)
1061 fde
= (const struct fuse_dirent
*)buf
;
1062 if (!fde
->namelen
) {
1066 freclen
= FUSE_DIRENT_SIZE(fde
);
1070 * getdirentries(2) in sys/kern/vfs_syscalls.c
1071 * readdir(3) in lib/libc/gen/readdir.c
1073 if (cur_offset
>= uio
->uio_offset
) {
1075 if (vop_write_dirent(&error
, uio
, fde
->ino
, fde
->type
,
1076 fde
->namelen
, fde
->name
))
1080 fuse_dbg("ino=%ju type=%d name=%s len=%u\n",
1081 fde
->ino
, fde
->type
, fde
->name
, fde
->namelen
);
1084 cur_offset
+= _DIRENT_RECLEN(fde
->namelen
);
1094 fuse_vop_readlink(struct vop_readlink_args
*ap
)
1096 struct vnode
*vp
= ap
->a_vp
;
1097 struct fuse_mount
*fmp
= VFSTOFUSE(vp
->v_mount
);
1098 struct fuse_ipc
*fip
;
1101 if (fuse_test_dead(fmp
))
1104 if (fuse_test_nosys(fmp
, FUSE_READLINK
))
1107 if (vp
->v_type
!= VLNK
)
1110 fip
= fuse_ipc_get(fmp
, 0);
1111 fuse_ipc_fill(fip
, FUSE_READLINK
, VTOI(vp
)->ino
, ap
->a_cred
);
1113 error
= fuse_ipc_tx(fip
);
1117 error
= uiomove(fuse_out_data(fip
), fuse_out_data_size(fip
), ap
->a_uio
);
1125 fuse_vop_nrename(struct vop_nrename_args
*ap
)
1127 struct namecache
*fncp
= ap
->a_fnch
->ncp
;
1128 struct namecache
*tncp
= ap
->a_tnch
->ncp
;
1129 struct vnode
*fdvp
= ap
->a_fdvp
;
1130 struct vnode
*fvp
= fncp
->nc_vp
;
1131 struct vnode
*tdvp
= ap
->a_tdvp
;
1133 struct fuse_mount
*fmp
= VFSTOFUSE(fdvp
->v_mount
);
1134 struct fuse_node
*fdfnp
= VTOI(fdvp
);
1135 struct fuse_node
*ffnp
= VTOI(fvp
);
1136 struct fuse_node
*tdfnp
= VTOI(tdvp
);
1137 struct fuse_node
*tfnp
;
1138 struct fuse_dent
*ffep
;
1139 struct fuse_dent
*tfep
;
1140 struct fuse_ipc
*fip
;
1141 struct fuse_rename_in
*fri
;
1142 char *p
, *newname
, *oldname
;
1145 KKASSERT(fdvp
->v_mount
== fvp
->v_mount
);
1147 if (fuse_test_dead(fmp
))
1150 if (fuse_test_nosys(fmp
, FUSE_RENAME
))
1153 error
= cache_vget(ap
->a_tnch
, ap
->a_cred
, LK_SHARED
, &tvp
);
1160 /* Disallow cross-device renames.
1161 * Why isn't this done by the caller? */
1162 if (fvp
->v_mount
!= tdvp
->v_mount
||
1163 (tvp
&& fvp
->v_mount
!= tvp
->v_mount
)) {
1172 error
= fuse_dent_find(fdfnp
, fncp
->nc_name
, fncp
->nc_nlen
, &ffep
);
1173 if (error
== ENOENT
)
1175 KKASSERT(ffep
->fnp
== ffnp
);
1179 if (ffnp
->type
== VDIR
&& tfnp
->type
== VDIR
) {
1180 if (!RB_EMPTY(&tfnp
->dent_head
)) {
1184 } else if (ffnp
->type
== VDIR
&& tfnp
->type
!= VDIR
) {
1187 } else if (ffnp
->type
!= VDIR
&& tfnp
->type
== VDIR
) {
1191 KKASSERT(ffnp
->type
!= VDIR
&& tfnp
->type
!= VDIR
);
1194 fip
= fuse_ipc_get(fmp
,
1195 sizeof(*fri
) + fncp
->nc_nlen
+ tncp
->nc_nlen
+ 2);
1196 /* There is also fuse_rename2_in with flags. */
1197 fri
= fuse_ipc_fill(fip
, FUSE_RENAME
, fdfnp
->ino
, ap
->a_cred
);
1198 fri
->newdir
= tdfnp
->ino
;
1200 p
= (char*)(fri
+ 1);
1201 memcpy(p
, fncp
->nc_name
, fncp
->nc_nlen
);
1202 p
[fncp
->nc_nlen
] = '\0';
1203 memcpy(p
+ fncp
->nc_nlen
+ 1, tncp
->nc_name
, tncp
->nc_nlen
);
1204 p
[fncp
->nc_nlen
+ 1 + tncp
->nc_nlen
] = '\0';
1206 error
= fuse_ipc_tx(fip
);
1211 if (fncp
->nc_nlen
!= tncp
->nc_nlen
||
1212 memcmp(fncp
->nc_name
, tncp
->nc_name
, fncp
->nc_nlen
)) {
1213 newname
= kmalloc(tncp
->nc_nlen
+ 1, M_TEMP
, M_WAITOK
| M_ZERO
);
1215 memcpy(newname
, tncp
->nc_name
, tncp
->nc_nlen
);
1216 newname
[tncp
->nc_nlen
] = '\0';
1217 fuse_dbg("newname=\"%s\"\n", newname
);
1221 mtx_lock(&tdfnp
->node_lock
);
1222 mtx_lock(&fdfnp
->node_lock
);
1223 mtx_lock(&ffnp
->node_lock
);
1225 fuse_dbg("detach from_dent=\"%s\"\n", ffep
->name
);
1226 fuse_dent_detach(fdfnp
, ffep
);
1229 oldname
= ffep
->name
;
1230 ffep
->name
= newname
;
1235 mtx_lock(&tfnp
->node_lock
);
1236 error
= fuse_dent_find(tdfnp
, tncp
->nc_name
, tncp
->nc_nlen
,
1239 fuse_dbg("detach/free to_dent=\"%s\"\n", tfep
->name
);
1240 fuse_dent_detach(tdfnp
, tfep
);
1241 fuse_dent_free(tfep
);
1242 mtx_unlock(&tfnp
->node_lock
);
1243 fuse_knote(tdvp
, NOTE_DELETE
);
1246 fuse_dbg("attach from_dent=\"%s\"\n", ffep
->name
);
1247 fuse_dent_attach(tdfnp
, ffep
);
1249 mtx_unlock(&ffnp
->node_lock
);
1250 mtx_unlock(&fdfnp
->node_lock
);
1251 mtx_unlock(&tdfnp
->node_lock
);
1254 kfree(newname
, M_TEMP
);
1256 cache_rename(ap
->a_fnch
, ap
->a_tnch
);
1257 fuse_knote(fdvp
, NOTE_WRITE
);
1258 fuse_knote(tdvp
, NOTE_WRITE
);
1259 fuse_knote(fvp
, NOTE_RENAME
);
1268 fuse_vop_nsymlink(struct vop_nsymlink_args
*ap
)
1270 struct vnode
*dvp
= ap
->a_dvp
;
1272 struct namecache
*ncp
= ap
->a_nch
->ncp
;
1273 struct fuse_mount
*fmp
= VFSTOFUSE(dvp
->v_mount
);
1274 struct fuse_node
*dfnp
= VTOI(dvp
);
1275 struct fuse_node
*fnp
;
1276 struct fuse_ipc
*fip
;
1277 struct fuse_entry_out
*feo
;
1281 if (fuse_test_dead(fmp
))
1284 if (fuse_test_nosys(fmp
, FUSE_SYMLINK
))
1287 fip
= fuse_ipc_get(fmp
, strlen(ap
->a_target
) + 1 + ncp
->nc_nlen
+ 1);
1288 p
= fuse_ipc_fill(fip
, FUSE_SYMLINK
, dfnp
->ino
, ap
->a_cred
);
1290 memcpy(p
, ncp
->nc_name
, ncp
->nc_nlen
);
1291 p
[ncp
->nc_nlen
] = '\0';
1292 memcpy(p
+ ncp
->nc_nlen
+ 1, ap
->a_target
, strlen(ap
->a_target
) + 1);
1294 error
= fuse_ipc_tx(fip
);
1298 feo
= fuse_out_data(fip
);
1299 if (IFTOVT(feo
->attr
.mode
) != VLNK
) {
1304 error
= fuse_alloc_node(dfnp
, feo
->nodeid
, p
, strlen(p
), VLNK
, &vp
);
1310 KKASSERT(vn_islocked(vp
));
1313 mtx_lock(&fnp
->node_lock
);
1314 fuse_set_attr(fnp
, &feo
->attr
);
1315 mtx_unlock(&fnp
->node_lock
);
1317 cache_setunresolved(ap
->a_nch
);
1318 cache_setvp(ap
->a_nch
, vp
);
1320 fuse_knote(vp
, NOTE_WRITE
);
1326 //feo->entry_valid_nsec;
1327 //feo->attr_valid_nsec;
1335 fuse_vop_read(struct vop_read_args
*ap
)
1337 struct vnode
*vp
= ap
->a_vp
;
1338 struct uio
*uio
= ap
->a_uio
;
1339 struct fuse_mount
*fmp
= VFSTOFUSE(vp
->v_mount
);
1341 fuse_dbg("ino=%ju ioflag=%x\n", VTOI(vp
)->ino
, ap
->a_ioflag
);
1343 if (fuse_test_dead(fmp
))
1346 if (fuse_test_nosys(fmp
, FUSE_READ
))
1349 if (!uio
->uio_resid
)
1352 return fuse_read(ap
);
1356 fuse_vop_write(struct vop_write_args
*ap
)
1358 struct vnode
*vp
= ap
->a_vp
;
1359 struct uio
*uio
= ap
->a_uio
;
1360 struct fuse_mount
*fmp
= VFSTOFUSE(vp
->v_mount
);
1362 fuse_dbg("ino=%ju ioflag=%x\n", VTOI(vp
)->ino
, ap
->a_ioflag
);
1363 return EOPNOTSUPP
; /* XXX disabled */
1365 if (fuse_test_dead(fmp
))
1368 if (fuse_test_nosys(fmp
, FUSE_WRITE
))
1371 if (!uio
->uio_resid
)
1374 if (ap
->a_ioflag
& IO_DIRECT
)
1375 return fuse_dio_write(ap
);
1377 return fuse_write(ap
);
1381 fuse_vop_strategy(struct vop_strategy_args
*ap
)
1383 struct bio
*bio
= ap
->a_bio
;
1384 struct buf
*bp
= bio
->bio_buf
;
1386 fuse_dbg("ino=%ju b_cmd=%d\n", VTOI(ap
->a_vp
)->ino
, bp
->b_cmd
);
1396 fuse_bmap(struct vop_bmap_args
*ap
)
1398 fuse_dbg("ino=%ju a_cmd=%d a_loffset=%ju\n",
1399 VTOI(ap
->a_vp
)->ino
, ap
->a_cmd
, ap
->a_loffset
);
1405 fuse_vop_print(struct vop_print_args
*ap
)
1407 struct fuse_node
*fnp
= VTOI(ap
->a_vp
);
1409 fuse_print("tag VT_FUSE, node %p, ino %ju, parent ino %ju\n",
1410 fnp
, VTOI(ap
->a_vp
)->ino
, VTOI(fnp
->pfnp
->vp
)->ino
);
1416 fuse_vop_inactive(struct vop_inactive_args
*ap
)
1418 struct vnode
*vp
= ap
->a_vp
;
1419 struct mount
*mp
= vp
->v_mount
;
1420 struct fuse_node
*fnp
= VTOI(vp
);
1422 lwkt_gettoken(&mp
->mnt_token
);
1425 lwkt_reltoken(&mp
->mnt_token
);
1429 fuse_dbg("ino=%ju nlink=%d\n", fnp
->ino
, fnp
->nlink
);
1430 vinvalbuf(vp
, V_SAVE
, 0, 0);
1431 lwkt_reltoken(&mp
->mnt_token
);
1437 fuse_vop_reclaim(struct vop_reclaim_args
*ap
)
1439 struct vnode
*vp
= ap
->a_vp
;
1440 struct mount
*mp
= vp
->v_mount
;
1441 struct fuse_node
*fnp
= VTOI(vp
);
1443 lwkt_gettoken(&mp
->mnt_token
);
1445 fuse_dbg("ino=%ju\n", fnp
->ino
);
1446 fuse_node_free(fnp
);
1449 lwkt_reltoken(&mp
->mnt_token
);
1455 fuse_vop_mountctl(struct vop_mountctl_args
*ap
)
1460 mp
= ap
->a_head
.a_ops
->head
.vv_mount
;
1461 lwkt_gettoken(&mp
->mnt_token
);
1464 //case MOUNTCTL_MOUNTFLAGS:
1468 res
= vop_stdmountctl(ap
);
1472 lwkt_reltoken(&mp
->mnt_token
);
1476 static void filt_fusedetach(struct knote
*);
1477 static int filt_fuseread(struct knote
*, long);
1478 static int filt_fusewrite(struct knote
*, long);
1479 static int filt_fusevnode(struct knote
*, long);
1481 static struct filterops fuseread_filtops
=
1482 { FILTEROP_ISFD
| FILTEROP_MPSAFE
,
1483 NULL
, filt_fusedetach
, filt_fuseread
};
1484 static struct filterops fusewrite_filtops
=
1485 { FILTEROP_ISFD
| FILTEROP_MPSAFE
,
1486 NULL
, filt_fusedetach
, filt_fusewrite
};
1487 static struct filterops fusevnode_filtops
=
1488 { FILTEROP_ISFD
| FILTEROP_MPSAFE
,
1489 NULL
, filt_fusedetach
, filt_fusevnode
};
1492 fuse_kqfilter(struct vop_kqfilter_args
*ap
)
1494 struct vnode
*vp
= ap
->a_vp
;
1495 struct knote
*kn
= ap
->a_kn
;
1497 switch (kn
->kn_filter
) {
1499 kn
->kn_fop
= &fuseread_filtops
;
1502 kn
->kn_fop
= &fusewrite_filtops
;
1505 kn
->kn_fop
= &fusevnode_filtops
;
1511 kn
->kn_hook
= (caddr_t
)vp
;
1512 knote_insert(&vp
->v_pollinfo
.vpi_kqinfo
.ki_note
, kn
);
1518 filt_fusedetach(struct knote
*kn
)
1520 struct vnode
*vp
= (void*)kn
->kn_hook
;
1522 knote_remove(&vp
->v_pollinfo
.vpi_kqinfo
.ki_note
, kn
);
1526 filt_fuseread(struct knote
*kn
, long hint
)
1528 struct vnode
*vp
= (void*)kn
->kn_hook
;
1529 struct fuse_node
*fnp
= VTOI(vp
);
1532 if (hint
== NOTE_REVOKE
) {
1533 kn
->kn_flags
|= (EV_EOF
| EV_NODATA
| EV_ONESHOT
);
1538 * Interlock against MP races when performing this function.
1540 mtx_lock(&fnp
->node_lock
);
1541 off
= fnp
->size
- kn
->kn_fp
->f_offset
;
1542 kn
->kn_data
= (off
< INTPTR_MAX
) ? off
: INTPTR_MAX
;
1543 if (kn
->kn_sfflags
& NOTE_OLDAPI
) {
1544 mtx_unlock(&fnp
->node_lock
);
1548 kn
->kn_data
= (off
< INTPTR_MAX
) ? off
: INTPTR_MAX
;
1549 mtx_unlock(&fnp
->node_lock
);
1551 return kn
->kn_data
!= 0;
1555 filt_fusewrite(struct knote
*kn
, long hint
)
1557 if (hint
== NOTE_REVOKE
)
1558 kn
->kn_flags
|= (EV_EOF
| EV_NODATA
| EV_ONESHOT
);
1565 filt_fusevnode(struct knote
*kn
, long hint
)
1567 if (kn
->kn_sfflags
& hint
)
1568 kn
->kn_fflags
|= hint
;
1569 if (hint
== NOTE_REVOKE
) {
1570 kn
->kn_flags
|= (EV_EOF
| EV_NODATA
);
1574 return kn
->kn_fflags
!= 0;
1578 fuse_vop_getpages(struct vop_getpages_args
*ap
)
1580 if (!ap
->a_vp
->v_mount
)
1581 return VM_PAGER_BAD
;
1583 return vnode_pager_generic_getpages(ap
->a_vp
, ap
->a_m
, ap
->a_count
,
1584 ap
->a_reqpage
, ap
->a_seqaccess
);
1588 fuse_vop_putpages(struct vop_putpages_args
*ap
)
1590 if (!ap
->a_vp
->v_mount
)
1591 return VM_PAGER_BAD
;
1593 return vnode_pager_generic_putpages(ap
->a_vp
, ap
->a_m
, ap
->a_count
,
1594 ap
->a_flags
, ap
->a_rtvals
);
1597 struct vop_ops fuse_vnode_vops
= {
1598 .vop_default
= vop_defaultop
,
1599 .vop_access
= fuse_vop_access
,
1600 .vop_open
= fuse_vop_open
,
1601 .vop_close
= fuse_vop_close
,
1602 .vop_fsync
= fuse_vop_fsync
,
1603 .vop_getattr
= fuse_vop_getattr
,
1604 .vop_setattr
= fuse_vop_setattr
,
1605 .vop_nresolve
= fuse_vop_nresolve
,
1606 //.vop_nlookupdotdot = fuse_nlookupdotdot,
1607 .vop_nlink
= fuse_vop_nlink
,
1608 .vop_ncreate
= fuse_vop_ncreate
,
1609 .vop_nmknod
= fuse_vop_nmknod
,
1610 .vop_nremove
= fuse_vop_nremove
,
1611 .vop_nmkdir
= fuse_vop_nmkdir
,
1612 .vop_nrmdir
= fuse_vop_nrmdir
,
1613 .vop_pathconf
= fuse_vop_pathconf
,
1614 .vop_readdir
= fuse_vop_readdir
,
1615 .vop_readlink
= fuse_vop_readlink
,
1616 .vop_nrename
= fuse_vop_nrename
,
1617 .vop_nsymlink
= fuse_vop_nsymlink
,
1618 .vop_read
= fuse_vop_read
,
1619 .vop_write
= fuse_vop_write
,
1620 .vop_strategy
= fuse_vop_strategy
,
1621 .vop_bmap
= fuse_bmap
,
1622 //.vop_advlock = fuse_advlock,
1623 .vop_print
= fuse_vop_print
,
1624 .vop_inactive
= fuse_vop_inactive
,
1625 .vop_reclaim
= fuse_vop_reclaim
,
1626 .vop_mountctl
= fuse_vop_mountctl
,
1627 .vop_kqfilter
= fuse_kqfilter
,
1628 .vop_getpages
= fuse_vop_getpages
,
1629 .vop_putpages
= fuse_vop_putpages
,
1632 struct vop_ops fuse_spec_vops
= {
1633 .vop_default
= vop_defaultop
,
1634 .vop_access
= fuse_vop_access
,
1635 .vop_close
= fuse_vop_close
,
1636 .vop_fsync
= fuse_vop_fsync
,
1637 .vop_getattr
= fuse_vop_getattr
,
1638 .vop_setattr
= fuse_vop_setattr
,
1639 .vop_read
= vop_stdnoread
,
1640 .vop_write
= vop_stdnowrite
,
1641 //.vop_markatime = fuse_vop_markatime,
1642 .vop_print
= fuse_vop_print
,
1643 .vop_inactive
= fuse_vop_inactive
,
1644 .vop_reclaim
= fuse_vop_reclaim
,