]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/fuse/fuse_ipc.c
fusefs: rename the SDT probes from "fuse" to "fusefs"
[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/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/sx.h>
72 #include <sys/mutex.h>
73 #include <sys/proc.h>
74 #include <sys/mount.h>
75 #include <sys/sdt.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 SDT_PROVIDER_DECLARE(fusefs);
88 /* 
89  * Fuse trace probe:
90  * arg0: verbosity.  Higher numbers give more verbose messages
91  * arg1: Textual message
92  */
93 SDT_PROBE_DEFINE2(fusefs, , ipc, trace, "int", "char*");
94
95 static void fdisp_make_pid(struct fuse_dispatcher *fdip, enum fuse_opcode op,
96     struct fuse_data *data, uint64_t nid, pid_t pid, struct ucred *cred);
97 static void fiov_clear(struct fuse_iov *fiov);
98 static void fuse_interrupt_send(struct fuse_ticket *otick, int err);
99 static struct fuse_ticket *fticket_alloc(struct fuse_data *data);
100 static void fticket_refresh(struct fuse_ticket *ftick);
101 static void fticket_destroy(struct fuse_ticket *ftick);
102 static int fticket_wait_answer(struct fuse_ticket *ftick);
103 static inline int 
104 fticket_aw_pull_uio(struct fuse_ticket *ftick,
105     struct uio *uio);
106
107 static int fuse_body_audit(struct fuse_ticket *ftick, size_t blen);
108
109 static fuse_handler_t fuse_standard_handler;
110
111 SYSCTL_NODE(_vfs, OID_AUTO, fusefs, CTLFLAG_RW, 0, "FUSE tunables");
112 static int fuse_ticket_count = 0;
113
114 SYSCTL_INT(_vfs_fusefs, OID_AUTO, ticket_count, CTLFLAG_RW,
115     &fuse_ticket_count, 0, "number of allocated tickets");
116 static long fuse_iov_permanent_bufsize = 1 << 19;
117
118 SYSCTL_LONG(_vfs_fusefs, OID_AUTO, iov_permanent_bufsize, CTLFLAG_RW,
119     &fuse_iov_permanent_bufsize, 0,
120     "limit for permanently stored buffer size for fuse_iovs");
121 static int fuse_iov_credit = 16;
122
123 SYSCTL_INT(_vfs_fusefs, OID_AUTO, iov_credit, CTLFLAG_RW,
124     &fuse_iov_credit, 0,
125     "how many times is an oversized fuse_iov tolerated");
126
127 MALLOC_DEFINE(M_FUSEMSG, "fuse_msgbuf", "fuse message buffer");
128 static uma_zone_t ticket_zone;
129
130 /* 
131  * TODO: figure out how to timeout INTERRUPT requests, because the daemon may
132  * leagally never respond
133  * 
134  * TODO: remove an INTERRUPT request if the daemon responds to the original
135  */
136 static int
137 fuse_interrupt_callback(struct fuse_ticket *tick, struct uio *uio)
138 {
139         struct fuse_ticket *otick, *x_tick;
140         struct fuse_interrupt_in *fii;
141         struct fuse_data *data;
142         data = tick->tk_data;
143         bool found = false;
144
145         fii = (struct fuse_interrupt_in*)((char*)tick->tk_ms_fiov.base +
146                 sizeof(struct fuse_in_header));
147
148         fuse_lck_mtx_lock(data->aw_mtx);
149         TAILQ_FOREACH_SAFE(otick, &data->aw_head, tk_aw_link, x_tick) {
150                 if (otick->tk_unique == fii->unique) {
151                         found = true;
152                         break;
153                 }
154         }
155         fuse_lck_mtx_unlock(data->aw_mtx);
156
157         if (!found) {
158                 /* Original is already complete.  Just return */
159                 return 0;
160         }
161
162         /* Clear the original ticket's interrupt association */
163         otick->irq_unique = 0;
164
165         if (tick->tk_aw_ohead.error == EAGAIN) {
166                 /* 
167                  * There are two reasons we might get this:
168                  * 1) the daemon received the INTERRUPT request before the
169                  *    original, or
170                  * 2) the daemon received the INTERRUPT request after it
171                  *    completed the original request.
172                  * In the first case we should re-send the INTERRUPT.  In the
173                  * second, we should ignore it.
174                  */
175                 /* Resend */
176                 fuse_interrupt_send(otick, EINTR);
177                 return 0;
178         } else {
179                 /* Illegal FUSE_INTERRUPT response */
180                 return EINVAL;
181         }
182 }
183
184 /* Interrupt the operation otick.  Return err as its error code */
185 void
186 fuse_interrupt_send(struct fuse_ticket *otick, int err)
187 {
188         struct fuse_dispatcher fdi;
189         struct fuse_interrupt_in *fii;
190         struct fuse_in_header *ftick_hdr;
191         struct fuse_data *data = otick->tk_data;
192         struct fuse_ticket *tick, *xtick;
193         struct ucred reused_creds;
194
195         if (otick->irq_unique == 0) {
196                 /* 
197                  * If the daemon hasn't yet received otick, then we can answer
198                  * it ourselves and return.
199                  */
200                 fuse_lck_mtx_lock(data->ms_mtx);
201                 STAILQ_FOREACH_SAFE(tick, &otick->tk_data->ms_head, tk_ms_link,
202                         xtick) {
203                         if (tick == otick) {
204                                 STAILQ_REMOVE(&otick->tk_data->ms_head, tick,
205                                         fuse_ticket, tk_ms_link);
206                                 otick->tk_ms_link.stqe_next = NULL;
207                                 fuse_lck_mtx_unlock(data->ms_mtx);
208
209                                 fuse_lck_mtx_lock(otick->tk_aw_mtx);
210                                 if (!fticket_answered(otick)) {
211                                         fticket_set_answered(otick);
212                                         otick->tk_aw_errno = err;
213                                         wakeup(otick);
214                                 }
215                                 fuse_lck_mtx_unlock(otick->tk_aw_mtx);
216
217                                 fuse_ticket_drop(tick);
218                                 return;
219                         }
220                 }
221                 fuse_lck_mtx_unlock(data->ms_mtx);
222
223                 /* 
224                  * If the fuse daemon has already received otick, then we must
225                  * send FUSE_INTERRUPT.
226                  */
227                 ftick_hdr = fticket_in_header(otick);
228                 reused_creds.cr_uid = ftick_hdr->uid;
229                 reused_creds.cr_rgid = ftick_hdr->gid;
230                 fdisp_init(&fdi, sizeof(*fii));
231                 fdisp_make_pid(&fdi, FUSE_INTERRUPT, data, ftick_hdr->nodeid,
232                         ftick_hdr->pid, &reused_creds);
233
234                 fii = fdi.indata;
235                 fii->unique = otick->tk_unique;
236                 fuse_insert_callback(fdi.tick, fuse_interrupt_callback);
237
238                 otick->irq_unique = fdi.tick->tk_unique;
239                 /* Interrupt ops should be delivered ASAP */
240                 fuse_insert_message(fdi.tick, true);
241                 fdisp_destroy(&fdi);
242         } else {
243                 /* This ticket has already been interrupted */
244         }
245 }
246
247 void
248 fiov_init(struct fuse_iov *fiov, size_t size)
249 {
250         uint32_t msize = FU_AT_LEAST(size);
251
252         fiov->len = 0;
253
254         fiov->base = malloc(msize, M_FUSEMSG, M_WAITOK | M_ZERO);
255
256         fiov->allocated_size = msize;
257         fiov->credit = fuse_iov_credit;
258 }
259
260 void
261 fiov_teardown(struct fuse_iov *fiov)
262 {
263         MPASS(fiov->base != NULL);
264         free(fiov->base, M_FUSEMSG);
265 }
266
267 void
268 fiov_adjust(struct fuse_iov *fiov, size_t size)
269 {
270         if (fiov->allocated_size < size ||
271             (fuse_iov_permanent_bufsize >= 0 &&
272             fiov->allocated_size - size > fuse_iov_permanent_bufsize &&
273             --fiov->credit < 0)) {
274
275                 fiov->base = realloc(fiov->base, FU_AT_LEAST(size), M_FUSEMSG,
276                     M_WAITOK | M_ZERO);
277                 if (!fiov->base) {
278                         panic("FUSE: realloc failed");
279                 }
280                 fiov->allocated_size = FU_AT_LEAST(size);
281                 fiov->credit = fuse_iov_credit;
282                 /* Clear data buffer after reallocation */
283                 bzero(fiov->base, size);
284         } else if (size > fiov->len) {
285                 /* Clear newly extended portion of data buffer */
286                 bzero((char*)fiov->base + fiov->len, size - fiov->len);
287         }
288         fiov->len = size;
289 }
290
291 /* Clear the fiov's data buffer */
292 static void
293 fiov_clear(struct fuse_iov *fiov)
294 {
295         bzero(fiov->base, fiov->len);
296 }
297
298 /* Resize the fiov if needed, and clear it's buffer */
299 void
300 fiov_refresh(struct fuse_iov *fiov)
301 {
302         fiov_adjust(fiov, 0);
303 }
304
305 static int
306 fticket_ctor(void *mem, int size, void *arg, int flags)
307 {
308         struct fuse_ticket *ftick = mem;
309         struct fuse_data *data = arg;
310
311         FUSE_ASSERT_MS_DONE(ftick);
312         FUSE_ASSERT_AW_DONE(ftick);
313
314         ftick->tk_data = data;
315
316         if (ftick->tk_unique != 0)
317                 fticket_refresh(ftick);
318
319         /* May be truncated to 32 bits */
320         ftick->tk_unique = atomic_fetchadd_long(&data->ticketer, 1);
321         if (ftick->tk_unique == 0)
322                 ftick->tk_unique = atomic_fetchadd_long(&data->ticketer, 1);
323
324         ftick->irq_unique = 0;
325
326         refcount_init(&ftick->tk_refcount, 1);
327         atomic_add_acq_int(&fuse_ticket_count, 1);
328
329         return 0;
330 }
331
332 static void
333 fticket_dtor(void *mem, int size, void *arg)
334 {
335 #ifdef INVARIANTS
336         struct fuse_ticket *ftick = mem;
337 #endif
338
339         FUSE_ASSERT_MS_DONE(ftick);
340         FUSE_ASSERT_AW_DONE(ftick);
341
342         atomic_subtract_acq_int(&fuse_ticket_count, 1);
343 }
344
345 static int
346 fticket_init(void *mem, int size, int flags)
347 {
348         struct fuse_ticket *ftick = mem;
349
350         bzero(ftick, sizeof(struct fuse_ticket));
351
352         fiov_init(&ftick->tk_ms_fiov, sizeof(struct fuse_in_header));
353         ftick->tk_ms_type = FT_M_FIOV;
354
355         mtx_init(&ftick->tk_aw_mtx, "fuse answer delivery mutex", NULL, MTX_DEF);
356         fiov_init(&ftick->tk_aw_fiov, 0);
357         ftick->tk_aw_type = FT_A_FIOV;
358
359         return 0;
360 }
361
362 static void
363 fticket_fini(void *mem, int size)
364 {
365         struct fuse_ticket *ftick = mem;
366
367         fiov_teardown(&ftick->tk_ms_fiov);
368         fiov_teardown(&ftick->tk_aw_fiov);
369         mtx_destroy(&ftick->tk_aw_mtx);
370 }
371
372 static inline struct fuse_ticket *
373 fticket_alloc(struct fuse_data *data)
374 {
375         return uma_zalloc_arg(ticket_zone, data, M_WAITOK);
376 }
377
378 static inline void
379 fticket_destroy(struct fuse_ticket *ftick)
380 {
381         return uma_zfree(ticket_zone, ftick);
382 }
383
384 static inline
385 void
386 fticket_refresh(struct fuse_ticket *ftick)
387 {
388         FUSE_ASSERT_MS_DONE(ftick);
389         FUSE_ASSERT_AW_DONE(ftick);
390
391         fiov_refresh(&ftick->tk_ms_fiov);
392         ftick->tk_ms_bufdata = NULL;
393         ftick->tk_ms_bufsize = 0;
394         ftick->tk_ms_type = FT_M_FIOV;
395
396         bzero(&ftick->tk_aw_ohead, sizeof(struct fuse_out_header));
397
398         fiov_refresh(&ftick->tk_aw_fiov);
399         ftick->tk_aw_errno = 0;
400         ftick->tk_aw_bufdata = NULL;
401         ftick->tk_aw_bufsize = 0;
402         ftick->tk_aw_type = FT_A_FIOV;
403
404         ftick->tk_flag = 0;
405 }
406
407 /* Prepar the ticket to be reused, but don't clear its data buffers */
408 static inline void
409 fticket_reset(struct fuse_ticket *ftick)
410 {
411         FUSE_ASSERT_MS_DONE(ftick);
412         FUSE_ASSERT_AW_DONE(ftick);
413
414         ftick->tk_ms_bufdata = NULL;
415         ftick->tk_ms_bufsize = 0;
416         ftick->tk_ms_type = FT_M_FIOV;
417
418         bzero(&ftick->tk_aw_ohead, sizeof(struct fuse_out_header));
419
420         ftick->tk_aw_errno = 0;
421         ftick->tk_aw_bufdata = NULL;
422         ftick->tk_aw_bufsize = 0;
423         ftick->tk_aw_type = FT_A_FIOV;
424
425         ftick->tk_flag = 0;
426 }
427
428 static int
429 fticket_wait_answer(struct fuse_ticket *ftick)
430 {
431         struct thread *td = curthread;
432         sigset_t blockedset, oldset;
433         int err = 0;
434         struct fuse_data *data;
435         SIGEMPTYSET(blockedset);
436
437         kern_sigprocmask(td, SIG_BLOCK, NULL, &oldset, 0);
438
439         fuse_lck_mtx_lock(ftick->tk_aw_mtx);
440
441 retry:
442         if (fticket_answered(ftick)) {
443                 goto out;
444         }
445         data = ftick->tk_data;
446
447         if (fdata_get_dead(data)) {
448                 err = ENOTCONN;
449                 fticket_set_answered(ftick);
450                 goto out;
451         }
452         kern_sigprocmask(td, SIG_BLOCK, &blockedset, NULL, 0);
453         err = msleep(ftick, &ftick->tk_aw_mtx, PCATCH, "fu_ans",
454             data->daemon_timeout * hz);
455         kern_sigprocmask(td, SIG_SETMASK, &oldset, NULL, 0);
456         if (err == EWOULDBLOCK) {
457                 SDT_PROBE2(fusefs, , ipc, trace, 3,
458                         "fticket_wait_answer: EWOULDBLOCK");
459 #ifdef XXXIP                            /* die conditionally */
460                 if (!fdata_get_dead(data)) {
461                         fdata_set_dead(data);
462                 }
463 #endif
464                 err = ETIMEDOUT;
465                 fticket_set_answered(ftick);
466         } else if ((err == EINTR || err == ERESTART)) {
467                 /*
468                  * Whether we get EINTR or ERESTART depends on whether
469                  * SA_RESTART was set by sigaction(2).
470                  *
471                  * Try to interrupt the operation and wait for an EINTR response
472                  * to the original operation.  If the file system does not
473                  * support FUSE_INTERRUPT, then we'll just wait for it to
474                  * complete like normal.  If it does support FUSE_INTERRUPT,
475                  * then it will either respond EINTR to the original operation,
476                  * or EAGAIN to the interrupt.
477                  */
478                 int sig;
479
480                 SDT_PROBE2(fusefs, , ipc, trace, 4,
481                         "fticket_wait_answer: interrupt");
482                 fuse_lck_mtx_unlock(ftick->tk_aw_mtx);
483                 fuse_interrupt_send(ftick, err);
484
485                 PROC_LOCK(td->td_proc);
486                 mtx_lock(&td->td_proc->p_sigacts->ps_mtx);
487                 sig = cursig(td);
488                 mtx_unlock(&td->td_proc->p_sigacts->ps_mtx);
489                 PROC_UNLOCK(td->td_proc);
490
491                 fuse_lck_mtx_lock(ftick->tk_aw_mtx);
492                 if (!sig_isfatal(td->td_proc, sig)) {
493                         /* 
494                          * Block the just-delivered signal while we wait for an
495                          * interrupt response
496                          */
497                         SIGADDSET(blockedset, sig);
498                         goto retry;
499                 } else {
500                         /* Return immediately for fatal signals */
501                 }
502         } else if (err) {
503                 SDT_PROBE2(fusefs, , ipc, trace, 6,
504                         "fticket_wait_answer: other error");
505         } else {
506                 SDT_PROBE2(fusefs, , ipc, trace, 7, "fticket_wait_answer: OK");
507         }
508 out:
509         if (!(err || fticket_answered(ftick))) {
510                 SDT_PROBE2(fusefs, , ipc, trace, 1,
511                         "FUSE: requester was woken up but still no answer");
512                 err = ENXIO;
513         }
514         fuse_lck_mtx_unlock(ftick->tk_aw_mtx);
515
516         return err;
517 }
518
519 static  inline
520 int
521 fticket_aw_pull_uio(struct fuse_ticket *ftick, struct uio *uio)
522 {
523         int err = 0;
524         size_t len = uio_resid(uio);
525
526         if (len) {
527                 switch (ftick->tk_aw_type) {
528                 case FT_A_FIOV:
529                         fiov_adjust(fticket_resp(ftick), len);
530                         err = uiomove(fticket_resp(ftick)->base, len, uio);
531                         break;
532
533                 case FT_A_BUF:
534                         ftick->tk_aw_bufsize = len;
535                         err = uiomove(ftick->tk_aw_bufdata, len, uio);
536                         break;
537
538                 default:
539                         panic("FUSE: unknown answer type for ticket %p", ftick);
540                 }
541         }
542         return err;
543 }
544
545 int
546 fticket_pull(struct fuse_ticket *ftick, struct uio *uio)
547 {
548         int err = 0;
549
550         if (ftick->tk_aw_ohead.error) {
551                 return 0;
552         }
553         err = fuse_body_audit(ftick, uio_resid(uio));
554         if (!err) {
555                 err = fticket_aw_pull_uio(ftick, uio);
556         }
557         return err;
558 }
559
560 struct fuse_data *
561 fdata_alloc(struct cdev *fdev, struct ucred *cred)
562 {
563         struct fuse_data *data;
564
565         data = malloc(sizeof(struct fuse_data), M_FUSEMSG, M_WAITOK | M_ZERO);
566
567         data->fdev = fdev;
568         mtx_init(&data->ms_mtx, "fuse message list mutex", NULL, MTX_DEF);
569         STAILQ_INIT(&data->ms_head);
570         mtx_init(&data->aw_mtx, "fuse answer list mutex", NULL, MTX_DEF);
571         TAILQ_INIT(&data->aw_head);
572         data->daemoncred = crhold(cred);
573         data->daemon_timeout = FUSE_DEFAULT_DAEMON_TIMEOUT;
574         sx_init(&data->rename_lock, "fuse rename lock");
575         data->ref = 1;
576
577         return data;
578 }
579
580 void
581 fdata_trydestroy(struct fuse_data *data)
582 {
583         data->ref--;
584         MPASS(data->ref >= 0);
585         if (data->ref != 0)
586                 return;
587
588         /* Driving off stage all that stuff thrown at device... */
589         mtx_destroy(&data->ms_mtx);
590         mtx_destroy(&data->aw_mtx);
591         sx_destroy(&data->rename_lock);
592
593         crfree(data->daemoncred);
594
595         free(data, M_FUSEMSG);
596 }
597
598 void
599 fdata_set_dead(struct fuse_data *data)
600 {
601         FUSE_LOCK();
602         if (fdata_get_dead(data)) {
603                 FUSE_UNLOCK();
604                 return;
605         }
606         fuse_lck_mtx_lock(data->ms_mtx);
607         data->dataflags |= FSESS_DEAD;
608         wakeup_one(data);
609         selwakeuppri(&data->ks_rsel, PZERO + 1);
610         wakeup(&data->ticketer);
611         fuse_lck_mtx_unlock(data->ms_mtx);
612         FUSE_UNLOCK();
613 }
614
615 struct fuse_ticket *
616 fuse_ticket_fetch(struct fuse_data *data)
617 {
618         int err = 0;
619         struct fuse_ticket *ftick;
620
621         ftick = fticket_alloc(data);
622
623         if (!(data->dataflags & FSESS_INITED)) {
624                 /* Sleep until get answer for INIT messsage */
625                 FUSE_LOCK();
626                 if (!(data->dataflags & FSESS_INITED) && data->ticketer > 2) {
627                         err = msleep(&data->ticketer, &fuse_mtx, PCATCH | PDROP,
628                             "fu_ini", 0);
629                         if (err)
630                                 fdata_set_dead(data);
631                 } else
632                         FUSE_UNLOCK();
633         }
634         return ftick;
635 }
636
637 int
638 fuse_ticket_drop(struct fuse_ticket *ftick)
639 {
640         int die;
641
642         die = refcount_release(&ftick->tk_refcount);
643         if (die)
644                 fticket_destroy(ftick);
645
646         return die;
647 }
648
649 void
650 fuse_insert_callback(struct fuse_ticket *ftick, fuse_handler_t * handler)
651 {
652         if (fdata_get_dead(ftick->tk_data)) {
653                 return;
654         }
655         ftick->tk_aw_handler = handler;
656
657         fuse_lck_mtx_lock(ftick->tk_data->aw_mtx);
658         fuse_aw_push(ftick);
659         fuse_lck_mtx_unlock(ftick->tk_data->aw_mtx);
660 }
661
662 /*
663  * Insert a new upgoing ticket into the message queue
664  *
665  * If urgent is true, insert at the front of the queue.  Otherwise, insert in
666  * FIFO order.
667  */
668 void
669 fuse_insert_message(struct fuse_ticket *ftick, bool urgent)
670 {
671         if (ftick->tk_flag & FT_DIRTY) {
672                 panic("FUSE: ticket reused without being refreshed");
673         }
674         ftick->tk_flag |= FT_DIRTY;
675
676         if (fdata_get_dead(ftick->tk_data)) {
677                 return;
678         }
679         fuse_lck_mtx_lock(ftick->tk_data->ms_mtx);
680         if (urgent)
681                 fuse_ms_push_head(ftick);
682         else
683                 fuse_ms_push(ftick);
684         wakeup_one(ftick->tk_data);
685         selwakeuppri(&ftick->tk_data->ks_rsel, PZERO + 1);
686         fuse_lck_mtx_unlock(ftick->tk_data->ms_mtx);
687 }
688
689 static int
690 fuse_body_audit(struct fuse_ticket *ftick, size_t blen)
691 {
692         int err = 0;
693         enum fuse_opcode opcode;
694
695         opcode = fticket_opcode(ftick);
696
697         switch (opcode) {
698         case FUSE_LOOKUP:
699                 err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
700                 break;
701
702         case FUSE_FORGET:
703                 panic("FUSE: a handler has been intalled for FUSE_FORGET");
704                 break;
705
706         case FUSE_GETATTR:
707                 err = (blen == sizeof(struct fuse_attr_out)) ? 0 : EINVAL;
708                 break;
709
710         case FUSE_SETATTR:
711                 err = (blen == sizeof(struct fuse_attr_out)) ? 0 : EINVAL;
712                 break;
713
714         case FUSE_READLINK:
715                 err = (PAGE_SIZE >= blen) ? 0 : EINVAL;
716                 break;
717
718         case FUSE_SYMLINK:
719                 err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
720                 break;
721
722         case FUSE_MKNOD:
723                 err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
724                 break;
725
726         case FUSE_MKDIR:
727                 err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
728                 break;
729
730         case FUSE_UNLINK:
731                 err = (blen == 0) ? 0 : EINVAL;
732                 break;
733
734         case FUSE_RMDIR:
735                 err = (blen == 0) ? 0 : EINVAL;
736                 break;
737
738         case FUSE_RENAME:
739                 err = (blen == 0) ? 0 : EINVAL;
740                 break;
741
742         case FUSE_LINK:
743                 err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
744                 break;
745
746         case FUSE_OPEN:
747                 err = (blen == sizeof(struct fuse_open_out)) ? 0 : EINVAL;
748                 break;
749
750         case FUSE_READ:
751                 err = (((struct fuse_read_in *)(
752                     (char *)ftick->tk_ms_fiov.base +
753                     sizeof(struct fuse_in_header)
754                     ))->size >= blen) ? 0 : EINVAL;
755                 break;
756
757         case FUSE_WRITE:
758                 err = (blen == sizeof(struct fuse_write_out)) ? 0 : EINVAL;
759                 break;
760
761         case FUSE_STATFS:
762                 if (fuse_libabi_geq(ftick->tk_data, 7, 4)) {
763                         err = (blen == sizeof(struct fuse_statfs_out)) ? 
764                           0 : EINVAL;
765                 } else {
766                         err = (blen == FUSE_COMPAT_STATFS_SIZE) ? 0 : EINVAL;
767                 }
768                 break;
769
770         case FUSE_RELEASE:
771                 err = (blen == 0) ? 0 : EINVAL;
772                 break;
773
774         case FUSE_FSYNC:
775                 err = (blen == 0) ? 0 : EINVAL;
776                 break;
777
778         case FUSE_SETXATTR:
779                 err = (blen == 0) ? 0 : EINVAL;
780                 break;
781
782         case FUSE_GETXATTR:
783         case FUSE_LISTXATTR:
784                 /*
785                  * These can have varying response lengths, and 0 length
786                  * isn't necessarily invalid.
787                  */
788                 err = 0;
789                 break;
790
791         case FUSE_REMOVEXATTR:
792                 err = (blen == 0) ? 0 : EINVAL;
793                 break;
794
795         case FUSE_FLUSH:
796                 err = (blen == 0) ? 0 : EINVAL;
797                 break;
798
799         case FUSE_INIT:
800                 if (blen == sizeof(struct fuse_init_out) || blen == 8) {
801                         err = 0;
802                 } else {
803                         err = EINVAL;
804                 }
805                 break;
806
807         case FUSE_OPENDIR:
808                 err = (blen == sizeof(struct fuse_open_out)) ? 0 : EINVAL;
809                 break;
810
811         case FUSE_READDIR:
812                 err = (((struct fuse_read_in *)(
813                     (char *)ftick->tk_ms_fiov.base +
814                     sizeof(struct fuse_in_header)
815                     ))->size >= blen) ? 0 : EINVAL;
816                 break;
817
818         case FUSE_RELEASEDIR:
819                 err = (blen == 0) ? 0 : EINVAL;
820                 break;
821
822         case FUSE_FSYNCDIR:
823                 err = (blen == 0) ? 0 : EINVAL;
824                 break;
825
826         case FUSE_GETLK:
827                 err = (blen == sizeof(struct fuse_lk_out)) ? 0 : EINVAL;
828                 break;
829
830         case FUSE_SETLK:
831                 err = (blen == 0) ? 0 : EINVAL;
832                 break;
833
834         case FUSE_SETLKW:
835                 err = (blen == 0) ? 0 : EINVAL;
836                 break;
837
838         case FUSE_ACCESS:
839                 err = (blen == 0) ? 0 : EINVAL;
840                 break;
841
842         case FUSE_CREATE:
843                 err = (blen == sizeof(struct fuse_entry_out) +
844                     sizeof(struct fuse_open_out)) ? 0 : EINVAL;
845                 break;
846
847         case FUSE_DESTROY:
848                 err = (blen == 0) ? 0 : EINVAL;
849                 break;
850
851         default:
852                 panic("FUSE: opcodes out of sync (%d)\n", opcode);
853         }
854
855         return err;
856 }
857
858 static inline void
859 fuse_setup_ihead(struct fuse_in_header *ihead, struct fuse_ticket *ftick,
860     uint64_t nid, enum fuse_opcode op, size_t blen, pid_t pid,
861     struct ucred *cred)
862 {
863         ihead->len = sizeof(*ihead) + blen;
864         ihead->unique = ftick->tk_unique;
865         ihead->nodeid = nid;
866         ihead->opcode = op;
867
868         ihead->pid = pid;
869         ihead->uid = cred->cr_uid;
870         ihead->gid = cred->cr_rgid;
871 }
872
873 /*
874  * fuse_standard_handler just pulls indata and wakes up pretender.
875  * Doesn't try to interpret data, that's left for the pretender.
876  * Though might do a basic size verification before the pull-in takes place
877  */
878
879 static int
880 fuse_standard_handler(struct fuse_ticket *ftick, struct uio *uio)
881 {
882         int err = 0;
883
884         err = fticket_pull(ftick, uio);
885
886         fuse_lck_mtx_lock(ftick->tk_aw_mtx);
887
888         if (!fticket_answered(ftick)) {
889                 fticket_set_answered(ftick);
890                 ftick->tk_aw_errno = err;
891                 wakeup(ftick);
892         }
893         fuse_lck_mtx_unlock(ftick->tk_aw_mtx);
894
895         return err;
896 }
897
898 /*
899  * Reinitialize a dispatcher from a pid and node id, without resizing or
900  * clearing its data buffers
901  */
902 static void
903 fdisp_refresh_pid(struct fuse_dispatcher *fdip, enum fuse_opcode op,
904     struct mount *mp, uint64_t nid, pid_t pid, struct ucred *cred)
905 {
906         MPASS(fdip->tick);
907         MPASS2(sizeof(fdip->finh) + fdip->iosize <= fdip->tick->tk_ms_fiov.len,
908                 "Must use fdisp_make_pid to increase the size of the fiov");
909         fticket_reset(fdip->tick);
910
911         FUSE_DIMALLOC(&fdip->tick->tk_ms_fiov, fdip->finh,
912             fdip->indata, fdip->iosize);
913
914         fuse_setup_ihead(fdip->finh, fdip->tick, nid, op, fdip->iosize, pid,
915                 cred);
916 }
917
918 /* Initialize a dispatcher from a pid and node id */
919 static void
920 fdisp_make_pid(struct fuse_dispatcher *fdip, enum fuse_opcode op,
921     struct fuse_data *data, uint64_t nid, pid_t pid, struct ucred *cred)
922 {
923         if (fdip->tick) {
924                 fticket_refresh(fdip->tick);
925         } else {
926                 fdip->tick = fuse_ticket_fetch(data);
927         }
928
929         /* FUSE_DIMALLOC will bzero the fiovs when it enlarges them */
930         FUSE_DIMALLOC(&fdip->tick->tk_ms_fiov, fdip->finh,
931             fdip->indata, fdip->iosize);
932
933         fuse_setup_ihead(fdip->finh, fdip->tick, nid, op, fdip->iosize, pid, cred);
934 }
935
936 void
937 fdisp_make(struct fuse_dispatcher *fdip, enum fuse_opcode op, struct mount *mp,
938     uint64_t nid, struct thread *td, struct ucred *cred)
939 {
940         struct fuse_data *data = fuse_get_mpdata(mp);
941         RECTIFY_TDCR(td, cred);
942
943         return fdisp_make_pid(fdip, op, data, nid, td->td_proc->p_pid, cred);
944 }
945
946 void
947 fdisp_make_vp(struct fuse_dispatcher *fdip, enum fuse_opcode op,
948     struct vnode *vp, struct thread *td, struct ucred *cred)
949 {
950         struct mount *mp = vnode_mount(vp);
951         struct fuse_data *data = fuse_get_mpdata(mp);
952
953         RECTIFY_TDCR(td, cred);
954         return fdisp_make_pid(fdip, op, data, VTOI(vp),
955             td->td_proc->p_pid, cred);
956 }
957
958 /* Refresh a fuse_dispatcher so it can be reused, but don't zero its data */
959 void
960 fdisp_refresh_vp(struct fuse_dispatcher *fdip, enum fuse_opcode op,
961     struct vnode *vp, struct thread *td, struct ucred *cred)
962 {
963         RECTIFY_TDCR(td, cred);
964         return fdisp_refresh_pid(fdip, op, vnode_mount(vp), VTOI(vp),
965             td->td_proc->p_pid, cred);
966 }
967
968 void
969 fdisp_refresh(struct fuse_dispatcher *fdip)
970 {
971         fticket_refresh(fdip->tick);
972 }
973
974 SDT_PROBE_DEFINE2(fusefs, , ipc, fdisp_wait_answ_error, "char*", "int");
975
976 int
977 fdisp_wait_answ(struct fuse_dispatcher *fdip)
978 {
979         int err = 0;
980
981         fdip->answ_stat = 0;
982         fuse_insert_callback(fdip->tick, fuse_standard_handler);
983         fuse_insert_message(fdip->tick, false);
984
985         if ((err = fticket_wait_answer(fdip->tick))) {
986                 fuse_lck_mtx_lock(fdip->tick->tk_aw_mtx);
987
988                 if (fticket_answered(fdip->tick)) {
989                         /*
990                          * Just between noticing the interrupt and getting here,
991                          * the standard handler has completed his job.
992                          * So we drop the ticket and exit as usual.
993                          */
994                         SDT_PROBE2(fusefs, , ipc, fdisp_wait_answ_error,
995                                 "IPC: interrupted, already answered", err);
996                         fuse_lck_mtx_unlock(fdip->tick->tk_aw_mtx);
997                         goto out;
998                 } else {
999                         /*
1000                          * So we were faster than the standard handler.
1001                          * Then by setting the answered flag we get *him*
1002                          * to drop the ticket.
1003                          */
1004                         SDT_PROBE2(fusefs, , ipc, fdisp_wait_answ_error,
1005                                 "IPC: interrupted, setting to answered", err);
1006                         fticket_set_answered(fdip->tick);
1007                         fuse_lck_mtx_unlock(fdip->tick->tk_aw_mtx);
1008                         return err;
1009                 }
1010         }
1011
1012         if (fdip->tick->tk_aw_errno) {
1013                 SDT_PROBE2(fusefs, , ipc, fdisp_wait_answ_error,
1014                         "IPC: explicit EIO-ing", fdip->tick->tk_aw_errno);
1015                 err = EIO;
1016                 goto out;
1017         }
1018         if ((err = fdip->tick->tk_aw_ohead.error)) {
1019                 SDT_PROBE2(fusefs, , ipc, fdisp_wait_answ_error,
1020                         "IPC: setting status", fdip->tick->tk_aw_ohead.error);
1021                 /*
1022                  * This means a "proper" fuse syscall error.
1023                  * We record this value so the caller will
1024                  * be able to know it's not a boring messaging
1025                  * failure, if she wishes so (and if not, she can
1026                  * just simply propagate the return value of this routine).
1027                  * [XXX Maybe a bitflag would do the job too,
1028                  * if other flags needed, this will be converted thusly.]
1029                  */
1030                 fdip->answ_stat = err;
1031                 goto out;
1032         }
1033         fdip->answ = fticket_resp(fdip->tick)->base;
1034         fdip->iosize = fticket_resp(fdip->tick)->len;
1035
1036         return 0;
1037
1038 out:
1039         return err;
1040 }
1041
1042 void
1043 fuse_ipc_init(void)
1044 {
1045         ticket_zone = uma_zcreate("fuse_ticket", sizeof(struct fuse_ticket),
1046             fticket_ctor, fticket_dtor, fticket_init, fticket_fini,
1047             UMA_ALIGN_PTR, 0);
1048 }
1049
1050 void
1051 fuse_ipc_destroy(void)
1052 {
1053         uma_zdestroy(ticket_zone);
1054 }