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