xref: /freebsd/sys/fs/fuse/fuse_ipc.c (revision f0cfa1b168014f56c02b83e5f28412cc5f78d117)
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 }
904