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