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