]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/fuse/fuse_internal.c
fusefs: WIP supporting -o default_permissions
[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(fuse);
97 /* 
98  * Fuse trace probe:
99  * arg0: verbosity.  Higher numbers give more verbose messages
100  * arg1: Textual message
101  */
102 SDT_PROBE_DEFINE2(fuse, , 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 fuse_access_param *facp,
114     struct thread *td,
115     struct ucred *cred)
116 {
117         int err = 0;
118         uint32_t mask = F_OK;
119         int dataflags;
120         int vtype;
121         struct mount *mp;
122         struct fuse_dispatcher fdi;
123         struct fuse_access_in *fai;
124         struct fuse_data *data;
125
126         mp = vnode_mount(vp);
127         vtype = vnode_vtype(vp);
128
129         data = fuse_get_mpdata(mp);
130         dataflags = data->dataflags;
131
132         if (mode & VMODIFY_PERMS && vfs_isrdonly(mp)) {
133                 switch (vp->v_type) {
134                 case VDIR:
135                         /* FALLTHROUGH */
136                 case VLNK:
137                         /* FALLTHROUGH */
138                 case VREG:
139                         return EROFS;
140                 default:
141                         break;
142                 }
143         }
144
145         /* Unless explicitly permitted, deny everyone except the fs owner. */
146         if (!(facp->facc_flags)) {
147                 if (!(dataflags & FSESS_DAEMON_CAN_SPY)) {
148                         int denied = fuse_match_cred(data->daemoncred, cred);
149
150                         if (denied)
151                                 return EPERM;
152                 }
153         }
154
155         if (dataflags & FSESS_DEFAULT_PERMISSIONS) {
156                 struct vattr va;
157
158                 fuse_internal_getattr(vp, &va, cred, td);
159                 return vaccess(vp->v_type, va.va_mode, va.va_uid,
160                     va.va_gid, mode, cred, NULL);
161         }
162
163         if (!fsess_isimpl(mp, FUSE_ACCESS))
164                 return 0;
165
166         if ((mode & (VWRITE | VAPPEND | VADMIN)) != 0)
167                 mask |= W_OK;
168         if ((mode & VREAD) != 0)
169                 mask |= R_OK;
170         if ((mode & VEXEC) != 0)
171                 mask |= X_OK;
172
173         fdisp_init(&fdi, sizeof(*fai));
174         fdisp_make_vp(&fdi, FUSE_ACCESS, vp, td, cred);
175
176         fai = fdi.indata;
177         fai->mask = mask;
178
179         err = fdisp_wait_answ(&fdi);
180         fdisp_destroy(&fdi);
181
182         if (err == ENOSYS) {
183                 fsess_set_notimpl(mp, FUSE_ACCESS);
184                 err = 0;
185         }
186         return err;
187 }
188
189 /*
190  * Cache FUSE attributes from attr, in attribute cache associated with vnode
191  * 'vp'.  Optionally, if argument 'vap' is not NULL, store a copy of the
192  * converted attributes there as well.
193  *
194  * If the nominal attribute cache TTL is zero, do not cache on the 'vp' (but do
195  * return the result to the caller).
196  */
197 void
198 fuse_internal_cache_attrs(struct vnode *vp, struct fuse_attr *attr,
199         uint64_t attr_valid, uint32_t attr_valid_nsec, struct vattr *vap)
200 {
201         struct mount *mp;
202         struct fuse_vnode_data *fvdat;
203         struct vattr *vp_cache_at;
204
205         mp = vnode_mount(vp);
206         fvdat = VTOFUD(vp);
207
208         fuse_validity_2_bintime(attr_valid, attr_valid_nsec,
209                 &fvdat->attr_cache_timeout);
210
211         vp_cache_at = VTOVA(vp);
212
213         if (vap == NULL && vp_cache_at == NULL)
214                 return;
215
216         if (vap == NULL)
217                 vap = vp_cache_at;
218
219         vattr_null(vap);
220
221         vap->va_fsid = mp->mnt_stat.f_fsid.val[0];
222         vap->va_fileid = attr->ino;
223         vap->va_mode = attr->mode & ~S_IFMT;
224         vap->va_nlink     = attr->nlink;
225         vap->va_uid       = attr->uid;
226         vap->va_gid       = attr->gid;
227         vap->va_rdev      = attr->rdev;
228         vap->va_size      = attr->size;
229         /* XXX on i386, seconds are truncated to 32 bits */
230         vap->va_atime.tv_sec  = attr->atime;
231         vap->va_atime.tv_nsec = attr->atimensec;
232         vap->va_mtime.tv_sec  = attr->mtime;
233         vap->va_mtime.tv_nsec = attr->mtimensec;
234         vap->va_ctime.tv_sec  = attr->ctime;
235         vap->va_ctime.tv_nsec = attr->ctimensec;
236         vap->va_blocksize = PAGE_SIZE;
237         vap->va_type = IFTOVT(attr->mode);
238         vap->va_bytes = attr->blocks * S_BLKSIZE;
239         vap->va_flags = 0;
240
241         if (vap != vp_cache_at && vp_cache_at != NULL)
242                 memcpy(vp_cache_at, vap, sizeof(*vap));
243 }
244
245
246 /* fsync */
247
248 int
249 fuse_internal_fsync_callback(struct fuse_ticket *tick, struct uio *uio)
250 {
251         if (tick->tk_aw_ohead.error == ENOSYS) {
252                 fsess_set_notimpl(tick->tk_data->mp, fticket_opcode(tick));
253         }
254         return 0;
255 }
256
257 int
258 fuse_internal_fsync(struct vnode *vp,
259     struct thread *td,
260     int waitfor,
261     bool datasync)
262 {
263         struct fuse_fsync_in *ffsi = NULL;
264         struct fuse_dispatcher fdi;
265         struct fuse_filehandle *fufh;
266         struct fuse_vnode_data *fvdat = VTOFUD(vp);
267         int op = FUSE_FSYNC;
268         int err = 0;
269
270         if (!fsess_isimpl(vnode_mount(vp),
271             (vnode_vtype(vp) == VDIR ? FUSE_FSYNCDIR : FUSE_FSYNC))) {
272                 return 0;
273         }
274         if (vnode_isdir(vp))
275                 op = FUSE_FSYNCDIR;
276
277         fdisp_init(&fdi, sizeof(*ffsi));
278         /*
279          * fsync every open file handle for this file, because we can't be sure
280          * which file handle the caller is really referring to.
281          */
282         LIST_FOREACH(fufh, &fvdat->handles, next) {
283                 if (ffsi == NULL)
284                         fdisp_make_vp(&fdi, op, vp, td, NULL);
285                 else
286                         fdisp_refresh_vp(&fdi, op, vp, td, NULL);
287                 ffsi = fdi.indata;
288                 ffsi->fh = fufh->fh_id;
289                 ffsi->fsync_flags = 0;
290
291                 if (datasync)
292                         ffsi->fsync_flags = 1;
293
294                 if (waitfor == MNT_WAIT) {
295                         err = fdisp_wait_answ(&fdi);
296                 } else {
297                         fuse_insert_callback(fdi.tick,
298                                 fuse_internal_fsync_callback);
299                         fuse_insert_message(fdi.tick);
300                 }
301         }
302         fdisp_destroy(&fdi);
303
304         return err;
305 }
306
307 /* readdir */
308
309 int
310 fuse_internal_readdir(struct vnode *vp,
311     struct uio *uio,
312     struct fuse_filehandle *fufh,
313     struct fuse_iov *cookediov)
314 {
315         int err = 0;
316         struct fuse_dispatcher fdi;
317         struct fuse_read_in *fri = NULL;
318
319         if (uio_resid(uio) == 0) {
320                 return 0;
321         }
322         fdisp_init(&fdi, 0);
323
324         /*
325          * Note that we DO NOT have a UIO_SYSSPACE here (so no need for p2p
326          * I/O).
327          */
328
329         while (uio_resid(uio) > 0) {
330                 fdi.iosize = sizeof(*fri);
331                 if (fri == NULL)
332                         fdisp_make_vp(&fdi, FUSE_READDIR, vp, NULL, NULL);
333                 else
334                         fdisp_refresh_vp(&fdi, FUSE_READDIR, vp, NULL, NULL);
335
336                 fri = fdi.indata;
337                 fri->fh = fufh->fh_id;
338                 fri->offset = uio_offset(uio);
339                 fri->size = MIN(uio->uio_resid,
340                     fuse_get_mpdata(vp->v_mount)->max_read);
341
342                     if ((err = fdisp_wait_answ(&fdi))) {
343                         break;
344                 }
345                 if ((err = fuse_internal_readdir_processdata(uio, fri->size, fdi.answ,
346                     fdi.iosize, cookediov))) {
347                         break;
348                 }
349         }
350
351         fdisp_destroy(&fdi);
352         return ((err == -1) ? 0 : err);
353 }
354
355 int
356 fuse_internal_readdir_processdata(struct uio *uio,
357     size_t reqsize,
358     void *buf,
359     size_t bufsize,
360     void *param)
361 {
362         int err = 0;
363         int cou = 0;
364         int bytesavail;
365         size_t freclen;
366
367         struct dirent *de;
368         struct fuse_dirent *fudge;
369         struct fuse_iov *cookediov = param;
370
371         if (bufsize < FUSE_NAME_OFFSET) {
372                 return -1;
373         }
374         for (;;) {
375
376                 if (bufsize < FUSE_NAME_OFFSET) {
377                         err = -1;
378                         break;
379                 }
380                 fudge = (struct fuse_dirent *)buf;
381                 freclen = FUSE_DIRENT_SIZE(fudge);
382
383                 cou++;
384
385                 if (bufsize < freclen) {
386                         err = ((cou == 1) ? -1 : 0);
387                         break;
388                 }
389 #ifdef ZERO_PAD_INCOMPLETE_BUFS
390                 if (isbzero(buf, FUSE_NAME_OFFSET)) {
391                         err = -1;
392                         break;
393                 }
394 #endif
395
396                 if (!fudge->namelen || fudge->namelen > MAXNAMLEN) {
397                         err = EINVAL;
398                         break;
399                 }
400                 bytesavail = GENERIC_DIRSIZ((struct pseudo_dirent *)
401                                             &fudge->namelen);
402
403                 if (bytesavail > uio_resid(uio)) {
404                         err = -1;
405                         break;
406                 }
407                 fiov_adjust(cookediov, bytesavail);
408                 bzero(cookediov->base, bytesavail);
409
410                 de = (struct dirent *)cookediov->base;
411                 de->d_fileno = fudge->ino;
412                 de->d_reclen = bytesavail;
413                 de->d_type = fudge->type;
414                 de->d_namlen = fudge->namelen;
415                 memcpy((char *)cookediov->base + sizeof(struct dirent) - 
416                        MAXNAMLEN - 1,
417                        (char *)buf + FUSE_NAME_OFFSET, fudge->namelen);
418                 dirent_terminate(de);
419
420                 err = uiomove(cookediov->base, cookediov->len, uio);
421                 if (err) {
422                         break;
423                 }
424                 buf = (char *)buf + freclen;
425                 bufsize -= freclen;
426                 uio_setoffset(uio, fudge->off);
427         }
428
429         return err;
430 }
431
432 /* remove */
433
434 int
435 fuse_internal_remove(struct vnode *dvp,
436     struct vnode *vp,
437     struct componentname *cnp,
438     enum fuse_opcode op)
439 {
440         struct fuse_dispatcher fdi;
441         int err = 0;
442
443         fdisp_init(&fdi, cnp->cn_namelen + 1);
444         fdisp_make_vp(&fdi, op, dvp, cnp->cn_thread, cnp->cn_cred);
445
446         memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
447         ((char *)fdi.indata)[cnp->cn_namelen] = '\0';
448
449         err = fdisp_wait_answ(&fdi);
450         fdisp_destroy(&fdi);
451         return err;
452 }
453
454 /* rename */
455
456 int
457 fuse_internal_rename(struct vnode *fdvp,
458     struct componentname *fcnp,
459     struct vnode *tdvp,
460     struct componentname *tcnp)
461 {
462         struct fuse_dispatcher fdi;
463         struct fuse_rename_in *fri;
464         int err = 0;
465
466         fdisp_init(&fdi, sizeof(*fri) + fcnp->cn_namelen + tcnp->cn_namelen + 2);
467         fdisp_make_vp(&fdi, FUSE_RENAME, fdvp, tcnp->cn_thread, tcnp->cn_cred);
468
469         fri = fdi.indata;
470         fri->newdir = VTOI(tdvp);
471         memcpy((char *)fdi.indata + sizeof(*fri), fcnp->cn_nameptr,
472             fcnp->cn_namelen);
473         ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen] = '\0';
474         memcpy((char *)fdi.indata + sizeof(*fri) + fcnp->cn_namelen + 1,
475             tcnp->cn_nameptr, tcnp->cn_namelen);
476         ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen +
477             tcnp->cn_namelen + 1] = '\0';
478
479         err = fdisp_wait_answ(&fdi);
480         fdisp_destroy(&fdi);
481         return err;
482 }
483
484 /* strategy */
485
486 /* entity creation */
487
488 void
489 fuse_internal_newentry_makerequest(struct mount *mp,
490     uint64_t dnid,
491     struct componentname *cnp,
492     enum fuse_opcode op,
493     void *buf,
494     size_t bufsize,
495     struct fuse_dispatcher *fdip)
496 {
497         fdip->iosize = bufsize + cnp->cn_namelen + 1;
498
499         fdisp_make(fdip, op, mp, dnid, cnp->cn_thread, cnp->cn_cred);
500         memcpy(fdip->indata, buf, bufsize);
501         memcpy((char *)fdip->indata + bufsize, cnp->cn_nameptr, cnp->cn_namelen);
502         ((char *)fdip->indata)[bufsize + cnp->cn_namelen] = '\0';
503 }
504
505 int
506 fuse_internal_newentry_core(struct vnode *dvp,
507     struct vnode **vpp,
508     struct componentname *cnp,
509     enum vtype vtyp,
510     struct fuse_dispatcher *fdip)
511 {
512         int err = 0;
513         struct fuse_entry_out *feo;
514         struct mount *mp = vnode_mount(dvp);
515
516         if ((err = fdisp_wait_answ(fdip))) {
517                 return err;
518         }
519         feo = fdip->answ;
520
521         if ((err = fuse_internal_checkentry(feo, vtyp))) {
522                 return err;
523         }
524         err = fuse_vnode_get(mp, feo, feo->nodeid, dvp, vpp, cnp, vtyp);
525         if (err) {
526                 fuse_internal_forget_send(mp, cnp->cn_thread, cnp->cn_cred,
527                     feo->nodeid, 1);
528                 return err;
529         }
530         fuse_internal_cache_attrs(*vpp, &feo->attr, feo->attr_valid,
531                 feo->attr_valid_nsec, NULL);
532
533         return err;
534 }
535
536 int
537 fuse_internal_newentry(struct vnode *dvp,
538     struct vnode **vpp,
539     struct componentname *cnp,
540     enum fuse_opcode op,
541     void *buf,
542     size_t bufsize,
543     enum vtype vtype)
544 {
545         int err;
546         struct fuse_dispatcher fdi;
547         struct mount *mp = vnode_mount(dvp);
548
549         fdisp_init(&fdi, 0);
550         fuse_internal_newentry_makerequest(mp, VTOI(dvp), cnp, op, buf,
551             bufsize, &fdi);
552         err = fuse_internal_newentry_core(dvp, vpp, cnp, vtype, &fdi);
553         fdisp_destroy(&fdi);
554
555         return err;
556 }
557
558 /* entity destruction */
559
560 int
561 fuse_internal_forget_callback(struct fuse_ticket *ftick, struct uio *uio)
562 {
563         fuse_internal_forget_send(ftick->tk_data->mp, curthread, NULL,
564             ((struct fuse_in_header *)ftick->tk_ms_fiov.base)->nodeid, 1);
565
566         return 0;
567 }
568
569 void
570 fuse_internal_forget_send(struct mount *mp,
571     struct thread *td,
572     struct ucred *cred,
573     uint64_t nodeid,
574     uint64_t nlookup)
575 {
576
577         struct fuse_dispatcher fdi;
578         struct fuse_forget_in *ffi;
579
580         /*
581          * KASSERT(nlookup > 0, ("zero-times forget for vp #%llu",
582          *         (long long unsigned) nodeid));
583          */
584
585         fdisp_init(&fdi, sizeof(*ffi));
586         fdisp_make(&fdi, FUSE_FORGET, mp, nodeid, td, cred);
587
588         ffi = fdi.indata;
589         ffi->nlookup = nlookup;
590
591         fuse_insert_message(fdi.tick);
592         fdisp_destroy(&fdi);
593 }
594
595 /* Read a vnode's attributes from cache or fetch them from the fuse daemon */
596 int
597 fuse_internal_getattr(struct vnode *vp, struct vattr *vap, struct ucred *cred,
598         struct thread *td)
599 {
600         struct fuse_dispatcher fdi;
601         struct fuse_vnode_data *fvdat = VTOFUD(vp);
602         struct vattr *attrs;
603         struct fuse_attr_out *fao;
604         int err = 0;
605
606         if ((attrs = VTOVA(vp)) != NULL) {
607                 /* struct copy */
608                 *vap = *attrs;
609                 if ((fvdat->flag & FN_SIZECHANGE) != 0)
610                         vap->va_size = fvdat->filesize;
611                 return 0;
612         }
613
614         fdisp_init(&fdi, 0);
615         if ((err = fdisp_simple_putget_vp(&fdi, FUSE_GETATTR, vp, td, cred))) {
616                 if (err == ENOENT) {
617                         fuse_internal_vnode_disappear(vp);
618                 }
619                 goto out;
620         }
621
622         fao = (struct fuse_attr_out *)fdi.answ;
623         fuse_internal_cache_attrs(vp, &fao->attr, fao->attr_valid,
624                 fao->attr_valid_nsec, vap);
625         if (vap->va_type != vnode_vtype(vp)) {
626                 fuse_internal_vnode_disappear(vp);
627                 err = ENOENT;
628                 goto out;
629         }
630         if ((fvdat->flag & FN_SIZECHANGE) != 0)
631                 vap->va_size = fvdat->filesize;
632
633         if (vnode_isreg(vp) && (fvdat->flag & FN_SIZECHANGE) == 0) {
634                 /*
635                  * This is for those cases when the file size changed without us
636                  * knowing, and we want to catch up.
637                  */
638                 off_t new_filesize = fao->attr.size;
639
640                 if (fvdat->filesize != new_filesize) {
641                         fuse_vnode_setsize(vp, cred, new_filesize);
642                         fvdat->flag &= ~FN_SIZECHANGE;
643                 }
644         }
645
646 out:
647         fdisp_destroy(&fdi);
648         return err;
649 }
650
651 void
652 fuse_internal_vnode_disappear(struct vnode *vp)
653 {
654         struct fuse_vnode_data *fvdat = VTOFUD(vp);
655
656         ASSERT_VOP_ELOCKED(vp, "fuse_internal_vnode_disappear");
657         fvdat->flag |= FN_REVOKED;
658         bintime_clear(&fvdat->attr_cache_timeout);
659         cache_purge(vp);
660 }
661
662 /* fuse start/stop */
663
664 int
665 fuse_internal_init_callback(struct fuse_ticket *tick, struct uio *uio)
666 {
667         int err = 0;
668         struct fuse_data *data = tick->tk_data;
669         struct fuse_init_out *fiio;
670
671         if ((err = tick->tk_aw_ohead.error)) {
672                 goto out;
673         }
674         if ((err = fticket_pull(tick, uio))) {
675                 goto out;
676         }
677         fiio = fticket_resp(tick)->base;
678
679         /* XXX: Do we want to check anything further besides this? */
680         if (fiio->major < 7) {
681                 SDT_PROBE2(fuse, , internal, trace, 1,
682                         "userpace version too low");
683                 err = EPROTONOSUPPORT;
684                 goto out;
685         }
686         data->fuse_libabi_major = fiio->major;
687         data->fuse_libabi_minor = fiio->minor;
688
689         if (fuse_libabi_geq(data, 7, 5)) {
690                 if (fticket_resp(tick)->len == sizeof(struct fuse_init_out)) {
691                         data->max_write = fiio->max_write;
692                 } else {
693                         err = EINVAL;
694                 }
695         } else {
696                 /* Old fix values */
697                 data->max_write = 4096;
698         }
699
700 out:
701         if (err) {
702                 fdata_set_dead(data);
703         }
704         FUSE_LOCK();
705         data->dataflags |= FSESS_INITED;
706         wakeup(&data->ticketer);
707         FUSE_UNLOCK();
708
709         return 0;
710 }
711
712 void
713 fuse_internal_send_init(struct fuse_data *data, struct thread *td)
714 {
715         struct fuse_init_in *fiii;
716         struct fuse_dispatcher fdi;
717
718         fdisp_init(&fdi, sizeof(*fiii));
719         fdisp_make(&fdi, FUSE_INIT, data->mp, 0, td, NULL);
720         fiii = fdi.indata;
721         fiii->major = FUSE_KERNEL_VERSION;
722         fiii->minor = FUSE_KERNEL_MINOR_VERSION;
723         /* 
724          * fusefs currently doesn't do any readahead other than fetching whole
725          * buffer cache block sized regions at once.  So the max readahead is
726          * the size of a buffer cache block.
727          */
728         fiii->max_readahead = maxbcachebuf;
729         fiii->flags = 0;
730
731         fuse_insert_callback(fdi.tick, fuse_internal_init_callback);
732         fuse_insert_message(fdi.tick);
733         fdisp_destroy(&fdi);
734 }
735
736 #ifdef ZERO_PAD_INCOMPLETE_BUFS
737 static int
738 isbzero(void *buf, size_t len)
739 {
740         int i;
741
742         for (i = 0; i < len; i++) {
743                 if (((char *)buf)[i])
744                         return (0);
745         }
746
747         return (1);
748 }
749
750 #endif