]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/fuse/fuse_vnops.c
fusefs: fix error handling in fuse_vnop_strategy
[FreeBSD/FreeBSD.git] / sys / fs / fuse / fuse_vnops.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2007-2009 Google Inc. and Amit Singh
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are
9  * met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  *   copyright notice, this list of conditions and the following disclaimer
15  *   in the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of Google Inc. nor the names of its
18  *   contributors may be used to endorse or promote products derived from
19  *   this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Copyright (C) 2005 Csaba Henk.
34  * All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  *
45  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
46  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
49  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55  * SUCH DAMAGE.
56  */
57
58 #include <sys/cdefs.h>
59 __FBSDID("$FreeBSD$");
60
61 #include <sys/param.h>
62 #include <sys/module.h>
63 #include <sys/systm.h>
64 #include <sys/errno.h>
65 #include <sys/kernel.h>
66 #include <sys/conf.h>
67 #include <sys/uio.h>
68 #include <sys/malloc.h>
69 #include <sys/queue.h>
70 #include <sys/lock.h>
71 #include <sys/rwlock.h>
72 #include <sys/sx.h>
73 #include <sys/proc.h>
74 #include <sys/mount.h>
75 #include <sys/vnode.h>
76 #include <sys/namei.h>
77 #include <sys/extattr.h>
78 #include <sys/stat.h>
79 #include <sys/unistd.h>
80 #include <sys/filedesc.h>
81 #include <sys/file.h>
82 #include <sys/fcntl.h>
83 #include <sys/dirent.h>
84 #include <sys/bio.h>
85 #include <sys/buf.h>
86 #include <sys/sysctl.h>
87 #include <sys/vmmeter.h>
88
89 #include <vm/vm.h>
90 #include <vm/vm_extern.h>
91 #include <vm/pmap.h>
92 #include <vm/vm_map.h>
93 #include <vm/vm_page.h>
94 #include <vm/vm_param.h>
95 #include <vm/vm_object.h>
96 #include <vm/vm_pager.h>
97 #include <vm/vnode_pager.h>
98 #include <vm/vm_object.h>
99
100 #include "fuse.h"
101 #include "fuse_file.h"
102 #include "fuse_internal.h"
103 #include "fuse_ipc.h"
104 #include "fuse_node.h"
105 #include "fuse_io.h"
106
107 #include <sys/priv.h>
108
109 /* Maximum number of hardlinks to a single FUSE file */
110 #define FUSE_LINK_MAX                      UINT32_MAX
111
112 SDT_PROVIDER_DECLARE(fuse);
113 /* 
114  * Fuse trace probe:
115  * arg0: verbosity.  Higher numbers give more verbose messages
116  * arg1: Textual message
117  */
118 SDT_PROBE_DEFINE2(fuse, , vnops, trace, "int", "char*");
119
120 /* vnode ops */
121 static vop_access_t fuse_vnop_access;
122 static vop_close_t fuse_vnop_close;
123 static vop_create_t fuse_vnop_create;
124 static vop_deleteextattr_t fuse_vnop_deleteextattr;
125 static vop_fdatasync_t fuse_vnop_fdatasync;
126 static vop_fsync_t fuse_vnop_fsync;
127 static vop_getattr_t fuse_vnop_getattr;
128 static vop_getextattr_t fuse_vnop_getextattr;
129 static vop_inactive_t fuse_vnop_inactive;
130 static vop_link_t fuse_vnop_link;
131 static vop_listextattr_t fuse_vnop_listextattr;
132 static vop_lookup_t fuse_vnop_lookup;
133 static vop_mkdir_t fuse_vnop_mkdir;
134 static vop_mknod_t fuse_vnop_mknod;
135 static vop_open_t fuse_vnop_open;
136 static vop_pathconf_t fuse_vnop_pathconf;
137 static vop_read_t fuse_vnop_read;
138 static vop_readdir_t fuse_vnop_readdir;
139 static vop_readlink_t fuse_vnop_readlink;
140 static vop_reclaim_t fuse_vnop_reclaim;
141 static vop_remove_t fuse_vnop_remove;
142 static vop_rename_t fuse_vnop_rename;
143 static vop_rmdir_t fuse_vnop_rmdir;
144 static vop_setattr_t fuse_vnop_setattr;
145 static vop_setextattr_t fuse_vnop_setextattr;
146 static vop_strategy_t fuse_vnop_strategy;
147 static vop_symlink_t fuse_vnop_symlink;
148 static vop_write_t fuse_vnop_write;
149 static vop_getpages_t fuse_vnop_getpages;
150 static vop_putpages_t fuse_vnop_putpages;
151 static vop_print_t fuse_vnop_print;
152
153 struct vop_vector fuse_vnops = {
154         .vop_default = &default_vnodeops,
155         .vop_access = fuse_vnop_access,
156         .vop_close = fuse_vnop_close,
157         .vop_create = fuse_vnop_create,
158         .vop_deleteextattr = fuse_vnop_deleteextattr,
159         .vop_fsync = fuse_vnop_fsync,
160         .vop_fdatasync = fuse_vnop_fdatasync,
161         .vop_getattr = fuse_vnop_getattr,
162         .vop_getextattr = fuse_vnop_getextattr,
163         .vop_inactive = fuse_vnop_inactive,
164         .vop_link = fuse_vnop_link,
165         .vop_listextattr = fuse_vnop_listextattr,
166         .vop_lookup = fuse_vnop_lookup,
167         .vop_mkdir = fuse_vnop_mkdir,
168         .vop_mknod = fuse_vnop_mknod,
169         .vop_open = fuse_vnop_open,
170         .vop_pathconf = fuse_vnop_pathconf,
171         .vop_read = fuse_vnop_read,
172         .vop_readdir = fuse_vnop_readdir,
173         .vop_readlink = fuse_vnop_readlink,
174         .vop_reclaim = fuse_vnop_reclaim,
175         .vop_remove = fuse_vnop_remove,
176         .vop_rename = fuse_vnop_rename,
177         .vop_rmdir = fuse_vnop_rmdir,
178         .vop_setattr = fuse_vnop_setattr,
179         .vop_setextattr = fuse_vnop_setextattr,
180         .vop_strategy = fuse_vnop_strategy,
181         .vop_symlink = fuse_vnop_symlink,
182         .vop_write = fuse_vnop_write,
183         .vop_getpages = fuse_vnop_getpages,
184         .vop_putpages = fuse_vnop_putpages,
185         .vop_print = fuse_vnop_print,
186 };
187
188 static u_long fuse_lookup_cache_hits = 0;
189
190 SYSCTL_ULONG(_vfs_fusefs, OID_AUTO, lookup_cache_hits, CTLFLAG_RD,
191     &fuse_lookup_cache_hits, 0, "number of positive cache hits in lookup");
192
193 static u_long fuse_lookup_cache_misses = 0;
194
195 SYSCTL_ULONG(_vfs_fusefs, OID_AUTO, lookup_cache_misses, CTLFLAG_RD,
196     &fuse_lookup_cache_misses, 0, "number of cache misses in lookup");
197
198 int     fuse_lookup_cache_enable = 1;
199
200 SYSCTL_INT(_vfs_fusefs, OID_AUTO, lookup_cache_enable, CTLFLAG_RW,
201     &fuse_lookup_cache_enable, 0, "if non-zero, enable lookup cache");
202
203 /*
204  * XXX: This feature is highly experimental and can bring to instabilities,
205  * needs revisiting before to be enabled by default.
206  */
207 static int fuse_reclaim_revoked = 0;
208
209 SYSCTL_INT(_vfs_fusefs, OID_AUTO, reclaim_revoked, CTLFLAG_RW,
210     &fuse_reclaim_revoked, 0, "");
211
212 uma_zone_t fuse_pbuf_zone;
213
214 #define fuse_vm_page_lock(m)            vm_page_lock((m));
215 #define fuse_vm_page_unlock(m)          vm_page_unlock((m));
216 #define fuse_vm_page_lock_queues()      ((void)0)
217 #define fuse_vm_page_unlock_queues()    ((void)0)
218
219 /*
220     struct vnop_access_args {
221         struct vnode *a_vp;
222 #if VOP_ACCESS_TAKES_ACCMODE_T
223         accmode_t a_accmode;
224 #else
225         int a_mode;
226 #endif
227         struct ucred *a_cred;
228         struct thread *a_td;
229     };
230 */
231 static int
232 fuse_vnop_access(struct vop_access_args *ap)
233 {
234         struct vnode *vp = ap->a_vp;
235         int accmode = ap->a_accmode;
236         struct ucred *cred = ap->a_cred;
237
238         struct fuse_access_param facp;
239         struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp));
240
241         int err;
242
243         if (fuse_isdeadfs(vp)) {
244                 if (vnode_isvroot(vp)) {
245                         return 0;
246                 }
247                 return ENXIO;
248         }
249         if (!(data->dataflags & FSESS_INITED)) {
250                 if (vnode_isvroot(vp)) {
251                         if (priv_check_cred(cred, PRIV_VFS_ADMIN) ||
252                             (fuse_match_cred(data->daemoncred, cred) == 0)) {
253                                 return 0;
254                         }
255                 }
256                 return EBADF;
257         }
258         if (vnode_islnk(vp)) {
259                 return 0;
260         }
261         bzero(&facp, sizeof(facp));
262
263         err = fuse_internal_access(vp, accmode, &facp, ap->a_td, ap->a_cred);
264         return err;
265 }
266
267 /*
268     struct vnop_close_args {
269         struct vnode *a_vp;
270         int  a_fflag;
271         struct ucred *a_cred;
272         struct thread *a_td;
273     };
274 */
275 static int
276 fuse_vnop_close(struct vop_close_args *ap)
277 {
278         struct vnode *vp = ap->a_vp;
279         struct ucred *cred = ap->a_cred;
280         int fflag = ap->a_fflag;
281         fufh_type_t fufh_type;
282
283         if (fuse_isdeadfs(vp)) {
284                 return 0;
285         }
286         if (vnode_isdir(vp)) {
287                 if (fuse_filehandle_valid(vp, FUFH_RDONLY)) {
288                         fuse_filehandle_close(vp, FUFH_RDONLY, NULL, cred);
289                 }
290                 return 0;
291         }
292         if (fflag & IO_NDELAY) {
293                 return 0;
294         }
295         fufh_type = fuse_filehandle_xlate_from_fflags(fflag);
296
297         if (!fuse_filehandle_valid(vp, fufh_type)) {
298                 int i;
299
300                 for (i = 0; i < FUFH_MAXTYPE; i++)
301                         if (fuse_filehandle_valid(vp, i))
302                                 break;
303                 if (i == FUFH_MAXTYPE)
304                         panic("FUSE: fufh type %d found to be invalid in close"
305                               " (fflag=0x%x)\n",
306                               fufh_type, fflag);
307         }
308         if ((VTOFUD(vp)->flag & FN_SIZECHANGE) != 0) {
309                 fuse_vnode_savesize(vp, cred);
310         }
311         return 0;
312 }
313
314 static void
315 fdisp_make_mknod_for_fallback(
316         struct fuse_dispatcher *fdip,
317         struct componentname *cnp,
318         struct vnode *dvp,
319         uint64_t parentnid,
320         struct thread *td,
321         struct ucred *cred,
322         mode_t mode,
323         enum fuse_opcode *op)
324 {
325         struct fuse_mknod_in *fmni;
326
327         fdisp_init(fdip, sizeof(*fmni) + cnp->cn_namelen + 1);
328         *op = FUSE_MKNOD;
329         fdisp_make(fdip, *op, vnode_mount(dvp), parentnid, td, cred);
330         fmni = fdip->indata;
331         fmni->mode = mode;
332         fmni->rdev = 0;
333         memcpy((char *)fdip->indata + sizeof(*fmni), cnp->cn_nameptr,
334             cnp->cn_namelen);
335         ((char *)fdip->indata)[sizeof(*fmni) + cnp->cn_namelen] = '\0';
336 }
337 /*
338     struct vnop_create_args {
339         struct vnode *a_dvp;
340         struct vnode **a_vpp;
341         struct componentname *a_cnp;
342         struct vattr *a_vap;
343     };
344 */
345 static int
346 fuse_vnop_create(struct vop_create_args *ap)
347 {
348         struct vnode *dvp = ap->a_dvp;
349         struct vnode **vpp = ap->a_vpp;
350         struct componentname *cnp = ap->a_cnp;
351         struct vattr *vap = ap->a_vap;
352         struct thread *td = cnp->cn_thread;
353         struct ucred *cred = cnp->cn_cred;
354
355         struct fuse_open_in *foi;
356         struct fuse_entry_out *feo;
357         struct fuse_open_out *foo;
358         struct fuse_dispatcher fdi, fdi2;
359         struct fuse_dispatcher *fdip = &fdi;
360         struct fuse_dispatcher *fdip2 = NULL;
361
362         int err;
363
364         struct mount *mp = vnode_mount(dvp);
365         uint64_t parentnid = VTOFUD(dvp)->nid;
366         mode_t mode = MAKEIMODE(vap->va_type, vap->va_mode);
367         enum fuse_opcode op;
368
369         if (fuse_isdeadfs(dvp)) {
370                 return ENXIO;
371         }
372         bzero(&fdi, sizeof(fdi));
373
374         if ((vap->va_type != VREG))
375                 return (EINVAL);
376
377         if (!fsess_isimpl(mp, FUSE_CREATE)) {
378                 /* Fallback to FUSE_MKNOD/FUSE_OPEN */
379                 fdisp_make_mknod_for_fallback(fdip, cnp, dvp, parentnid, td,
380                         cred, mode, &op);
381         } else {
382                 /* Use FUSE_CREATE */
383                 op = FUSE_CREATE;
384                 fdisp_init(fdip, sizeof(*foi) + cnp->cn_namelen + 1);
385                 fdisp_make(fdip, op, vnode_mount(dvp), parentnid, td, cred);
386                 foi = fdip->indata;
387                 foi->mode = mode;
388                 foi->flags = O_CREAT | O_RDWR;
389                 memcpy((char *)fdip->indata + sizeof(*foi), cnp->cn_nameptr,
390                     cnp->cn_namelen);
391                 ((char *)fdip->indata)[sizeof(*foi) + cnp->cn_namelen] = '\0';
392         }
393
394         err = fdisp_wait_answ(fdip);
395
396         if (err) {
397                 if (err == ENOSYS && op == FUSE_CREATE) {
398                         fsess_set_notimpl(mp, FUSE_CREATE);
399                         fdisp_make_mknod_for_fallback(fdip, cnp, dvp,
400                                 parentnid, td, cred, mode, &op);
401                         err = fdisp_wait_answ(fdip);
402                 }
403                 if (err)
404                         goto out;
405         }
406
407         feo = fdip->answ;
408
409         if ((err = fuse_internal_checkentry(feo, VREG))) {
410                 goto out;
411         }
412
413         if (op == FUSE_CREATE) {
414                 foo = (struct fuse_open_out*)(feo + 1);
415         } else {
416                 /* Issue a separate FUSE_OPEN */
417                 fdip2 = &fdi2;
418                 fdisp_init(fdip2, sizeof(*foi));
419                 fdisp_make(fdip2, FUSE_OPEN, vnode_mount(dvp), feo->nodeid, td,
420                         cred);
421                 foi = fdip2->indata;
422                 foi->mode = mode;
423                 foi->flags = O_RDWR;
424                 err = fdisp_wait_answ(fdip2);
425                 if (err)
426                         goto out;
427                 foo = fdip2->answ;
428         }
429         err = fuse_vnode_get(mp, feo, feo->nodeid, dvp, vpp, cnp, VREG);
430         if (err) {
431                 struct fuse_release_in *fri;
432                 uint64_t nodeid = feo->nodeid;
433                 uint64_t fh_id = foo->fh;
434
435                 fdisp_init(fdip, sizeof(*fri));
436                 fdisp_make(fdip, FUSE_RELEASE, mp, nodeid, td, cred);
437                 fri = fdip->indata;
438                 fri->fh = fh_id;
439                 fri->flags = fuse_filehandle_xlate_to_oflags(FUFH_RDWR);
440                 fuse_insert_callback(fdip->tick, fuse_internal_forget_callback);
441                 fuse_insert_message(fdip->tick);
442                 goto out;
443         }
444         ASSERT_VOP_ELOCKED(*vpp, "fuse_vnop_create");
445
446         fuse_filehandle_init(*vpp, FUFH_RDWR, NULL, foo->fh);
447         fuse_vnode_open(*vpp, foo->open_flags, td);
448         cache_purge_negative(dvp);
449
450 out:
451         if (fdip2)
452                 fdisp_destroy(fdip2);
453         fdisp_destroy(fdip);
454         return err;
455 }
456
457 /*
458     struct vnop_fdatasync_args {
459         struct vop_generic_args a_gen;
460         struct vnode * a_vp;
461         struct thread * a_td;
462     };
463 */
464 static int
465 fuse_vnop_fdatasync(struct vop_fdatasync_args *ap)
466 {
467         struct vnode *vp = ap->a_vp;
468         struct thread *td = ap->a_td;
469         int waitfor = MNT_WAIT;
470
471         int err = 0;
472
473         if (fuse_isdeadfs(vp)) {
474                 return 0;
475         }
476         if ((err = vop_stdfdatasync_buf(ap)))
477                 return err;
478
479         return fuse_internal_fsync(vp, td, waitfor, true);
480 }
481
482 /*
483     struct vnop_fsync_args {
484         struct vop_generic_args a_gen;
485         struct vnode * a_vp;
486         int  a_waitfor;
487         struct thread * a_td;
488     };
489 */
490 static int
491 fuse_vnop_fsync(struct vop_fsync_args *ap)
492 {
493         struct vnode *vp = ap->a_vp;
494         struct thread *td = ap->a_td;
495         int waitfor = ap->a_waitfor;
496         int err = 0;
497
498         if (fuse_isdeadfs(vp)) {
499                 return 0;
500         }
501         if ((err = vop_stdfsync(ap)))
502                 return err;
503
504         return fuse_internal_fsync(vp, td, waitfor, false);
505 }
506
507 /*
508     struct vnop_getattr_args {
509         struct vnode *a_vp;
510         struct vattr *a_vap;
511         struct ucred *a_cred;
512         struct thread *a_td;
513     };
514 */
515 static int
516 fuse_vnop_getattr(struct vop_getattr_args *ap)
517 {
518         struct vnode *vp = ap->a_vp;
519         struct vattr *vap = ap->a_vap;
520         struct ucred *cred = ap->a_cred;
521         struct thread *td = curthread;
522         struct fuse_vnode_data *fvdat = VTOFUD(vp);
523         struct fuse_attr_out *fao;
524
525         int err = 0;
526         int dataflags;
527         struct fuse_dispatcher fdi;
528
529         dataflags = fuse_get_mpdata(vnode_mount(vp))->dataflags;
530
531         /* Note that we are not bailing out on a dead file system just yet. */
532
533         if (!(dataflags & FSESS_INITED)) {
534                 if (!vnode_isvroot(vp)) {
535                         fdata_set_dead(fuse_get_mpdata(vnode_mount(vp)));
536                         err = ENOTCONN;
537                         return err;
538                 } else {
539                         goto fake;
540                 }
541         }
542         fdisp_init(&fdi, 0);
543         if ((err = fdisp_simple_putget_vp(&fdi, FUSE_GETATTR, vp, td, cred))) {
544                 if ((err == ENOTCONN) && vnode_isvroot(vp)) {
545                         /* see comment in fuse_vfsop_statfs() */
546                         fdisp_destroy(&fdi);
547                         goto fake;
548                 }
549                 if (err == ENOENT) {
550                         fuse_internal_vnode_disappear(vp);
551                 }
552                 goto out;
553         }
554
555         fao = (struct fuse_attr_out *)fdi.answ;
556         fuse_internal_cache_attrs(vp, &fao->attr, fao->attr_valid,
557                 fao->attr_valid_nsec, vap);
558         if (vap->va_type != vnode_vtype(vp)) {
559                 fuse_internal_vnode_disappear(vp);
560                 err = ENOENT;
561                 goto out;
562         }
563         if ((fvdat->flag & FN_SIZECHANGE) != 0)
564                 vap->va_size = fvdat->filesize;
565
566         if (vnode_isreg(vp) && (fvdat->flag & FN_SIZECHANGE) == 0) {
567                 /*
568                  * This is for those cases when the file size changed without us
569                  * knowing, and we want to catch up.
570                  */
571                 off_t new_filesize = ((struct fuse_attr_out *)
572                                       fdi.answ)->attr.size;
573
574                 if (fvdat->filesize != new_filesize) {
575                         fuse_vnode_setsize(vp, cred, new_filesize);
576                         fvdat->flag &= ~FN_SIZECHANGE;
577                 }
578         }
579
580 out:
581         fdisp_destroy(&fdi);
582         return err;
583
584 fake:
585         bzero(vap, sizeof(*vap));
586         vap->va_type = vnode_vtype(vp);
587
588         return 0;
589 }
590
591 /*
592     struct vnop_inactive_args {
593         struct vnode *a_vp;
594         struct thread *a_td;
595     };
596 */
597 static int
598 fuse_vnop_inactive(struct vop_inactive_args *ap)
599 {
600         struct vnode *vp = ap->a_vp;
601         struct thread *td = ap->a_td;
602
603         struct fuse_vnode_data *fvdat = VTOFUD(vp);
604         struct fuse_filehandle *fufh = NULL;
605
606         int type, need_flush = 1;
607
608         for (type = 0; type < FUFH_MAXTYPE; type++) {
609                 fufh = &(fvdat->fufh[type]);
610                 if (FUFH_IS_VALID(fufh)) {
611                         if (need_flush && vp->v_type == VREG) {
612                                 if ((VTOFUD(vp)->flag & FN_SIZECHANGE) != 0) {
613                                         fuse_vnode_savesize(vp, NULL);
614                                 }
615                                 if (fuse_data_cache_invalidate ||
616                                     (fvdat->flag & FN_REVOKED) != 0)
617                                         fuse_io_invalbuf(vp, td);
618                                 else
619                                         fuse_io_flushbuf(vp, MNT_WAIT, td);
620                                 need_flush = 0;
621                         }
622                         fuse_filehandle_close(vp, type, td, NULL);
623                 }
624         }
625
626         if ((fvdat->flag & FN_REVOKED) != 0 && fuse_reclaim_revoked) {
627                 vrecycle(vp);
628         }
629         return 0;
630 }
631
632 /*
633     struct vnop_link_args {
634         struct vnode *a_tdvp;
635         struct vnode *a_vp;
636         struct componentname *a_cnp;
637     };
638 */
639 static int
640 fuse_vnop_link(struct vop_link_args *ap)
641 {
642         struct vnode *vp = ap->a_vp;
643         struct vnode *tdvp = ap->a_tdvp;
644         struct componentname *cnp = ap->a_cnp;
645
646         struct vattr *vap = VTOVA(vp);
647
648         struct fuse_dispatcher fdi;
649         struct fuse_entry_out *feo;
650         struct fuse_link_in fli;
651
652         int err;
653
654         if (fuse_isdeadfs(vp)) {
655                 return ENXIO;
656         }
657         if (vnode_mount(tdvp) != vnode_mount(vp)) {
658                 return EXDEV;
659         }
660
661         /*
662          * This is a seatbelt check to protect naive userspace filesystems from
663          * themselves and the limitations of the FUSE IPC protocol.  If a
664          * filesystem does not allow attribute caching, assume it is capable of
665          * validating that nlink does not overflow.
666          */
667         if (vap != NULL && vap->va_nlink >= FUSE_LINK_MAX)
668                 return EMLINK;
669         fli.oldnodeid = VTOI(vp);
670
671         fdisp_init(&fdi, 0);
672         fuse_internal_newentry_makerequest(vnode_mount(tdvp), VTOI(tdvp), cnp,
673             FUSE_LINK, &fli, sizeof(fli), &fdi);
674         if ((err = fdisp_wait_answ(&fdi))) {
675                 goto out;
676         }
677         feo = fdi.answ;
678
679         err = fuse_internal_checkentry(feo, vnode_vtype(vp));
680 out:
681         fdisp_destroy(&fdi);
682         return err;
683 }
684
685 /*
686     struct vnop_lookup_args {
687         struct vnodeop_desc *a_desc;
688         struct vnode *a_dvp;
689         struct vnode **a_vpp;
690         struct componentname *a_cnp;
691     };
692 */
693 int
694 fuse_vnop_lookup(struct vop_lookup_args *ap)
695 {
696         struct vnode *dvp = ap->a_dvp;
697         struct vnode **vpp = ap->a_vpp;
698         struct componentname *cnp = ap->a_cnp;
699         struct thread *td = cnp->cn_thread;
700         struct ucred *cred = cnp->cn_cred;
701
702         int nameiop = cnp->cn_nameiop;
703         int flags = cnp->cn_flags;
704         int wantparent = flags & (LOCKPARENT | WANTPARENT);
705         int islastcn = flags & ISLASTCN;
706         struct mount *mp = vnode_mount(dvp);
707
708         int err = 0;
709         int lookup_err = 0;
710         struct vnode *vp = NULL;
711
712         struct fuse_dispatcher fdi;
713         enum fuse_opcode op;
714
715         uint64_t nid;
716         struct fuse_access_param facp;
717
718         if (fuse_isdeadfs(dvp)) {
719                 *vpp = NULL;
720                 return ENXIO;
721         }
722         if (!vnode_isdir(dvp)) {
723                 return ENOTDIR;
724         }
725         if (islastcn && vfs_isrdonly(mp) && (nameiop != LOOKUP)) {
726                 return EROFS;
727         }
728         /*
729          * We do access check prior to doing anything else only in the case
730          * when we are at fs root (we'd like to say, "we are at the first
731          * component", but that's not exactly the same... nevermind).
732          * See further comments at further access checks.
733          */
734
735         bzero(&facp, sizeof(facp));
736         if (vnode_isvroot(dvp)) {       /* early permission check hack */
737                 if ((err = fuse_internal_access(dvp, VEXEC, &facp, td, cred))) {
738                         return err;
739                 }
740         }
741         if (flags & ISDOTDOT) {
742                 nid = VTOFUD(dvp)->parent_nid;
743                 if (nid == 0) {
744                         return ENOENT;
745                 }
746                 fdisp_init(&fdi, 0);
747                 op = FUSE_GETATTR;
748                 goto calldaemon;
749         } else if (cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.') {
750                 nid = VTOI(dvp);
751                 fdisp_init(&fdi, 0);
752                 op = FUSE_GETATTR;
753                 goto calldaemon;
754         } else if (fuse_lookup_cache_enable) {
755                 err = cache_lookup(dvp, vpp, cnp, NULL, NULL);
756                 switch (err) {
757
758                 case -1:                /* positive match */
759                         atomic_add_acq_long(&fuse_lookup_cache_hits, 1);
760                         return 0;
761
762                 case 0:         /* no match in cache */
763                         atomic_add_acq_long(&fuse_lookup_cache_misses, 1);
764                         break;
765
766                 case ENOENT:            /* negative match */
767                         /* fall through */
768                 default:
769                         return err;
770                 }
771         }
772         nid = VTOI(dvp);
773         fdisp_init(&fdi, cnp->cn_namelen + 1);
774         op = FUSE_LOOKUP;
775
776 calldaemon:
777         fdisp_make(&fdi, op, mp, nid, td, cred);
778
779         if (op == FUSE_LOOKUP) {
780                 memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
781                 ((char *)fdi.indata)[cnp->cn_namelen] = '\0';
782         }
783         lookup_err = fdisp_wait_answ(&fdi);
784
785         if ((op == FUSE_LOOKUP) && !lookup_err) {       /* lookup call succeeded */
786                 nid = ((struct fuse_entry_out *)fdi.answ)->nodeid;
787                 if (!nid) {
788                         /*
789                          * zero nodeid is the same as "not found",
790                          * but it's also cacheable (which we keep
791                          * keep on doing not as of writing this)
792                          */
793                         fdi.answ_stat = ENOENT;
794                         lookup_err = ENOENT;
795                 } else if (nid == FUSE_ROOT_ID) {
796                         lookup_err = EINVAL;
797                 }
798         }
799         if (lookup_err &&
800             (!fdi.answ_stat || lookup_err != ENOENT || op != FUSE_LOOKUP)) {
801                 fdisp_destroy(&fdi);
802                 return lookup_err;
803         }
804         /* lookup_err, if non-zero, must be ENOENT at this point */
805
806         if (lookup_err) {
807
808                 if ((nameiop == CREATE || nameiop == RENAME) && islastcn
809                      /* && directory dvp has not been removed */ ) {
810
811                         if (vfs_isrdonly(mp)) {
812                                 err = EROFS;
813                                 goto out;
814                         }
815 #if 0 /* THINK_ABOUT_THIS */
816                         if ((err = fuse_internal_access(dvp, VWRITE, cred, td, &facp))) {
817                                 goto out;
818                         }
819 #endif
820
821                         /*
822                          * Possibly record the position of a slot in the
823                          * directory large enough for the new component name.
824                          * This can be recorded in the vnode private data for
825                          * dvp. Set the SAVENAME flag to hold onto the
826                          * pathname for use later in VOP_CREATE or VOP_RENAME.
827                          */
828                         cnp->cn_flags |= SAVENAME;
829
830                         err = EJUSTRETURN;
831                         goto out;
832                 }
833                 /* Consider inserting name into cache. */
834
835                 /*
836                  * No we can't use negative caching, as the fs
837                  * changes are out of our control.
838                  * False positives' falseness turns out just as things
839                  * go by, but false negatives' falseness doesn't.
840                  * (and aiding the caching mechanism with extra control
841                  * mechanisms comes quite close to beating the whole purpose
842                  * caching...)
843                  */
844 #if 0
845                 if ((cnp->cn_flags & MAKEENTRY) != 0) {
846                         SDT_PROBE2(fuse, , vnops, trace, 1,
847                                 "inserting NULL into cache");
848                         cache_enter(dvp, NULL, cnp);
849                 }
850 #endif
851                 err = ENOENT;
852                 goto out;
853
854         } else {
855
856                 /* !lookup_err */
857
858                 struct fuse_entry_out *feo = NULL;
859                 struct fuse_attr *fattr = NULL;
860
861                 if (op == FUSE_GETATTR) {
862                         fattr = &((struct fuse_attr_out *)fdi.answ)->attr;
863                 } else {
864                         feo = (struct fuse_entry_out *)fdi.answ;
865                         fattr = &(feo->attr);
866                 }
867
868                 /*
869                  * If deleting, and at end of pathname, return parameters
870                  * which can be used to remove file.  If the wantparent flag
871                  * isn't set, we return only the directory, otherwise we go on
872                  * and lock the inode, being careful with ".".
873                  */
874                 if (nameiop == DELETE && islastcn) {
875                         /*
876                          * Check for write access on directory.
877                          */
878                         facp.xuid = fattr->uid;
879                         facp.facc_flags |= FACCESS_STICKY;
880                         err = fuse_internal_access(dvp, VWRITE, &facp, td, cred);
881                         facp.facc_flags &= ~FACCESS_XQUERIES;
882
883                         if (err) {
884                                 goto out;
885                         }
886                         if (nid == VTOI(dvp)) {
887                                 vref(dvp);
888                                 *vpp = dvp;
889                         } else {
890                                 err = fuse_vnode_get(dvp->v_mount, feo, nid,
891                                     dvp, &vp, cnp, IFTOVT(fattr->mode));
892                                 if (err)
893                                         goto out;
894                                 *vpp = vp;
895                         }
896
897                         /*
898                          * Save the name for use in VOP_RMDIR and VOP_REMOVE
899                          * later.
900                          */
901                         cnp->cn_flags |= SAVENAME;
902                         goto out;
903
904                 }
905                 /*
906                  * If rewriting (RENAME), return the inode and the
907                  * information required to rewrite the present directory
908                  * Must get inode of directory entry to verify it's a
909                  * regular file, or empty directory.
910                  */
911                 if (nameiop == RENAME && wantparent && islastcn) {
912
913 #if 0 /* THINK_ABOUT_THIS */
914                         if ((err = fuse_internal_access(dvp, VWRITE, cred, td, &facp))) {
915                                 goto out;
916                         }
917 #endif
918
919                         /*
920                          * Check for "."
921                          */
922                         if (nid == VTOI(dvp)) {
923                                 err = EISDIR;
924                                 goto out;
925                         }
926                         err = fuse_vnode_get(vnode_mount(dvp), feo, nid, dvp,
927                             &vp, cnp, IFTOVT(fattr->mode));
928                         if (err) {
929                                 goto out;
930                         }
931                         *vpp = vp;
932                         /*
933                          * Save the name for use in VOP_RENAME later.
934                          */
935                         cnp->cn_flags |= SAVENAME;
936
937                         goto out;
938                 }
939                 if (flags & ISDOTDOT) {
940                         struct mount *mp;
941                         int ltype;
942
943                         /*
944                          * Expanded copy of vn_vget_ino() so that
945                          * fuse_vnode_get() can be used.
946                          */
947                         mp = dvp->v_mount;
948                         ltype = VOP_ISLOCKED(dvp);
949                         err = vfs_busy(mp, MBF_NOWAIT);
950                         if (err != 0) {
951                                 vfs_ref(mp);
952                                 VOP_UNLOCK(dvp, 0);
953                                 err = vfs_busy(mp, 0);
954                                 vn_lock(dvp, ltype | LK_RETRY);
955                                 vfs_rel(mp);
956                                 if (err)
957                                         goto out;
958                                 if ((dvp->v_iflag & VI_DOOMED) != 0) {
959                                         err = ENOENT;
960                                         vfs_unbusy(mp);
961                                         goto out;
962                                 }
963                         }
964                         VOP_UNLOCK(dvp, 0);
965                         err = fuse_vnode_get(vnode_mount(dvp), feo, nid, NULL,
966                             &vp, cnp, IFTOVT(fattr->mode));
967                         vfs_unbusy(mp);
968                         vn_lock(dvp, ltype | LK_RETRY);
969                         if ((dvp->v_iflag & VI_DOOMED) != 0) {
970                                 if (err == 0)
971                                         vput(vp);
972                                 err = ENOENT;
973                         }
974                         if (err)
975                                 goto out;
976                         *vpp = vp;
977                 } else if (nid == VTOI(dvp)) {
978                         vref(dvp);
979                         *vpp = dvp;
980                 } else {
981                         struct fuse_vnode_data *fvdat;
982
983                         err = fuse_vnode_get(vnode_mount(dvp), feo, nid, dvp,
984                             &vp, cnp, IFTOVT(fattr->mode));
985                         if (err) {
986                                 goto out;
987                         }
988                         fuse_vnode_setparent(vp, dvp);
989
990                         /*
991                          * In the case where we are looking up a FUSE node
992                          * represented by an existing cached vnode, and the
993                          * true size reported by FUSE_LOOKUP doesn't match
994                          * the vnode's cached size, fix the vnode cache to
995                          * match the real object size.
996                          *
997                          * This can occur via FUSE distributed filesystems,
998                          * irregular files, etc.
999                          */
1000                         fvdat = VTOFUD(vp);
1001                         if (vnode_isreg(vp) &&
1002                             fattr->size != fvdat->filesize) {
1003                                 /*
1004                                  * The FN_SIZECHANGE flag reflects a dirty
1005                                  * append.  If userspace lets us know our cache
1006                                  * is invalid, that write was lost.  (Dirty
1007                                  * writes that do not cause append are also
1008                                  * lost, but we don't detect them here.)
1009                                  *
1010                                  * XXX: Maybe disable WB caching on this mount.
1011                                  */
1012                                 if (fvdat->flag & FN_SIZECHANGE)
1013                                         printf("%s: WB cache incoherent on "
1014                                             "%s!\n", __func__,
1015                                             vnode_mount(vp)->mnt_stat.f_mntonname);
1016
1017                                 (void)fuse_vnode_setsize(vp, cred, fattr->size);
1018                                 fvdat->flag &= ~FN_SIZECHANGE;
1019                         }
1020                         *vpp = vp;
1021                 }
1022
1023                 if (op == FUSE_GETATTR) {
1024                         struct fuse_attr_out *fao =
1025                                 (struct fuse_attr_out*)fdi.answ;
1026                         fuse_internal_cache_attrs(*vpp,
1027                                 &fao->attr, fao->attr_valid,
1028                                 fao->attr_valid_nsec, NULL);
1029                 } else {
1030                         struct fuse_entry_out *feo =
1031                                 (struct fuse_entry_out*)fdi.answ;
1032                         fuse_internal_cache_attrs(*vpp,
1033                                 &feo->attr, feo->attr_valid,
1034                                 feo->attr_valid_nsec, NULL);
1035                 }
1036
1037                 /* Insert name into cache if appropriate. */
1038
1039                 /*
1040                  * Nooo, caching is evil. With caching, we can't avoid stale
1041                  * information taking over the playground (cached info is not
1042                  * just positive/negative, it does have qualitative aspects,
1043                  * too). And a (VOP/FUSE)_GETATTR is always thrown anyway, when
1044                  * walking down along cached path components, and that's not
1045                  * any cheaper than FUSE_LOOKUP. This might change with
1046                  * implementing kernel side attr caching, but... In Linux,
1047                  * lookup results are not cached, and the daemon is bombarded
1048                  * with FUSE_LOOKUPS on and on. This shows that by design, the
1049                  * daemon is expected to handle frequent lookup queries
1050                  * efficiently, do its caching in userspace, and so on.
1051                  *
1052                  * So just leave the name cache alone.
1053                  */
1054
1055                 /*
1056                  * Well, now I know, Linux caches lookups, but with a
1057                  * timeout... So it's the same thing as attribute caching:
1058                  * we can deal with it when implement timeouts.
1059                  */
1060 #if 0
1061                 if (cnp->cn_flags & MAKEENTRY) {
1062                         cache_enter(dvp, *vpp, cnp);
1063                 }
1064 #endif
1065         }
1066 out:
1067         if (!lookup_err) {
1068
1069                 /* No lookup error; need to clean up. */
1070
1071                 if (err) {              /* Found inode; exit with no vnode. */
1072                         if (op == FUSE_LOOKUP) {
1073                                 fuse_internal_forget_send(vnode_mount(dvp), td, cred,
1074                                     nid, 1);
1075                         }
1076                         fdisp_destroy(&fdi);
1077                         return err;
1078                 } else {
1079 #ifndef NO_EARLY_PERM_CHECK_HACK
1080                         if (!islastcn) {
1081                                 /*
1082                                  * We have the attributes of the next item
1083                                  * *now*, and it's a fact, and we do not
1084                                  * have to do extra work for it (ie, beg the
1085                                  * daemon), and it neither depends on such
1086                                  * accidental things like attr caching. So
1087                                  * the big idea: check credentials *now*,
1088                                  * not at the beginning of the next call to
1089                                  * lookup.
1090                                  * 
1091                                  * The first item of the lookup chain (fs root)
1092                                  * won't be checked then here, of course, as
1093                                  * its never "the next". But go and see that
1094                                  * the root is taken care about at the very
1095                                  * beginning of this function.
1096                                  * 
1097                                  * Now, given we want to do the access check
1098                                  * this way, one might ask: so then why not
1099                                  * do the access check just after fetching
1100                                  * the inode and its attributes from the
1101                                  * daemon? Why bother with producing the
1102                                  * corresponding vnode at all if something
1103                                  * is not OK? We know what's the deal as
1104                                  * soon as we get those attrs... There is
1105                                  * one bit of info though not given us by
1106                                  * the daemon: whether his response is
1107                                  * authoritative or not... His response should
1108                                  * be ignored if something is mounted over
1109                                  * the dir in question. But that can be
1110                                  * known only by having the vnode...
1111                                  */
1112                                 int tmpvtype = vnode_vtype(*vpp);
1113
1114                                 bzero(&facp, sizeof(facp));
1115                                 /*the early perm check hack */
1116                                     facp.facc_flags |= FACCESS_VA_VALID;
1117
1118                                 if ((tmpvtype != VDIR) && (tmpvtype != VLNK)) {
1119                                         err = ENOTDIR;
1120                                 }
1121                                 if (!err && !vnode_mountedhere(*vpp)) {
1122                                         err = fuse_internal_access(*vpp, VEXEC, &facp, td, cred);
1123                                 }
1124                                 if (err) {
1125                                         if (tmpvtype == VLNK)
1126                                                 SDT_PROBE2(fuse, , vnops, trace,
1127                                                     1, "weird, permission "
1128                                                     "error with a symlink?");
1129                                         vput(*vpp);
1130                                         *vpp = NULL;
1131                                 }
1132                         }
1133 #endif
1134                 }
1135         }
1136         fdisp_destroy(&fdi);
1137
1138         return err;
1139 }
1140
1141 /*
1142     struct vnop_mkdir_args {
1143         struct vnode *a_dvp;
1144         struct vnode **a_vpp;
1145         struct componentname *a_cnp;
1146         struct vattr *a_vap;
1147     };
1148 */
1149 static int
1150 fuse_vnop_mkdir(struct vop_mkdir_args *ap)
1151 {
1152         struct vnode *dvp = ap->a_dvp;
1153         struct vnode **vpp = ap->a_vpp;
1154         struct componentname *cnp = ap->a_cnp;
1155         struct vattr *vap = ap->a_vap;
1156
1157         struct fuse_mkdir_in fmdi;
1158
1159         if (fuse_isdeadfs(dvp)) {
1160                 return ENXIO;
1161         }
1162         fmdi.mode = MAKEIMODE(vap->va_type, vap->va_mode);
1163
1164         return (fuse_internal_newentry(dvp, vpp, cnp, FUSE_MKDIR, &fmdi,
1165             sizeof(fmdi), VDIR));
1166 }
1167
1168 /*
1169     struct vnop_mknod_args {
1170         struct vnode *a_dvp;
1171         struct vnode **a_vpp;
1172         struct componentname *a_cnp;
1173         struct vattr *a_vap;
1174     };
1175 */
1176 static int
1177 fuse_vnop_mknod(struct vop_mknod_args *ap)
1178 {
1179
1180         struct vnode *dvp = ap->a_dvp;
1181         struct vnode **vpp = ap->a_vpp;
1182         struct componentname *cnp = ap->a_cnp;
1183         struct vattr *vap = ap->a_vap;
1184         struct fuse_mknod_in fmni;
1185
1186         if (fuse_isdeadfs(dvp))
1187                 return ENXIO;
1188
1189         fmni.mode = MAKEIMODE(vap->va_type, vap->va_mode);
1190         fmni.rdev = vap->va_rdev;
1191         return (fuse_internal_newentry(dvp, vpp, cnp, FUSE_MKNOD, &fmni,
1192             sizeof(fmni), vap->va_type));
1193 }
1194
1195 /*
1196     struct vnop_open_args {
1197         struct vnode *a_vp;
1198         int  a_mode;
1199         struct ucred *a_cred;
1200         struct thread *a_td;
1201         int a_fdidx; / struct file *a_fp;
1202     };
1203 */
1204 static int
1205 fuse_vnop_open(struct vop_open_args *ap)
1206 {
1207         struct vnode *vp = ap->a_vp;
1208         int mode = ap->a_mode;
1209         struct thread *td = ap->a_td;
1210         struct ucred *cred = ap->a_cred;
1211         int32_t fuse_open_flags = 0;
1212
1213         fufh_type_t fufh_type;
1214         struct fuse_vnode_data *fvdat;
1215
1216         if (fuse_isdeadfs(vp))
1217                 return ENXIO;
1218         if (vp->v_type == VCHR || vp->v_type == VBLK || vp->v_type == VFIFO)
1219                 return (EOPNOTSUPP);
1220         if ((mode & (FREAD | FWRITE)) == 0)
1221                 return EINVAL;
1222
1223         fvdat = VTOFUD(vp);
1224
1225         if (vnode_isdir(vp)) {
1226                 fufh_type = FUFH_RDONLY;
1227         } else {
1228                 fufh_type = fuse_filehandle_xlate_from_fflags(mode);
1229         }
1230
1231         /*
1232          * For WRONLY opens, force DIRECT_IO.  This is necessary since writing
1233          * a partial block through the buffer cache will result in a read of
1234          * the block and that read won't be allowed by the WRONLY open.
1235          */
1236         if (fufh_type == FUFH_WRONLY || (fvdat->flag & FN_DIRECTIO) != 0)
1237                 fuse_open_flags = FOPEN_DIRECT_IO;
1238
1239         if (fuse_filehandle_validrw(vp, fufh_type) != FUFH_INVALID) {
1240                 fuse_vnode_open(vp, fuse_open_flags, td);
1241                 return 0;
1242         }
1243
1244         return fuse_filehandle_open(vp, fufh_type, NULL, td, cred);
1245 }
1246
1247 static int
1248 fuse_vnop_pathconf(struct vop_pathconf_args *ap)
1249 {
1250
1251         switch (ap->a_name) {
1252         case _PC_FILESIZEBITS:
1253                 *ap->a_retval = 64;
1254                 return (0);
1255         case _PC_NAME_MAX:
1256                 *ap->a_retval = NAME_MAX;
1257                 return (0);
1258         case _PC_LINK_MAX:
1259                 *ap->a_retval = MIN(LONG_MAX, FUSE_LINK_MAX);
1260                 return (0);
1261         case _PC_SYMLINK_MAX:
1262                 *ap->a_retval = MAXPATHLEN;
1263                 return (0);
1264         case _PC_NO_TRUNC:
1265                 *ap->a_retval = 1;
1266                 return (0);
1267         default:
1268                 return (vop_stdpathconf(ap));
1269         }
1270 }
1271
1272 /*
1273     struct vnop_read_args {
1274         struct vnode *a_vp;
1275         struct uio *a_uio;
1276         int  a_ioflag;
1277         struct ucred *a_cred;
1278     };
1279 */
1280 static int
1281 fuse_vnop_read(struct vop_read_args *ap)
1282 {
1283         struct vnode *vp = ap->a_vp;
1284         struct uio *uio = ap->a_uio;
1285         int ioflag = ap->a_ioflag;
1286         struct ucred *cred = ap->a_cred;
1287
1288         if (fuse_isdeadfs(vp)) {
1289                 return ENXIO;
1290         }
1291
1292         if (VTOFUD(vp)->flag & FN_DIRECTIO) {
1293                 ioflag |= IO_DIRECT;
1294         }
1295
1296         return fuse_io_dispatch(vp, uio, ioflag, cred);
1297 }
1298
1299 /*
1300     struct vnop_readdir_args {
1301         struct vnode *a_vp;
1302         struct uio *a_uio;
1303         struct ucred *a_cred;
1304         int *a_eofflag;
1305         int *ncookies;
1306         u_long **a_cookies;
1307     };
1308 */
1309 static int
1310 fuse_vnop_readdir(struct vop_readdir_args *ap)
1311 {
1312         struct vnode *vp = ap->a_vp;
1313         struct uio *uio = ap->a_uio;
1314         struct ucred *cred = ap->a_cred;
1315
1316         struct fuse_filehandle *fufh = NULL;
1317         struct fuse_iov cookediov;
1318
1319         int err = 0;
1320         int freefufh = 0;
1321
1322         if (fuse_isdeadfs(vp)) {
1323                 return ENXIO;
1324         }
1325         if (                            /* XXXIP ((uio_iovcnt(uio) > 1)) || */
1326             (uio_resid(uio) < sizeof(struct dirent))) {
1327                 return EINVAL;
1328         }
1329
1330         if (!fuse_filehandle_valid(vp, FUFH_RDONLY)) {
1331                 SDT_PROBE2(fuse, , vnops, trace, 1,
1332                         "calling readdir() before open()");
1333                 err = fuse_filehandle_open(vp, FUFH_RDONLY, &fufh, NULL, cred);
1334                 freefufh = 1;
1335         } else {
1336                 err = fuse_filehandle_get(vp, FUFH_RDONLY, &fufh);
1337         }
1338         if (err) {
1339                 return (err);
1340         }
1341 #define DIRCOOKEDSIZE FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + MAXNAMLEN + 1)
1342         fiov_init(&cookediov, DIRCOOKEDSIZE);
1343
1344         err = fuse_internal_readdir(vp, uio, fufh, &cookediov);
1345
1346         fiov_teardown(&cookediov);
1347         if (freefufh) {
1348                 fuse_filehandle_close(vp, FUFH_RDONLY, NULL, cred);
1349         }
1350         return err;
1351 }
1352
1353 /*
1354     struct vnop_readlink_args {
1355         struct vnode *a_vp;
1356         struct uio *a_uio;
1357         struct ucred *a_cred;
1358     };
1359 */
1360 static int
1361 fuse_vnop_readlink(struct vop_readlink_args *ap)
1362 {
1363         struct vnode *vp = ap->a_vp;
1364         struct uio *uio = ap->a_uio;
1365         struct ucred *cred = ap->a_cred;
1366
1367         struct fuse_dispatcher fdi;
1368         int err;
1369
1370         if (fuse_isdeadfs(vp)) {
1371                 return ENXIO;
1372         }
1373         if (!vnode_islnk(vp)) {
1374                 return EINVAL;
1375         }
1376         fdisp_init(&fdi, 0);
1377         err = fdisp_simple_putget_vp(&fdi, FUSE_READLINK, vp, curthread, cred);
1378         if (err) {
1379                 goto out;
1380         }
1381         if (((char *)fdi.answ)[0] == '/' &&
1382             fuse_get_mpdata(vnode_mount(vp))->dataflags & FSESS_PUSH_SYMLINKS_IN) {
1383                 char *mpth = vnode_mount(vp)->mnt_stat.f_mntonname;
1384
1385                 err = uiomove(mpth, strlen(mpth), uio);
1386         }
1387         if (!err) {
1388                 err = uiomove(fdi.answ, fdi.iosize, uio);
1389         }
1390 out:
1391         fdisp_destroy(&fdi);
1392         return err;
1393 }
1394
1395 /*
1396     struct vnop_reclaim_args {
1397         struct vnode *a_vp;
1398         struct thread *a_td;
1399     };
1400 */
1401 static int
1402 fuse_vnop_reclaim(struct vop_reclaim_args *ap)
1403 {
1404         struct vnode *vp = ap->a_vp;
1405         struct thread *td = ap->a_td;
1406
1407         struct fuse_vnode_data *fvdat = VTOFUD(vp);
1408         struct fuse_filehandle *fufh = NULL;
1409
1410         int type;
1411
1412         if (!fvdat) {
1413                 panic("FUSE: no vnode data during recycling");
1414         }
1415         for (type = 0; type < FUFH_MAXTYPE; type++) {
1416                 fufh = &(fvdat->fufh[type]);
1417                 if (FUFH_IS_VALID(fufh)) {
1418                         printf("FUSE: vnode being reclaimed but fufh (type=%d) is valid",
1419                             type);
1420                         fuse_filehandle_close(vp, type, td, NULL);
1421                 }
1422         }
1423
1424         if ((!fuse_isdeadfs(vp)) && (fvdat->nlookup)) {
1425                 fuse_internal_forget_send(vnode_mount(vp), td, NULL, VTOI(vp),
1426                     fvdat->nlookup);
1427         }
1428         fuse_vnode_setparent(vp, NULL);
1429         cache_purge(vp);
1430         vfs_hash_remove(vp);
1431         vnode_destroy_vobject(vp);
1432         fuse_vnode_destroy(vp);
1433
1434         return 0;
1435 }
1436
1437 /*
1438     struct vnop_remove_args {
1439         struct vnode *a_dvp;
1440         struct vnode *a_vp;
1441         struct componentname *a_cnp;
1442     };
1443 */
1444 static int
1445 fuse_vnop_remove(struct vop_remove_args *ap)
1446 {
1447         struct vnode *dvp = ap->a_dvp;
1448         struct vnode *vp = ap->a_vp;
1449         struct componentname *cnp = ap->a_cnp;
1450
1451         int err;
1452
1453         if (fuse_isdeadfs(vp)) {
1454                 return ENXIO;
1455         }
1456         if (vnode_isdir(vp)) {
1457                 return EPERM;
1458         }
1459         cache_purge(vp);
1460
1461         err = fuse_internal_remove(dvp, vp, cnp, FUSE_UNLINK);
1462
1463         if (err == 0)
1464                 fuse_internal_vnode_disappear(vp);
1465         return err;
1466 }
1467
1468 /*
1469     struct vnop_rename_args {
1470         struct vnode *a_fdvp;
1471         struct vnode *a_fvp;
1472         struct componentname *a_fcnp;
1473         struct vnode *a_tdvp;
1474         struct vnode *a_tvp;
1475         struct componentname *a_tcnp;
1476     };
1477 */
1478 static int
1479 fuse_vnop_rename(struct vop_rename_args *ap)
1480 {
1481         struct vnode *fdvp = ap->a_fdvp;
1482         struct vnode *fvp = ap->a_fvp;
1483         struct componentname *fcnp = ap->a_fcnp;
1484         struct vnode *tdvp = ap->a_tdvp;
1485         struct vnode *tvp = ap->a_tvp;
1486         struct componentname *tcnp = ap->a_tcnp;
1487         struct fuse_data *data;
1488
1489         int err = 0;
1490
1491         if (fuse_isdeadfs(fdvp)) {
1492                 return ENXIO;
1493         }
1494         if (fvp->v_mount != tdvp->v_mount ||
1495             (tvp && fvp->v_mount != tvp->v_mount)) {
1496                 SDT_PROBE2(fuse, , vnops, trace, 1, "cross-device rename");
1497                 err = EXDEV;
1498                 goto out;
1499         }
1500         cache_purge(fvp);
1501
1502         /*
1503          * FUSE library is expected to check if target directory is not
1504          * under the source directory in the file system tree.
1505          * Linux performs this check at VFS level.
1506          */
1507         data = fuse_get_mpdata(vnode_mount(tdvp));
1508         sx_xlock(&data->rename_lock);
1509         err = fuse_internal_rename(fdvp, fcnp, tdvp, tcnp);
1510         if (err == 0) {
1511                 if (tdvp != fdvp)
1512                         fuse_vnode_setparent(fvp, tdvp);
1513                 if (tvp != NULL)
1514                         fuse_vnode_setparent(tvp, NULL);
1515         }
1516         sx_unlock(&data->rename_lock);
1517
1518         if (tvp != NULL && tvp != fvp) {
1519                 cache_purge(tvp);
1520         }
1521         if (vnode_isdir(fvp)) {
1522                 if ((tvp != NULL) && vnode_isdir(tvp)) {
1523                         cache_purge(tdvp);
1524                 }
1525                 cache_purge(fdvp);
1526         }
1527 out:
1528         if (tdvp == tvp) {
1529                 vrele(tdvp);
1530         } else {
1531                 vput(tdvp);
1532         }
1533         if (tvp != NULL) {
1534                 vput(tvp);
1535         }
1536         vrele(fdvp);
1537         vrele(fvp);
1538
1539         return err;
1540 }
1541
1542 /*
1543     struct vnop_rmdir_args {
1544             struct vnode *a_dvp;
1545             struct vnode *a_vp;
1546             struct componentname *a_cnp;
1547     } *ap;
1548 */
1549 static int
1550 fuse_vnop_rmdir(struct vop_rmdir_args *ap)
1551 {
1552         struct vnode *dvp = ap->a_dvp;
1553         struct vnode *vp = ap->a_vp;
1554
1555         int err;
1556
1557         if (fuse_isdeadfs(vp)) {
1558                 return ENXIO;
1559         }
1560         if (VTOFUD(vp) == VTOFUD(dvp)) {
1561                 return EINVAL;
1562         }
1563         err = fuse_internal_remove(dvp, vp, ap->a_cnp, FUSE_RMDIR);
1564
1565         if (err == 0)
1566                 fuse_internal_vnode_disappear(vp);
1567         return err;
1568 }
1569
1570 /*
1571     struct vnop_setattr_args {
1572         struct vnode *a_vp;
1573         struct vattr *a_vap;
1574         struct ucred *a_cred;
1575         struct thread *a_td;
1576     };
1577 */
1578 static int
1579 fuse_vnop_setattr(struct vop_setattr_args *ap)
1580 {
1581         struct vnode *vp = ap->a_vp;
1582         struct vattr *vap = ap->a_vap;
1583         struct ucred *cred = ap->a_cred;
1584         struct thread *td = curthread;
1585         struct fuse_dispatcher fdi;
1586         struct fuse_setattr_in *fsai;
1587         struct fuse_access_param facp;
1588
1589         int err = 0;
1590         enum vtype vtyp;
1591         int sizechanged = 0;
1592         uint64_t newsize = 0;
1593
1594         if (fuse_isdeadfs(vp)) {
1595                 return ENXIO;
1596         }
1597         fdisp_init(&fdi, sizeof(*fsai));
1598         fdisp_make_vp(&fdi, FUSE_SETATTR, vp, td, cred);
1599         fsai = fdi.indata;
1600         fsai->valid = 0;
1601
1602         bzero(&facp, sizeof(facp));
1603
1604         facp.xuid = vap->va_uid;
1605         facp.xgid = vap->va_gid;
1606
1607         if (vap->va_uid != (uid_t)VNOVAL) {
1608                 facp.facc_flags |= FACCESS_CHOWN;
1609                 fsai->uid = vap->va_uid;
1610                 fsai->valid |= FATTR_UID;
1611         }
1612         if (vap->va_gid != (gid_t)VNOVAL) {
1613                 facp.facc_flags |= FACCESS_CHOWN;
1614                 fsai->gid = vap->va_gid;
1615                 fsai->valid |= FATTR_GID;
1616         }
1617         if (vap->va_size != VNOVAL) {
1618
1619                 struct fuse_filehandle *fufh = NULL;
1620
1621                 /*Truncate to a new value. */
1622                     fsai->size = vap->va_size;
1623                 sizechanged = 1;
1624                 newsize = vap->va_size;
1625                 fsai->valid |= FATTR_SIZE;
1626
1627                 fuse_filehandle_getrw(vp, FUFH_WRONLY, &fufh);
1628                 if (fufh) {
1629                         fsai->fh = fufh->fh_id;
1630                         fsai->valid |= FATTR_FH;
1631                 }
1632         }
1633         if (vap->va_atime.tv_sec != VNOVAL) {
1634                 fsai->atime = vap->va_atime.tv_sec;
1635                 fsai->atimensec = vap->va_atime.tv_nsec;
1636                 fsai->valid |= FATTR_ATIME;
1637         }
1638         if (vap->va_mtime.tv_sec != VNOVAL) {
1639                 fsai->mtime = vap->va_mtime.tv_sec;
1640                 fsai->mtimensec = vap->va_mtime.tv_nsec;
1641                 fsai->valid |= FATTR_MTIME;
1642         }
1643         if (vap->va_mode != (mode_t)VNOVAL) {
1644                 fsai->mode = vap->va_mode & ALLPERMS;
1645                 fsai->valid |= FATTR_MODE;
1646         }
1647         if (!fsai->valid) {
1648                 goto out;
1649         }
1650         vtyp = vnode_vtype(vp);
1651
1652         if (fsai->valid & FATTR_SIZE && vtyp == VDIR) {
1653                 err = EISDIR;
1654                 goto out;
1655         }
1656         if (vfs_isrdonly(vnode_mount(vp)) && (fsai->valid & ~FATTR_SIZE || vtyp == VREG)) {
1657                 err = EROFS;
1658                 goto out;
1659         }
1660
1661         if ((err = fdisp_wait_answ(&fdi)))
1662                 goto out;
1663         vtyp = IFTOVT(((struct fuse_attr_out *)fdi.answ)->attr.mode);
1664
1665         if (vnode_vtype(vp) != vtyp) {
1666                 if (vnode_vtype(vp) == VNON && vtyp != VNON) {
1667                         SDT_PROBE2(fuse, , vnops, trace, 1, "FUSE: Dang! "
1668                                 "vnode_vtype is VNON and vtype isn't.");
1669                 } else {
1670                         /*
1671                          * STALE vnode, ditch
1672                          *
1673                          * The vnode has changed its type "behind our back".
1674                          * There's nothing really we can do, so let us just
1675                          * force an internal revocation and tell the caller to
1676                          * try again, if interested.
1677                          */
1678                         fuse_internal_vnode_disappear(vp);
1679                         err = EAGAIN;
1680                 }
1681         }
1682         if (err == 0) {
1683                 struct fuse_attr_out *fao = (struct fuse_attr_out*)fdi.answ;
1684                 fuse_internal_cache_attrs(vp, &fao->attr, fao->attr_valid,
1685                         fao->attr_valid_nsec, NULL);
1686         }
1687
1688 out:
1689         fdisp_destroy(&fdi);
1690         if (!err && sizechanged) {
1691                 fuse_vnode_setsize(vp, cred, newsize);
1692                 VTOFUD(vp)->flag &= ~FN_SIZECHANGE;
1693         }
1694         return err;
1695 }
1696
1697 /*
1698     struct vnop_strategy_args {
1699         struct vnode *a_vp;
1700         struct buf *a_bp;
1701     };
1702 */
1703 static int
1704 fuse_vnop_strategy(struct vop_strategy_args *ap)
1705 {
1706         struct vnode *vp = ap->a_vp;
1707         struct buf *bp = ap->a_bp;
1708
1709         if (!vp || fuse_isdeadfs(vp)) {
1710                 bp->b_ioflags |= BIO_ERROR;
1711                 bp->b_error = ENXIO;
1712                 bufdone(bp);
1713                 return 0;
1714         }
1715         if (bp->b_iocmd == BIO_WRITE) {
1716                 int err;
1717
1718                 err = fuse_vnode_refreshsize(vp, NOCRED);
1719                 if (err) {
1720                         bp->b_ioflags |= BIO_ERROR;
1721                         bp->b_error = err;
1722                         bufdone(bp);
1723                         return 0;
1724                 }
1725         }
1726
1727         /*
1728          * VOP_STRATEGY always returns zero and signals error via bp->b_ioflags.
1729          * fuse_io_strategy sets bp's error fields
1730          */
1731         (void)fuse_io_strategy(vp, bp);
1732
1733         return 0;
1734 }
1735
1736
1737 /*
1738     struct vnop_symlink_args {
1739         struct vnode *a_dvp;
1740         struct vnode **a_vpp;
1741         struct componentname *a_cnp;
1742         struct vattr *a_vap;
1743         char *a_target;
1744     };
1745 */
1746 static int
1747 fuse_vnop_symlink(struct vop_symlink_args *ap)
1748 {
1749         struct vnode *dvp = ap->a_dvp;
1750         struct vnode **vpp = ap->a_vpp;
1751         struct componentname *cnp = ap->a_cnp;
1752         const char *target = ap->a_target;
1753
1754         struct fuse_dispatcher fdi;
1755
1756         int err;
1757         size_t len;
1758
1759         if (fuse_isdeadfs(dvp)) {
1760                 return ENXIO;
1761         }
1762         /*
1763          * Unlike the other creator type calls, here we have to create a message
1764          * where the name of the new entry comes first, and the data describing
1765          * the entry comes second.
1766          * Hence we can't rely on our handy fuse_internal_newentry() routine,
1767          * but put together the message manually and just call the core part.
1768          */
1769
1770         len = strlen(target) + 1;
1771         fdisp_init(&fdi, len + cnp->cn_namelen + 1);
1772         fdisp_make_vp(&fdi, FUSE_SYMLINK, dvp, curthread, NULL);
1773
1774         memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
1775         ((char *)fdi.indata)[cnp->cn_namelen] = '\0';
1776         memcpy((char *)fdi.indata + cnp->cn_namelen + 1, target, len);
1777
1778         err = fuse_internal_newentry_core(dvp, vpp, cnp, VLNK, &fdi);
1779         fdisp_destroy(&fdi);
1780         return err;
1781 }
1782
1783 /*
1784     struct vnop_write_args {
1785         struct vnode *a_vp;
1786         struct uio *a_uio;
1787         int  a_ioflag;
1788         struct ucred *a_cred;
1789     };
1790 */
1791 static int
1792 fuse_vnop_write(struct vop_write_args *ap)
1793 {
1794         struct vnode *vp = ap->a_vp;
1795         struct uio *uio = ap->a_uio;
1796         int ioflag = ap->a_ioflag;
1797         struct ucred *cred = ap->a_cred;
1798         int err;
1799
1800         if (fuse_isdeadfs(vp)) {
1801                 return ENXIO;
1802         }
1803         err = fuse_vnode_refreshsize(vp, cred);
1804         if (err)
1805                 return err;
1806
1807         if (VTOFUD(vp)->flag & FN_DIRECTIO) {
1808                 ioflag |= IO_DIRECT;
1809         }
1810
1811         return fuse_io_dispatch(vp, uio, ioflag, cred);
1812 }
1813
1814 SDT_PROBE_DEFINE1(fuse, , vnops, vnop_getpages_error, "int");
1815 /*
1816     struct vnop_getpages_args {
1817         struct vnode *a_vp;
1818         vm_page_t *a_m;
1819         int a_count;
1820         int a_reqpage;
1821     };
1822 */
1823 static int
1824 fuse_vnop_getpages(struct vop_getpages_args *ap)
1825 {
1826         int i, error, nextoff, size, toff, count, npages;
1827         struct uio uio;
1828         struct iovec iov;
1829         vm_offset_t kva;
1830         struct buf *bp;
1831         struct vnode *vp;
1832         struct thread *td;
1833         struct ucred *cred;
1834         vm_page_t *pages;
1835
1836         vp = ap->a_vp;
1837         KASSERT(vp->v_object, ("objectless vp passed to getpages"));
1838         td = curthread;                 /* XXX */
1839         cred = curthread->td_ucred;     /* XXX */
1840         pages = ap->a_m;
1841         npages = ap->a_count;
1842
1843         if (!fsess_opt_mmap(vnode_mount(vp))) {
1844                 SDT_PROBE2(fuse, , vnops, trace, 1,
1845                         "called on non-cacheable vnode??\n");
1846                 return (VM_PAGER_ERROR);
1847         }
1848
1849         /*
1850          * If the last page is partially valid, just return it and allow
1851          * the pager to zero-out the blanks.  Partially valid pages can
1852          * only occur at the file EOF.
1853          *
1854          * XXXGL: is that true for FUSE, which is a local filesystem,
1855          * but still somewhat disconnected from the kernel?
1856          */
1857         VM_OBJECT_WLOCK(vp->v_object);
1858         if (pages[npages - 1]->valid != 0 && --npages == 0)
1859                 goto out;
1860         VM_OBJECT_WUNLOCK(vp->v_object);
1861
1862         /*
1863          * We use only the kva address for the buffer, but this is extremely
1864          * convenient and fast.
1865          */
1866         bp = uma_zalloc(fuse_pbuf_zone, M_WAITOK);
1867
1868         kva = (vm_offset_t)bp->b_data;
1869         pmap_qenter(kva, pages, npages);
1870         VM_CNT_INC(v_vnodein);
1871         VM_CNT_ADD(v_vnodepgsin, npages);
1872
1873         count = npages << PAGE_SHIFT;
1874         iov.iov_base = (caddr_t)kva;
1875         iov.iov_len = count;
1876         uio.uio_iov = &iov;
1877         uio.uio_iovcnt = 1;
1878         uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
1879         uio.uio_resid = count;
1880         uio.uio_segflg = UIO_SYSSPACE;
1881         uio.uio_rw = UIO_READ;
1882         uio.uio_td = td;
1883
1884         error = fuse_io_dispatch(vp, &uio, IO_DIRECT, cred);
1885         pmap_qremove(kva, npages);
1886
1887         uma_zfree(fuse_pbuf_zone, bp);
1888
1889         if (error && (uio.uio_resid == count)) {
1890                 SDT_PROBE1(fuse, , vnops, vnop_getpages_error, error);
1891                 return VM_PAGER_ERROR;
1892         }
1893         /*
1894          * Calculate the number of bytes read and validate only that number
1895          * of bytes.  Note that due to pending writes, size may be 0.  This
1896          * does not mean that the remaining data is invalid!
1897          */
1898
1899         size = count - uio.uio_resid;
1900         VM_OBJECT_WLOCK(vp->v_object);
1901         fuse_vm_page_lock_queues();
1902         for (i = 0, toff = 0; i < npages; i++, toff = nextoff) {
1903                 vm_page_t m;
1904
1905                 nextoff = toff + PAGE_SIZE;
1906                 m = pages[i];
1907
1908                 if (nextoff <= size) {
1909                         /*
1910                          * Read operation filled an entire page
1911                          */
1912                         m->valid = VM_PAGE_BITS_ALL;
1913                         KASSERT(m->dirty == 0,
1914                             ("fuse_getpages: page %p is dirty", m));
1915                 } else if (size > toff) {
1916                         /*
1917                          * Read operation filled a partial page.
1918                          */
1919                         m->valid = 0;
1920                         vm_page_set_valid_range(m, 0, size - toff);
1921                         KASSERT(m->dirty == 0,
1922                             ("fuse_getpages: page %p is dirty", m));
1923                 } else {
1924                         /*
1925                          * Read operation was short.  If no error occurred
1926                          * we may have hit a zero-fill section.   We simply
1927                          * leave valid set to 0.
1928                          */
1929                         ;
1930                 }
1931         }
1932         fuse_vm_page_unlock_queues();
1933 out:
1934         VM_OBJECT_WUNLOCK(vp->v_object);
1935         if (ap->a_rbehind)
1936                 *ap->a_rbehind = 0;
1937         if (ap->a_rahead)
1938                 *ap->a_rahead = 0;
1939         return (VM_PAGER_OK);
1940 }
1941
1942 /*
1943     struct vnop_putpages_args {
1944         struct vnode *a_vp;
1945         vm_page_t *a_m;
1946         int a_count;
1947         int a_sync;
1948         int *a_rtvals;
1949         vm_ooffset_t a_offset;
1950     };
1951 */
1952 static int
1953 fuse_vnop_putpages(struct vop_putpages_args *ap)
1954 {
1955         struct uio uio;
1956         struct iovec iov;
1957         vm_offset_t kva;
1958         struct buf *bp;
1959         int i, error, npages, count;
1960         off_t offset;
1961         int *rtvals;
1962         struct vnode *vp;
1963         struct thread *td;
1964         struct ucred *cred;
1965         vm_page_t *pages;
1966         vm_ooffset_t fsize;
1967
1968         vp = ap->a_vp;
1969         KASSERT(vp->v_object, ("objectless vp passed to putpages"));
1970         fsize = vp->v_object->un_pager.vnp.vnp_size;
1971         td = curthread;                 /* XXX */
1972         cred = curthread->td_ucred;     /* XXX */
1973         pages = ap->a_m;
1974         count = ap->a_count;
1975         rtvals = ap->a_rtvals;
1976         npages = btoc(count);
1977         offset = IDX_TO_OFF(pages[0]->pindex);
1978
1979         if (!fsess_opt_mmap(vnode_mount(vp))) {
1980                 SDT_PROBE2(fuse, , vnops, trace, 1,
1981                         "called on non-cacheable vnode??\n");
1982         }
1983         for (i = 0; i < npages; i++)
1984                 rtvals[i] = VM_PAGER_AGAIN;
1985
1986         /*
1987          * When putting pages, do not extend file past EOF.
1988          */
1989
1990         if (offset + count > fsize) {
1991                 count = fsize - offset;
1992                 if (count < 0)
1993                         count = 0;
1994         }
1995         /*
1996          * We use only the kva address for the buffer, but this is extremely
1997          * convenient and fast.
1998          */
1999         bp = uma_zalloc(fuse_pbuf_zone, M_WAITOK);
2000
2001         kva = (vm_offset_t)bp->b_data;
2002         pmap_qenter(kva, pages, npages);
2003         VM_CNT_INC(v_vnodeout);
2004         VM_CNT_ADD(v_vnodepgsout, count);
2005
2006         iov.iov_base = (caddr_t)kva;
2007         iov.iov_len = count;
2008         uio.uio_iov = &iov;
2009         uio.uio_iovcnt = 1;
2010         uio.uio_offset = offset;
2011         uio.uio_resid = count;
2012         uio.uio_segflg = UIO_SYSSPACE;
2013         uio.uio_rw = UIO_WRITE;
2014         uio.uio_td = td;
2015
2016         error = fuse_io_dispatch(vp, &uio, IO_DIRECT, cred);
2017
2018         pmap_qremove(kva, npages);
2019         uma_zfree(fuse_pbuf_zone, bp);
2020
2021         if (!error) {
2022                 int nwritten = round_page(count - uio.uio_resid) / PAGE_SIZE;
2023
2024                 for (i = 0; i < nwritten; i++) {
2025                         rtvals[i] = VM_PAGER_OK;
2026                         VM_OBJECT_WLOCK(pages[i]->object);
2027                         vm_page_undirty(pages[i]);
2028                         VM_OBJECT_WUNLOCK(pages[i]->object);
2029                 }
2030         }
2031         return rtvals[0];
2032 }
2033
2034 static const char extattr_namespace_separator = '.';
2035
2036 /*
2037     struct vop_getextattr_args {
2038         struct vop_generic_args a_gen;
2039         struct vnode *a_vp;
2040         int a_attrnamespace;
2041         const char *a_name;
2042         struct uio *a_uio;
2043         size_t *a_size;
2044         struct ucred *a_cred;
2045         struct thread *a_td;
2046     };
2047 */
2048 static int
2049 fuse_vnop_getextattr(struct vop_getextattr_args *ap)
2050 {
2051         struct vnode *vp = ap->a_vp;
2052         struct uio *uio = ap->a_uio;
2053         struct fuse_dispatcher fdi;
2054         struct fuse_getxattr_in *get_xattr_in;
2055         struct fuse_getxattr_out *get_xattr_out;
2056         struct mount *mp = vnode_mount(vp);
2057         struct thread *td = ap->a_td;
2058         struct ucred *cred = ap->a_cred;
2059         char *prefix;
2060         char *attr_str;
2061         size_t len;
2062         int err;
2063
2064         if (fuse_isdeadfs(vp))
2065                 return (ENXIO);
2066
2067         /* Default to looking for user attributes. */
2068         if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
2069                 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
2070         else
2071                 prefix = EXTATTR_NAMESPACE_USER_STRING;
2072
2073         len = strlen(prefix) + sizeof(extattr_namespace_separator) +
2074             strlen(ap->a_name) + 1;
2075
2076         fdisp_init(&fdi, len + sizeof(*get_xattr_in));
2077         fdisp_make_vp(&fdi, FUSE_GETXATTR, vp, td, cred);
2078
2079         get_xattr_in = fdi.indata;
2080         /*
2081          * Check to see whether we're querying the available size or
2082          * issuing the actual request.  If we pass in 0, we get back struct
2083          * fuse_getxattr_out.  If we pass in a non-zero size, we get back
2084          * that much data, without the struct fuse_getxattr_out header.
2085          */
2086         if (uio == NULL)
2087                 get_xattr_in->size = 0;
2088         else
2089                 get_xattr_in->size = uio->uio_resid;
2090
2091         attr_str = (char *)fdi.indata + sizeof(*get_xattr_in);
2092         snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
2093             ap->a_name);
2094
2095         err = fdisp_wait_answ(&fdi);
2096         if (err != 0) {
2097                 if (err == ENOSYS)
2098                         fsess_set_notimpl(mp, FUSE_GETXATTR);
2099                 goto out;
2100         }
2101
2102         get_xattr_out = fdi.answ;
2103
2104         if (ap->a_size != NULL)
2105                 *ap->a_size = get_xattr_out->size;
2106
2107         if (uio != NULL)
2108                 err = uiomove(fdi.answ, fdi.iosize, uio);
2109
2110 out:
2111         fdisp_destroy(&fdi);
2112         return (err);
2113 }
2114
2115 /*
2116     struct vop_setextattr_args {
2117         struct vop_generic_args a_gen;
2118         struct vnode *a_vp;
2119         int a_attrnamespace;
2120         const char *a_name;
2121         struct uio *a_uio;
2122         struct ucred *a_cred;
2123         struct thread *a_td;
2124     };
2125 */
2126 static int
2127 fuse_vnop_setextattr(struct vop_setextattr_args *ap)
2128 {
2129         struct vnode *vp = ap->a_vp;
2130         struct uio *uio = ap->a_uio;
2131         struct fuse_dispatcher fdi;
2132         struct fuse_setxattr_in *set_xattr_in;
2133         struct mount *mp = vnode_mount(vp);
2134         struct thread *td = ap->a_td;
2135         struct ucred *cred = ap->a_cred;
2136         char *prefix;
2137         size_t len;
2138         char *attr_str;
2139         int err;
2140         
2141         if (fuse_isdeadfs(vp))
2142                 return (ENXIO);
2143
2144         /* Default to looking for user attributes. */
2145         if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
2146                 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
2147         else
2148                 prefix = EXTATTR_NAMESPACE_USER_STRING;
2149
2150         len = strlen(prefix) + sizeof(extattr_namespace_separator) +
2151             strlen(ap->a_name) + 1;
2152
2153         fdisp_init(&fdi, len + sizeof(*set_xattr_in) + uio->uio_resid);
2154         fdisp_make_vp(&fdi, FUSE_SETXATTR, vp, td, cred);
2155
2156         set_xattr_in = fdi.indata;
2157         set_xattr_in->size = uio->uio_resid;
2158
2159         attr_str = (char *)fdi.indata + sizeof(*set_xattr_in);
2160         snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
2161             ap->a_name);
2162
2163         err = uiomove((char *)fdi.indata + sizeof(*set_xattr_in) + len,
2164             uio->uio_resid, uio);
2165         if (err != 0) {
2166                 goto out;
2167         }
2168
2169         err = fdisp_wait_answ(&fdi);
2170
2171         if (err != 0) {
2172                 if (err == ENOSYS)
2173                         fsess_set_notimpl(mp, FUSE_SETXATTR);
2174                 goto out;
2175         }
2176
2177 out:
2178         fdisp_destroy(&fdi);
2179         return (err);
2180 }
2181
2182 /*
2183  * The Linux / FUSE extended attribute list is simply a collection of
2184  * NUL-terminated strings.  The FreeBSD extended attribute list is a single
2185  * byte length followed by a non-NUL terminated string.  So, this allows
2186  * conversion of the Linux / FUSE format to the FreeBSD format in place.
2187  * Linux attribute names are reported with the namespace as a prefix (e.g.
2188  * "user.attribute_name"), but in FreeBSD they are reported without the
2189  * namespace prefix (e.g. "attribute_name").  So, we're going from:
2190  *
2191  * user.attr_name1\0user.attr_name2\0
2192  *
2193  * to:
2194  *
2195  * <num>attr_name1<num>attr_name2
2196  *
2197  * Where "<num>" is a single byte number of characters in the attribute name.
2198  * 
2199  * Args:
2200  * prefix - exattr namespace prefix string
2201  * list, list_len - input list with namespace prefixes
2202  * bsd_list, bsd_list_len - output list compatible with bsd vfs
2203  */
2204 static int
2205 fuse_xattrlist_convert(char *prefix, const char *list, int list_len,
2206     char *bsd_list, int *bsd_list_len)
2207 {
2208         int len, pos, dist_to_next, prefix_len;
2209
2210         pos = 0;
2211         *bsd_list_len = 0;
2212         prefix_len = strlen(prefix);
2213
2214         while (pos < list_len && list[pos] != '\0') {
2215                 dist_to_next = strlen(&list[pos]) + 1;
2216                 if (bcmp(&list[pos], prefix, prefix_len) == 0 &&
2217                     list[pos + prefix_len] == extattr_namespace_separator) {
2218                         len = dist_to_next -
2219                             (prefix_len + sizeof(extattr_namespace_separator)) - 1;
2220                         if (len >= EXTATTR_MAXNAMELEN)
2221                                 return (ENAMETOOLONG);
2222
2223                         bsd_list[*bsd_list_len] = len;
2224                         memcpy(&bsd_list[*bsd_list_len + 1],
2225                             &list[pos + prefix_len +
2226                             sizeof(extattr_namespace_separator)], len);
2227
2228                         *bsd_list_len += len + 1;
2229                 }
2230
2231                 pos += dist_to_next;
2232         }
2233
2234         return (0);
2235 }
2236
2237 /*
2238     struct vop_listextattr_args {
2239         struct vop_generic_args a_gen;
2240         struct vnode *a_vp;
2241         int a_attrnamespace;
2242         struct uio *a_uio;
2243         size_t *a_size;
2244         struct ucred *a_cred;
2245         struct thread *a_td;
2246     };
2247 */
2248 static int
2249 fuse_vnop_listextattr(struct vop_listextattr_args *ap)
2250 {
2251         struct vnode *vp = ap->a_vp;
2252         struct uio *uio = ap->a_uio;
2253         struct fuse_dispatcher fdi;
2254         struct fuse_listxattr_in *list_xattr_in;
2255         struct fuse_listxattr_out *list_xattr_out;
2256         struct mount *mp = vnode_mount(vp);
2257         struct thread *td = ap->a_td;
2258         struct ucred *cred = ap->a_cred;
2259         size_t len;
2260         char *prefix;
2261         char *attr_str;
2262         char *bsd_list = NULL;
2263         char *linux_list;
2264         int bsd_list_len;
2265         int linux_list_len;
2266         int err;
2267
2268         if (fuse_isdeadfs(vp))
2269                 return (ENXIO);
2270
2271         /*
2272          * Add space for a NUL and the period separator if enabled.
2273          * Default to looking for user attributes.
2274          */
2275         if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
2276                 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
2277         else
2278                 prefix = EXTATTR_NAMESPACE_USER_STRING;
2279
2280         len = strlen(prefix) + sizeof(extattr_namespace_separator) + 1;
2281
2282         fdisp_init(&fdi, sizeof(*list_xattr_in) + len);
2283         fdisp_make_vp(&fdi, FUSE_LISTXATTR, vp, td, cred);
2284
2285         /*
2286          * Retrieve Linux / FUSE compatible list size.
2287          */
2288         list_xattr_in = fdi.indata;
2289         list_xattr_in->size = 0;
2290         attr_str = (char *)fdi.indata + sizeof(*list_xattr_in);
2291         snprintf(attr_str, len, "%s%c", prefix, extattr_namespace_separator);
2292
2293         err = fdisp_wait_answ(&fdi);
2294         if (err != 0) {
2295                 if (err == ENOSYS)
2296                         fsess_set_notimpl(mp, FUSE_LISTXATTR);
2297                 goto out;
2298         }
2299
2300         list_xattr_out = fdi.answ;
2301         linux_list_len = list_xattr_out->size;
2302         if (linux_list_len == 0) {
2303                 if (ap->a_size != NULL)
2304                         *ap->a_size = linux_list_len;
2305                 goto out;
2306         }
2307
2308         /*
2309          * Retrieve Linux / FUSE compatible list values.
2310          */
2311         fdisp_make_vp(&fdi, FUSE_LISTXATTR, vp, td, cred);
2312         list_xattr_in = fdi.indata;
2313         list_xattr_in->size = linux_list_len + sizeof(*list_xattr_out);
2314         attr_str = (char *)fdi.indata + sizeof(*list_xattr_in);
2315         snprintf(attr_str, len, "%s%c", prefix, extattr_namespace_separator);
2316
2317         err = fdisp_wait_answ(&fdi);
2318         if (err != 0)
2319                 goto out;
2320
2321         linux_list = fdi.answ;
2322         linux_list_len = fdi.iosize;
2323
2324         /*
2325          * Retrieve the BSD compatible list values.
2326          * The Linux / FUSE attribute list format isn't the same
2327          * as FreeBSD's format. So we need to transform it into
2328          * FreeBSD's format before giving it to the user.
2329          */
2330         bsd_list = malloc(linux_list_len, M_TEMP, M_WAITOK);
2331         err = fuse_xattrlist_convert(prefix, linux_list, linux_list_len,
2332             bsd_list, &bsd_list_len);
2333         if (err != 0)
2334                 goto out;
2335
2336         if (ap->a_size != NULL)
2337                 *ap->a_size = bsd_list_len;
2338
2339         if (uio != NULL)
2340                 err = uiomove(bsd_list, bsd_list_len, uio);
2341
2342 out:
2343         free(bsd_list, M_TEMP);
2344         fdisp_destroy(&fdi);
2345         return (err);
2346 }
2347
2348 /*
2349     struct vop_deleteextattr_args {
2350         struct vop_generic_args a_gen;
2351         struct vnode *a_vp;
2352         int a_attrnamespace;
2353         const char *a_name;
2354         struct ucred *a_cred;
2355         struct thread *a_td;
2356     };
2357 */
2358 static int
2359 fuse_vnop_deleteextattr(struct vop_deleteextattr_args *ap)
2360 {
2361         struct vnode *vp = ap->a_vp;
2362         struct fuse_dispatcher fdi;
2363         struct mount *mp = vnode_mount(vp);
2364         struct thread *td = ap->a_td;
2365         struct ucred *cred = ap->a_cred;
2366         char *prefix;
2367         size_t len;
2368         char *attr_str;
2369         int err;
2370
2371         if (fuse_isdeadfs(vp))
2372                 return (ENXIO);
2373
2374         /* Default to looking for user attributes. */
2375         if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
2376                 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
2377         else
2378                 prefix = EXTATTR_NAMESPACE_USER_STRING;
2379
2380         len = strlen(prefix) + sizeof(extattr_namespace_separator) +
2381             strlen(ap->a_name) + 1;
2382
2383         fdisp_init(&fdi, len);
2384         fdisp_make_vp(&fdi, FUSE_REMOVEXATTR, vp, td, cred);
2385
2386         attr_str = fdi.indata;
2387         snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
2388             ap->a_name);
2389
2390         err = fdisp_wait_answ(&fdi);
2391         if (err != 0) {
2392                 if (err == ENOSYS)
2393                         fsess_set_notimpl(mp, FUSE_REMOVEXATTR);
2394         }
2395
2396         fdisp_destroy(&fdi);
2397         return (err);
2398 }
2399
2400 /*
2401     struct vnop_print_args {
2402         struct vnode *a_vp;
2403     };
2404 */
2405 static int
2406 fuse_vnop_print(struct vop_print_args *ap)
2407 {
2408         struct fuse_vnode_data *fvdat = VTOFUD(ap->a_vp);
2409
2410         printf("nodeid: %ju, parent nodeid: %ju, nlookup: %ju, flag: %#x\n",
2411             (uintmax_t)VTOILLU(ap->a_vp), (uintmax_t)fvdat->parent_nid,
2412             (uintmax_t)fvdat->nlookup,
2413             fvdat->flag);
2414
2415         return 0;
2416 }