]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/fuse/fuse_vnops.c
fusefs: delete dead code in fuse_vnop_setattr
[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 ENXIO;
1714         }
1715         if (bp->b_iocmd == BIO_WRITE)
1716                 fuse_vnode_refreshsize(vp, NOCRED);
1717
1718         (void)fuse_io_strategy(vp, bp);
1719
1720         /*
1721          * This is a dangerous function. If returns error, that might mean a
1722          * panic. We prefer pretty much anything over being forced to panic
1723          * by a malicious daemon (a demon?). So we just return 0 anyway. You
1724          * should never mind this: this function has its own error
1725          * propagation mechanism via the argument buffer, so
1726          * not-that-melodramatic residents of the call chain still will be
1727          * able to know what to do.
1728          */
1729         return 0;
1730 }
1731
1732
1733 /*
1734     struct vnop_symlink_args {
1735         struct vnode *a_dvp;
1736         struct vnode **a_vpp;
1737         struct componentname *a_cnp;
1738         struct vattr *a_vap;
1739         char *a_target;
1740     };
1741 */
1742 static int
1743 fuse_vnop_symlink(struct vop_symlink_args *ap)
1744 {
1745         struct vnode *dvp = ap->a_dvp;
1746         struct vnode **vpp = ap->a_vpp;
1747         struct componentname *cnp = ap->a_cnp;
1748         const char *target = ap->a_target;
1749
1750         struct fuse_dispatcher fdi;
1751
1752         int err;
1753         size_t len;
1754
1755         if (fuse_isdeadfs(dvp)) {
1756                 return ENXIO;
1757         }
1758         /*
1759          * Unlike the other creator type calls, here we have to create a message
1760          * where the name of the new entry comes first, and the data describing
1761          * the entry comes second.
1762          * Hence we can't rely on our handy fuse_internal_newentry() routine,
1763          * but put together the message manually and just call the core part.
1764          */
1765
1766         len = strlen(target) + 1;
1767         fdisp_init(&fdi, len + cnp->cn_namelen + 1);
1768         fdisp_make_vp(&fdi, FUSE_SYMLINK, dvp, curthread, NULL);
1769
1770         memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
1771         ((char *)fdi.indata)[cnp->cn_namelen] = '\0';
1772         memcpy((char *)fdi.indata + cnp->cn_namelen + 1, target, len);
1773
1774         err = fuse_internal_newentry_core(dvp, vpp, cnp, VLNK, &fdi);
1775         fdisp_destroy(&fdi);
1776         return err;
1777 }
1778
1779 /*
1780     struct vnop_write_args {
1781         struct vnode *a_vp;
1782         struct uio *a_uio;
1783         int  a_ioflag;
1784         struct ucred *a_cred;
1785     };
1786 */
1787 static int
1788 fuse_vnop_write(struct vop_write_args *ap)
1789 {
1790         struct vnode *vp = ap->a_vp;
1791         struct uio *uio = ap->a_uio;
1792         int ioflag = ap->a_ioflag;
1793         struct ucred *cred = ap->a_cred;
1794
1795         if (fuse_isdeadfs(vp)) {
1796                 return ENXIO;
1797         }
1798         fuse_vnode_refreshsize(vp, cred);
1799
1800         if (VTOFUD(vp)->flag & FN_DIRECTIO) {
1801                 ioflag |= IO_DIRECT;
1802         }
1803
1804         return fuse_io_dispatch(vp, uio, ioflag, cred);
1805 }
1806
1807 SDT_PROBE_DEFINE1(fuse, , vnops, vnop_getpages_error, "int");
1808 /*
1809     struct vnop_getpages_args {
1810         struct vnode *a_vp;
1811         vm_page_t *a_m;
1812         int a_count;
1813         int a_reqpage;
1814     };
1815 */
1816 static int
1817 fuse_vnop_getpages(struct vop_getpages_args *ap)
1818 {
1819         int i, error, nextoff, size, toff, count, npages;
1820         struct uio uio;
1821         struct iovec iov;
1822         vm_offset_t kva;
1823         struct buf *bp;
1824         struct vnode *vp;
1825         struct thread *td;
1826         struct ucred *cred;
1827         vm_page_t *pages;
1828
1829         vp = ap->a_vp;
1830         KASSERT(vp->v_object, ("objectless vp passed to getpages"));
1831         td = curthread;                 /* XXX */
1832         cred = curthread->td_ucred;     /* XXX */
1833         pages = ap->a_m;
1834         npages = ap->a_count;
1835
1836         if (!fsess_opt_mmap(vnode_mount(vp))) {
1837                 SDT_PROBE2(fuse, , vnops, trace, 1,
1838                         "called on non-cacheable vnode??\n");
1839                 return (VM_PAGER_ERROR);
1840         }
1841
1842         /*
1843          * If the last page is partially valid, just return it and allow
1844          * the pager to zero-out the blanks.  Partially valid pages can
1845          * only occur at the file EOF.
1846          *
1847          * XXXGL: is that true for FUSE, which is a local filesystem,
1848          * but still somewhat disconnected from the kernel?
1849          */
1850         VM_OBJECT_WLOCK(vp->v_object);
1851         if (pages[npages - 1]->valid != 0 && --npages == 0)
1852                 goto out;
1853         VM_OBJECT_WUNLOCK(vp->v_object);
1854
1855         /*
1856          * We use only the kva address for the buffer, but this is extremely
1857          * convenient and fast.
1858          */
1859         bp = uma_zalloc(fuse_pbuf_zone, M_WAITOK);
1860
1861         kva = (vm_offset_t)bp->b_data;
1862         pmap_qenter(kva, pages, npages);
1863         VM_CNT_INC(v_vnodein);
1864         VM_CNT_ADD(v_vnodepgsin, npages);
1865
1866         count = npages << PAGE_SHIFT;
1867         iov.iov_base = (caddr_t)kva;
1868         iov.iov_len = count;
1869         uio.uio_iov = &iov;
1870         uio.uio_iovcnt = 1;
1871         uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
1872         uio.uio_resid = count;
1873         uio.uio_segflg = UIO_SYSSPACE;
1874         uio.uio_rw = UIO_READ;
1875         uio.uio_td = td;
1876
1877         error = fuse_io_dispatch(vp, &uio, IO_DIRECT, cred);
1878         pmap_qremove(kva, npages);
1879
1880         uma_zfree(fuse_pbuf_zone, bp);
1881
1882         if (error && (uio.uio_resid == count)) {
1883                 SDT_PROBE1(fuse, , vnops, vnop_getpages_error, error);
1884                 return VM_PAGER_ERROR;
1885         }
1886         /*
1887          * Calculate the number of bytes read and validate only that number
1888          * of bytes.  Note that due to pending writes, size may be 0.  This
1889          * does not mean that the remaining data is invalid!
1890          */
1891
1892         size = count - uio.uio_resid;
1893         VM_OBJECT_WLOCK(vp->v_object);
1894         fuse_vm_page_lock_queues();
1895         for (i = 0, toff = 0; i < npages; i++, toff = nextoff) {
1896                 vm_page_t m;
1897
1898                 nextoff = toff + PAGE_SIZE;
1899                 m = pages[i];
1900
1901                 if (nextoff <= size) {
1902                         /*
1903                          * Read operation filled an entire page
1904                          */
1905                         m->valid = VM_PAGE_BITS_ALL;
1906                         KASSERT(m->dirty == 0,
1907                             ("fuse_getpages: page %p is dirty", m));
1908                 } else if (size > toff) {
1909                         /*
1910                          * Read operation filled a partial page.
1911                          */
1912                         m->valid = 0;
1913                         vm_page_set_valid_range(m, 0, size - toff);
1914                         KASSERT(m->dirty == 0,
1915                             ("fuse_getpages: page %p is dirty", m));
1916                 } else {
1917                         /*
1918                          * Read operation was short.  If no error occurred
1919                          * we may have hit a zero-fill section.   We simply
1920                          * leave valid set to 0.
1921                          */
1922                         ;
1923                 }
1924         }
1925         fuse_vm_page_unlock_queues();
1926 out:
1927         VM_OBJECT_WUNLOCK(vp->v_object);
1928         if (ap->a_rbehind)
1929                 *ap->a_rbehind = 0;
1930         if (ap->a_rahead)
1931                 *ap->a_rahead = 0;
1932         return (VM_PAGER_OK);
1933 }
1934
1935 /*
1936     struct vnop_putpages_args {
1937         struct vnode *a_vp;
1938         vm_page_t *a_m;
1939         int a_count;
1940         int a_sync;
1941         int *a_rtvals;
1942         vm_ooffset_t a_offset;
1943     };
1944 */
1945 static int
1946 fuse_vnop_putpages(struct vop_putpages_args *ap)
1947 {
1948         struct uio uio;
1949         struct iovec iov;
1950         vm_offset_t kva;
1951         struct buf *bp;
1952         int i, error, npages, count;
1953         off_t offset;
1954         int *rtvals;
1955         struct vnode *vp;
1956         struct thread *td;
1957         struct ucred *cred;
1958         vm_page_t *pages;
1959         vm_ooffset_t fsize;
1960
1961         vp = ap->a_vp;
1962         KASSERT(vp->v_object, ("objectless vp passed to putpages"));
1963         fsize = vp->v_object->un_pager.vnp.vnp_size;
1964         td = curthread;                 /* XXX */
1965         cred = curthread->td_ucred;     /* XXX */
1966         pages = ap->a_m;
1967         count = ap->a_count;
1968         rtvals = ap->a_rtvals;
1969         npages = btoc(count);
1970         offset = IDX_TO_OFF(pages[0]->pindex);
1971
1972         if (!fsess_opt_mmap(vnode_mount(vp))) {
1973                 SDT_PROBE2(fuse, , vnops, trace, 1,
1974                         "called on non-cacheable vnode??\n");
1975         }
1976         for (i = 0; i < npages; i++)
1977                 rtvals[i] = VM_PAGER_AGAIN;
1978
1979         /*
1980          * When putting pages, do not extend file past EOF.
1981          */
1982
1983         if (offset + count > fsize) {
1984                 count = fsize - offset;
1985                 if (count < 0)
1986                         count = 0;
1987         }
1988         /*
1989          * We use only the kva address for the buffer, but this is extremely
1990          * convenient and fast.
1991          */
1992         bp = uma_zalloc(fuse_pbuf_zone, M_WAITOK);
1993
1994         kva = (vm_offset_t)bp->b_data;
1995         pmap_qenter(kva, pages, npages);
1996         VM_CNT_INC(v_vnodeout);
1997         VM_CNT_ADD(v_vnodepgsout, count);
1998
1999         iov.iov_base = (caddr_t)kva;
2000         iov.iov_len = count;
2001         uio.uio_iov = &iov;
2002         uio.uio_iovcnt = 1;
2003         uio.uio_offset = offset;
2004         uio.uio_resid = count;
2005         uio.uio_segflg = UIO_SYSSPACE;
2006         uio.uio_rw = UIO_WRITE;
2007         uio.uio_td = td;
2008
2009         error = fuse_io_dispatch(vp, &uio, IO_DIRECT, cred);
2010
2011         pmap_qremove(kva, npages);
2012         uma_zfree(fuse_pbuf_zone, bp);
2013
2014         if (!error) {
2015                 int nwritten = round_page(count - uio.uio_resid) / PAGE_SIZE;
2016
2017                 for (i = 0; i < nwritten; i++) {
2018                         rtvals[i] = VM_PAGER_OK;
2019                         VM_OBJECT_WLOCK(pages[i]->object);
2020                         vm_page_undirty(pages[i]);
2021                         VM_OBJECT_WUNLOCK(pages[i]->object);
2022                 }
2023         }
2024         return rtvals[0];
2025 }
2026
2027 static const char extattr_namespace_separator = '.';
2028
2029 /*
2030     struct vop_getextattr_args {
2031         struct vop_generic_args a_gen;
2032         struct vnode *a_vp;
2033         int a_attrnamespace;
2034         const char *a_name;
2035         struct uio *a_uio;
2036         size_t *a_size;
2037         struct ucred *a_cred;
2038         struct thread *a_td;
2039     };
2040 */
2041 static int
2042 fuse_vnop_getextattr(struct vop_getextattr_args *ap)
2043 {
2044         struct vnode *vp = ap->a_vp;
2045         struct uio *uio = ap->a_uio;
2046         struct fuse_dispatcher fdi;
2047         struct fuse_getxattr_in *get_xattr_in;
2048         struct fuse_getxattr_out *get_xattr_out;
2049         struct mount *mp = vnode_mount(vp);
2050         struct thread *td = ap->a_td;
2051         struct ucred *cred = ap->a_cred;
2052         char *prefix;
2053         char *attr_str;
2054         size_t len;
2055         int err;
2056
2057         if (fuse_isdeadfs(vp))
2058                 return (ENXIO);
2059
2060         /* Default to looking for user attributes. */
2061         if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
2062                 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
2063         else
2064                 prefix = EXTATTR_NAMESPACE_USER_STRING;
2065
2066         len = strlen(prefix) + sizeof(extattr_namespace_separator) +
2067             strlen(ap->a_name) + 1;
2068
2069         fdisp_init(&fdi, len + sizeof(*get_xattr_in));
2070         fdisp_make_vp(&fdi, FUSE_GETXATTR, vp, td, cred);
2071
2072         get_xattr_in = fdi.indata;
2073         /*
2074          * Check to see whether we're querying the available size or
2075          * issuing the actual request.  If we pass in 0, we get back struct
2076          * fuse_getxattr_out.  If we pass in a non-zero size, we get back
2077          * that much data, without the struct fuse_getxattr_out header.
2078          */
2079         if (uio == NULL)
2080                 get_xattr_in->size = 0;
2081         else
2082                 get_xattr_in->size = uio->uio_resid;
2083
2084         attr_str = (char *)fdi.indata + sizeof(*get_xattr_in);
2085         snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
2086             ap->a_name);
2087
2088         err = fdisp_wait_answ(&fdi);
2089         if (err != 0) {
2090                 if (err == ENOSYS)
2091                         fsess_set_notimpl(mp, FUSE_GETXATTR);
2092                 goto out;
2093         }
2094
2095         get_xattr_out = fdi.answ;
2096
2097         if (ap->a_size != NULL)
2098                 *ap->a_size = get_xattr_out->size;
2099
2100         if (uio != NULL)
2101                 err = uiomove(fdi.answ, fdi.iosize, uio);
2102
2103 out:
2104         fdisp_destroy(&fdi);
2105         return (err);
2106 }
2107
2108 /*
2109     struct vop_setextattr_args {
2110         struct vop_generic_args a_gen;
2111         struct vnode *a_vp;
2112         int a_attrnamespace;
2113         const char *a_name;
2114         struct uio *a_uio;
2115         struct ucred *a_cred;
2116         struct thread *a_td;
2117     };
2118 */
2119 static int
2120 fuse_vnop_setextattr(struct vop_setextattr_args *ap)
2121 {
2122         struct vnode *vp = ap->a_vp;
2123         struct uio *uio = ap->a_uio;
2124         struct fuse_dispatcher fdi;
2125         struct fuse_setxattr_in *set_xattr_in;
2126         struct mount *mp = vnode_mount(vp);
2127         struct thread *td = ap->a_td;
2128         struct ucred *cred = ap->a_cred;
2129         char *prefix;
2130         size_t len;
2131         char *attr_str;
2132         int err;
2133         
2134         if (fuse_isdeadfs(vp))
2135                 return (ENXIO);
2136
2137         /* Default to looking for user attributes. */
2138         if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
2139                 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
2140         else
2141                 prefix = EXTATTR_NAMESPACE_USER_STRING;
2142
2143         len = strlen(prefix) + sizeof(extattr_namespace_separator) +
2144             strlen(ap->a_name) + 1;
2145
2146         fdisp_init(&fdi, len + sizeof(*set_xattr_in) + uio->uio_resid);
2147         fdisp_make_vp(&fdi, FUSE_SETXATTR, vp, td, cred);
2148
2149         set_xattr_in = fdi.indata;
2150         set_xattr_in->size = uio->uio_resid;
2151
2152         attr_str = (char *)fdi.indata + sizeof(*set_xattr_in);
2153         snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
2154             ap->a_name);
2155
2156         err = uiomove((char *)fdi.indata + sizeof(*set_xattr_in) + len,
2157             uio->uio_resid, uio);
2158         if (err != 0) {
2159                 goto out;
2160         }
2161
2162         err = fdisp_wait_answ(&fdi);
2163
2164         if (err != 0) {
2165                 if (err == ENOSYS)
2166                         fsess_set_notimpl(mp, FUSE_SETXATTR);
2167                 goto out;
2168         }
2169
2170 out:
2171         fdisp_destroy(&fdi);
2172         return (err);
2173 }
2174
2175 /*
2176  * The Linux / FUSE extended attribute list is simply a collection of
2177  * NUL-terminated strings.  The FreeBSD extended attribute list is a single
2178  * byte length followed by a non-NUL terminated string.  So, this allows
2179  * conversion of the Linux / FUSE format to the FreeBSD format in place.
2180  * Linux attribute names are reported with the namespace as a prefix (e.g.
2181  * "user.attribute_name"), but in FreeBSD they are reported without the
2182  * namespace prefix (e.g. "attribute_name").  So, we're going from:
2183  *
2184  * user.attr_name1\0user.attr_name2\0
2185  *
2186  * to:
2187  *
2188  * <num>attr_name1<num>attr_name2
2189  *
2190  * Where "<num>" is a single byte number of characters in the attribute name.
2191  * 
2192  * Args:
2193  * prefix - exattr namespace prefix string
2194  * list, list_len - input list with namespace prefixes
2195  * bsd_list, bsd_list_len - output list compatible with bsd vfs
2196  */
2197 static int
2198 fuse_xattrlist_convert(char *prefix, const char *list, int list_len,
2199     char *bsd_list, int *bsd_list_len)
2200 {
2201         int len, pos, dist_to_next, prefix_len;
2202
2203         pos = 0;
2204         *bsd_list_len = 0;
2205         prefix_len = strlen(prefix);
2206
2207         while (pos < list_len && list[pos] != '\0') {
2208                 dist_to_next = strlen(&list[pos]) + 1;
2209                 if (bcmp(&list[pos], prefix, prefix_len) == 0 &&
2210                     list[pos + prefix_len] == extattr_namespace_separator) {
2211                         len = dist_to_next -
2212                             (prefix_len + sizeof(extattr_namespace_separator)) - 1;
2213                         if (len >= EXTATTR_MAXNAMELEN)
2214                                 return (ENAMETOOLONG);
2215
2216                         bsd_list[*bsd_list_len] = len;
2217                         memcpy(&bsd_list[*bsd_list_len + 1],
2218                             &list[pos + prefix_len +
2219                             sizeof(extattr_namespace_separator)], len);
2220
2221                         *bsd_list_len += len + 1;
2222                 }
2223
2224                 pos += dist_to_next;
2225         }
2226
2227         return (0);
2228 }
2229
2230 /*
2231     struct vop_listextattr_args {
2232         struct vop_generic_args a_gen;
2233         struct vnode *a_vp;
2234         int a_attrnamespace;
2235         struct uio *a_uio;
2236         size_t *a_size;
2237         struct ucred *a_cred;
2238         struct thread *a_td;
2239     };
2240 */
2241 static int
2242 fuse_vnop_listextattr(struct vop_listextattr_args *ap)
2243 {
2244         struct vnode *vp = ap->a_vp;
2245         struct uio *uio = ap->a_uio;
2246         struct fuse_dispatcher fdi;
2247         struct fuse_listxattr_in *list_xattr_in;
2248         struct fuse_listxattr_out *list_xattr_out;
2249         struct mount *mp = vnode_mount(vp);
2250         struct thread *td = ap->a_td;
2251         struct ucred *cred = ap->a_cred;
2252         size_t len;
2253         char *prefix;
2254         char *attr_str;
2255         char *bsd_list = NULL;
2256         char *linux_list;
2257         int bsd_list_len;
2258         int linux_list_len;
2259         int err;
2260
2261         if (fuse_isdeadfs(vp))
2262                 return (ENXIO);
2263
2264         /*
2265          * Add space for a NUL and the period separator if enabled.
2266          * Default to looking for user attributes.
2267          */
2268         if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
2269                 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
2270         else
2271                 prefix = EXTATTR_NAMESPACE_USER_STRING;
2272
2273         len = strlen(prefix) + sizeof(extattr_namespace_separator) + 1;
2274
2275         fdisp_init(&fdi, sizeof(*list_xattr_in) + len);
2276         fdisp_make_vp(&fdi, FUSE_LISTXATTR, vp, td, cred);
2277
2278         /*
2279          * Retrieve Linux / FUSE compatible list size.
2280          */
2281         list_xattr_in = fdi.indata;
2282         list_xattr_in->size = 0;
2283         attr_str = (char *)fdi.indata + sizeof(*list_xattr_in);
2284         snprintf(attr_str, len, "%s%c", prefix, extattr_namespace_separator);
2285
2286         err = fdisp_wait_answ(&fdi);
2287         if (err != 0) {
2288                 if (err == ENOSYS)
2289                         fsess_set_notimpl(mp, FUSE_LISTXATTR);
2290                 goto out;
2291         }
2292
2293         list_xattr_out = fdi.answ;
2294         linux_list_len = list_xattr_out->size;
2295         if (linux_list_len == 0) {
2296                 if (ap->a_size != NULL)
2297                         *ap->a_size = linux_list_len;
2298                 goto out;
2299         }
2300
2301         /*
2302          * Retrieve Linux / FUSE compatible list values.
2303          */
2304         fdisp_make_vp(&fdi, FUSE_LISTXATTR, vp, td, cred);
2305         list_xattr_in = fdi.indata;
2306         list_xattr_in->size = linux_list_len + sizeof(*list_xattr_out);
2307         attr_str = (char *)fdi.indata + sizeof(*list_xattr_in);
2308         snprintf(attr_str, len, "%s%c", prefix, extattr_namespace_separator);
2309
2310         err = fdisp_wait_answ(&fdi);
2311         if (err != 0)
2312                 goto out;
2313
2314         linux_list = fdi.answ;
2315         linux_list_len = fdi.iosize;
2316
2317         /*
2318          * Retrieve the BSD compatible list values.
2319          * The Linux / FUSE attribute list format isn't the same
2320          * as FreeBSD's format. So we need to transform it into
2321          * FreeBSD's format before giving it to the user.
2322          */
2323         bsd_list = malloc(linux_list_len, M_TEMP, M_WAITOK);
2324         err = fuse_xattrlist_convert(prefix, linux_list, linux_list_len,
2325             bsd_list, &bsd_list_len);
2326         if (err != 0)
2327                 goto out;
2328
2329         if (ap->a_size != NULL)
2330                 *ap->a_size = bsd_list_len;
2331
2332         if (uio != NULL)
2333                 err = uiomove(bsd_list, bsd_list_len, uio);
2334
2335 out:
2336         free(bsd_list, M_TEMP);
2337         fdisp_destroy(&fdi);
2338         return (err);
2339 }
2340
2341 /*
2342     struct vop_deleteextattr_args {
2343         struct vop_generic_args a_gen;
2344         struct vnode *a_vp;
2345         int a_attrnamespace;
2346         const char *a_name;
2347         struct ucred *a_cred;
2348         struct thread *a_td;
2349     };
2350 */
2351 static int
2352 fuse_vnop_deleteextattr(struct vop_deleteextattr_args *ap)
2353 {
2354         struct vnode *vp = ap->a_vp;
2355         struct fuse_dispatcher fdi;
2356         struct mount *mp = vnode_mount(vp);
2357         struct thread *td = ap->a_td;
2358         struct ucred *cred = ap->a_cred;
2359         char *prefix;
2360         size_t len;
2361         char *attr_str;
2362         int err;
2363
2364         if (fuse_isdeadfs(vp))
2365                 return (ENXIO);
2366
2367         /* Default to looking for user attributes. */
2368         if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
2369                 prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
2370         else
2371                 prefix = EXTATTR_NAMESPACE_USER_STRING;
2372
2373         len = strlen(prefix) + sizeof(extattr_namespace_separator) +
2374             strlen(ap->a_name) + 1;
2375
2376         fdisp_init(&fdi, len);
2377         fdisp_make_vp(&fdi, FUSE_REMOVEXATTR, vp, td, cred);
2378
2379         attr_str = fdi.indata;
2380         snprintf(attr_str, len, "%s%c%s", prefix, extattr_namespace_separator,
2381             ap->a_name);
2382
2383         err = fdisp_wait_answ(&fdi);
2384         if (err != 0) {
2385                 if (err == ENOSYS)
2386                         fsess_set_notimpl(mp, FUSE_REMOVEXATTR);
2387         }
2388
2389         fdisp_destroy(&fdi);
2390         return (err);
2391 }
2392
2393 /*
2394     struct vnop_print_args {
2395         struct vnode *a_vp;
2396     };
2397 */
2398 static int
2399 fuse_vnop_print(struct vop_print_args *ap)
2400 {
2401         struct fuse_vnode_data *fvdat = VTOFUD(ap->a_vp);
2402
2403         printf("nodeid: %ju, parent nodeid: %ju, nlookup: %ju, flag: %#x\n",
2404             (uintmax_t)VTOILLU(ap->a_vp), (uintmax_t)fvdat->parent_nid,
2405             (uintmax_t)fvdat->nlookup,
2406             fvdat->flag);
2407
2408         return 0;
2409 }