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