Merge remote-tracking branch 'origin/vendor/LIBEDIT'
[dragonfly.git] / sys / vfs / fuse / fuse_vnops.c
1 /*-
2  * Copyright (c) 2019 Tomohiro Kusumi <tkusumi@netbsd.org>
3  * Copyright (c) 2019 The DragonFly Project
4  * All rights reserved.
5  *
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.
14  *
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.
26  */
27
28 #include "fuse.h"
29
30 #include <sys/fcntl.h>
31 #include <sys/dirent.h>
32 #include <sys/namei.h>
33 #include <sys/uio.h>
34 #include <sys/mountctl.h>
35 #include <vm/vm_pager.h>
36 #include <vm/vnode_pager.h>
37
38 static int
39 fuse_set_attr(struct fuse_node *fnp, struct fuse_attr *fat)
40 {
41         struct vattr *vap = &fnp->attr;
42         int error = 0;
43
44         vattr_null(vap);
45
46         vap->va_type = IFTOVT(fat->mode);
47         vap->va_size = fat->size;
48         vap->va_bytes = fat->blocks * S_BLKSIZE;
49         vap->va_mode = fat->mode & ~S_IFMT;
50         if (!fat->nlink) /* XXX .fuse_hidden* has 0 link */
51                 vap->va_nlink = 1;
52         else
53                 vap->va_nlink = fat->nlink;
54         vap->va_uid = fat->uid;
55         vap->va_gid = fat->gid;
56         vap->va_fsid = fnp->fmp->mp->mnt_stat.f_fsid.val[0];
57         vap->va_fileid = fat->ino;
58         vap->va_blocksize = FUSE_BLKSIZE;
59         vap->va_rmajor = VNOVAL;
60         vap->va_rminor = VNOVAL;
61         vap->va_atime.tv_sec = fat->atime;
62         vap->va_atime.tv_nsec = fat->atimensec;
63         vap->va_mtime.tv_sec = fat->mtime;
64         vap->va_mtime.tv_nsec = fat->mtimensec;
65         vap->va_ctime.tv_sec = fat->ctime;
66         vap->va_ctime.tv_nsec = fat->ctimensec;
67         vap->va_flags = 0;
68         vap->va_gen = VNOVAL;
69         vap->va_vaflags = 0;
70
71         KKASSERT(vap->va_type == fnp->type);
72
73         if (fnp->nlink != vap->va_nlink) {
74                 fuse_dbg("ino=%ju update nlink %d -> %ju\n",
75                     fnp->ino, fnp->nlink, vap->va_nlink);
76                 fnp->nlink = vap->va_nlink;
77         }
78
79         if (fnp->vp->v_object && fnp->size != vap->va_size)
80                 error = fuse_node_truncate(fnp, fnp->size, vap->va_size);
81
82         return error;
83 }
84
85 static int
86 fuse_vop_access(struct vop_access_args *ap)
87 {
88         struct vnode *vp = ap->a_vp;
89         mode_t mode = ap->a_mode;
90         struct fuse_mount *fmp = VFSTOFUSE(vp->v_mount);
91         struct fuse_ipc *fip;
92         struct fuse_access_in *fai;
93         uint32_t mask;
94         int error;
95
96         if (fuse_test_dead(fmp))
97                 return 0;
98
99         if (fuse_test_nosys(fmp, FUSE_ACCESS))
100                 return 0;
101
102         switch (vp->v_type) {
103         case VDIR:
104         case VLNK:
105         case VREG:
106                 if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY))
107                         return EROFS;
108                 break;
109         case VBLK:
110         case VCHR:
111         case VSOCK:
112         case VFIFO:
113                 break;
114         default:
115                 return EINVAL;
116         }
117
118         mask = F_OK;
119         if (mode & VEXEC)
120                 mask |= X_OK;
121         if (mode & VWRITE)
122                 mask |= W_OK;
123         if (mode & VREAD)
124                 mask |= R_OK;
125
126         fip = fuse_ipc_get(fmp, sizeof(*fai));
127         fai = fuse_ipc_fill(fip, FUSE_ACCESS, VTOI(vp)->ino, ap->a_cred);
128         fai->mask = mask;
129
130         error = fuse_ipc_tx(fip);
131         if (error) {
132                 if (error == ENOSYS)
133                         error = 0;
134                 if (error == ENOTCONN && (vp->v_flag & VROOT))
135                         error = 0;
136                 return error;
137         }
138
139         fuse_ipc_put(fip);
140
141         return 0;
142 }
143
144 static int
145 fuse_vop_open(struct vop_open_args *ap)
146 {
147         struct vnode *vp = ap->a_vp;
148         struct fuse_mount *fmp = VFSTOFUSE(vp->v_mount);
149         struct fuse_node *fnp = VTOI(vp);
150         struct fuse_ipc *fip;
151         struct fuse_open_in *foi;
152         struct fuse_open_out *foo;
153         int error, op;
154
155         if (fuse_test_dead(fmp))
156                 return ENOTCONN;
157
158         if (fuse_test_nosys(fmp, FUSE_OPEN))
159                 return EOPNOTSUPP;
160
161         if (vp->v_type == VDIR)
162                 op = FUSE_OPENDIR;
163         else
164                 op = FUSE_OPEN;
165
166         fip = fuse_ipc_get(fmp, sizeof(*foi));
167         foi = fuse_ipc_fill(fip, op, fnp->ino, ap->a_cred);
168         foi->flags = OFLAGS(ap->a_mode);
169         fuse_dbg("flags=%X\n", foi->flags);
170         if (foi->flags & O_CREAT) {
171                 fuse_dbg("drop O_CREAT\n");
172                 foi->flags &= ~O_CREAT;
173         }
174
175         error = fuse_ipc_tx(fip);
176         if (error)
177                 return error;
178
179         /* XXX unused */
180         foo = fuse_out_data(fip);
181         if (foo->open_flags & FOPEN_DIRECT_IO)
182                 ;
183         else if (foo->open_flags & FOPEN_KEEP_CACHE)
184                 ;
185         else if (foo->open_flags & FOPEN_NONSEEKABLE)
186                 ;
187         else if (foo->open_flags & FOPEN_CACHE_DIR)
188                 ;
189
190         fnp->closed = false;
191         fuse_get_nfh(VTOI(vp), foo->fh);
192         if (ap->a_fp) {
193 #if 1
194                 fuse_get_fh(ap->a_fp, foo->fh);
195 #else
196                 /* see #if0'd code in fuse_vop_setattr() */
197                 if (!ap->a_fp->private_data)
198                         fuse_get_fh(ap->a_fp, foo->fh);
199                 else {
200                         uint64_t *fhp = ap->a_fp->private_data;
201                         *fhp = foo->fh;
202                 }
203 #endif
204         }
205
206         fuse_ipc_put(fip);
207
208         return vop_stdopen(ap);
209 }
210
211 static int
212 fuse_vop_close(struct vop_close_args *ap)
213 {
214         struct vnode *vp = ap->a_vp;
215         struct fuse_mount *fmp = VFSTOFUSE(vp->v_mount);
216         struct fuse_node *fnp = VTOI(vp);
217         struct fuse_ipc *fip;
218         struct fuse_release_in *fri;
219         int error, op;
220
221         if (fuse_test_dead(fmp))
222                 return 0;
223
224         if (fuse_test_nosys(fmp, FUSE_RELEASE) ||
225             fuse_test_nosys(fmp, FUSE_RELEASEDIR))
226                 return EOPNOTSUPP;
227
228         if (vp->v_type == VDIR)
229                 op = FUSE_RELEASEDIR;
230         else
231                 op = FUSE_RELEASE;
232
233         fip = fuse_ipc_get(fmp, sizeof(*fri));
234         fri = fuse_ipc_fill(fip, op, fnp->ino, NULL);
235         /* unused */
236         //fri->flags = ...;
237         //fri->release_flags = ...;
238         //fri->lock_owner = ...;
239         fri->fh = fuse_nfh(VTOI(vp));
240         if (ap->a_fp)
241                 fri->fh = fuse_fh(ap->a_fp);
242
243         error = fuse_ipc_tx(fip);
244         if (error)
245                 return error;
246
247         fuse_ipc_put(fip);
248
249         fnp->closed = true;
250         fuse_put_nfh(VTOI(vp));
251         if (ap->a_fp)
252                 fuse_put_fh(ap->a_fp);
253
254         return vop_stdclose(ap);
255 }
256
257 static int
258 fuse_vop_fsync(struct vop_fsync_args *ap)
259 {
260         struct vnode *vp = ap->a_vp;
261         struct fuse_mount *fmp = VFSTOFUSE(vp->v_mount);
262         struct fuse_ipc *fip;
263         struct fuse_fsync_in *fsi;
264         int error, op;
265
266         if (fuse_test_dead(fmp))
267                 return 0;
268
269         if (fuse_test_nosys(fmp, FUSE_FSYNC))
270                 return 0;
271
272         if (vp->v_type == VDIR)
273                 op = FUSE_FSYNCDIR;
274         else
275                 op = FUSE_FSYNC;
276
277         fip = fuse_ipc_get(fmp, sizeof(*fsi));
278         fsi = fuse_ipc_fill(fip, op, VTOI(vp)->ino, NULL);
279         fsi->fh = fuse_nfh(VTOI(vp));
280         if (ap->a_fp)
281                 fsi->fh = fuse_fh(ap->a_fp);
282         fsi->fsync_flags = 1; /* datasync */
283
284         error = fuse_ipc_tx(fip);
285         if (error)
286                 return error;
287         fuse_ipc_put(fip);
288
289         vn_syncer_remove(vp, 1);
290         vfsync(ap->a_vp, ap->a_waitfor, 1, NULL, NULL);
291         vclrisdirty(vp);
292
293         return 0;
294 }
295
296 static int
297 fuse_vop_getattr(struct vop_getattr_args *ap)
298 {
299         struct vnode *vp = ap->a_vp;
300         struct vattr *vap = ap->a_vap;
301         struct fuse_mount *fmp = VFSTOFUSE(vp->v_mount);
302         struct fuse_node *fnp = VTOI(vp);
303         struct fuse_ipc *fip;
304         struct fuse_getattr_in *fgi;
305         struct fuse_attr_out *fao;
306         int error;
307
308         if (fuse_test_dead(fmp))
309                 return 0;
310
311         if (fuse_test_nosys(fmp, FUSE_GETATTR))
312                 return 0;
313
314         fip = fuse_ipc_get(fmp, sizeof(*fgi));
315         fgi = fuse_ipc_fill(fip, FUSE_GETATTR, fnp->ino, NULL);
316 #if 0
317         /* this may be called before open when fh is 0 */
318         fgi->getattr_flags |= FUSE_GETATTR_FH;
319         fgi->fh = fuse_nfh(fnp);
320         if (ap->a_fp)
321                 fgi->fh = fuse_fh(ap->a_fp);
322 #endif
323         error = fuse_ipc_tx(fip);
324         if (error) {
325                 if (error == ENOSYS)
326                         error = 0;
327                 if (error == ENOTCONN && (vp->v_flag & VROOT)) {
328                         memset(vap, 0, sizeof(*vap));
329                         vap->va_type = vp->v_type;
330                         error = 0;
331                 }
332                 return error;
333         }
334
335         fao = fuse_out_data(fip);
336         mtx_lock(&fnp->node_lock);
337         fuse_set_attr(fnp, &fao->attr);
338         memcpy(vap, &fnp->attr, sizeof(*vap));
339         /* unused */
340         //fao->attr_valid;
341         //fao->attr_valid_nsec;
342         mtx_unlock(&fnp->node_lock);
343
344         fuse_ipc_put(fip);
345
346         if (vap->va_type != vp->v_type)
347                 return EINVAL;
348
349         return 0;
350 }
351
352 static int
353 fuse_vop_setattr(struct vop_setattr_args *ap)
354 {
355         struct vnode *vp = ap->a_vp;
356         struct vattr *vap = ap->a_vap;
357         struct fuse_mount *fmp = VFSTOFUSE(vp->v_mount);
358         struct fuse_node *fnp = VTOI(vp);
359         struct fuse_ipc *fip;
360         struct fuse_setattr_in *fsi, arg;
361         struct fuse_attr_out *fao;
362         int kflags = 0;
363         int error = 0;
364
365         if (fuse_test_dead(fmp))
366                 return 0;
367
368         if (fuse_test_nosys(fmp, FUSE_SETATTR))
369                 return 0;
370
371         if (vp->v_mount->mnt_flag & MNT_RDONLY)
372                 return EROFS;
373
374         memset(&arg, 0, sizeof(arg));
375         mtx_lock(&fnp->node_lock);
376
377         if (!error && (vap->va_flags != VNOVAL)) {
378                 mtx_unlock(&fnp->node_lock);
379                 kflags |= NOTE_ATTRIB;
380                 return EOPNOTSUPP; /* XXX */
381         }
382
383         if (!error && (vap->va_size != VNOVAL)) {
384                 if (vp->v_type == VDIR) {
385                         mtx_unlock(&fnp->node_lock);
386                         return EISDIR;
387                 }
388                 if (vp->v_type == VREG &&
389                     (vp->v_mount->mnt_flag & MNT_RDONLY)) {
390                         mtx_unlock(&fnp->node_lock);
391                         return EROFS;
392                 }
393                 arg.size = vap->va_size;
394                 arg.valid |= FATTR_SIZE;
395                 if (vap->va_size > fnp->size)
396                         kflags |= NOTE_WRITE | NOTE_EXTEND;
397                 else
398                         kflags |= NOTE_WRITE;
399         }
400
401         if (!error && (vap->va_uid != (uid_t)VNOVAL ||
402             vap->va_gid != (gid_t)VNOVAL)) {
403                 mode_t mode;
404                 error = vop_helper_chown(vp, vap->va_uid, vap->va_gid,
405                     ap->a_cred, &arg.uid, &arg.gid, &mode);
406                 arg.valid |= FATTR_UID;
407                 arg.valid |= FATTR_GID;
408                 kflags |= NOTE_ATTRIB;
409         }
410
411         if (!error && (vap->va_mode != (mode_t)VNOVAL)) {
412                 error = vop_helper_chmod(vp, vap->va_mode, ap->a_cred,
413                     vap->va_uid, vap->va_gid, (mode_t*)&arg.mode);
414                 arg.valid |= FATTR_MODE;
415                 kflags |= NOTE_ATTRIB;
416         }
417
418         if (!error && (vap->va_atime.tv_sec != VNOVAL &&
419             vap->va_atime.tv_nsec != VNOVAL)) {
420                 arg.atime = vap->va_atime.tv_sec;
421                 arg.atimensec = vap->va_atime.tv_nsec;
422                 arg.valid |= FATTR_ATIME;
423                 kflags |= NOTE_ATTRIB;
424         }
425
426         if (!error && (vap->va_mtime.tv_sec != VNOVAL &&
427             vap->va_mtime.tv_nsec != VNOVAL)) {
428                 arg.mtime = vap->va_mtime.tv_sec;
429                 arg.mtimensec = vap->va_mtime.tv_nsec;
430                 arg.valid |= FATTR_MTIME;
431                 kflags |= NOTE_ATTRIB;
432         }
433
434         if (!error && (vap->va_ctime.tv_sec != VNOVAL &&
435             vap->va_ctime.tv_nsec != VNOVAL)) {
436                 arg.ctime = vap->va_ctime.tv_sec;
437                 arg.ctimensec = vap->va_ctime.tv_nsec;
438                 arg.valid |= FATTR_CTIME;
439                 kflags |= NOTE_ATTRIB;
440         }
441
442         mtx_unlock(&fnp->node_lock);
443
444         if (error)
445                 return error;
446         if (!arg.valid)
447                 return 0;
448
449         fip = fuse_ipc_get(fmp, sizeof(*fsi));
450         fsi = fuse_ipc_fill(fip, FUSE_SETATTR, fnp->ino, ap->a_cred);
451         memcpy(fsi, &arg, sizeof(arg));
452 #if 0
453         fsi->valid |= FATTR_FH;
454         fsi->fh = fuse_nfh(fnp);
455         if (ap->a_fp) {
456                 /* vn_open() may call VOP_SETATTR_FP() prior to VOP_OPEN(). */
457                 if (!ap->a_fp->private_data)
458                         fuse_get_fh(ap->a_fp, 0); /* XXX */
459                 fsi->fh = fuse_fh(ap->a_fp);
460         }
461 #endif
462         error = fuse_ipc_tx(fip);
463         if (error)
464                 return error;
465
466         fao = fuse_out_data(fip);
467         if (IFTOVT(fao->attr.mode) != vp->v_type) {
468                 fuse_ipc_put(fip);
469                 return EINVAL;
470         }
471         mtx_lock(&fnp->node_lock);
472         fuse_set_attr(fnp, &fao->attr);
473         /* unused */
474         //fao->attr_valid;
475         //fao->attr_valid_nsec;
476         mtx_unlock(&fnp->node_lock);
477
478         fuse_ipc_put(fip);
479         fuse_knote(vp, kflags);
480
481         return 0;
482 }
483
484 static int
485 fuse_vop_nresolve(struct vop_nresolve_args *ap)
486 {
487         struct vnode *dvp = ap->a_dvp;
488         struct vnode *vp;
489         struct namecache *ncp = ap->a_nch->ncp;
490         struct fuse_mount *fmp = VFSTOFUSE(dvp->v_mount);
491         struct fuse_node *dfnp = VTOI(dvp);
492         struct fuse_ipc *fip;
493         struct fuse_entry_out *feo;
494         char *p, tmp[1024];
495         uint32_t mode;
496         enum vtype vtyp;
497         int error;
498
499         if (fuse_test_dead(fmp))
500                 return ENOTCONN;
501
502         if (fuse_test_nosys(fmp, FUSE_LOOKUP))
503                 return EOPNOTSUPP;
504
505         fip = fuse_ipc_get(fmp, ncp->nc_nlen + 1);
506         p = fuse_ipc_fill(fip, FUSE_LOOKUP, dfnp->ino, ap->a_cred);
507
508         memcpy(p, ncp->nc_name, ncp->nc_nlen);
509         p[ncp->nc_nlen] = '\0';
510         strlcpy(tmp, p, sizeof(tmp));
511
512         error = fuse_ipc_tx(fip);
513         if (error == ENOENT) {
514                 cache_setvp(ap->a_nch, NULL);
515                 fuse_dbg("lookup \"%s\" ENOENT\n", tmp);
516                 return ENOENT;
517         } else if (error) {
518                 fuse_dbg("lookup \"%s\" error=%d\n", tmp, error);
519                 return error;
520         }
521
522         feo = fuse_out_data(fip);
523         fuse_dbg("lookup \"%s\" ino=%ju/%ju\n", p, feo->nodeid, feo->attr.ino);
524
525         mode = feo->attr.mode;
526         if (S_ISREG(mode))
527                 vtyp = VREG;
528         else if (S_ISDIR(mode))
529                 vtyp = VDIR;
530         else if (S_ISBLK(mode))
531                 vtyp = VBLK;
532         else if (S_ISCHR(mode))
533                 vtyp = VCHR;
534         else if (S_ISLNK(mode))
535                 vtyp = VLNK;
536         else if (S_ISSOCK(mode))
537                 vtyp = VSOCK;
538         else if (S_ISFIFO(mode))
539                 vtyp = VFIFO;
540         else
541                 vtyp = VBAD;
542
543         error = fuse_alloc_node(dfnp, feo->nodeid, p, strlen(p), vtyp, &vp);
544         if (error) {
545                 fuse_ipc_put(fip);
546                 return error;
547         }
548         KKASSERT(vp);
549         KKASSERT(vn_islocked(vp));
550
551         vn_unlock(vp);
552         cache_setvp(ap->a_nch, vp);
553         vrele(vp);
554
555         /* unused */
556         //feo->generation;
557         //feo->entry_valid;
558         //feo->attr_valid;
559         //feo->entry_valid_nsec;
560         //feo->attr_valid_nsec;
561
562         fuse_ipc_put(fip);
563
564         return 0;
565 }
566
567 static int
568 fuse_vop_nlink(struct vop_nlink_args *ap)
569 {
570         struct vnode *dvp = ap->a_dvp;
571         struct vnode *vp = ap->a_vp;
572         struct namecache *ncp = ap->a_nch->ncp;
573         struct fuse_mount *fmp = VFSTOFUSE(vp->v_mount);
574         struct fuse_node *dfnp = VTOI(dvp);
575         struct fuse_node *fnp = VTOI(vp);
576         struct fuse_dent *fep;
577         struct fuse_ipc *fip;
578         struct fuse_link_in *fli;
579         struct fuse_entry_out *feo;
580         char *p;
581         int error;
582
583         if (fuse_test_dead(fmp))
584                 return ENOTCONN;
585
586         if (fuse_test_nosys(fmp, FUSE_LINK))
587                 return EOPNOTSUPP;
588
589         if (vp->v_type == VDIR)
590                 return EPERM;
591         if (dvp->v_mount != vp->v_mount)
592                 return EXDEV;
593         if (fnp->nlink >= LINK_MAX)
594                 return EMLINK;
595
596         fip = fuse_ipc_get(fmp, sizeof(fli) + ncp->nc_nlen + 1);
597         fli = fuse_ipc_fill(fip, FUSE_LINK, dfnp->ino, ap->a_cred);
598         fli->oldnodeid = fnp->ino;
599
600         p = (char*)(fli + 1);
601         memcpy(p, ncp->nc_name, ncp->nc_nlen);
602         p[ncp->nc_nlen] = '\0';
603
604         error = fuse_ipc_tx(fip);
605         if (error)
606                 return error;
607
608         feo = fuse_out_data(fip);
609         if (IFTOVT(feo->attr.mode) != vp->v_type) {
610                 fuse_ipc_put(fip);
611                 return EINVAL;
612         }
613
614         mtx_lock(&dfnp->node_lock);
615         mtx_lock(&fnp->node_lock);
616         fuse_dent_new(fnp, p, strlen(p), &fep);
617         fuse_dent_attach(dfnp, fep);
618         fuse_set_attr(fnp, &feo->attr);
619         mtx_unlock(&fnp->node_lock);
620         mtx_unlock(&dfnp->node_lock);
621
622         cache_setunresolved(ap->a_nch);
623         cache_setvp(ap->a_nch, vp);
624         fuse_knote(dvp, NOTE_WRITE);
625         fuse_knote(vp, NOTE_LINK);
626
627         /* unused */
628         //feo->nodeid;
629         //feo->generation;
630         //feo->entry_valid;
631         //feo->attr_valid;
632         //feo->entry_valid_nsec;
633         //feo->attr_valid_nsec;
634
635         fuse_ipc_put(fip);
636
637         return 0;
638 }
639
640 static int
641 fuse_vop_ncreate(struct vop_ncreate_args *ap)
642 {
643         struct vnode *dvp = ap->a_dvp;
644         struct vnode *vp;
645         struct namecache *ncp = ap->a_nch->ncp;
646         struct fuse_mount *fmp = VFSTOFUSE(dvp->v_mount);
647         struct fuse_node *dfnp = VTOI(dvp);
648         struct fuse_node *fnp;
649         struct fuse_ipc *fip;
650         struct fuse_create_in *fci;
651         struct fuse_entry_out *feo;
652         struct fuse_open_out *foo;
653         enum vtype vtyp;
654         char *p;
655         int error;
656
657         if (fuse_test_dead(fmp))
658                 return ENOTCONN;
659
660         if (fuse_test_nosys(fmp, FUSE_CREATE))
661                 return EOPNOTSUPP;
662
663         fip = fuse_ipc_get(fmp, sizeof(*fci) + ncp->nc_nlen + 1);
664         fci = fuse_ipc_fill(fip, FUSE_CREATE, dfnp->ino, ap->a_cred);
665         fci->flags = OFLAGS(ap->a_vap->va_fuseflags);
666         fci->mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode);
667         /* unused */
668         //fci->umask = ...;
669         fuse_dbg("flags=%X mode=%X\n", fci->flags, fci->mode);
670
671         p = (char*)(fci + 1);
672         memcpy(p, ncp->nc_name, ncp->nc_nlen);
673         p[ncp->nc_nlen] = '\0';
674
675         error = fuse_ipc_tx(fip);
676         if (error)
677                 return error;
678
679         feo = fuse_out_data(fip);
680         foo = (struct fuse_open_out*)(feo + 1);
681         vtyp = IFTOVT(feo->attr.mode);
682         if (vtyp != VREG && vtyp != VSOCK) {
683                 fuse_ipc_put(fip);
684                 return EINVAL;
685         }
686
687         error = fuse_alloc_node(dfnp, feo->nodeid, p, strlen(p), VREG, &vp);
688         if (error) {
689                 fuse_ipc_put(fip);
690                 return error;
691         }
692         KKASSERT(vp);
693         KKASSERT(vn_islocked(vp));
694
695         fnp = VTOI(vp);
696         mtx_lock(&fnp->node_lock);
697         fuse_set_attr(fnp, &feo->attr);
698         mtx_unlock(&fnp->node_lock);
699
700         cache_setunresolved(ap->a_nch);
701         cache_setvp(ap->a_nch, vp);
702         *(ap->a_vpp) = vp;
703         fuse_knote(dvp, NOTE_WRITE);
704
705         /* unused */
706         //feo->generation;
707         //feo->entry_valid;
708         //feo->attr_valid;
709         //feo->entry_valid_nsec;
710         //feo->attr_valid_nsec;
711         /* unused */
712         //foo->open_flags;
713
714         fuse_ipc_put(fip);
715
716         return 0;
717 }
718
719 static int
720 fuse_vop_nmknod(struct vop_nmknod_args *ap)
721 {
722         struct vnode *dvp = ap->a_dvp;
723         struct vnode *vp;
724         struct namecache *ncp = ap->a_nch->ncp;
725         struct fuse_mount *fmp = VFSTOFUSE(dvp->v_mount);
726         struct fuse_node *dfnp = VTOI(dvp);
727         struct fuse_node *fnp;
728         struct fuse_ipc *fip;
729         struct fuse_mknod_in *fmi;
730         struct fuse_entry_out *feo;
731         enum vtype vtyp;
732         char *p;
733         int error;
734
735         if (fuse_test_dead(fmp))
736                 return ENOTCONN;
737
738         if (fuse_test_nosys(fmp, FUSE_MKNOD))
739                 return EOPNOTSUPP;
740
741         fip = fuse_ipc_get(fmp, sizeof(*fmi) + ncp->nc_nlen + 1);
742         fmi = fuse_ipc_fill(fip, FUSE_MKNOD, dfnp->ino, ap->a_cred);
743         fmi->mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode);
744         /* unused */
745         //fmi->rdev = ...;
746         //fmi->umask = ...;
747
748         p = (char*)(fmi + 1);
749         memcpy(p, ncp->nc_name, ncp->nc_nlen);
750         p[ncp->nc_nlen] = '\0';
751
752         error = fuse_ipc_tx(fip);
753         if (error)
754                 return error;
755
756         feo = fuse_out_data(fip);
757         vtyp = IFTOVT(feo->attr.mode);
758         if (vtyp != VBLK && vtyp != VCHR && vtyp != VFIFO) {
759                 fuse_ipc_put(fip);
760                 return EINVAL;
761         }
762
763         error = fuse_alloc_node(dfnp, feo->nodeid, p, strlen(p),
764             ap->a_vap->va_type, &vp);
765         if (error) {
766                 fuse_ipc_put(fip);
767                 return error;
768         }
769         KKASSERT(vp);
770         KKASSERT(vn_islocked(vp));
771
772         fnp = VTOI(vp);
773         mtx_lock(&fnp->node_lock);
774         fuse_set_attr(fnp, &feo->attr);
775         mtx_unlock(&fnp->node_lock);
776
777         cache_setunresolved(ap->a_nch);
778         cache_setvp(ap->a_nch, vp);
779         *(ap->a_vpp) = vp;
780         fuse_knote(dvp, NOTE_WRITE);
781
782         /* unused */
783         //feo->generation;
784         //feo->entry_valid;
785         //feo->attr_valid;
786         //feo->entry_valid_nsec;
787         //feo->attr_valid_nsec;
788
789         fuse_ipc_put(fip);
790
791         return 0;
792 }
793
794 static int
795 fuse_vop_nremove(struct vop_nremove_args *ap)
796 {
797         struct vnode *dvp = ap->a_dvp;
798         struct vnode *vp;
799         struct namecache *ncp = ap->a_nch->ncp;
800         struct fuse_mount *fmp = VFSTOFUSE(dvp->v_mount);
801         struct fuse_node *dfnp = VTOI(dvp);
802         struct fuse_node *fnp;
803         struct fuse_dent *fep;
804         struct fuse_ipc *fip;
805         char *p;
806         int error;
807
808         if (fuse_test_dead(fmp))
809                 return ENOTCONN;
810
811         if (fuse_test_nosys(fmp, FUSE_UNLINK))
812                 return EOPNOTSUPP;
813
814         error = cache_vget(ap->a_nch, ap->a_cred, LK_SHARED, &vp);
815         KKASSERT(vp->v_mount == dvp->v_mount);
816         KKASSERT(!error); /* from tmpfs */
817         vn_unlock(vp);
818
819         fip = fuse_ipc_get(fmp, ncp->nc_nlen + 1);
820         p = fuse_ipc_fill(fip, FUSE_UNLINK, dfnp->ino, ap->a_cred);
821
822         memcpy(p, ncp->nc_name, ncp->nc_nlen);
823         p[ncp->nc_nlen] = '\0';
824
825         error = fuse_ipc_tx(fip);
826         if (error) {
827                 vrele(vp);
828                 return error;
829         }
830
831         fnp = VTOI(vp);
832         mtx_lock(&dfnp->node_lock);
833         mtx_lock(&fnp->node_lock);
834         error = fuse_dent_find(dfnp, p, strlen(p), &fep);
835         if (error == ENOENT) {
836                 mtx_unlock(&fnp->node_lock);
837                 mtx_unlock(&dfnp->node_lock);
838                 fuse_ipc_put(fip);
839                 vrele(vp);
840                 return error;
841         }
842         fuse_dent_detach(dfnp, fep);
843         fuse_dent_free(fep);
844         mtx_unlock(&fnp->node_lock);
845         mtx_unlock(&dfnp->node_lock);
846
847         cache_unlink(ap->a_nch);
848         fuse_knote(dvp, NOTE_WRITE);
849         fuse_knote(vp, NOTE_DELETE);
850
851         fuse_ipc_put(fip);
852         vrele(vp);
853
854         return 0;
855 }
856
857 static int
858 fuse_vop_nmkdir(struct vop_nmkdir_args *ap)
859 {
860         struct vnode *dvp = ap->a_dvp;
861         struct vnode *vp;
862         struct namecache *ncp = ap->a_nch->ncp;
863         struct fuse_mount *fmp = VFSTOFUSE(dvp->v_mount);
864         struct fuse_node *dfnp = VTOI(dvp);
865         struct fuse_node *fnp;
866         struct fuse_ipc *fip;
867         struct fuse_mkdir_in *fmi;
868         struct fuse_entry_out *feo;
869         char *p;
870         int error;
871
872         if (fuse_test_dead(fmp))
873                 return ENOTCONN;
874
875         if (fuse_test_nosys(fmp, FUSE_MKDIR))
876                 return EOPNOTSUPP;
877
878         fip = fuse_ipc_get(fmp, sizeof(*fmi) + ncp->nc_nlen + 1);
879         fmi = fuse_ipc_fill(fip, FUSE_MKDIR, dfnp->ino, ap->a_cred);
880         fmi->mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode);
881
882         p = (char*)(fmi + 1);
883         memcpy(p, ncp->nc_name, ncp->nc_nlen);
884         p[ncp->nc_nlen] = '\0';
885
886         error = fuse_ipc_tx(fip);
887         if (error)
888                 return error;
889
890         feo = fuse_out_data(fip);
891         if (IFTOVT(feo->attr.mode) != VDIR) {
892                 fuse_ipc_put(fip);
893                 return EINVAL;
894         }
895
896         error = fuse_alloc_node(dfnp, feo->nodeid, p, strlen(p), VDIR, &vp);
897         if (error) {
898                 fuse_ipc_put(fip);
899                 return error;
900         }
901         KKASSERT(vp);
902         KKASSERT(vn_islocked(vp));
903
904         fnp = VTOI(vp);
905         mtx_lock(&fnp->node_lock);
906         fuse_set_attr(fnp, &feo->attr);
907         mtx_unlock(&fnp->node_lock);
908
909         cache_setunresolved(ap->a_nch);
910         cache_setvp(ap->a_nch, vp);
911         *(ap->a_vpp) = vp;
912         fuse_knote(dvp, NOTE_WRITE | NOTE_LINK);
913
914         /* unused */
915         //feo->generation;
916         //feo->entry_valid;
917         //feo->attr_valid;
918         //feo->entry_valid_nsec;
919         //feo->attr_valid_nsec;
920
921         fuse_ipc_put(fip);
922
923         return 0;
924 }
925
926 static int
927 fuse_vop_nrmdir(struct vop_nrmdir_args *ap)
928 {
929         struct vnode *dvp = ap->a_dvp;
930         struct vnode *vp;
931         struct namecache *ncp = ap->a_nch->ncp;
932         struct fuse_mount *fmp = VFSTOFUSE(dvp->v_mount);
933         struct fuse_node *dfnp = VTOI(dvp);
934         struct fuse_node *fnp;
935         struct fuse_dent *fep;
936         struct fuse_ipc *fip;
937         char *p;
938         int error;
939
940         if (fuse_test_dead(fmp))
941                 return ENOTCONN;
942
943         if (fuse_test_nosys(fmp, FUSE_RMDIR))
944                 return EOPNOTSUPP;
945
946         error = cache_vget(ap->a_nch, ap->a_cred, LK_SHARED, &vp);
947         KKASSERT(vp->v_mount == dvp->v_mount);
948         KKASSERT(!error); /* from tmpfs */
949         vn_unlock(vp);
950
951         fip = fuse_ipc_get(fmp, ncp->nc_nlen + 1);
952         p = fuse_ipc_fill(fip, FUSE_RMDIR, dfnp->ino, ap->a_cred);
953
954         memcpy(p, ncp->nc_name, ncp->nc_nlen);
955         p[ncp->nc_nlen] = '\0';
956
957         error = fuse_ipc_tx(fip);
958         if (error) {
959                 vrele(vp);
960                 return error;
961         }
962
963         fnp = VTOI(vp);
964         mtx_lock(&dfnp->node_lock);
965         mtx_lock(&fnp->node_lock);
966         error = fuse_dent_find(dfnp, p, strlen(p), &fep);
967         if (error == ENOENT) {
968                 mtx_unlock(&fnp->node_lock);
969                 mtx_unlock(&dfnp->node_lock);
970                 fuse_ipc_put(fip);
971                 vrele(vp);
972                 return error;
973         }
974         fuse_dent_detach(dfnp, fep);
975         fuse_dent_free(fep);
976         mtx_unlock(&fnp->node_lock);
977         mtx_unlock(&dfnp->node_lock);
978
979         cache_unlink(ap->a_nch);
980         fuse_knote(dvp, NOTE_WRITE | NOTE_LINK);
981
982         fuse_ipc_put(fip);
983         vrele(vp);
984
985         return 0;
986 }
987
988 static int
989 fuse_vop_pathconf(struct vop_pathconf_args *ap)
990 {
991         switch (ap->a_name) {
992         case _PC_FILESIZEBITS:
993                 *ap->a_retval = 64;
994                 break;
995         case _PC_NO_TRUNC:
996                 *ap->a_retval = 1;
997                 break;
998         default:
999                 return vop_stdpathconf(ap);
1000         }
1001
1002         return 0;
1003 }
1004
1005 static int
1006 fuse_vop_readdir(struct vop_readdir_args *ap)
1007 {
1008         struct vnode *vp = ap->a_vp;
1009         struct uio *uio = ap->a_uio;
1010         struct fuse_mount *fmp = VFSTOFUSE(vp->v_mount);
1011         struct fuse_ipc *fip;
1012         struct fuse_read_in *fri;
1013         const char *buf;
1014         size_t len;
1015         off_t cur_offset = 0;
1016         int error;
1017
1018         if (fuse_test_dead(fmp))
1019                 return ENOTCONN;
1020
1021         if (fuse_test_nosys(fmp, FUSE_READDIR))
1022                 return EOPNOTSUPP;
1023
1024         fip = fuse_ipc_get(fmp, sizeof(*fri));
1025         fri = fuse_ipc_fill(fip, FUSE_READDIR, VTOI(vp)->ino, ap->a_cred);
1026         fri->fh = fuse_nfh(VTOI(vp));
1027         if (ap->a_fp)
1028                 fri->fh = fuse_fh(ap->a_fp);
1029         fri->offset = 0;
1030         /*
1031          * XXX This needs to be large enough to read all entries at once.
1032          * FUSE filesystems typically just opendir/readdir and return entries.
1033          */
1034         fri->size = FUSE_BLKSIZE * 10;
1035         /* unused */
1036         //fri->read_flags = ...;
1037         //fri->lock_owner = ...;
1038         //fri->flags = ...;
1039
1040         error = fuse_ipc_tx(fip);
1041         if (error)
1042                 return error;
1043
1044         buf = fuse_out_data(fip);
1045         len = fuse_out_data_size(fip);
1046
1047         while (1) {
1048                 const struct fuse_dirent *fde;
1049                 size_t freclen;
1050
1051                 fuse_dbg("uio_offset=%ju uio_resid=%ju\n",
1052                     uio->uio_offset, uio->uio_resid);
1053
1054                 if (len < FUSE_NAME_OFFSET) {
1055                         if (ap->a_eofflag)
1056                                 *ap->a_eofflag = 1;
1057                         break;
1058                 }
1059                 if (uio->uio_resid < FUSE_NAME_OFFSET)
1060                         break;
1061
1062                 fde = (const struct fuse_dirent*)buf;
1063                 if (!fde->namelen) {
1064                         error = EINVAL;
1065                         break;
1066                 }
1067                 freclen = FUSE_DIRENT_SIZE(fde);
1068
1069                 /*
1070                  * Also see
1071                  * getdirentries(2) in sys/kern/vfs_syscalls.c
1072                  * readdir(3) in lib/libc/gen/readdir.c
1073                  */
1074                 if (cur_offset >= uio->uio_offset) {
1075                         error = 0;
1076                         if (vop_write_dirent(&error, uio, fde->ino, fde->type,
1077                             fde->namelen, fde->name))
1078                                 error = EINVAL;
1079                         if (error)
1080                                 break;
1081                         fuse_dbg("ino=%ju type=%d name=%s len=%u\n",
1082                             fde->ino, fde->type, fde->name, fde->namelen);
1083                 }
1084
1085                 cur_offset += _DIRENT_RECLEN(fde->namelen);
1086                 buf += freclen;
1087                 len -= freclen;
1088         }
1089         fuse_ipc_put(fip);
1090
1091         return error;
1092 }
1093
1094 static int
1095 fuse_vop_readlink(struct vop_readlink_args *ap)
1096 {
1097         struct vnode *vp = ap->a_vp;
1098         struct fuse_mount *fmp = VFSTOFUSE(vp->v_mount);
1099         struct fuse_ipc *fip;
1100         int error;
1101
1102         if (fuse_test_dead(fmp))
1103                 return ENOTCONN;
1104
1105         if (fuse_test_nosys(fmp, FUSE_READLINK))
1106                 return EOPNOTSUPP;
1107
1108         if (vp->v_type != VLNK)
1109                 return EINVAL;
1110
1111         fip = fuse_ipc_get(fmp, 0);
1112         fuse_ipc_fill(fip, FUSE_READLINK, VTOI(vp)->ino, ap->a_cred);
1113
1114         error = fuse_ipc_tx(fip);
1115         if (error)
1116                 return error;
1117
1118         error = uiomove(fuse_out_data(fip), fuse_out_data_size(fip), ap->a_uio);
1119
1120         fuse_ipc_put(fip);
1121
1122         return error;
1123 }
1124
1125 static int
1126 fuse_vop_nrename(struct vop_nrename_args *ap)
1127 {
1128         struct namecache *fncp = ap->a_fnch->ncp;
1129         struct namecache *tncp = ap->a_tnch->ncp;
1130         struct vnode *fdvp = ap->a_fdvp;
1131         struct vnode *fvp = fncp->nc_vp;
1132         struct vnode *tdvp = ap->a_tdvp;
1133         struct vnode *tvp;
1134         struct fuse_mount *fmp = VFSTOFUSE(fdvp->v_mount);
1135         struct fuse_node *fdfnp = VTOI(fdvp);
1136         struct fuse_node *ffnp = VTOI(fvp);
1137         struct fuse_node *tdfnp = VTOI(tdvp);
1138         struct fuse_node *tfnp;
1139         struct fuse_dent *ffep;
1140         struct fuse_dent *tfep;
1141         struct fuse_ipc *fip;
1142         struct fuse_rename_in *fri;
1143         char *p, *newname, *oldname;
1144         int error;
1145
1146         KKASSERT(fdvp->v_mount == fvp->v_mount);
1147
1148         if (fuse_test_dead(fmp))
1149                 return ENOTCONN;
1150
1151         if (fuse_test_nosys(fmp, FUSE_RENAME))
1152                 return EOPNOTSUPP;
1153
1154         error = cache_vget(ap->a_tnch, ap->a_cred, LK_SHARED, &tvp);
1155         if (!error) {
1156                 tfnp = VTOI(tvp);
1157                 vn_unlock(tvp);
1158         } else
1159                 tfnp = NULL;
1160
1161         /* Disallow cross-device renames.
1162          * Why isn't this done by the caller? */
1163         if (fvp->v_mount != tdvp->v_mount ||
1164             (tvp && fvp->v_mount != tvp->v_mount)) {
1165                 error = EXDEV;
1166                 goto out;
1167         }
1168
1169         if (fvp == tvp) {
1170                 error = 0;
1171                 goto out;
1172         }
1173         error = fuse_dent_find(fdfnp, fncp->nc_name, fncp->nc_nlen, &ffep);
1174         if (error == ENOENT)
1175                 goto out;
1176         KKASSERT(ffep->fnp == ffnp);
1177
1178         if (tvp) {
1179                 KKASSERT(tfnp);
1180                 if (ffnp->type == VDIR && tfnp->type == VDIR) {
1181                         if (!RB_EMPTY(&tfnp->dent_head)) {
1182                                 error = ENOTEMPTY;
1183                                 goto out;
1184                         }
1185                 } else if (ffnp->type == VDIR && tfnp->type != VDIR) {
1186                         error = ENOTDIR;
1187                         goto out;
1188                 } else if (ffnp->type != VDIR && tfnp->type == VDIR) {
1189                         error = EISDIR;
1190                         goto out;
1191                 } else
1192                         KKASSERT(ffnp->type != VDIR && tfnp->type != VDIR);
1193         }
1194
1195         fip = fuse_ipc_get(fmp,
1196             sizeof(*fri) + fncp->nc_nlen + tncp->nc_nlen + 2);
1197         /* There is also fuse_rename2_in with flags. */
1198         fri = fuse_ipc_fill(fip, FUSE_RENAME, fdfnp->ino, ap->a_cred);
1199         fri->newdir = tdfnp->ino;
1200
1201         p = (char*)(fri + 1);
1202         memcpy(p, fncp->nc_name, fncp->nc_nlen);
1203         p[fncp->nc_nlen] = '\0';
1204         memcpy(p + fncp->nc_nlen + 1, tncp->nc_name, tncp->nc_nlen);
1205         p[fncp->nc_nlen + 1 + tncp->nc_nlen] = '\0';
1206
1207         error = fuse_ipc_tx(fip);
1208         if (error)
1209                 goto out;
1210         fuse_ipc_put(fip);
1211
1212         if (fncp->nc_nlen != tncp->nc_nlen ||
1213             memcmp(fncp->nc_name, tncp->nc_name, fncp->nc_nlen)) {
1214                 newname = kmalloc(tncp->nc_nlen + 1, M_TEMP, M_WAITOK | M_ZERO);
1215                 KKASSERT(newname);
1216                 memcpy(newname, tncp->nc_name, tncp->nc_nlen);
1217                 newname[tncp->nc_nlen] = '\0';
1218                 fuse_dbg("newname=\"%s\"\n", newname);
1219         } else
1220                 newname = NULL;
1221
1222         mtx_lock(&tdfnp->node_lock);
1223         mtx_lock(&fdfnp->node_lock);
1224         mtx_lock(&ffnp->node_lock);
1225
1226         fuse_dbg("detach from_dent=\"%s\"\n", ffep->name);
1227         fuse_dent_detach(fdfnp, ffep);
1228
1229         if (newname) {
1230                 oldname = ffep->name;
1231                 ffep->name = newname;
1232                 newname = oldname;
1233         }
1234
1235         if (tvp) {
1236                 mtx_lock(&tfnp->node_lock);
1237                 error = fuse_dent_find(tdfnp, tncp->nc_name, tncp->nc_nlen,
1238                     &tfep);
1239                 KKASSERT(!error);
1240                 fuse_dbg("detach/free to_dent=\"%s\"\n", tfep->name);
1241                 fuse_dent_detach(tdfnp, tfep);
1242                 fuse_dent_free(tfep);
1243                 mtx_unlock(&tfnp->node_lock);
1244                 fuse_knote(tdvp, NOTE_DELETE);
1245         }
1246
1247         fuse_dbg("attach from_dent=\"%s\"\n", ffep->name);
1248         fuse_dent_attach(tdfnp, ffep);
1249
1250         mtx_unlock(&ffnp->node_lock);
1251         mtx_unlock(&fdfnp->node_lock);
1252         mtx_unlock(&tdfnp->node_lock);
1253
1254         if (newname)
1255                 kfree(newname, M_TEMP);
1256
1257         cache_rename(ap->a_fnch, ap->a_tnch);
1258         fuse_knote(fdvp, NOTE_WRITE);
1259         fuse_knote(tdvp, NOTE_WRITE);
1260         fuse_knote(fvp, NOTE_RENAME);
1261 out:
1262         if (tvp)
1263                 vrele(tvp);
1264
1265         return error;
1266 }
1267
1268 static int
1269 fuse_vop_nsymlink(struct vop_nsymlink_args *ap)
1270 {
1271         struct vnode *dvp = ap->a_dvp;
1272         struct vnode *vp;
1273         struct namecache *ncp = ap->a_nch->ncp;
1274         struct fuse_mount *fmp = VFSTOFUSE(dvp->v_mount);
1275         struct fuse_node *dfnp = VTOI(dvp);
1276         struct fuse_node *fnp;
1277         struct fuse_ipc *fip;
1278         struct fuse_entry_out *feo;
1279         char *p;
1280         int error;
1281
1282         if (fuse_test_dead(fmp))
1283                 return ENOTCONN;
1284
1285         if (fuse_test_nosys(fmp, FUSE_SYMLINK))
1286                 return EOPNOTSUPP;
1287
1288         fip = fuse_ipc_get(fmp, strlen(ap->a_target) + 1 + ncp->nc_nlen + 1);
1289         p = fuse_ipc_fill(fip, FUSE_SYMLINK, dfnp->ino, ap->a_cred);
1290
1291         memcpy(p, ncp->nc_name, ncp->nc_nlen);
1292         p[ncp->nc_nlen] = '\0';
1293         memcpy(p + ncp->nc_nlen + 1, ap->a_target, strlen(ap->a_target) + 1);
1294
1295         error = fuse_ipc_tx(fip);
1296         if (error)
1297                 return error;
1298
1299         feo = fuse_out_data(fip);
1300         if (IFTOVT(feo->attr.mode) != VLNK) {
1301                 fuse_ipc_put(fip);
1302                 return EINVAL;
1303         }
1304
1305         error = fuse_alloc_node(dfnp, feo->nodeid, p, strlen(p), VLNK, &vp);
1306         if (error) {
1307                 fuse_ipc_put(fip);
1308                 return error;
1309         }
1310         KKASSERT(vp);
1311         KKASSERT(vn_islocked(vp));
1312
1313         fnp = VTOI(vp);
1314         mtx_lock(&fnp->node_lock);
1315         fuse_set_attr(fnp, &feo->attr);
1316         mtx_unlock(&fnp->node_lock);
1317
1318         cache_setunresolved(ap->a_nch);
1319         cache_setvp(ap->a_nch, vp);
1320         *(ap->a_vpp) = vp;
1321         fuse_knote(vp, NOTE_WRITE);
1322
1323         /* unused */
1324         //feo->generation;
1325         //feo->entry_valid;
1326         //feo->attr_valid;
1327         //feo->entry_valid_nsec;
1328         //feo->attr_valid_nsec;
1329
1330         fuse_ipc_put(fip);
1331
1332         return 0;
1333 }
1334
1335 static int
1336 fuse_vop_read(struct vop_read_args *ap)
1337 {
1338         struct vnode *vp = ap->a_vp;
1339         struct uio *uio = ap->a_uio;
1340         struct fuse_mount *fmp = VFSTOFUSE(vp->v_mount);
1341
1342         fuse_dbg("ino=%ju ioflag=%x\n", VTOI(vp)->ino, ap->a_ioflag);
1343
1344         if (fuse_test_dead(fmp))
1345                 return ENOTCONN;
1346
1347         if (fuse_test_nosys(fmp, FUSE_READ))
1348                 return EOPNOTSUPP;
1349
1350         if (!uio->uio_resid)
1351                 return 0;
1352
1353         return fuse_read(ap);
1354 }
1355
1356 static int
1357 fuse_vop_write(struct vop_write_args *ap)
1358 {
1359         struct vnode *vp = ap->a_vp;
1360         struct uio *uio = ap->a_uio;
1361         struct fuse_mount *fmp = VFSTOFUSE(vp->v_mount);
1362
1363         fuse_dbg("ino=%ju ioflag=%x\n", VTOI(vp)->ino, ap->a_ioflag);
1364         return EOPNOTSUPP; /* XXX disabled */
1365
1366         if (fuse_test_dead(fmp))
1367                 return ENOTCONN;
1368
1369         if (fuse_test_nosys(fmp, FUSE_WRITE))
1370                 return EOPNOTSUPP;
1371
1372         if (!uio->uio_resid)
1373                 return 0;
1374
1375         if (ap->a_ioflag & IO_DIRECT)
1376                 return fuse_dio_write(ap);
1377         else
1378                 return fuse_write(ap);
1379 }
1380
1381 static int
1382 fuse_vop_strategy(struct vop_strategy_args *ap)
1383 {
1384         struct bio *bio = ap->a_bio;
1385         struct buf *bp = bio->bio_buf;
1386
1387         fuse_dbg("ino=%ju b_cmd=%d\n", VTOI(ap->a_vp)->ino, bp->b_cmd);
1388
1389         bp->b_resid = 0;
1390         bp->b_error = 0;
1391         biodone(bio);
1392
1393         return 0;
1394 }
1395
1396 static int
1397 fuse_bmap(struct vop_bmap_args *ap)
1398 {
1399         fuse_dbg("ino=%ju a_cmd=%d a_loffset=%ju\n",
1400             VTOI(ap->a_vp)->ino, ap->a_cmd, ap->a_loffset);
1401
1402         return EOPNOTSUPP;
1403 }
1404
1405 static int
1406 fuse_vop_print(struct vop_print_args *ap)
1407 {
1408         struct fuse_node *fnp = VTOI(ap->a_vp);
1409
1410         fuse_print("tag VT_FUSE, node %p, ino %ju, parent ino %ju\n",
1411             fnp, VTOI(ap->a_vp)->ino, VTOI(fnp->pfnp->vp)->ino);
1412
1413         return 0;
1414 }
1415
1416 static int
1417 fuse_vop_inactive(struct vop_inactive_args *ap)
1418 {
1419         struct vnode *vp = ap->a_vp;
1420         struct mount *mp = vp->v_mount;
1421         struct fuse_node *fnp = VTOI(vp);
1422
1423         lwkt_gettoken(&mp->mnt_token);
1424         if (!fnp) {
1425                 vrecycle(ap->a_vp);
1426                 lwkt_reltoken(&mp->mnt_token);
1427                 return 0;
1428         }
1429
1430         fuse_dbg("ino=%ju nlink=%d\n", fnp->ino, fnp->nlink);
1431         vinvalbuf(vp, V_SAVE, 0, 0);
1432         lwkt_reltoken(&mp->mnt_token);
1433
1434         return 0;
1435 }
1436
1437 static int
1438 fuse_vop_reclaim(struct vop_reclaim_args *ap)
1439 {
1440         struct vnode *vp = ap->a_vp;
1441         struct mount *mp = vp->v_mount;
1442         struct fuse_node *fnp = VTOI(vp);
1443
1444         lwkt_gettoken(&mp->mnt_token);
1445         if (fnp) {
1446                 fuse_dbg("ino=%ju\n", fnp->ino);
1447                 fuse_node_free(fnp);
1448                 vclrisdirty(vp);
1449         }
1450         lwkt_reltoken(&mp->mnt_token);
1451
1452         return 0;
1453 }
1454
1455 static int
1456 fuse_vop_mountctl(struct vop_mountctl_args *ap)
1457 {
1458         struct mount *mp;
1459         int res = 0;
1460
1461         mp = ap->a_head.a_ops->head.vv_mount;
1462         lwkt_gettoken(&mp->mnt_token);
1463
1464         switch (ap->a_op) {
1465         //case MOUNTCTL_MOUNTFLAGS:
1466         //      ...
1467         //      break;
1468         default:
1469                 res = vop_stdmountctl(ap);
1470                 break;
1471         }
1472
1473         lwkt_reltoken(&mp->mnt_token);
1474         return res;
1475 }
1476
1477 static void filt_fusedetach(struct knote*);
1478 static int filt_fuseread(struct knote*, long);
1479 static int filt_fusewrite(struct knote*, long);
1480 static int filt_fusevnode(struct knote*, long);
1481
1482 static struct filterops fuseread_filtops =
1483         { FILTEROP_ISFD | FILTEROP_MPSAFE,
1484           NULL, filt_fusedetach, filt_fuseread };
1485 static struct filterops fusewrite_filtops =
1486         { FILTEROP_ISFD | FILTEROP_MPSAFE,
1487           NULL, filt_fusedetach, filt_fusewrite };
1488 static struct filterops fusevnode_filtops =
1489         { FILTEROP_ISFD | FILTEROP_MPSAFE,
1490           NULL, filt_fusedetach, filt_fusevnode };
1491
1492 static int
1493 fuse_kqfilter(struct vop_kqfilter_args *ap)
1494 {
1495         struct vnode *vp = ap->a_vp;
1496         struct knote *kn = ap->a_kn;
1497
1498         switch (kn->kn_filter) {
1499         case EVFILT_READ:
1500                 kn->kn_fop = &fuseread_filtops;
1501                 break;
1502         case EVFILT_WRITE:
1503                 kn->kn_fop = &fusewrite_filtops;
1504                 break;
1505         case EVFILT_VNODE:
1506                 kn->kn_fop = &fusevnode_filtops;
1507                 break;
1508         default:
1509                 return EOPNOTSUPP;
1510         }
1511
1512         kn->kn_hook = (caddr_t)vp;
1513         knote_insert(&vp->v_pollinfo.vpi_kqinfo.ki_note, kn);
1514
1515         return 0;
1516 }
1517
1518 static void
1519 filt_fusedetach(struct knote *kn)
1520 {
1521         struct vnode *vp = (void*)kn->kn_hook;
1522
1523         knote_remove(&vp->v_pollinfo.vpi_kqinfo.ki_note, kn);
1524 }
1525
1526 static int
1527 filt_fuseread(struct knote *kn, long hint)
1528 {
1529         struct vnode *vp = (void*)kn->kn_hook;
1530         struct fuse_node *fnp = VTOI(vp);
1531         off_t off;
1532
1533         if (hint == NOTE_REVOKE) {
1534                 kn->kn_flags |= (EV_EOF | EV_NODATA | EV_ONESHOT);
1535                 return 1;
1536         }
1537
1538         /*
1539          * Interlock against MP races when performing this function.
1540          */
1541         mtx_lock(&fnp->node_lock);
1542         off = fnp->size - kn->kn_fp->f_offset;
1543         kn->kn_data = (off < INTPTR_MAX) ? off : INTPTR_MAX;
1544         if (kn->kn_sfflags & NOTE_OLDAPI) {
1545                 mtx_unlock(&fnp->node_lock);
1546                 return 1;
1547         }
1548         if (!kn->kn_data)
1549                 kn->kn_data = (off < INTPTR_MAX) ? off : INTPTR_MAX;
1550         mtx_unlock(&fnp->node_lock);
1551
1552         return kn->kn_data != 0;
1553 }
1554
1555 static int
1556 filt_fusewrite(struct knote *kn, long hint)
1557 {
1558         if (hint == NOTE_REVOKE)
1559                 kn->kn_flags |= (EV_EOF | EV_NODATA | EV_ONESHOT);
1560         kn->kn_data = 0;
1561
1562         return 1;
1563 }
1564
1565 static int
1566 filt_fusevnode(struct knote *kn, long hint)
1567 {
1568         if (kn->kn_sfflags & hint)
1569                 kn->kn_fflags |= hint;
1570         if (hint == NOTE_REVOKE) {
1571                 kn->kn_flags |= (EV_EOF | EV_NODATA);
1572                 return 1;
1573         }
1574
1575         return kn->kn_fflags != 0;
1576 }
1577
1578 static int
1579 fuse_vop_getpages(struct vop_getpages_args *ap)
1580 {
1581         if (!ap->a_vp->v_mount)
1582                 return VM_PAGER_BAD;
1583
1584         return vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count,
1585             ap->a_reqpage, ap->a_seqaccess);
1586 }
1587
1588 static int
1589 fuse_vop_putpages(struct vop_putpages_args *ap)
1590 {
1591         if (!ap->a_vp->v_mount)
1592                 return VM_PAGER_BAD;
1593
1594         return vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count,
1595             ap->a_sync, ap->a_rtvals);
1596 }
1597
1598 struct vop_ops fuse_vnode_vops = {
1599         .vop_default =          vop_defaultop,
1600         .vop_access =           fuse_vop_access,
1601         .vop_open =             fuse_vop_open,
1602         .vop_close =            fuse_vop_close,
1603         .vop_fsync =            fuse_vop_fsync,
1604         .vop_getattr =          fuse_vop_getattr,
1605         .vop_setattr =          fuse_vop_setattr,
1606         .vop_nresolve =         fuse_vop_nresolve,
1607         //.vop_nlookupdotdot =  fuse_nlookupdotdot,
1608         .vop_nlink =            fuse_vop_nlink,
1609         .vop_ncreate =          fuse_vop_ncreate,
1610         .vop_nmknod =           fuse_vop_nmknod,
1611         .vop_nremove =          fuse_vop_nremove,
1612         .vop_nmkdir =           fuse_vop_nmkdir,
1613         .vop_nrmdir =           fuse_vop_nrmdir,
1614         .vop_pathconf =         fuse_vop_pathconf,
1615         .vop_readdir =          fuse_vop_readdir,
1616         .vop_readlink =         fuse_vop_readlink,
1617         .vop_nrename =          fuse_vop_nrename,
1618         .vop_nsymlink =         fuse_vop_nsymlink,
1619         .vop_read =             fuse_vop_read,
1620         .vop_write =            fuse_vop_write,
1621         .vop_strategy =         fuse_vop_strategy,
1622         .vop_bmap =             fuse_bmap,
1623         //.vop_advlock =        fuse_advlock,
1624         .vop_print =            fuse_vop_print,
1625         .vop_inactive =         fuse_vop_inactive,
1626         .vop_reclaim =          fuse_vop_reclaim,
1627         .vop_mountctl =         fuse_vop_mountctl,
1628         .vop_kqfilter =         fuse_kqfilter,
1629         .vop_getpages =         fuse_vop_getpages,
1630         .vop_putpages =         fuse_vop_putpages,
1631 };
1632
1633 struct vop_ops fuse_spec_vops = {
1634         .vop_default =          vop_defaultop,
1635         .vop_access =           fuse_vop_access,
1636         .vop_close =            fuse_vop_close,
1637         .vop_fsync =            fuse_vop_fsync,
1638         .vop_getattr =          fuse_vop_getattr,
1639         .vop_setattr =          fuse_vop_setattr,
1640         .vop_read =             vop_stdnoread,
1641         .vop_write =            vop_stdnowrite,
1642         //.vop_markatime =      fuse_vop_markatime,
1643         .vop_print =            fuse_vop_print,
1644         .vop_inactive =         fuse_vop_inactive,
1645         .vop_reclaim =          fuse_vop_reclaim,
1646 };