kernel/vm: Rename *_putpages()'s 'sync' argument to 'flags'.
[dragonfly.git] / sys / vfs / fuse / fuse_vnops.c
blobeb0b32ed752d4111e60e4c2f5f70ad6b85db7b93
1 /*-
2 * Copyright (c) 2019 Tomohiro Kusumi <tkusumi@netbsd.org>
3 * Copyright (c) 2019 The DragonFly Project
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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
25 * SUCH DAMAGE.
28 #include "fuse.h"
30 #include <sys/fcntl.h>
31 #include <sys/dirent.h>
32 #include <sys/uio.h>
33 #include <sys/mountctl.h>
34 #include <vm/vm_pager.h>
35 #include <vm/vnode_pager.h>
37 static int
38 fuse_set_attr(struct fuse_node *fnp, struct fuse_attr *fat)
40 struct vattr *vap = &fnp->attr;
41 int error = 0;
43 vattr_null(vap);
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 */
50 vap->va_nlink = 1;
51 else
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;
66 vap->va_flags = 0;
67 vap->va_gen = VNOVAL;
68 vap->va_vaflags = 0;
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);
81 return error;
84 static int
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);
90 struct fuse_ipc *fip;
91 struct fuse_access_in *fai;
92 uint32_t mask;
93 int error;
95 if (fuse_test_dead(fmp))
96 return 0;
98 if (fuse_test_nosys(fmp, FUSE_ACCESS))
99 return 0;
101 switch (vp->v_type) {
102 case VDIR:
103 case VLNK:
104 case VREG:
105 if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY))
106 return EROFS;
107 break;
108 case VBLK:
109 case VCHR:
110 case VSOCK:
111 case VFIFO:
112 break;
113 default:
114 return EINVAL;
117 mask = F_OK;
118 if (mode & VEXEC)
119 mask |= X_OK;
120 if (mode & VWRITE)
121 mask |= W_OK;
122 if (mode & VREAD)
123 mask |= R_OK;
125 fip = fuse_ipc_get(fmp, sizeof(*fai));
126 fai = fuse_ipc_fill(fip, FUSE_ACCESS, VTOI(vp)->ino, ap->a_cred);
127 fai->mask = mask;
129 error = fuse_ipc_tx(fip);
130 if (error) {
131 if (error == ENOSYS)
132 error = 0;
133 if (error == ENOTCONN && (vp->v_flag & VROOT))
134 error = 0;
135 return error;
138 fuse_ipc_put(fip);
140 return 0;
143 static int
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;
152 int error, op;
154 if (fuse_test_dead(fmp))
155 return ENOTCONN;
157 if (fuse_test_nosys(fmp, FUSE_OPEN))
158 return EOPNOTSUPP;
160 if (vp->v_type == VDIR)
161 op = FUSE_OPENDIR;
162 else
163 op = FUSE_OPEN;
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);
175 if (error)
176 return error;
178 /* XXX unused */
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)
189 fnp->closed = false;
190 fuse_get_nfh(VTOI(vp), foo->fh);
191 if (ap->a_fp) {
192 #if 1
193 fuse_get_fh(ap->a_fp, foo->fh);
194 #else
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);
198 else {
199 uint64_t *fhp = ap->a_fp->private_data;
200 *fhp = foo->fh;
202 #endif
205 fuse_ipc_put(fip);
207 return vop_stdopen(ap);
210 static int
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;
218 int error, op;
220 if (fuse_test_dead(fmp))
221 return 0;
223 if (fuse_test_nosys(fmp, FUSE_RELEASE) ||
224 fuse_test_nosys(fmp, FUSE_RELEASEDIR))
225 return EOPNOTSUPP;
227 if (vp->v_type == VDIR)
228 op = FUSE_RELEASEDIR;
229 else
230 op = FUSE_RELEASE;
232 fip = fuse_ipc_get(fmp, sizeof(*fri));
233 fri = fuse_ipc_fill(fip, op, fnp->ino, NULL);
234 /* unused */
235 //fri->flags = ...;
236 //fri->release_flags = ...;
237 //fri->lock_owner = ...;
238 fri->fh = fuse_nfh(VTOI(vp));
239 if (ap->a_fp)
240 fri->fh = fuse_fh(ap->a_fp);
242 error = fuse_ipc_tx(fip);
243 if (error)
244 return error;
246 fuse_ipc_put(fip);
248 fnp->closed = true;
249 fuse_put_nfh(VTOI(vp));
250 if (ap->a_fp)
251 fuse_put_fh(ap->a_fp);
253 return vop_stdclose(ap);
256 static int
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;
263 int error, op;
265 if (fuse_test_dead(fmp))
266 return 0;
268 if (fuse_test_nosys(fmp, FUSE_FSYNC))
269 return 0;
271 if (vp->v_type == VDIR)
272 op = FUSE_FSYNCDIR;
273 else
274 op = FUSE_FSYNC;
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));
279 if (ap->a_fp)
280 fsi->fh = fuse_fh(ap->a_fp);
281 fsi->fsync_flags = 1; /* datasync */
283 error = fuse_ipc_tx(fip);
284 if (error)
285 return error;
286 fuse_ipc_put(fip);
288 vn_syncer_remove(vp, 1);
289 vfsync(ap->a_vp, ap->a_waitfor, 1, NULL, NULL);
290 vclrisdirty(vp);
292 return 0;
295 static int
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;
305 int error;
307 if (fuse_test_dead(fmp))
308 return 0;
310 if (fuse_test_nosys(fmp, FUSE_GETATTR))
311 return 0;
313 fip = fuse_ipc_get(fmp, sizeof(*fgi));
314 fgi = fuse_ipc_fill(fip, FUSE_GETATTR, fnp->ino, NULL);
315 #if 0
316 /* this may be called before open when fh is 0 */
317 fgi->getattr_flags |= FUSE_GETATTR_FH;
318 fgi->fh = fuse_nfh(fnp);
319 if (ap->a_fp)
320 fgi->fh = fuse_fh(ap->a_fp);
321 #endif
322 error = fuse_ipc_tx(fip);
323 if (error) {
324 if (error == ENOSYS)
325 error = 0;
326 if (error == ENOTCONN && (vp->v_flag & VROOT)) {
327 memset(vap, 0, sizeof(*vap));
328 vap->va_type = vp->v_type;
329 error = 0;
331 return error;
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));
338 /* unused */
339 //fao->attr_valid;
340 //fao->attr_valid_nsec;
341 mtx_unlock(&fnp->node_lock);
343 fuse_ipc_put(fip);
345 if (vap->va_type != vp->v_type)
346 return EINVAL;
348 return 0;
351 static int
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;
361 int kflags = 0;
362 int error = 0;
364 if (fuse_test_dead(fmp))
365 return 0;
367 if (fuse_test_nosys(fmp, FUSE_SETATTR))
368 return 0;
370 if (vp->v_mount->mnt_flag & MNT_RDONLY)
371 return EROFS;
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);
385 return EISDIR;
387 if (vp->v_type == VREG &&
388 (vp->v_mount->mnt_flag & MNT_RDONLY)) {
389 mtx_unlock(&fnp->node_lock);
390 return EROFS;
392 arg.size = vap->va_size;
393 arg.valid |= FATTR_SIZE;
394 if (vap->va_size > fnp->size)
395 kflags |= NOTE_WRITE | NOTE_EXTEND;
396 else
397 kflags |= NOTE_WRITE;
400 if (!error && (vap->va_uid != (uid_t)VNOVAL ||
401 vap->va_gid != (gid_t)VNOVAL)) {
402 mode_t mode;
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);
443 if (error)
444 return error;
445 if (!arg.valid)
446 return 0;
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));
451 #if 0
452 fsi->valid |= FATTR_FH;
453 fsi->fh = fuse_nfh(fnp);
454 if (ap->a_fp) {
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);
460 #endif
461 error = fuse_ipc_tx(fip);
462 if (error)
463 return error;
465 fao = fuse_out_data(fip);
466 if (IFTOVT(fao->attr.mode) != vp->v_type) {
467 fuse_ipc_put(fip);
468 return EINVAL;
470 mtx_lock(&fnp->node_lock);
471 fuse_set_attr(fnp, &fao->attr);
472 /* unused */
473 //fao->attr_valid;
474 //fao->attr_valid_nsec;
475 mtx_unlock(&fnp->node_lock);
477 fuse_ipc_put(fip);
478 fuse_knote(vp, kflags);
480 return 0;
483 static int
484 fuse_vop_nresolve(struct vop_nresolve_args *ap)
486 struct vnode *dvp = ap->a_dvp;
487 struct vnode *vp;
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;
493 char *p, tmp[1024];
494 uint32_t mode;
495 enum vtype vtyp;
496 int error;
498 if (fuse_test_dead(fmp))
499 return ENOTCONN;
501 if (fuse_test_nosys(fmp, FUSE_LOOKUP))
502 return EOPNOTSUPP;
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);
515 return ENOENT;
516 } else if (error) {
517 fuse_dbg("lookup \"%s\" error=%d\n", tmp, error);
518 return 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;
525 if (S_ISREG(mode))
526 vtyp = VREG;
527 else if (S_ISDIR(mode))
528 vtyp = VDIR;
529 else if (S_ISBLK(mode))
530 vtyp = VBLK;
531 else if (S_ISCHR(mode))
532 vtyp = VCHR;
533 else if (S_ISLNK(mode))
534 vtyp = VLNK;
535 else if (S_ISSOCK(mode))
536 vtyp = VSOCK;
537 else if (S_ISFIFO(mode))
538 vtyp = VFIFO;
539 else
540 vtyp = VBAD;
542 error = fuse_alloc_node(dfnp, feo->nodeid, p, strlen(p), vtyp, &vp);
543 if (error) {
544 fuse_ipc_put(fip);
545 return error;
547 KKASSERT(vp);
548 KKASSERT(vn_islocked(vp));
550 vn_unlock(vp);
551 cache_setvp(ap->a_nch, vp);
552 vrele(vp);
554 /* unused */
555 //feo->generation;
556 //feo->entry_valid;
557 //feo->attr_valid;
558 //feo->entry_valid_nsec;
559 //feo->attr_valid_nsec;
561 fuse_ipc_put(fip);
563 return 0;
566 static int
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;
579 char *p;
580 int error;
582 if (fuse_test_dead(fmp))
583 return ENOTCONN;
585 if (fuse_test_nosys(fmp, FUSE_LINK))
586 return EOPNOTSUPP;
588 if (vp->v_type == VDIR)
589 return EPERM;
590 if (dvp->v_mount != vp->v_mount)
591 return EXDEV;
592 if (fnp->nlink >= LINK_MAX)
593 return EMLINK;
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);
604 if (error)
605 return error;
607 feo = fuse_out_data(fip);
608 if (IFTOVT(feo->attr.mode) != vp->v_type) {
609 fuse_ipc_put(fip);
610 return EINVAL;
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);
626 /* unused */
627 //feo->nodeid;
628 //feo->generation;
629 //feo->entry_valid;
630 //feo->attr_valid;
631 //feo->entry_valid_nsec;
632 //feo->attr_valid_nsec;
634 fuse_ipc_put(fip);
636 return 0;
639 static int
640 fuse_vop_ncreate(struct vop_ncreate_args *ap)
642 struct vnode *dvp = ap->a_dvp;
643 struct vnode *vp;
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;
652 enum vtype vtyp;
653 char *p;
654 int error;
656 if (fuse_test_dead(fmp))
657 return ENOTCONN;
659 if (fuse_test_nosys(fmp, FUSE_CREATE))
660 return EOPNOTSUPP;
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);
666 /* unused */
667 //fci->umask = ...;
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);
675 if (error)
676 return error;
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) {
682 fuse_ipc_put(fip);
683 return EINVAL;
686 error = fuse_alloc_node(dfnp, feo->nodeid, p, strlen(p), VREG, &vp);
687 if (error) {
688 fuse_ipc_put(fip);
689 return error;
691 KKASSERT(vp);
692 KKASSERT(vn_islocked(vp));
694 fnp = VTOI(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);
701 *(ap->a_vpp) = vp;
702 fuse_knote(dvp, NOTE_WRITE);
704 /* unused */
705 //feo->generation;
706 //feo->entry_valid;
707 //feo->attr_valid;
708 //feo->entry_valid_nsec;
709 //feo->attr_valid_nsec;
710 /* unused */
711 //foo->open_flags;
713 fuse_ipc_put(fip);
715 return 0;
718 static int
719 fuse_vop_nmknod(struct vop_nmknod_args *ap)
721 struct vnode *dvp = ap->a_dvp;
722 struct vnode *vp;
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;
730 enum vtype vtyp;
731 char *p;
732 int error;
734 if (fuse_test_dead(fmp))
735 return ENOTCONN;
737 if (fuse_test_nosys(fmp, FUSE_MKNOD))
738 return EOPNOTSUPP;
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);
743 /* unused */
744 //fmi->rdev = ...;
745 //fmi->umask = ...;
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);
752 if (error)
753 return error;
755 feo = fuse_out_data(fip);
756 vtyp = IFTOVT(feo->attr.mode);
757 if (vtyp != VBLK && vtyp != VCHR && vtyp != VFIFO) {
758 fuse_ipc_put(fip);
759 return EINVAL;
762 error = fuse_alloc_node(dfnp, feo->nodeid, p, strlen(p),
763 ap->a_vap->va_type, &vp);
764 if (error) {
765 fuse_ipc_put(fip);
766 return error;
768 KKASSERT(vp);
769 KKASSERT(vn_islocked(vp));
771 fnp = VTOI(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);
778 *(ap->a_vpp) = vp;
779 fuse_knote(dvp, NOTE_WRITE);
781 /* unused */
782 //feo->generation;
783 //feo->entry_valid;
784 //feo->attr_valid;
785 //feo->entry_valid_nsec;
786 //feo->attr_valid_nsec;
788 fuse_ipc_put(fip);
790 return 0;
793 static int
794 fuse_vop_nremove(struct vop_nremove_args *ap)
796 struct vnode *dvp = ap->a_dvp;
797 struct vnode *vp;
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;
804 char *p;
805 int error;
807 if (fuse_test_dead(fmp))
808 return ENOTCONN;
810 if (fuse_test_nosys(fmp, FUSE_UNLINK))
811 return EOPNOTSUPP;
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 */
816 vn_unlock(vp);
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);
825 if (error) {
826 vrele(vp);
827 return error;
830 fnp = VTOI(vp);
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);
837 fuse_ipc_put(fip);
838 vrele(vp);
839 return error;
841 fuse_dent_detach(dfnp, fep);
842 fuse_dent_free(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);
850 fuse_ipc_put(fip);
851 vrele(vp);
853 return 0;
856 static int
857 fuse_vop_nmkdir(struct vop_nmkdir_args *ap)
859 struct vnode *dvp = ap->a_dvp;
860 struct vnode *vp;
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;
868 char *p;
869 int error;
871 if (fuse_test_dead(fmp))
872 return ENOTCONN;
874 if (fuse_test_nosys(fmp, FUSE_MKDIR))
875 return EOPNOTSUPP;
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);
886 if (error)
887 return error;
889 feo = fuse_out_data(fip);
890 if (IFTOVT(feo->attr.mode) != VDIR) {
891 fuse_ipc_put(fip);
892 return EINVAL;
895 error = fuse_alloc_node(dfnp, feo->nodeid, p, strlen(p), VDIR, &vp);
896 if (error) {
897 fuse_ipc_put(fip);
898 return error;
900 KKASSERT(vp);
901 KKASSERT(vn_islocked(vp));
903 fnp = VTOI(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);
910 *(ap->a_vpp) = vp;
911 fuse_knote(dvp, NOTE_WRITE | NOTE_LINK);
913 /* unused */
914 //feo->generation;
915 //feo->entry_valid;
916 //feo->attr_valid;
917 //feo->entry_valid_nsec;
918 //feo->attr_valid_nsec;
920 fuse_ipc_put(fip);
922 return 0;
925 static int
926 fuse_vop_nrmdir(struct vop_nrmdir_args *ap)
928 struct vnode *dvp = ap->a_dvp;
929 struct vnode *vp;
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;
936 char *p;
937 int error;
939 if (fuse_test_dead(fmp))
940 return ENOTCONN;
942 if (fuse_test_nosys(fmp, FUSE_RMDIR))
943 return EOPNOTSUPP;
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 */
948 vn_unlock(vp);
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);
957 if (error) {
958 vrele(vp);
959 return error;
962 fnp = VTOI(vp);
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);
969 fuse_ipc_put(fip);
970 vrele(vp);
971 return error;
973 fuse_dent_detach(dfnp, fep);
974 fuse_dent_free(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);
981 fuse_ipc_put(fip);
982 vrele(vp);
984 return 0;
987 static int
988 fuse_vop_pathconf(struct vop_pathconf_args *ap)
990 switch (ap->a_name) {
991 case _PC_FILESIZEBITS:
992 *ap->a_retval = 64;
993 break;
994 case _PC_NO_TRUNC:
995 *ap->a_retval = 1;
996 break;
997 default:
998 return vop_stdpathconf(ap);
1001 return 0;
1004 static int
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;
1012 const char *buf;
1013 size_t len;
1014 off_t cur_offset = 0;
1015 int error;
1017 if (fuse_test_dead(fmp))
1018 return ENOTCONN;
1020 if (fuse_test_nosys(fmp, FUSE_READDIR))
1021 return EOPNOTSUPP;
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));
1026 if (ap->a_fp)
1027 fri->fh = fuse_fh(ap->a_fp);
1028 fri->offset = 0;
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;
1034 /* unused */
1035 //fri->read_flags = ...;
1036 //fri->lock_owner = ...;
1037 //fri->flags = ...;
1039 error = fuse_ipc_tx(fip);
1040 if (error)
1041 return error;
1043 buf = fuse_out_data(fip);
1044 len = fuse_out_data_size(fip);
1046 while (1) {
1047 const struct fuse_dirent *fde;
1048 size_t freclen;
1050 fuse_dbg("uio_offset=%ju uio_resid=%ju\n",
1051 uio->uio_offset, uio->uio_resid);
1053 if (len < FUSE_NAME_OFFSET) {
1054 if (ap->a_eofflag)
1055 *ap->a_eofflag = 1;
1056 break;
1058 if (uio->uio_resid < FUSE_NAME_OFFSET)
1059 break;
1061 fde = (const struct fuse_dirent*)buf;
1062 if (!fde->namelen) {
1063 error = EINVAL;
1064 break;
1066 freclen = FUSE_DIRENT_SIZE(fde);
1069 * Also see
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) {
1074 error = 0;
1075 if (vop_write_dirent(&error, uio, fde->ino, fde->type,
1076 fde->namelen, fde->name))
1077 error = EINVAL;
1078 if (error)
1079 break;
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);
1085 buf += freclen;
1086 len -= freclen;
1088 fuse_ipc_put(fip);
1090 return error;
1093 static int
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;
1099 int error;
1101 if (fuse_test_dead(fmp))
1102 return ENOTCONN;
1104 if (fuse_test_nosys(fmp, FUSE_READLINK))
1105 return EOPNOTSUPP;
1107 if (vp->v_type != VLNK)
1108 return EINVAL;
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);
1114 if (error)
1115 return error;
1117 error = uiomove(fuse_out_data(fip), fuse_out_data_size(fip), ap->a_uio);
1119 fuse_ipc_put(fip);
1121 return error;
1124 static int
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;
1132 struct vnode *tvp;
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;
1143 int error;
1145 KKASSERT(fdvp->v_mount == fvp->v_mount);
1147 if (fuse_test_dead(fmp))
1148 return ENOTCONN;
1150 if (fuse_test_nosys(fmp, FUSE_RENAME))
1151 return EOPNOTSUPP;
1153 error = cache_vget(ap->a_tnch, ap->a_cred, LK_SHARED, &tvp);
1154 if (!error) {
1155 tfnp = VTOI(tvp);
1156 vn_unlock(tvp);
1157 } else
1158 tfnp = NULL;
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)) {
1164 error = EXDEV;
1165 goto out;
1168 if (fvp == tvp) {
1169 error = 0;
1170 goto out;
1172 error = fuse_dent_find(fdfnp, fncp->nc_name, fncp->nc_nlen, &ffep);
1173 if (error == ENOENT)
1174 goto out;
1175 KKASSERT(ffep->fnp == ffnp);
1177 if (tvp) {
1178 KKASSERT(tfnp);
1179 if (ffnp->type == VDIR && tfnp->type == VDIR) {
1180 if (!RB_EMPTY(&tfnp->dent_head)) {
1181 error = ENOTEMPTY;
1182 goto out;
1184 } else if (ffnp->type == VDIR && tfnp->type != VDIR) {
1185 error = ENOTDIR;
1186 goto out;
1187 } else if (ffnp->type != VDIR && tfnp->type == VDIR) {
1188 error = EISDIR;
1189 goto out;
1190 } else
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);
1207 if (error)
1208 goto out;
1209 fuse_ipc_put(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);
1214 KKASSERT(newname);
1215 memcpy(newname, tncp->nc_name, tncp->nc_nlen);
1216 newname[tncp->nc_nlen] = '\0';
1217 fuse_dbg("newname=\"%s\"\n", newname);
1218 } else
1219 newname = NULL;
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);
1228 if (newname) {
1229 oldname = ffep->name;
1230 ffep->name = newname;
1231 newname = oldname;
1234 if (tvp) {
1235 mtx_lock(&tfnp->node_lock);
1236 error = fuse_dent_find(tdfnp, tncp->nc_name, tncp->nc_nlen,
1237 &tfep);
1238 KKASSERT(!error);
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);
1253 if (newname)
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);
1260 out:
1261 if (tvp)
1262 vrele(tvp);
1264 return error;
1267 static int
1268 fuse_vop_nsymlink(struct vop_nsymlink_args *ap)
1270 struct vnode *dvp = ap->a_dvp;
1271 struct vnode *vp;
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;
1278 char *p;
1279 int error;
1281 if (fuse_test_dead(fmp))
1282 return ENOTCONN;
1284 if (fuse_test_nosys(fmp, FUSE_SYMLINK))
1285 return EOPNOTSUPP;
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);
1295 if (error)
1296 return error;
1298 feo = fuse_out_data(fip);
1299 if (IFTOVT(feo->attr.mode) != VLNK) {
1300 fuse_ipc_put(fip);
1301 return EINVAL;
1304 error = fuse_alloc_node(dfnp, feo->nodeid, p, strlen(p), VLNK, &vp);
1305 if (error) {
1306 fuse_ipc_put(fip);
1307 return error;
1309 KKASSERT(vp);
1310 KKASSERT(vn_islocked(vp));
1312 fnp = VTOI(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);
1319 *(ap->a_vpp) = vp;
1320 fuse_knote(vp, NOTE_WRITE);
1322 /* unused */
1323 //feo->generation;
1324 //feo->entry_valid;
1325 //feo->attr_valid;
1326 //feo->entry_valid_nsec;
1327 //feo->attr_valid_nsec;
1329 fuse_ipc_put(fip);
1331 return 0;
1334 static int
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))
1344 return ENOTCONN;
1346 if (fuse_test_nosys(fmp, FUSE_READ))
1347 return EOPNOTSUPP;
1349 if (!uio->uio_resid)
1350 return 0;
1352 return fuse_read(ap);
1355 static int
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))
1366 return ENOTCONN;
1368 if (fuse_test_nosys(fmp, FUSE_WRITE))
1369 return EOPNOTSUPP;
1371 if (!uio->uio_resid)
1372 return 0;
1374 if (ap->a_ioflag & IO_DIRECT)
1375 return fuse_dio_write(ap);
1376 else
1377 return fuse_write(ap);
1380 static int
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);
1388 bp->b_resid = 0;
1389 bp->b_error = 0;
1390 biodone(bio);
1392 return 0;
1395 static int
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);
1401 return EOPNOTSUPP;
1404 static int
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);
1412 return 0;
1415 static int
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);
1423 if (!fnp) {
1424 vrecycle(ap->a_vp);
1425 lwkt_reltoken(&mp->mnt_token);
1426 return 0;
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);
1433 return 0;
1436 static int
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);
1444 if (fnp) {
1445 fuse_dbg("ino=%ju\n", fnp->ino);
1446 fuse_node_free(fnp);
1447 vclrisdirty(vp);
1449 lwkt_reltoken(&mp->mnt_token);
1451 return 0;
1454 static int
1455 fuse_vop_mountctl(struct vop_mountctl_args *ap)
1457 struct mount *mp;
1458 int res = 0;
1460 mp = ap->a_head.a_ops->head.vv_mount;
1461 lwkt_gettoken(&mp->mnt_token);
1463 switch (ap->a_op) {
1464 //case MOUNTCTL_MOUNTFLAGS:
1465 // ...
1466 // break;
1467 default:
1468 res = vop_stdmountctl(ap);
1469 break;
1472 lwkt_reltoken(&mp->mnt_token);
1473 return res;
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 };
1491 static int
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) {
1498 case EVFILT_READ:
1499 kn->kn_fop = &fuseread_filtops;
1500 break;
1501 case EVFILT_WRITE:
1502 kn->kn_fop = &fusewrite_filtops;
1503 break;
1504 case EVFILT_VNODE:
1505 kn->kn_fop = &fusevnode_filtops;
1506 break;
1507 default:
1508 return EOPNOTSUPP;
1511 kn->kn_hook = (caddr_t)vp;
1512 knote_insert(&vp->v_pollinfo.vpi_kqinfo.ki_note, kn);
1514 return 0;
1517 static void
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);
1525 static int
1526 filt_fuseread(struct knote *kn, long hint)
1528 struct vnode *vp = (void*)kn->kn_hook;
1529 struct fuse_node *fnp = VTOI(vp);
1530 off_t off;
1532 if (hint == NOTE_REVOKE) {
1533 kn->kn_flags |= (EV_EOF | EV_NODATA | EV_ONESHOT);
1534 return 1;
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);
1545 return 1;
1547 if (!kn->kn_data)
1548 kn->kn_data = (off < INTPTR_MAX) ? off : INTPTR_MAX;
1549 mtx_unlock(&fnp->node_lock);
1551 return kn->kn_data != 0;
1554 static int
1555 filt_fusewrite(struct knote *kn, long hint)
1557 if (hint == NOTE_REVOKE)
1558 kn->kn_flags |= (EV_EOF | EV_NODATA | EV_ONESHOT);
1559 kn->kn_data = 0;
1561 return 1;
1564 static int
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);
1571 return 1;
1574 return kn->kn_fflags != 0;
1577 static int
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);
1587 static int
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,