]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/fuse/fuse_ipc.c
Update OpenSSL to 1.1.1.
[FreeBSD/FreeBSD.git] / sys / fs / fuse / fuse_ipc.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/types.h>
62 #include <sys/module.h>
63 #include <sys/systm.h>
64 #include <sys/errno.h>
65 #include <sys/param.h>
66 #include <sys/kernel.h>
67 #include <sys/conf.h>
68 #include <sys/uio.h>
69 #include <sys/malloc.h>
70 #include <sys/queue.h>
71 #include <sys/lock.h>
72 #include <sys/sx.h>
73 #include <sys/mutex.h>
74 #include <sys/proc.h>
75 #include <sys/mount.h>
76 #include <sys/vnode.h>
77 #include <sys/signalvar.h>
78 #include <sys/syscallsubr.h>
79 #include <sys/sysctl.h>
80 #include <vm/uma.h>
81
82 #include "fuse.h"
83 #include "fuse_node.h"
84 #include "fuse_ipc.h"
85 #include "fuse_internal.h"
86
87 #define FUSE_DEBUG_MODULE IPC
88 #include "fuse_debug.h"
89
90 static struct fuse_ticket *fticket_alloc(struct fuse_data *data);
91 static void fticket_refresh(struct fuse_ticket *ftick);
92 static void fticket_destroy(struct fuse_ticket *ftick);
93 static int fticket_wait_answer(struct fuse_ticket *ftick);
94 static __inline__ int 
95 fticket_aw_pull_uio(struct fuse_ticket *ftick,
96     struct uio *uio);
97
98 static int fuse_body_audit(struct fuse_ticket *ftick, size_t blen);
99 static __inline__ void 
100 fuse_setup_ihead(struct fuse_in_header *ihead,
101     struct fuse_ticket *ftick,
102     uint64_t nid,
103     enum fuse_opcode op,
104     size_t blen,
105     pid_t pid,
106     struct ucred *cred);
107
108 static fuse_handler_t fuse_standard_handler;
109
110 SYSCTL_NODE(_vfs, OID_AUTO, fuse, CTLFLAG_RW, 0, "FUSE tunables");
111 SYSCTL_STRING(_vfs_fuse, OID_AUTO, version, CTLFLAG_RD,
112     FUSE_FREEBSD_VERSION, 0, "fuse-freebsd version");
113 static int fuse_ticket_count = 0;
114
115 SYSCTL_INT(_vfs_fuse, OID_AUTO, ticket_count, CTLFLAG_RW,
116     &fuse_ticket_count, 0, "number of allocated tickets");
117 static long fuse_iov_permanent_bufsize = 1 << 19;
118
119 SYSCTL_LONG(_vfs_fuse, OID_AUTO, iov_permanent_bufsize, CTLFLAG_RW,
120     &fuse_iov_permanent_bufsize, 0,
121     "limit for permanently stored buffer size for fuse_iovs");
122 static int fuse_iov_credit = 16;
123
124 SYSCTL_INT(_vfs_fuse, OID_AUTO, iov_credit, CTLFLAG_RW,
125     &fuse_iov_credit, 0,
126     "how many times is an oversized fuse_iov tolerated");
127
128 MALLOC_DEFINE(M_FUSEMSG, "fuse_msgbuf", "fuse message buffer");
129 static uma_zone_t ticket_zone;
130
131 static void
132 fuse_block_sigs(sigset_t *oldset)
133 {
134         sigset_t newset;
135
136         SIGFILLSET(newset);
137         SIGDELSET(newset, SIGKILL);
138         if (kern_sigprocmask(curthread, SIG_BLOCK, &newset, oldset, 0))
139                 panic("%s: Invalid operation for kern_sigprocmask()",
140                     __func__);
141 }
142
143 static void
144 fuse_restore_sigs(sigset_t *oldset)
145 {
146
147         if (kern_sigprocmask(curthread, SIG_SETMASK, oldset, NULL, 0))
148                 panic("%s: Invalid operation for kern_sigprocmask()",
149                     __func__);
150 }
151
152 void
153 fiov_init(struct fuse_iov *fiov, size_t size)
154 {
155         uint32_t msize = FU_AT_LEAST(size);
156
157         debug_printf("fiov=%p, size=%zd\n", fiov, size);
158
159         fiov->len = 0;
160
161         fiov->base = malloc(msize, M_FUSEMSG, M_WAITOK | M_ZERO);
162
163         fiov->allocated_size = msize;
164         fiov->credit = fuse_iov_credit;
165 }
166
167 void
168 fiov_teardown(struct fuse_iov *fiov)
169 {
170         debug_printf("fiov=%p\n", fiov);
171
172         MPASS(fiov->base != NULL);
173         free(fiov->base, M_FUSEMSG);
174 }
175
176 void
177 fiov_adjust(struct fuse_iov *fiov, size_t size)
178 {
179         debug_printf("fiov=%p, size=%zd\n", fiov, size);
180
181         if (fiov->allocated_size < size ||
182             (fuse_iov_permanent_bufsize >= 0 &&
183             fiov->allocated_size - size > fuse_iov_permanent_bufsize &&
184             --fiov->credit < 0)) {
185
186                 fiov->base = realloc(fiov->base, FU_AT_LEAST(size), M_FUSEMSG,
187                     M_WAITOK | M_ZERO);
188                 if (!fiov->base) {
189                         panic("FUSE: realloc failed");
190                 }
191                 fiov->allocated_size = FU_AT_LEAST(size);
192                 fiov->credit = fuse_iov_credit;
193         }
194         fiov->len = size;
195 }
196
197 void
198 fiov_refresh(struct fuse_iov *fiov)
199 {
200         debug_printf("fiov=%p\n", fiov);
201
202         bzero(fiov->base, fiov->len);
203         fiov_adjust(fiov, 0);
204 }
205
206 static int
207 fticket_ctor(void *mem, int size, void *arg, int flags)
208 {
209         struct fuse_ticket *ftick = mem;
210         struct fuse_data *data = arg;
211
212         debug_printf("ftick=%p data=%p\n", ftick, data);
213
214         FUSE_ASSERT_MS_DONE(ftick);
215         FUSE_ASSERT_AW_DONE(ftick);
216
217         ftick->tk_data = data;
218
219         if (ftick->tk_unique != 0)
220                 fticket_refresh(ftick);
221
222         /* May be truncated to 32 bits */
223         ftick->tk_unique = atomic_fetchadd_long(&data->ticketer, 1);
224         if (ftick->tk_unique == 0)
225                 ftick->tk_unique = atomic_fetchadd_long(&data->ticketer, 1);
226
227         refcount_init(&ftick->tk_refcount, 1);
228         atomic_add_acq_int(&fuse_ticket_count, 1);
229
230         return 0;
231 }
232
233 static void
234 fticket_dtor(void *mem, int size, void *arg)
235 {
236         struct fuse_ticket *ftick = mem;
237
238         debug_printf("ftick=%p\n", ftick);
239
240         FUSE_ASSERT_MS_DONE(ftick);
241         FUSE_ASSERT_AW_DONE(ftick);
242
243         atomic_subtract_acq_int(&fuse_ticket_count, 1);
244 }
245
246 static int
247 fticket_init(void *mem, int size, int flags)
248 {
249         struct fuse_ticket *ftick = mem;
250
251         FS_DEBUG("ftick=%p\n", ftick);
252
253         bzero(ftick, sizeof(struct fuse_ticket));
254
255         fiov_init(&ftick->tk_ms_fiov, sizeof(struct fuse_in_header));
256         ftick->tk_ms_type = FT_M_FIOV;
257
258         mtx_init(&ftick->tk_aw_mtx, "fuse answer delivery mutex", NULL, MTX_DEF);
259         fiov_init(&ftick->tk_aw_fiov, 0);
260         ftick->tk_aw_type = FT_A_FIOV;
261
262         return 0;
263 }
264
265 static void
266 fticket_fini(void *mem, int size)
267 {
268         struct fuse_ticket *ftick = mem;
269
270         FS_DEBUG("ftick=%p\n", ftick);
271
272         fiov_teardown(&ftick->tk_ms_fiov);
273         fiov_teardown(&ftick->tk_aw_fiov);
274         mtx_destroy(&ftick->tk_aw_mtx);
275 }
276
277 static __inline struct fuse_ticket *
278 fticket_alloc(struct fuse_data *data)
279 {
280         return uma_zalloc_arg(ticket_zone, data, M_WAITOK);
281 }
282
283 static __inline void
284 fticket_destroy(struct fuse_ticket *ftick)
285 {
286         return uma_zfree(ticket_zone, ftick);
287 }
288
289 static  __inline__
290 void
291 fticket_refresh(struct fuse_ticket *ftick)
292 {
293         debug_printf("ftick=%p\n", ftick);
294
295         FUSE_ASSERT_MS_DONE(ftick);
296         FUSE_ASSERT_AW_DONE(ftick);
297
298         fiov_refresh(&ftick->tk_ms_fiov);
299         ftick->tk_ms_bufdata = NULL;
300         ftick->tk_ms_bufsize = 0;
301         ftick->tk_ms_type = FT_M_FIOV;
302
303         bzero(&ftick->tk_aw_ohead, sizeof(struct fuse_out_header));
304
305         fiov_refresh(&ftick->tk_aw_fiov);
306         ftick->tk_aw_errno = 0;
307         ftick->tk_aw_bufdata = NULL;
308         ftick->tk_aw_bufsize = 0;
309         ftick->tk_aw_type = FT_A_FIOV;
310
311         ftick->tk_flag = 0;
312 }
313
314 static int
315 fticket_wait_answer(struct fuse_ticket *ftick)
316 {
317         sigset_t tset;
318         int err = 0;
319         struct fuse_data *data;
320
321         debug_printf("ftick=%p\n", ftick);
322         fuse_lck_mtx_lock(ftick->tk_aw_mtx);
323
324         if (fticket_answered(ftick)) {
325                 goto out;
326         }
327         data = ftick->tk_data;
328
329         if (fdata_get_dead(data)) {
330                 err = ENOTCONN;
331                 fticket_set_answered(ftick);
332                 goto out;
333         }
334         fuse_block_sigs(&tset);
335         err = msleep(ftick, &ftick->tk_aw_mtx, PCATCH, "fu_ans",
336             data->daemon_timeout * hz);
337         fuse_restore_sigs(&tset);
338         if (err == EAGAIN) {            /* same as EWOULDBLOCK */
339 #ifdef XXXIP                            /* die conditionally */
340                 if (!fdata_get_dead(data)) {
341                         fdata_set_dead(data);
342                 }
343 #endif
344                 err = ETIMEDOUT;
345                 fticket_set_answered(ftick);
346         }
347 out:
348         if (!(err || fticket_answered(ftick))) {
349                 debug_printf("FUSE: requester was woken up but still no answer");
350                 err = ENXIO;
351         }
352         fuse_lck_mtx_unlock(ftick->tk_aw_mtx);
353
354         return err;
355 }
356
357 static  __inline__
358 int
359 fticket_aw_pull_uio(struct fuse_ticket *ftick, struct uio *uio)
360 {
361         int err = 0;
362         size_t len = uio_resid(uio);
363
364         debug_printf("ftick=%p, uio=%p\n", ftick, uio);
365
366         if (len) {
367                 switch (ftick->tk_aw_type) {
368                 case FT_A_FIOV:
369                         fiov_adjust(fticket_resp(ftick), len);
370                         err = uiomove(fticket_resp(ftick)->base, len, uio);
371                         if (err) {
372                                 debug_printf("FUSE: FT_A_FIOV: error is %d"
373                                              " (%p, %zd, %p)\n",
374                                              err, fticket_resp(ftick)->base, 
375                                              len, uio);
376                         }
377                         break;
378
379                 case FT_A_BUF:
380                         ftick->tk_aw_bufsize = len;
381                         err = uiomove(ftick->tk_aw_bufdata, len, uio);
382                         if (err) {
383                                 debug_printf("FUSE: FT_A_BUF: error is %d"
384                                              " (%p, %zd, %p)\n",
385                                              err, ftick->tk_aw_bufdata, len, uio);
386                         }
387                         break;
388
389                 default:
390                         panic("FUSE: unknown answer type for ticket %p", ftick);
391                 }
392         }
393         return err;
394 }
395
396 int
397 fticket_pull(struct fuse_ticket *ftick, struct uio *uio)
398 {
399         int err = 0;
400
401         debug_printf("ftick=%p, uio=%p\n", ftick, uio);
402
403         if (ftick->tk_aw_ohead.error) {
404                 return 0;
405         }
406         err = fuse_body_audit(ftick, uio_resid(uio));
407         if (!err) {
408                 err = fticket_aw_pull_uio(ftick, uio);
409         }
410         return err;
411 }
412
413 struct fuse_data *
414 fdata_alloc(struct cdev *fdev, struct ucred *cred)
415 {
416         struct fuse_data *data;
417
418         debug_printf("fdev=%p\n", fdev);
419
420         data = malloc(sizeof(struct fuse_data), M_FUSEMSG, M_WAITOK | M_ZERO);
421
422         data->fdev = fdev;
423         mtx_init(&data->ms_mtx, "fuse message list mutex", NULL, MTX_DEF);
424         STAILQ_INIT(&data->ms_head);
425         mtx_init(&data->aw_mtx, "fuse answer list mutex", NULL, MTX_DEF);
426         TAILQ_INIT(&data->aw_head);
427         data->daemoncred = crhold(cred);
428         data->daemon_timeout = FUSE_DEFAULT_DAEMON_TIMEOUT;
429         sx_init(&data->rename_lock, "fuse rename lock");
430         data->ref = 1;
431
432         return data;
433 }
434
435 void
436 fdata_trydestroy(struct fuse_data *data)
437 {
438         FS_DEBUG("data=%p data.mp=%p data.fdev=%p data.flags=%04x\n",
439             data, data->mp, data->fdev, data->dataflags);
440
441         FS_DEBUG("destroy: data=%p\n", data);
442         data->ref--;
443         MPASS(data->ref >= 0);
444         if (data->ref != 0)
445                 return;
446
447         /* Driving off stage all that stuff thrown at device... */
448         mtx_destroy(&data->ms_mtx);
449         mtx_destroy(&data->aw_mtx);
450         sx_destroy(&data->rename_lock);
451
452         crfree(data->daemoncred);
453
454         free(data, M_FUSEMSG);
455 }
456
457 void
458 fdata_set_dead(struct fuse_data *data)
459 {
460         debug_printf("data=%p\n", data);
461
462         FUSE_LOCK();
463         if (fdata_get_dead(data)) {
464                 FUSE_UNLOCK();
465                 return;
466         }
467         fuse_lck_mtx_lock(data->ms_mtx);
468         data->dataflags |= FSESS_DEAD;
469         wakeup_one(data);
470         selwakeuppri(&data->ks_rsel, PZERO + 1);
471         wakeup(&data->ticketer);
472         fuse_lck_mtx_unlock(data->ms_mtx);
473         FUSE_UNLOCK();
474 }
475
476 struct fuse_ticket *
477 fuse_ticket_fetch(struct fuse_data *data)
478 {
479         int err = 0;
480         struct fuse_ticket *ftick;
481
482         debug_printf("data=%p\n", data);
483
484         ftick = fticket_alloc(data);
485
486         if (!(data->dataflags & FSESS_INITED)) {
487                 /* Sleep until get answer for INIT messsage */
488                 FUSE_LOCK();
489                 if (!(data->dataflags & FSESS_INITED) && data->ticketer > 2) {
490                         err = msleep(&data->ticketer, &fuse_mtx, PCATCH | PDROP,
491                             "fu_ini", 0);
492                         if (err)
493                                 fdata_set_dead(data);
494                 } else
495                         FUSE_UNLOCK();
496         }
497         return ftick;
498 }
499
500 int
501 fuse_ticket_drop(struct fuse_ticket *ftick)
502 {
503         int die;
504
505         die = refcount_release(&ftick->tk_refcount);
506         debug_printf("ftick=%p refcount=%d\n", ftick, ftick->tk_refcount);
507         if (die)
508                 fticket_destroy(ftick);
509
510         return die;
511 }
512
513 void
514 fuse_insert_callback(struct fuse_ticket *ftick, fuse_handler_t * handler)
515 {
516         debug_printf("ftick=%p, handler=%p data=%p\n", ftick, ftick->tk_data, 
517                      handler);
518
519         if (fdata_get_dead(ftick->tk_data)) {
520                 return;
521         }
522         ftick->tk_aw_handler = handler;
523
524         fuse_lck_mtx_lock(ftick->tk_data->aw_mtx);
525         fuse_aw_push(ftick);
526         fuse_lck_mtx_unlock(ftick->tk_data->aw_mtx);
527 }
528
529 void
530 fuse_insert_message(struct fuse_ticket *ftick)
531 {
532         debug_printf("ftick=%p\n", ftick);
533
534         if (ftick->tk_flag & FT_DIRTY) {
535                 panic("FUSE: ticket reused without being refreshed");
536         }
537         ftick->tk_flag |= FT_DIRTY;
538
539         if (fdata_get_dead(ftick->tk_data)) {
540                 return;
541         }
542         fuse_lck_mtx_lock(ftick->tk_data->ms_mtx);
543         fuse_ms_push(ftick);
544         wakeup_one(ftick->tk_data);
545         selwakeuppri(&ftick->tk_data->ks_rsel, PZERO + 1);
546         fuse_lck_mtx_unlock(ftick->tk_data->ms_mtx);
547 }
548
549 static int
550 fuse_body_audit(struct fuse_ticket *ftick, size_t blen)
551 {
552         int err = 0;
553         enum fuse_opcode opcode;
554
555         debug_printf("ftick=%p, blen = %zu\n", ftick, blen);
556
557         opcode = fticket_opcode(ftick);
558
559         switch (opcode) {
560         case FUSE_LOOKUP:
561                 err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
562                 break;
563
564         case FUSE_FORGET:
565                 panic("FUSE: a handler has been intalled for FUSE_FORGET");
566                 break;
567
568         case FUSE_GETATTR:
569                 err = (blen == sizeof(struct fuse_attr_out)) ? 0 : EINVAL;
570                 break;
571
572         case FUSE_SETATTR:
573                 err = (blen == sizeof(struct fuse_attr_out)) ? 0 : EINVAL;
574                 break;
575
576         case FUSE_READLINK:
577                 err = (PAGE_SIZE >= blen) ? 0 : EINVAL;
578                 break;
579
580         case FUSE_SYMLINK:
581                 err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
582                 break;
583
584         case FUSE_MKNOD:
585                 err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
586                 break;
587
588         case FUSE_MKDIR:
589                 err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
590                 break;
591
592         case FUSE_UNLINK:
593                 err = (blen == 0) ? 0 : EINVAL;
594                 break;
595
596         case FUSE_RMDIR:
597                 err = (blen == 0) ? 0 : EINVAL;
598                 break;
599
600         case FUSE_RENAME:
601                 err = (blen == 0) ? 0 : EINVAL;
602                 break;
603
604         case FUSE_LINK:
605                 err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
606                 break;
607
608         case FUSE_OPEN:
609                 err = (blen == sizeof(struct fuse_open_out)) ? 0 : EINVAL;
610                 break;
611
612         case FUSE_READ:
613                 err = (((struct fuse_read_in *)(
614                     (char *)ftick->tk_ms_fiov.base +
615                     sizeof(struct fuse_in_header)
616                     ))->size >= blen) ? 0 : EINVAL;
617                 break;
618
619         case FUSE_WRITE:
620                 err = (blen == sizeof(struct fuse_write_out)) ? 0 : EINVAL;
621                 break;
622
623         case FUSE_STATFS:
624                 if (fuse_libabi_geq(ftick->tk_data, 7, 4)) {
625                         err = (blen == sizeof(struct fuse_statfs_out)) ? 
626                           0 : EINVAL;
627                 } else {
628                         err = (blen == FUSE_COMPAT_STATFS_SIZE) ? 0 : EINVAL;
629                 }
630                 break;
631
632         case FUSE_RELEASE:
633                 err = (blen == 0) ? 0 : EINVAL;
634                 break;
635
636         case FUSE_FSYNC:
637                 err = (blen == 0) ? 0 : EINVAL;
638                 break;
639
640         case FUSE_SETXATTR:
641                 err = (blen == 0) ? 0 : EINVAL;
642                 break;
643
644         case FUSE_GETXATTR:
645         case FUSE_LISTXATTR:
646                 /*
647                  * These can have varying response lengths, and 0 length
648                  * isn't necessarily invalid.
649                  */
650                 err = 0;
651                 break;
652
653         case FUSE_REMOVEXATTR:
654                 err = (blen == 0) ? 0 : EINVAL;
655                 break;
656
657         case FUSE_FLUSH:
658                 err = (blen == 0) ? 0 : EINVAL;
659                 break;
660
661         case FUSE_INIT:
662                 if (blen == sizeof(struct fuse_init_out) || blen == 8) {
663                         err = 0;
664                 } else {
665                         err = EINVAL;
666                 }
667                 break;
668
669         case FUSE_OPENDIR:
670                 err = (blen == sizeof(struct fuse_open_out)) ? 0 : EINVAL;
671                 break;
672
673         case FUSE_READDIR:
674                 err = (((struct fuse_read_in *)(
675                     (char *)ftick->tk_ms_fiov.base +
676                     sizeof(struct fuse_in_header)
677                     ))->size >= blen) ? 0 : EINVAL;
678                 break;
679
680         case FUSE_RELEASEDIR:
681                 err = (blen == 0) ? 0 : EINVAL;
682                 break;
683
684         case FUSE_FSYNCDIR:
685                 err = (blen == 0) ? 0 : EINVAL;
686                 break;
687
688         case FUSE_GETLK:
689                 panic("FUSE: no response body format check for FUSE_GETLK");
690                 break;
691
692         case FUSE_SETLK:
693                 panic("FUSE: no response body format check for FUSE_SETLK");
694                 break;
695
696         case FUSE_SETLKW:
697                 panic("FUSE: no response body format check for FUSE_SETLKW");
698                 break;
699
700         case FUSE_ACCESS:
701                 err = (blen == 0) ? 0 : EINVAL;
702                 break;
703
704         case FUSE_CREATE:
705                 err = (blen == sizeof(struct fuse_entry_out) +
706                     sizeof(struct fuse_open_out)) ? 0 : EINVAL;
707                 break;
708
709         case FUSE_DESTROY:
710                 err = (blen == 0) ? 0 : EINVAL;
711                 break;
712
713         default:
714                 panic("FUSE: opcodes out of sync (%d)\n", opcode);
715         }
716
717         return err;
718 }
719
720 static void
721 fuse_setup_ihead(struct fuse_in_header *ihead,
722     struct fuse_ticket *ftick,
723     uint64_t nid,
724     enum fuse_opcode op,
725     size_t blen,
726     pid_t pid,
727     struct ucred *cred)
728 {
729         ihead->len = sizeof(*ihead) + blen;
730         ihead->unique = ftick->tk_unique;
731         ihead->nodeid = nid;
732         ihead->opcode = op;
733
734         debug_printf("ihead=%p, ftick=%p, nid=%ju, op=%d, blen=%zu\n",
735             ihead, ftick, (uintmax_t)nid, op, blen);
736
737         ihead->pid = pid;
738         ihead->uid = cred->cr_uid;
739         ihead->gid = cred->cr_rgid;
740 }
741
742 /*
743  * fuse_standard_handler just pulls indata and wakes up pretender.
744  * Doesn't try to interpret data, that's left for the pretender.
745  * Though might do a basic size verification before the pull-in takes place
746  */
747
748 static int
749 fuse_standard_handler(struct fuse_ticket *ftick, struct uio *uio)
750 {
751         int err = 0;
752
753         debug_printf("ftick=%p, uio=%p\n", ftick, uio);
754
755         err = fticket_pull(ftick, uio);
756
757         fuse_lck_mtx_lock(ftick->tk_aw_mtx);
758
759         if (!fticket_answered(ftick)) {
760                 fticket_set_answered(ftick);
761                 ftick->tk_aw_errno = err;
762                 wakeup(ftick);
763         }
764         fuse_lck_mtx_unlock(ftick->tk_aw_mtx);
765
766         return err;
767 }
768
769 void
770 fdisp_make_pid(struct fuse_dispatcher *fdip,
771     enum fuse_opcode op,
772     struct mount *mp,
773     uint64_t nid,
774     pid_t pid,
775     struct ucred *cred)
776 {
777         struct fuse_data *data = fuse_get_mpdata(mp);
778
779         debug_printf("fdip=%p, op=%d, mp=%p, nid=%ju\n",
780             fdip, op, mp, (uintmax_t)nid);
781
782         if (fdip->tick) {
783                 fticket_refresh(fdip->tick);
784         } else {
785                 fdip->tick = fuse_ticket_fetch(data);
786         }
787
788         FUSE_DIMALLOC(&fdip->tick->tk_ms_fiov, fdip->finh,
789             fdip->indata, fdip->iosize);
790
791         fuse_setup_ihead(fdip->finh, fdip->tick, nid, op, fdip->iosize, pid, cred);
792 }
793
794 void
795 fdisp_make(struct fuse_dispatcher *fdip,
796     enum fuse_opcode op,
797     struct mount *mp,
798     uint64_t nid,
799     struct thread *td,
800     struct ucred *cred)
801 {
802         RECTIFY_TDCR(td, cred);
803
804         return fdisp_make_pid(fdip, op, mp, nid, td->td_proc->p_pid, cred);
805 }
806
807 void
808 fdisp_make_vp(struct fuse_dispatcher *fdip,
809     enum fuse_opcode op,
810     struct vnode *vp,
811     struct thread *td,
812     struct ucred *cred)
813 {
814         debug_printf("fdip=%p, op=%d, vp=%p\n", fdip, op, vp);
815         RECTIFY_TDCR(td, cred);
816         return fdisp_make_pid(fdip, op, vnode_mount(vp), VTOI(vp),
817             td->td_proc->p_pid, cred);
818 }
819
820 int
821 fdisp_wait_answ(struct fuse_dispatcher *fdip)
822 {
823         int err = 0;
824
825         fdip->answ_stat = 0;
826         fuse_insert_callback(fdip->tick, fuse_standard_handler);
827         fuse_insert_message(fdip->tick);
828
829         if ((err = fticket_wait_answer(fdip->tick))) {
830                 debug_printf("IPC: interrupted, err = %d\n", err);
831
832                 fuse_lck_mtx_lock(fdip->tick->tk_aw_mtx);
833
834                 if (fticket_answered(fdip->tick)) {
835                         /*
836                          * Just between noticing the interrupt and getting here,
837                          * the standard handler has completed his job.
838                          * So we drop the ticket and exit as usual.
839                          */
840                         debug_printf("IPC: already answered\n");
841                         fuse_lck_mtx_unlock(fdip->tick->tk_aw_mtx);
842                         goto out;
843                 } else {
844                         /*
845                          * So we were faster than the standard handler.
846                          * Then by setting the answered flag we get *him*
847                          * to drop the ticket.
848                          */
849                         debug_printf("IPC: setting to answered\n");
850                         fticket_set_answered(fdip->tick);
851                         fuse_lck_mtx_unlock(fdip->tick->tk_aw_mtx);
852                         return err;
853                 }
854         }
855         debug_printf("IPC: not interrupted, err = %d\n", err);
856
857         if (fdip->tick->tk_aw_errno) {
858                 debug_printf("IPC: explicit EIO-ing, tk_aw_errno = %d\n",
859                     fdip->tick->tk_aw_errno);
860                 err = EIO;
861                 goto out;
862         }
863         if ((err = fdip->tick->tk_aw_ohead.error)) {
864                 debug_printf("IPC: setting status to %d\n",
865                     fdip->tick->tk_aw_ohead.error);
866                 /*
867                  * This means a "proper" fuse syscall error.
868                  * We record this value so the caller will
869                  * be able to know it's not a boring messaging
870                  * failure, if she wishes so (and if not, she can
871                  * just simply propagate the return value of this routine).
872                  * [XXX Maybe a bitflag would do the job too,
873                  * if other flags needed, this will be converted thusly.]
874                  */
875                 fdip->answ_stat = err;
876                 goto out;
877         }
878         fdip->answ = fticket_resp(fdip->tick)->base;
879         fdip->iosize = fticket_resp(fdip->tick)->len;
880
881         debug_printf("IPC: all is well\n");
882
883         return 0;
884
885 out:
886         debug_printf("IPC: dropping ticket, err = %d\n", err);
887
888         return err;
889 }
890
891 void
892 fuse_ipc_init(void)
893 {
894         ticket_zone = uma_zcreate("fuse_ticket", sizeof(struct fuse_ticket),
895             fticket_ctor, fticket_dtor, fticket_init, fticket_fini,
896             UMA_ALIGN_PTR, 0);
897 }
898
899 void
900 fuse_ipc_destroy(void)
901 {
902         uma_zdestroy(ticket_zone);
903 }