]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/fuse/fuse_internal.c
fusefs: check the vnode cache when looking up files for the NFS server
[FreeBSD/FreeBSD.git] / sys / fs / fuse / fuse_internal.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/mutex.h>
72 #include <sys/sdt.h>
73 #include <sys/sx.h>
74 #include <sys/proc.h>
75 #include <sys/mount.h>
76 #include <sys/vnode.h>
77 #include <sys/namei.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/priv.h>
88
89 #include "fuse.h"
90 #include "fuse_file.h"
91 #include "fuse_internal.h"
92 #include "fuse_ipc.h"
93 #include "fuse_node.h"
94 #include "fuse_file.h"
95
96 SDT_PROVIDER_DECLARE(fusefs);
97 /* 
98  * Fuse trace probe:
99  * arg0: verbosity.  Higher numbers give more verbose messages
100  * arg1: Textual message
101  */
102 SDT_PROBE_DEFINE2(fusefs, , internal, trace, "int", "char*");
103
104 #ifdef ZERO_PAD_INCOMPLETE_BUFS
105 static int isbzero(void *buf, size_t len);
106
107 #endif
108
109 /* Synchronously send a FUSE_ACCESS operation */
110 int
111 fuse_internal_access(struct vnode *vp,
112     accmode_t mode,
113     struct thread *td,
114     struct ucred *cred)
115 {
116         int err = 0;
117         uint32_t mask = F_OK;
118         int dataflags;
119         int vtype;
120         struct mount *mp;
121         struct fuse_dispatcher fdi;
122         struct fuse_access_in *fai;
123         struct fuse_data *data;
124
125         mp = vnode_mount(vp);
126         vtype = vnode_vtype(vp);
127
128         data = fuse_get_mpdata(mp);
129         dataflags = data->dataflags;
130
131         if (mode == 0)
132                 return 0;
133
134         if (mode & VMODIFY_PERMS && vfs_isrdonly(mp)) {
135                 switch (vp->v_type) {
136                 case VDIR:
137                         /* FALLTHROUGH */
138                 case VLNK:
139                         /* FALLTHROUGH */
140                 case VREG:
141                         return EROFS;
142                 default:
143                         break;
144                 }
145         }
146
147         /* Unless explicitly permitted, deny everyone except the fs owner. */
148         if (!(dataflags & FSESS_DAEMON_CAN_SPY)) {
149                 if (fuse_match_cred(data->daemoncred, cred))
150                         return EPERM;
151         }
152
153         if (dataflags & FSESS_DEFAULT_PERMISSIONS) {
154                 struct vattr va;
155
156                 fuse_internal_getattr(vp, &va, cred, td);
157                 return vaccess(vp->v_type, va.va_mode, va.va_uid,
158                     va.va_gid, mode, cred, NULL);
159         }
160
161         if (!fsess_isimpl(mp, FUSE_ACCESS))
162                 return 0;
163
164         if ((mode & (VWRITE | VAPPEND | VADMIN)) != 0)
165                 mask |= W_OK;
166         if ((mode & VREAD) != 0)
167                 mask |= R_OK;
168         if ((mode & VEXEC) != 0)
169                 mask |= X_OK;
170
171         fdisp_init(&fdi, sizeof(*fai));
172         fdisp_make_vp(&fdi, FUSE_ACCESS, vp, td, cred);
173
174         fai = fdi.indata;
175         fai->mask = mask;
176
177         err = fdisp_wait_answ(&fdi);
178         fdisp_destroy(&fdi);
179
180         if (err == ENOSYS) {
181                 fsess_set_notimpl(mp, FUSE_ACCESS);
182                 err = 0;
183         }
184         return err;
185 }
186
187 /*
188  * Cache FUSE attributes from attr, in attribute cache associated with vnode
189  * 'vp'.  Optionally, if argument 'vap' is not NULL, store a copy of the
190  * converted attributes there as well.
191  *
192  * If the nominal attribute cache TTL is zero, do not cache on the 'vp' (but do
193  * return the result to the caller).
194  */
195 void
196 fuse_internal_cache_attrs(struct vnode *vp, struct ucred *cred,
197         struct fuse_attr *attr, uint64_t attr_valid, uint32_t attr_valid_nsec,
198         struct vattr *vap)
199 {
200         struct mount *mp;
201         struct fuse_vnode_data *fvdat;
202         struct fuse_data *data;
203         struct vattr *vp_cache_at;
204
205         mp = vnode_mount(vp);
206         fvdat = VTOFUD(vp);
207         data = fuse_get_mpdata(mp);
208         if (!cred)
209                 cred = curthread->td_ucred;
210
211         ASSERT_VOP_ELOCKED(vp, "fuse_internal_cache_attrs");
212
213         fuse_validity_2_bintime(attr_valid, attr_valid_nsec,
214                 &fvdat->attr_cache_timeout);
215
216         /* Fix our buffers if the filesize changed without us knowing */
217         if (vnode_isreg(vp) && attr->size != fvdat->cached_attrs.va_size) {
218                 (void)fuse_vnode_setsize(vp, cred, attr->size);
219                 fvdat->cached_attrs.va_size = attr->size;
220         }
221
222         if (attr_valid > 0 || attr_valid_nsec > 0)
223                 vp_cache_at = &(fvdat->cached_attrs);
224         else if (vap != NULL)
225                 vp_cache_at = vap;
226         else
227                 return;
228
229         vattr_null(vp_cache_at);
230         vp_cache_at->va_fsid = mp->mnt_stat.f_fsid.val[0];
231         vp_cache_at->va_fileid = attr->ino;
232         vp_cache_at->va_mode = attr->mode & ~S_IFMT;
233         vp_cache_at->va_nlink     = attr->nlink;
234         vp_cache_at->va_uid       = attr->uid;
235         vp_cache_at->va_gid       = attr->gid;
236         vp_cache_at->va_rdev      = attr->rdev;
237         vp_cache_at->va_size      = attr->size;
238         /* XXX on i386, seconds are truncated to 32 bits */
239         vp_cache_at->va_atime.tv_sec  = attr->atime;
240         vp_cache_at->va_atime.tv_nsec = attr->atimensec;
241         vp_cache_at->va_mtime.tv_sec  = attr->mtime;
242         vp_cache_at->va_mtime.tv_nsec = attr->mtimensec;
243         vp_cache_at->va_ctime.tv_sec  = attr->ctime;
244         vp_cache_at->va_ctime.tv_nsec = attr->ctimensec;
245         if (fuse_libabi_geq(data, 7, 9) && attr->blksize > 0)
246                 vp_cache_at->va_blocksize = attr->blksize;
247         else
248                 vp_cache_at->va_blocksize = PAGE_SIZE;
249         vp_cache_at->va_type = IFTOVT(attr->mode);
250         vp_cache_at->va_bytes = attr->blocks * S_BLKSIZE;
251         vp_cache_at->va_flags = 0;
252
253         if (vap != vp_cache_at && vap != NULL)
254                 memcpy(vap, vp_cache_at, sizeof(*vap));
255 }
256
257
258 /* fsync */
259
260 int
261 fuse_internal_fsync_callback(struct fuse_ticket *tick, struct uio *uio)
262 {
263         if (tick->tk_aw_ohead.error == ENOSYS) {
264                 fsess_set_notimpl(tick->tk_data->mp, fticket_opcode(tick));
265         }
266         return 0;
267 }
268
269 int
270 fuse_internal_fsync(struct vnode *vp,
271     struct thread *td,
272     int waitfor,
273     bool datasync)
274 {
275         struct fuse_fsync_in *ffsi = NULL;
276         struct fuse_dispatcher fdi;
277         struct fuse_filehandle *fufh;
278         struct fuse_vnode_data *fvdat = VTOFUD(vp);
279         struct mount *mp = vnode_mount(vp);
280         int op = FUSE_FSYNC;
281         int err = 0;
282
283         if (!fsess_isimpl(vnode_mount(vp),
284             (vnode_vtype(vp) == VDIR ? FUSE_FSYNCDIR : FUSE_FSYNC))) {
285                 return 0;
286         }
287         if (vnode_isdir(vp))
288                 op = FUSE_FSYNCDIR;
289
290         if (!fsess_isimpl(mp, op))
291                 return 0;
292
293         fdisp_init(&fdi, sizeof(*ffsi));
294         /*
295          * fsync every open file handle for this file, because we can't be sure
296          * which file handle the caller is really referring to.
297          */
298         LIST_FOREACH(fufh, &fvdat->handles, next) {
299                 if (ffsi == NULL)
300                         fdisp_make_vp(&fdi, op, vp, td, NULL);
301                 else
302                         fdisp_refresh_vp(&fdi, op, vp, td, NULL);
303                 ffsi = fdi.indata;
304                 ffsi->fh = fufh->fh_id;
305                 ffsi->fsync_flags = 0;
306
307                 if (datasync)
308                         ffsi->fsync_flags = 1;
309
310                 if (waitfor == MNT_WAIT) {
311                         err = fdisp_wait_answ(&fdi);
312                 } else {
313                         fuse_insert_callback(fdi.tick,
314                                 fuse_internal_fsync_callback);
315                         fuse_insert_message(fdi.tick, false);
316                 }
317                 if (err == ENOSYS) {
318                         /* ENOSYS means "success, and don't call again" */
319                         fsess_set_notimpl(mp, op);
320                         err = 0;
321                         break;
322                 }
323         }
324         fdisp_destroy(&fdi);
325
326         return err;
327 }
328
329 /* mknod */
330 int
331 fuse_internal_mknod(struct vnode *dvp, struct vnode **vpp,
332         struct componentname *cnp, struct vattr *vap)
333 {
334         struct fuse_data *data;
335         struct fuse_mknod_in fmni;
336         size_t insize;
337
338         data = fuse_get_mpdata(dvp->v_mount);
339
340         fmni.mode = MAKEIMODE(vap->va_type, vap->va_mode);
341         fmni.rdev = vap->va_rdev;
342         if (fuse_libabi_geq(data, 7, 12)) {
343                 insize = sizeof(fmni);
344                 fmni.umask = curthread->td_proc->p_fd->fd_cmask;
345         } else {
346                 insize = FUSE_COMPAT_MKNOD_IN_SIZE;
347         }
348         return (fuse_internal_newentry(dvp, vpp, cnp, FUSE_MKNOD, &fmni,
349             insize, vap->va_type));
350 }
351
352 /* readdir */
353
354 int
355 fuse_internal_readdir(struct vnode *vp,
356     struct uio *uio,
357     off_t startoff,
358     struct fuse_filehandle *fufh,
359     struct fuse_iov *cookediov,
360     int *ncookies,
361     u_long *cookies)
362 {
363         int err = 0;
364         struct fuse_dispatcher fdi;
365         struct fuse_read_in *fri = NULL;
366         int fnd_start;
367
368         if (uio_resid(uio) == 0)
369                 return 0;
370         fdisp_init(&fdi, 0);
371
372         /*
373          * Note that we DO NOT have a UIO_SYSSPACE here (so no need for p2p
374          * I/O).
375          */
376
377         /*
378          * fnd_start is set non-zero once the offset in the directory gets
379          * to the startoff.  This is done because directories must be read
380          * from the beginning (offset == 0) when fuse_vnop_readdir() needs
381          * to do an open of the directory.
382          * If it is not set non-zero here, it will be set non-zero in
383          * fuse_internal_readdir_processdata() when uio_offset == startoff.
384          */
385         fnd_start = 0;
386         if (uio->uio_offset == startoff)
387                 fnd_start = 1;
388         while (uio_resid(uio) > 0) {
389                 fdi.iosize = sizeof(*fri);
390                 if (fri == NULL)
391                         fdisp_make_vp(&fdi, FUSE_READDIR, vp, NULL, NULL);
392                 else
393                         fdisp_refresh_vp(&fdi, FUSE_READDIR, vp, NULL, NULL);
394
395                 fri = fdi.indata;
396                 fri->fh = fufh->fh_id;
397                 fri->offset = uio_offset(uio);
398                 fri->size = MIN(uio->uio_resid,
399                     fuse_get_mpdata(vp->v_mount)->max_read);
400
401                 if ((err = fdisp_wait_answ(&fdi)))
402                         break;
403                 if ((err = fuse_internal_readdir_processdata(uio, startoff,
404                     &fnd_start, fri->size, fdi.answ, fdi.iosize, cookediov,
405                     ncookies, &cookies)))
406                         break;
407         }
408
409         fdisp_destroy(&fdi);
410         return ((err == -1) ? 0 : err);
411 }
412
413 /*
414  * Return -1 to indicate that this readdir is finished, 0 if it copied
415  * all the directory data read in and it may be possible to read more
416  * and greater than 0 for a failure.
417  */
418 int
419 fuse_internal_readdir_processdata(struct uio *uio,
420     off_t startoff,
421     int *fnd_start,
422     size_t reqsize,
423     void *buf,
424     size_t bufsize,
425     struct fuse_iov *cookediov,
426     int *ncookies,
427     u_long **cookiesp)
428 {
429         int err = 0;
430         int bytesavail;
431         size_t freclen;
432
433         struct dirent *de;
434         struct fuse_dirent *fudge;
435         u_long *cookies;
436
437         cookies = *cookiesp;
438         if (bufsize < FUSE_NAME_OFFSET)
439                 return -1;
440         for (;;) {
441                 if (bufsize < FUSE_NAME_OFFSET) {
442                         err = -1;
443                         break;
444                 }
445                 fudge = (struct fuse_dirent *)buf;
446                 freclen = FUSE_DIRENT_SIZE(fudge);
447
448                 if (bufsize < freclen) {
449                         /*
450                          * This indicates a partial directory entry at the
451                          * end of the directory data.
452                          */
453                         err = -1;
454                         break;
455                 }
456 #ifdef ZERO_PAD_INCOMPLETE_BUFS
457                 if (isbzero(buf, FUSE_NAME_OFFSET)) {
458                         err = -1;
459                         break;
460                 }
461 #endif
462
463                 if (!fudge->namelen || fudge->namelen > MAXNAMLEN) {
464                         err = EINVAL;
465                         break;
466                 }
467                 bytesavail = GENERIC_DIRSIZ((struct pseudo_dirent *)
468                                             &fudge->namelen);
469
470                 if (bytesavail > uio_resid(uio)) {
471                         /* Out of space for the dir so we are done. */
472                         err = -1;
473                         break;
474                 }
475                 /*
476                  * Don't start to copy the directory entries out until
477                  * the requested offset in the directory is found.
478                  */
479                 if (*fnd_start != 0) {
480                         fiov_adjust(cookediov, bytesavail);
481                         bzero(cookediov->base, bytesavail);
482
483                         de = (struct dirent *)cookediov->base;
484                         de->d_fileno = fudge->ino;
485                         de->d_reclen = bytesavail;
486                         de->d_type = fudge->type;
487                         de->d_namlen = fudge->namelen;
488                         memcpy((char *)cookediov->base + sizeof(struct dirent) -
489                                MAXNAMLEN - 1,
490                                (char *)buf + FUSE_NAME_OFFSET, fudge->namelen);
491                         dirent_terminate(de);
492
493                         err = uiomove(cookediov->base, cookediov->len, uio);
494                         if (err)
495                                 break;
496                         if (cookies != NULL) {
497                                 if (*ncookies == 0) {
498                                         err = -1;
499                                         break;
500                                 }
501                                 *cookies = fudge->off;
502                                 cookies++;
503                                 (*ncookies)--;
504                         }
505                 } else if (startoff == fudge->off)
506                         *fnd_start = 1;
507                 buf = (char *)buf + freclen;
508                 bufsize -= freclen;
509                 uio_setoffset(uio, fudge->off);
510         }
511         *cookiesp = cookies;
512
513         return err;
514 }
515
516 /* remove */
517
518 int
519 fuse_internal_remove(struct vnode *dvp,
520     struct vnode *vp,
521     struct componentname *cnp,
522     enum fuse_opcode op)
523 {
524         struct fuse_dispatcher fdi;
525         int err = 0;
526
527         fdisp_init(&fdi, cnp->cn_namelen + 1);
528         fdisp_make_vp(&fdi, op, dvp, cnp->cn_thread, cnp->cn_cred);
529
530         memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
531         ((char *)fdi.indata)[cnp->cn_namelen] = '\0';
532
533         err = fdisp_wait_answ(&fdi);
534         fdisp_destroy(&fdi);
535         return err;
536 }
537
538 /* rename */
539
540 int
541 fuse_internal_rename(struct vnode *fdvp,
542     struct componentname *fcnp,
543     struct vnode *tdvp,
544     struct componentname *tcnp)
545 {
546         struct fuse_dispatcher fdi;
547         struct fuse_rename_in *fri;
548         int err = 0;
549
550         fdisp_init(&fdi, sizeof(*fri) + fcnp->cn_namelen + tcnp->cn_namelen + 2);
551         fdisp_make_vp(&fdi, FUSE_RENAME, fdvp, tcnp->cn_thread, tcnp->cn_cred);
552
553         fri = fdi.indata;
554         fri->newdir = VTOI(tdvp);
555         memcpy((char *)fdi.indata + sizeof(*fri), fcnp->cn_nameptr,
556             fcnp->cn_namelen);
557         ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen] = '\0';
558         memcpy((char *)fdi.indata + sizeof(*fri) + fcnp->cn_namelen + 1,
559             tcnp->cn_nameptr, tcnp->cn_namelen);
560         ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen +
561             tcnp->cn_namelen + 1] = '\0';
562
563         err = fdisp_wait_answ(&fdi);
564         fdisp_destroy(&fdi);
565         return err;
566 }
567
568 /* strategy */
569
570 /* entity creation */
571
572 void
573 fuse_internal_newentry_makerequest(struct mount *mp,
574     uint64_t dnid,
575     struct componentname *cnp,
576     enum fuse_opcode op,
577     void *buf,
578     size_t bufsize,
579     struct fuse_dispatcher *fdip)
580 {
581         fdip->iosize = bufsize + cnp->cn_namelen + 1;
582
583         fdisp_make(fdip, op, mp, dnid, cnp->cn_thread, cnp->cn_cred);
584         memcpy(fdip->indata, buf, bufsize);
585         memcpy((char *)fdip->indata + bufsize, cnp->cn_nameptr, cnp->cn_namelen);
586         ((char *)fdip->indata)[bufsize + cnp->cn_namelen] = '\0';
587 }
588
589 int
590 fuse_internal_newentry_core(struct vnode *dvp,
591     struct vnode **vpp,
592     struct componentname *cnp,
593     enum vtype vtyp,
594     struct fuse_dispatcher *fdip)
595 {
596         int err = 0;
597         struct fuse_entry_out *feo;
598         struct mount *mp = vnode_mount(dvp);
599
600         if ((err = fdisp_wait_answ(fdip))) {
601                 return err;
602         }
603         feo = fdip->answ;
604
605         if ((err = fuse_internal_checkentry(feo, vtyp))) {
606                 return err;
607         }
608         err = fuse_vnode_get(mp, feo, feo->nodeid, dvp, vpp, cnp, vtyp);
609         if (err) {
610                 fuse_internal_forget_send(mp, cnp->cn_thread, cnp->cn_cred,
611                     feo->nodeid, 1);
612                 return err;
613         }
614
615         /* 
616          * Purge the parent's attribute cache because the daemon should've
617          * updated its mtime and ctime
618          */
619         fuse_vnode_clear_attr_cache(dvp);
620
621         fuse_internal_cache_attrs(*vpp, NULL, &feo->attr, feo->attr_valid,
622                 feo->attr_valid_nsec, NULL);
623
624         return err;
625 }
626
627 int
628 fuse_internal_newentry(struct vnode *dvp,
629     struct vnode **vpp,
630     struct componentname *cnp,
631     enum fuse_opcode op,
632     void *buf,
633     size_t bufsize,
634     enum vtype vtype)
635 {
636         int err;
637         struct fuse_dispatcher fdi;
638         struct mount *mp = vnode_mount(dvp);
639
640         fdisp_init(&fdi, 0);
641         fuse_internal_newentry_makerequest(mp, VTOI(dvp), cnp, op, buf,
642             bufsize, &fdi);
643         err = fuse_internal_newentry_core(dvp, vpp, cnp, vtype, &fdi);
644         fdisp_destroy(&fdi);
645
646         return err;
647 }
648
649 /* entity destruction */
650
651 int
652 fuse_internal_forget_callback(struct fuse_ticket *ftick, struct uio *uio)
653 {
654         fuse_internal_forget_send(ftick->tk_data->mp, curthread, NULL,
655             ((struct fuse_in_header *)ftick->tk_ms_fiov.base)->nodeid, 1);
656
657         return 0;
658 }
659
660 void
661 fuse_internal_forget_send(struct mount *mp,
662     struct thread *td,
663     struct ucred *cred,
664     uint64_t nodeid,
665     uint64_t nlookup)
666 {
667
668         struct fuse_dispatcher fdi;
669         struct fuse_forget_in *ffi;
670
671         /*
672          * KASSERT(nlookup > 0, ("zero-times forget for vp #%llu",
673          *         (long long unsigned) nodeid));
674          */
675
676         fdisp_init(&fdi, sizeof(*ffi));
677         fdisp_make(&fdi, FUSE_FORGET, mp, nodeid, td, cred);
678
679         ffi = fdi.indata;
680         ffi->nlookup = nlookup;
681
682         fuse_insert_message(fdi.tick, false);
683         fdisp_destroy(&fdi);
684 }
685
686 /* Fetch the vnode's attributes from the daemon*/
687 int
688 fuse_internal_do_getattr(struct vnode *vp, struct vattr *vap,
689         struct ucred *cred, struct thread *td)
690 {
691         struct fuse_dispatcher fdi;
692         struct fuse_vnode_data *fvdat = VTOFUD(vp);
693         struct fuse_getattr_in *fgai;
694         struct fuse_attr_out *fao;
695         off_t old_filesize = fvdat->cached_attrs.va_size;
696         enum vtype vtyp;
697         int err;
698
699         fdisp_init(&fdi, 0);
700         fdisp_make_vp(&fdi, FUSE_GETATTR, vp, td, cred);
701         fgai = fdi.indata;
702         /* 
703          * We could look up a file handle and set it in fgai->fh, but that
704          * involves extra runtime work and I'm unaware of any file systems that
705          * care.
706          */
707         fgai->getattr_flags = 0;
708         if ((err = fdisp_simple_putget_vp(&fdi, FUSE_GETATTR, vp, td, cred))) {
709                 if (err == ENOENT)
710                         fuse_internal_vnode_disappear(vp);
711                 goto out;
712         }
713
714         fao = (struct fuse_attr_out *)fdi.answ;
715         vtyp = IFTOVT(fao->attr.mode);
716         if (fvdat->flag & FN_SIZECHANGE)
717                 fao->attr.size = old_filesize;
718         fuse_internal_cache_attrs(vp, NULL, &fao->attr, fao->attr_valid,
719                 fao->attr_valid_nsec, vap);
720         if (vtyp != vnode_vtype(vp)) {
721                 fuse_internal_vnode_disappear(vp);
722                 err = ENOENT;
723         }
724
725 out:
726         fdisp_destroy(&fdi);
727         return err;
728 }
729
730 /* Read a vnode's attributes from cache or fetch them from the fuse daemon */
731 int
732 fuse_internal_getattr(struct vnode *vp, struct vattr *vap, struct ucred *cred,
733         struct thread *td)
734 {
735         struct vattr *attrs;
736
737         if ((attrs = VTOVA(vp)) != NULL) {
738                 *vap = *attrs;  /* struct copy */
739                 return 0;
740         }
741
742         return fuse_internal_do_getattr(vp, vap, cred, td);
743 }
744
745 void
746 fuse_internal_vnode_disappear(struct vnode *vp)
747 {
748         struct fuse_vnode_data *fvdat = VTOFUD(vp);
749
750         ASSERT_VOP_ELOCKED(vp, "fuse_internal_vnode_disappear");
751         fvdat->flag |= FN_REVOKED;
752         bintime_clear(&fvdat->attr_cache_timeout);
753         bintime_clear(&fvdat->entry_cache_timeout);
754         cache_purge(vp);
755 }
756
757 /* fuse start/stop */
758
759 int
760 fuse_internal_init_callback(struct fuse_ticket *tick, struct uio *uio)
761 {
762         int err = 0;
763         struct fuse_data *data = tick->tk_data;
764         struct fuse_init_out *fiio;
765
766         if ((err = tick->tk_aw_ohead.error)) {
767                 goto out;
768         }
769         if ((err = fticket_pull(tick, uio))) {
770                 goto out;
771         }
772         fiio = fticket_resp(tick)->base;
773
774         /* XXX: Do we want to check anything further besides this? */
775         if (fiio->major < 7) {
776                 SDT_PROBE2(fusefs, , internal, trace, 1,
777                         "userpace version too low");
778                 err = EPROTONOSUPPORT;
779                 goto out;
780         }
781         data->fuse_libabi_major = fiio->major;
782         data->fuse_libabi_minor = fiio->minor;
783
784         if (fuse_libabi_geq(data, 7, 5)) {
785                 if (fticket_resp(tick)->len == sizeof(struct fuse_init_out)) {
786                         data->max_write = fiio->max_write;
787                         if (fiio->flags & FUSE_ASYNC_READ)
788                                 data->dataflags |= FSESS_ASYNC_READ;
789                         if (fiio->flags & FUSE_POSIX_LOCKS)
790                                 data->dataflags |= FSESS_POSIX_LOCKS;
791                         if (fiio->flags & FUSE_EXPORT_SUPPORT)
792                                 data->dataflags |= FSESS_EXPORT_SUPPORT;
793                         /* 
794                          * Don't bother to check FUSE_BIG_WRITES, because it's
795                          * redundant with max_write
796                          */
797                 } else {
798                         err = EINVAL;
799                 }
800         } else {
801                 /* Old fix values */
802                 data->max_write = 4096;
803         }
804
805 out:
806         if (err) {
807                 fdata_set_dead(data);
808         }
809         FUSE_LOCK();
810         data->dataflags |= FSESS_INITED;
811         wakeup(&data->ticketer);
812         FUSE_UNLOCK();
813
814         return 0;
815 }
816
817 void
818 fuse_internal_send_init(struct fuse_data *data, struct thread *td)
819 {
820         struct fuse_init_in *fiii;
821         struct fuse_dispatcher fdi;
822
823         fdisp_init(&fdi, sizeof(*fiii));
824         fdisp_make(&fdi, FUSE_INIT, data->mp, 0, td, NULL);
825         fiii = fdi.indata;
826         fiii->major = FUSE_KERNEL_VERSION;
827         fiii->minor = FUSE_KERNEL_MINOR_VERSION;
828         /* 
829          * fusefs currently doesn't do any readahead other than fetching whole
830          * buffer cache block sized regions at once.  So the max readahead is
831          * the size of a buffer cache block.
832          */
833         fiii->max_readahead = maxbcachebuf;
834         /*
835          * Unsupported features:
836          * FUSE_FILE_OPS: No known FUSE server or client supports it
837          * FUSE_ATOMIC_O_TRUNC: our VFS cannot support it
838          * FUSE_DONT_MASK: unlike Linux, FreeBSD always applies the umask, even
839          *      when default ACLs are in use.
840          */
841         fiii->flags = FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_EXPORT_SUPPORT
842                 | FUSE_BIG_WRITES;
843
844         fuse_insert_callback(fdi.tick, fuse_internal_init_callback);
845         fuse_insert_message(fdi.tick, false);
846         fdisp_destroy(&fdi);
847 }
848
849 /* 
850  * Send a FUSE_SETATTR operation with no permissions checks.  If cred is NULL,
851  * send the request with root credentials
852  */
853 int fuse_internal_setattr(struct vnode *vp, struct vattr *vap,
854         struct thread *td, struct ucred *cred)
855 {
856         struct fuse_dispatcher fdi;
857         struct fuse_setattr_in *fsai;
858         struct mount *mp;
859         pid_t pid = td->td_proc->p_pid;
860         struct fuse_data *data;
861         int dataflags;
862         int err = 0;
863         enum vtype vtyp;
864         int sizechanged = -1;
865         uint64_t newsize = 0;
866
867         mp = vnode_mount(vp);
868         data = fuse_get_mpdata(mp);
869         dataflags = data->dataflags;
870
871         fdisp_init(&fdi, sizeof(*fsai));
872         fdisp_make_vp(&fdi, FUSE_SETATTR, vp, td, cred);
873         if (!cred) {
874                 fdi.finh->uid = 0;
875                 fdi.finh->gid = 0;
876         }
877         fsai = fdi.indata;
878         fsai->valid = 0;
879
880         if (vap->va_uid != (uid_t)VNOVAL) {
881                 fsai->uid = vap->va_uid;
882                 fsai->valid |= FATTR_UID;
883         }
884         if (vap->va_gid != (gid_t)VNOVAL) {
885                 fsai->gid = vap->va_gid;
886                 fsai->valid |= FATTR_GID;
887         }
888         if (vap->va_size != VNOVAL) {
889                 struct fuse_filehandle *fufh = NULL;
890
891                 /*Truncate to a new value. */
892                 fsai->size = vap->va_size;
893                 sizechanged = 1;
894                 newsize = vap->va_size;
895                 fsai->valid |= FATTR_SIZE;
896
897                 fuse_filehandle_getrw(vp, FWRITE, &fufh, cred, pid);
898                 if (fufh) {
899                         fsai->fh = fufh->fh_id;
900                         fsai->valid |= FATTR_FH;
901                 }
902                 VTOFUD(vp)->flag &= ~FN_SIZECHANGE;
903         }
904         if (vap->va_atime.tv_sec != VNOVAL) {
905                 fsai->atime = vap->va_atime.tv_sec;
906                 fsai->atimensec = vap->va_atime.tv_nsec;
907                 fsai->valid |= FATTR_ATIME;
908                 if (vap->va_vaflags & VA_UTIMES_NULL)
909                         fsai->valid |= FATTR_ATIME_NOW;
910         }
911         if (vap->va_mtime.tv_sec != VNOVAL) {
912                 fsai->mtime = vap->va_mtime.tv_sec;
913                 fsai->mtimensec = vap->va_mtime.tv_nsec;
914                 fsai->valid |= FATTR_MTIME;
915                 if (vap->va_vaflags & VA_UTIMES_NULL)
916                         fsai->valid |= FATTR_MTIME_NOW;
917         }
918         if (vap->va_mode != (mode_t)VNOVAL) {
919                 fsai->mode = vap->va_mode & ALLPERMS;
920                 fsai->valid |= FATTR_MODE;
921         }
922         if (!fsai->valid) {
923                 goto out;
924         }
925
926         if ((err = fdisp_wait_answ(&fdi)))
927                 goto out;
928         vtyp = IFTOVT(((struct fuse_attr_out *)fdi.answ)->attr.mode);
929
930         if (vnode_vtype(vp) != vtyp) {
931                 if (vnode_vtype(vp) == VNON && vtyp != VNON) {
932                         SDT_PROBE2(fusefs, , internal, trace, 1, "FUSE: Dang! "
933                                 "vnode_vtype is VNON and vtype isn't.");
934                 } else {
935                         /*
936                          * STALE vnode, ditch
937                          *
938                          * The vnode has changed its type "behind our back".
939                          * There's nothing really we can do, so let us just
940                          * force an internal revocation and tell the caller to
941                          * try again, if interested.
942                          */
943                         fuse_internal_vnode_disappear(vp);
944                         err = EAGAIN;
945                 }
946         }
947         if (err == 0) {
948                 struct fuse_attr_out *fao = (struct fuse_attr_out*)fdi.answ;
949                 fuse_internal_cache_attrs(vp, cred, &fao->attr, fao->attr_valid,
950                         fao->attr_valid_nsec, NULL);
951         }
952
953 out:
954         fdisp_destroy(&fdi);
955         return err;
956 }
957
958 #ifdef ZERO_PAD_INCOMPLETE_BUFS
959 static int
960 isbzero(void *buf, size_t len)
961 {
962         int i;
963
964         for (i = 0; i < len; i++) {
965                 if (((char *)buf)[i])
966                         return (0);
967         }
968
969         return (1);
970 }
971
972 #endif