1241519Sattilio/* 2241519Sattilio * Copyright (c) 2007-2009 Google Inc. and Amit Singh 3241519Sattilio * All rights reserved. 4241519Sattilio * 5241519Sattilio * Redistribution and use in source and binary forms, with or without 6241519Sattilio * modification, are permitted provided that the following conditions are 7241519Sattilio * met: 8241519Sattilio * 9241519Sattilio * * Redistributions of source code must retain the above copyright 10241519Sattilio * notice, this list of conditions and the following disclaimer. 11241519Sattilio * * Redistributions in binary form must reproduce the above 12241519Sattilio * copyright notice, this list of conditions and the following disclaimer 13241519Sattilio * in the documentation and/or other materials provided with the 14241519Sattilio * distribution. 15241519Sattilio * * Neither the name of Google Inc. nor the names of its 16241519Sattilio * contributors may be used to endorse or promote products derived from 17241519Sattilio * this software without specific prior written permission. 18241519Sattilio * 19241519Sattilio * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20241519Sattilio * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21241519Sattilio * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22241519Sattilio * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23241519Sattilio * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24241519Sattilio * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25241519Sattilio * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26241519Sattilio * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27241519Sattilio * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28241519Sattilio * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29241519Sattilio * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30241519Sattilio * 31241519Sattilio * Copyright (C) 2005 Csaba Henk. 32241519Sattilio * All rights reserved. 33241519Sattilio * 34241519Sattilio * Redistribution and use in source and binary forms, with or without 35241519Sattilio * modification, are permitted provided that the following conditions 36241519Sattilio * are met: 37241519Sattilio * 1. Redistributions of source code must retain the above copyright 38241519Sattilio * notice, this list of conditions and the following disclaimer. 39241519Sattilio * 2. Redistributions in binary form must reproduce the above copyright 40241519Sattilio * notice, this list of conditions and the following disclaimer in the 41241519Sattilio * documentation and/or other materials provided with the distribution. 42241519Sattilio * 43241519Sattilio * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 44241519Sattilio * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 45241519Sattilio * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 46241519Sattilio * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 47241519Sattilio * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 48241519Sattilio * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 49241519Sattilio * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 50241519Sattilio * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 51241519Sattilio * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 52241519Sattilio * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 53241519Sattilio * SUCH DAMAGE. 54241519Sattilio */ 55241519Sattilio 56241519Sattilio#include <sys/cdefs.h> 57241519Sattilio__FBSDID("$FreeBSD: stable/10/sys/fs/fuse/fuse_ipc.c 325164 2017-10-30 20:31:48Z pfg $"); 58241519Sattilio 59241519Sattilio#include <sys/types.h> 60241519Sattilio#include <sys/module.h> 61241519Sattilio#include <sys/systm.h> 62241519Sattilio#include <sys/errno.h> 63241519Sattilio#include <sys/param.h> 64241519Sattilio#include <sys/kernel.h> 65241519Sattilio#include <sys/conf.h> 66241519Sattilio#include <sys/uio.h> 67241519Sattilio#include <sys/malloc.h> 68241519Sattilio#include <sys/queue.h> 69241519Sattilio#include <sys/lock.h> 70241519Sattilio#include <sys/sx.h> 71241519Sattilio#include <sys/mutex.h> 72241519Sattilio#include <sys/proc.h> 73241519Sattilio#include <sys/mount.h> 74241519Sattilio#include <sys/vnode.h> 75241519Sattilio#include <sys/signalvar.h> 76241519Sattilio#include <sys/syscallsubr.h> 77241519Sattilio#include <sys/sysctl.h> 78241519Sattilio#include <vm/uma.h> 79241519Sattilio 80241519Sattilio#include "fuse.h" 81241519Sattilio#include "fuse_node.h" 82241519Sattilio#include "fuse_ipc.h" 83241519Sattilio#include "fuse_internal.h" 84241519Sattilio 85241519Sattilio#define FUSE_DEBUG_MODULE IPC 86241519Sattilio#include "fuse_debug.h" 87241519Sattilio 88241519Sattiliostatic struct fuse_ticket *fticket_alloc(struct fuse_data *data); 89241519Sattiliostatic void fticket_refresh(struct fuse_ticket *ftick); 90241519Sattiliostatic void fticket_destroy(struct fuse_ticket *ftick); 91241519Sattiliostatic int fticket_wait_answer(struct fuse_ticket *ftick); 92241519Sattiliostatic __inline__ int 93241519Sattiliofticket_aw_pull_uio(struct fuse_ticket *ftick, 94241519Sattilio struct uio *uio); 95241519Sattilio 96241519Sattiliostatic int fuse_body_audit(struct fuse_ticket *ftick, size_t blen); 97241519Sattiliostatic __inline__ void 98241519Sattiliofuse_setup_ihead(struct fuse_in_header *ihead, 99241519Sattilio struct fuse_ticket *ftick, 100241519Sattilio uint64_t nid, 101241519Sattilio enum fuse_opcode op, 102241519Sattilio size_t blen, 103241519Sattilio pid_t pid, 104241519Sattilio struct ucred *cred); 105241519Sattilio 106241519Sattiliostatic fuse_handler_t fuse_standard_handler; 107241519Sattilio 108241519SattilioSYSCTL_NODE(_vfs, OID_AUTO, fuse, CTLFLAG_RW, 0, "FUSE tunables"); 109241519SattilioSYSCTL_STRING(_vfs_fuse, OID_AUTO, version, CTLFLAG_RD, 110241519Sattilio FUSE_FREEBSD_VERSION, 0, "fuse-freebsd version"); 111241519Sattiliostatic int fuse_ticket_count = 0; 112241519Sattilio 113241519SattilioSYSCTL_INT(_vfs_fuse, OID_AUTO, ticket_count, CTLFLAG_RW, 114241519Sattilio &fuse_ticket_count, 0, "number of allocated tickets"); 115241519Sattiliostatic long fuse_iov_permanent_bufsize = 1 << 19; 116241519Sattilio 117241519SattilioSYSCTL_LONG(_vfs_fuse, OID_AUTO, iov_permanent_bufsize, CTLFLAG_RW, 118241519Sattilio &fuse_iov_permanent_bufsize, 0, 119241519Sattilio "limit for permanently stored buffer size for fuse_iovs"); 120241519Sattiliostatic int fuse_iov_credit = 16; 121241519Sattilio 122241519SattilioSYSCTL_INT(_vfs_fuse, OID_AUTO, iov_credit, CTLFLAG_RW, 123241519Sattilio &fuse_iov_credit, 0, 124241519Sattilio "how many times is an oversized fuse_iov tolerated"); 125241519Sattilio 126241519SattilioMALLOC_DEFINE(M_FUSEMSG, "fuse_msgbuf", "fuse message buffer"); 127241519Sattiliostatic uma_zone_t ticket_zone; 128241519Sattilio 129241519Sattiliostatic void 130241519Sattiliofuse_block_sigs(sigset_t *oldset) 131241519Sattilio{ 132241519Sattilio sigset_t newset; 133241519Sattilio 134241519Sattilio SIGFILLSET(newset); 135241519Sattilio SIGDELSET(newset, SIGKILL); 136241519Sattilio if (kern_sigprocmask(curthread, SIG_BLOCK, &newset, oldset, 0)) 137241519Sattilio panic("%s: Invalid operation for kern_sigprocmask()", 138241519Sattilio __func__); 139241519Sattilio} 140241519Sattilio 141241519Sattiliostatic void 142241519Sattiliofuse_restore_sigs(sigset_t *oldset) 143241519Sattilio{ 144241519Sattilio 145241519Sattilio if (kern_sigprocmask(curthread, SIG_SETMASK, oldset, NULL, 0)) 146241519Sattilio panic("%s: Invalid operation for kern_sigprocmask()", 147241519Sattilio __func__); 148241519Sattilio} 149241519Sattilio 150241519Sattiliovoid 151241519Sattiliofiov_init(struct fuse_iov *fiov, size_t size) 152241519Sattilio{ 153241519Sattilio uint32_t msize = FU_AT_LEAST(size); 154241519Sattilio 155241519Sattilio debug_printf("fiov=%p, size=%zd\n", fiov, size); 156241519Sattilio 157241519Sattilio fiov->len = 0; 158241519Sattilio 159241519Sattilio fiov->base = malloc(msize, M_FUSEMSG, M_WAITOK | M_ZERO); 160241519Sattilio 161241519Sattilio fiov->allocated_size = msize; 162241519Sattilio fiov->credit = fuse_iov_credit; 163241519Sattilio} 164241519Sattilio 165241519Sattiliovoid 166241519Sattiliofiov_teardown(struct fuse_iov *fiov) 167241519Sattilio{ 168241519Sattilio debug_printf("fiov=%p\n", fiov); 169241519Sattilio 170241519Sattilio MPASS(fiov->base != NULL); 171241519Sattilio free(fiov->base, M_FUSEMSG); 172241519Sattilio} 173241519Sattilio 174241519Sattiliovoid 175241519Sattiliofiov_adjust(struct fuse_iov *fiov, size_t size) 176241519Sattilio{ 177241519Sattilio debug_printf("fiov=%p, size=%zd\n", fiov, size); 178241519Sattilio 179241519Sattilio if (fiov->allocated_size < size || 180241519Sattilio (fuse_iov_permanent_bufsize >= 0 && 181241519Sattilio fiov->allocated_size - size > fuse_iov_permanent_bufsize && 182241519Sattilio --fiov->credit < 0)) { 183241519Sattilio 184241519Sattilio fiov->base = realloc(fiov->base, FU_AT_LEAST(size), M_FUSEMSG, 185241519Sattilio M_WAITOK | M_ZERO); 186241519Sattilio if (!fiov->base) { 187241519Sattilio panic("FUSE: realloc failed"); 188241519Sattilio } 189241519Sattilio fiov->allocated_size = FU_AT_LEAST(size); 190241519Sattilio fiov->credit = fuse_iov_credit; 191241519Sattilio } 192241519Sattilio fiov->len = size; 193241519Sattilio} 194241519Sattilio 195241519Sattiliovoid 196241519Sattiliofiov_refresh(struct fuse_iov *fiov) 197241519Sattilio{ 198241519Sattilio debug_printf("fiov=%p\n", fiov); 199241519Sattilio 200241519Sattilio bzero(fiov->base, fiov->len); 201241519Sattilio fiov_adjust(fiov, 0); 202241519Sattilio} 203241519Sattilio 204241519Sattiliostatic int 205241519Sattiliofticket_ctor(void *mem, int size, void *arg, int flags) 206241519Sattilio{ 207241519Sattilio struct fuse_ticket *ftick = mem; 208241519Sattilio struct fuse_data *data = arg; 209241519Sattilio 210241519Sattilio debug_printf("ftick=%p data=%p\n", ftick, data); 211241519Sattilio 212241519Sattilio FUSE_ASSERT_MS_DONE(ftick); 213241519Sattilio FUSE_ASSERT_AW_DONE(ftick); 214241519Sattilio 215241519Sattilio ftick->tk_data = data; 216241519Sattilio 217241519Sattilio if (ftick->tk_unique != 0) 218241519Sattilio fticket_refresh(ftick); 219241519Sattilio 220241519Sattilio /* May be truncated to 32 bits */ 221241519Sattilio ftick->tk_unique = atomic_fetchadd_long(&data->ticketer, 1); 222241519Sattilio if (ftick->tk_unique == 0) 223241519Sattilio ftick->tk_unique = atomic_fetchadd_long(&data->ticketer, 1); 224241519Sattilio 225241519Sattilio refcount_init(&ftick->tk_refcount, 1); 226241519Sattilio atomic_add_acq_int(&fuse_ticket_count, 1); 227241519Sattilio 228241519Sattilio return 0; 229241519Sattilio} 230241519Sattilio 231241519Sattiliostatic void 232241519Sattiliofticket_dtor(void *mem, int size, void *arg) 233241519Sattilio{ 234241519Sattilio struct fuse_ticket *ftick = mem; 235241519Sattilio 236241519Sattilio debug_printf("ftick=%p\n", ftick); 237241519Sattilio 238241519Sattilio FUSE_ASSERT_MS_DONE(ftick); 239241519Sattilio FUSE_ASSERT_AW_DONE(ftick); 240241519Sattilio 241241519Sattilio atomic_subtract_acq_int(&fuse_ticket_count, 1); 242241519Sattilio} 243241519Sattilio 244241519Sattiliostatic int 245241519Sattiliofticket_init(void *mem, int size, int flags) 246241519Sattilio{ 247241519Sattilio struct fuse_ticket *ftick = mem; 248241519Sattilio 249241521Sattilio FS_DEBUG("ftick=%p\n", ftick); 250241519Sattilio 251241519Sattilio bzero(ftick, sizeof(struct fuse_ticket)); 252241519Sattilio 253241519Sattilio fiov_init(&ftick->tk_ms_fiov, sizeof(struct fuse_in_header)); 254241519Sattilio ftick->tk_ms_type = FT_M_FIOV; 255241519Sattilio 256241519Sattilio mtx_init(&ftick->tk_aw_mtx, "fuse answer delivery mutex", NULL, MTX_DEF); 257241519Sattilio fiov_init(&ftick->tk_aw_fiov, 0); 258241519Sattilio ftick->tk_aw_type = FT_A_FIOV; 259241519Sattilio 260241519Sattilio return 0; 261241519Sattilio} 262241519Sattilio 263241519Sattiliostatic void 264241519Sattiliofticket_fini(void *mem, int size) 265241519Sattilio{ 266241519Sattilio struct fuse_ticket *ftick = mem; 267241519Sattilio 268241521Sattilio FS_DEBUG("ftick=%p\n", ftick); 269241519Sattilio 270241519Sattilio fiov_teardown(&ftick->tk_ms_fiov); 271241519Sattilio fiov_teardown(&ftick->tk_aw_fiov); 272241519Sattilio mtx_destroy(&ftick->tk_aw_mtx); 273241519Sattilio} 274241519Sattilio 275241519Sattiliostatic __inline struct fuse_ticket * 276241519Sattiliofticket_alloc(struct fuse_data *data) 277241519Sattilio{ 278241519Sattilio return uma_zalloc_arg(ticket_zone, data, M_WAITOK); 279241519Sattilio} 280241519Sattilio 281241519Sattiliostatic __inline void 282241519Sattiliofticket_destroy(struct fuse_ticket *ftick) 283241519Sattilio{ 284241519Sattilio return uma_zfree(ticket_zone, ftick); 285241519Sattilio} 286241519Sattilio 287241519Sattiliostatic __inline__ 288241519Sattiliovoid 289241519Sattiliofticket_refresh(struct fuse_ticket *ftick) 290241519Sattilio{ 291241519Sattilio debug_printf("ftick=%p\n", ftick); 292241519Sattilio 293241519Sattilio FUSE_ASSERT_MS_DONE(ftick); 294241519Sattilio FUSE_ASSERT_AW_DONE(ftick); 295241519Sattilio 296241519Sattilio fiov_refresh(&ftick->tk_ms_fiov); 297241519Sattilio ftick->tk_ms_bufdata = NULL; 298241519Sattilio ftick->tk_ms_bufsize = 0; 299241519Sattilio ftick->tk_ms_type = FT_M_FIOV; 300241519Sattilio 301241519Sattilio bzero(&ftick->tk_aw_ohead, sizeof(struct fuse_out_header)); 302241519Sattilio 303241519Sattilio fiov_refresh(&ftick->tk_aw_fiov); 304241519Sattilio ftick->tk_aw_errno = 0; 305241519Sattilio ftick->tk_aw_bufdata = NULL; 306241519Sattilio ftick->tk_aw_bufsize = 0; 307241519Sattilio ftick->tk_aw_type = FT_A_FIOV; 308241519Sattilio 309241519Sattilio ftick->tk_flag = 0; 310241519Sattilio} 311241519Sattilio 312241519Sattiliostatic int 313241519Sattiliofticket_wait_answer(struct fuse_ticket *ftick) 314241519Sattilio{ 315241519Sattilio sigset_t tset; 316241519Sattilio int err = 0; 317241519Sattilio struct fuse_data *data; 318241519Sattilio 319241519Sattilio debug_printf("ftick=%p\n", ftick); 320241519Sattilio fuse_lck_mtx_lock(ftick->tk_aw_mtx); 321241519Sattilio 322241519Sattilio if (fticket_answered(ftick)) { 323241519Sattilio goto out; 324241519Sattilio } 325241519Sattilio data = ftick->tk_data; 326241519Sattilio 327241519Sattilio if (fdata_get_dead(data)) { 328241519Sattilio err = ENOTCONN; 329241519Sattilio fticket_set_answered(ftick); 330241519Sattilio goto out; 331241519Sattilio } 332241519Sattilio fuse_block_sigs(&tset); 333241519Sattilio err = msleep(ftick, &ftick->tk_aw_mtx, PCATCH, "fu_ans", 334241519Sattilio data->daemon_timeout * hz); 335241519Sattilio fuse_restore_sigs(&tset); 336241519Sattilio if (err == EAGAIN) { /* same as EWOULDBLOCK */ 337241519Sattilio#ifdef XXXIP /* die conditionally */ 338241519Sattilio if (!fdata_get_dead(data)) { 339241519Sattilio fdata_set_dead(data); 340241519Sattilio } 341241519Sattilio#endif 342241519Sattilio err = ETIMEDOUT; 343241519Sattilio fticket_set_answered(ftick); 344241519Sattilio } 345241519Sattilioout: 346241519Sattilio if (!(err || fticket_answered(ftick))) { 347241519Sattilio debug_printf("FUSE: requester was woken up but still no answer"); 348241519Sattilio err = ENXIO; 349241519Sattilio } 350241519Sattilio fuse_lck_mtx_unlock(ftick->tk_aw_mtx); 351241519Sattilio 352241519Sattilio return err; 353241519Sattilio} 354241519Sattilio 355241519Sattiliostatic __inline__ 356241519Sattilioint 357241519Sattiliofticket_aw_pull_uio(struct fuse_ticket *ftick, struct uio *uio) 358241519Sattilio{ 359241519Sattilio int err = 0; 360241519Sattilio size_t len = uio_resid(uio); 361241519Sattilio 362241519Sattilio debug_printf("ftick=%p, uio=%p\n", ftick, uio); 363241519Sattilio 364241519Sattilio if (len) { 365241519Sattilio switch (ftick->tk_aw_type) { 366241519Sattilio case FT_A_FIOV: 367241519Sattilio fiov_adjust(fticket_resp(ftick), len); 368241519Sattilio err = uiomove(fticket_resp(ftick)->base, len, uio); 369241519Sattilio if (err) { 370241519Sattilio debug_printf("FUSE: FT_A_FIOV: error is %d" 371241519Sattilio " (%p, %zd, %p)\n", 372241519Sattilio err, fticket_resp(ftick)->base, 373241519Sattilio len, uio); 374241519Sattilio } 375241519Sattilio break; 376241519Sattilio 377241519Sattilio case FT_A_BUF: 378241519Sattilio ftick->tk_aw_bufsize = len; 379241519Sattilio err = uiomove(ftick->tk_aw_bufdata, len, uio); 380241519Sattilio if (err) { 381241519Sattilio debug_printf("FUSE: FT_A_BUF: error is %d" 382241519Sattilio " (%p, %zd, %p)\n", 383241519Sattilio err, ftick->tk_aw_bufdata, len, uio); 384241519Sattilio } 385241519Sattilio break; 386241519Sattilio 387241519Sattilio default: 388241519Sattilio panic("FUSE: unknown answer type for ticket %p", ftick); 389241519Sattilio } 390241519Sattilio } 391241519Sattilio return err; 392241519Sattilio} 393241519Sattilio 394241519Sattilioint 395241519Sattiliofticket_pull(struct fuse_ticket *ftick, struct uio *uio) 396241519Sattilio{ 397241519Sattilio int err = 0; 398241519Sattilio 399241519Sattilio debug_printf("ftick=%p, uio=%p\n", ftick, uio); 400241519Sattilio 401241519Sattilio if (ftick->tk_aw_ohead.error) { 402241519Sattilio return 0; 403241519Sattilio } 404241519Sattilio err = fuse_body_audit(ftick, uio_resid(uio)); 405241519Sattilio if (!err) { 406241519Sattilio err = fticket_aw_pull_uio(ftick, uio); 407241519Sattilio } 408241519Sattilio return err; 409241519Sattilio} 410241519Sattilio 411241519Sattiliostruct fuse_data * 412241519Sattiliofdata_alloc(struct cdev *fdev, struct ucred *cred) 413241519Sattilio{ 414241519Sattilio struct fuse_data *data; 415241519Sattilio 416241519Sattilio debug_printf("fdev=%p\n", fdev); 417241519Sattilio 418241519Sattilio data = malloc(sizeof(struct fuse_data), M_FUSEMSG, M_WAITOK | M_ZERO); 419241519Sattilio 420241519Sattilio data->fdev = fdev; 421241519Sattilio mtx_init(&data->ms_mtx, "fuse message list mutex", NULL, MTX_DEF); 422241519Sattilio STAILQ_INIT(&data->ms_head); 423241519Sattilio mtx_init(&data->aw_mtx, "fuse answer list mutex", NULL, MTX_DEF); 424241519Sattilio TAILQ_INIT(&data->aw_head); 425241519Sattilio data->daemoncred = crhold(cred); 426241519Sattilio data->daemon_timeout = FUSE_DEFAULT_DAEMON_TIMEOUT; 427241519Sattilio sx_init(&data->rename_lock, "fuse rename lock"); 428241519Sattilio data->ref = 1; 429241519Sattilio 430241519Sattilio return data; 431241519Sattilio} 432241519Sattilio 433241519Sattiliovoid 434241519Sattiliofdata_trydestroy(struct fuse_data *data) 435241519Sattilio{ 436241521Sattilio FS_DEBUG("data=%p data.mp=%p data.fdev=%p data.flags=%04x\n", 437241519Sattilio data, data->mp, data->fdev, data->dataflags); 438241519Sattilio 439241521Sattilio FS_DEBUG("destroy: data=%p\n", data); 440241519Sattilio data->ref--; 441241519Sattilio MPASS(data->ref >= 0); 442241519Sattilio if (data->ref != 0) 443241519Sattilio return; 444241519Sattilio 445241519Sattilio /* Driving off stage all that stuff thrown at device... */ 446241519Sattilio mtx_destroy(&data->ms_mtx); 447241519Sattilio mtx_destroy(&data->aw_mtx); 448241519Sattilio sx_destroy(&data->rename_lock); 449241519Sattilio 450241519Sattilio crfree(data->daemoncred); 451241519Sattilio 452241519Sattilio free(data, M_FUSEMSG); 453241519Sattilio} 454241519Sattilio 455241519Sattiliovoid 456241519Sattiliofdata_set_dead(struct fuse_data *data) 457241519Sattilio{ 458241519Sattilio debug_printf("data=%p\n", data); 459241519Sattilio 460241519Sattilio FUSE_LOCK(); 461241519Sattilio if (fdata_get_dead(data)) { 462241519Sattilio FUSE_UNLOCK(); 463241519Sattilio return; 464241519Sattilio } 465241519Sattilio fuse_lck_mtx_lock(data->ms_mtx); 466241519Sattilio data->dataflags |= FSESS_DEAD; 467241519Sattilio wakeup_one(data); 468241519Sattilio selwakeuppri(&data->ks_rsel, PZERO + 1); 469241519Sattilio wakeup(&data->ticketer); 470241519Sattilio fuse_lck_mtx_unlock(data->ms_mtx); 471241519Sattilio FUSE_UNLOCK(); 472241519Sattilio} 473241519Sattilio 474241519Sattiliostruct fuse_ticket * 475241519Sattiliofuse_ticket_fetch(struct fuse_data *data) 476241519Sattilio{ 477241519Sattilio int err = 0; 478241519Sattilio struct fuse_ticket *ftick; 479241519Sattilio 480241519Sattilio debug_printf("data=%p\n", data); 481241519Sattilio 482241519Sattilio ftick = fticket_alloc(data); 483241519Sattilio 484241519Sattilio if (!(data->dataflags & FSESS_INITED)) { 485241519Sattilio /* Sleep until get answer for INIT messsage */ 486241519Sattilio FUSE_LOCK(); 487241519Sattilio if (!(data->dataflags & FSESS_INITED) && data->ticketer > 2) { 488241519Sattilio err = msleep(&data->ticketer, &fuse_mtx, PCATCH | PDROP, 489241519Sattilio "fu_ini", 0); 490241519Sattilio if (err) 491241519Sattilio fdata_set_dead(data); 492241519Sattilio } else 493241519Sattilio FUSE_UNLOCK(); 494241519Sattilio } 495241519Sattilio return ftick; 496241519Sattilio} 497241519Sattilio 498241519Sattilioint 499241519Sattiliofuse_ticket_drop(struct fuse_ticket *ftick) 500241519Sattilio{ 501241519Sattilio int die; 502241519Sattilio 503241519Sattilio die = refcount_release(&ftick->tk_refcount); 504241519Sattilio debug_printf("ftick=%p refcount=%d\n", ftick, ftick->tk_refcount); 505241519Sattilio if (die) 506241519Sattilio fticket_destroy(ftick); 507241519Sattilio 508241519Sattilio return die; 509241519Sattilio} 510241519Sattilio 511241519Sattiliovoid 512241519Sattiliofuse_insert_callback(struct fuse_ticket *ftick, fuse_handler_t * handler) 513241519Sattilio{ 514241519Sattilio debug_printf("ftick=%p, handler=%p data=%p\n", ftick, ftick->tk_data, 515241519Sattilio handler); 516241519Sattilio 517241519Sattilio if (fdata_get_dead(ftick->tk_data)) { 518241519Sattilio return; 519241519Sattilio } 520241519Sattilio ftick->tk_aw_handler = handler; 521241519Sattilio 522241519Sattilio fuse_lck_mtx_lock(ftick->tk_data->aw_mtx); 523241519Sattilio fuse_aw_push(ftick); 524241519Sattilio fuse_lck_mtx_unlock(ftick->tk_data->aw_mtx); 525241519Sattilio} 526241519Sattilio 527241519Sattiliovoid 528241519Sattiliofuse_insert_message(struct fuse_ticket *ftick) 529241519Sattilio{ 530241519Sattilio debug_printf("ftick=%p\n", ftick); 531241519Sattilio 532241519Sattilio if (ftick->tk_flag & FT_DIRTY) { 533241519Sattilio panic("FUSE: ticket reused without being refreshed"); 534241519Sattilio } 535241519Sattilio ftick->tk_flag |= FT_DIRTY; 536241519Sattilio 537241519Sattilio if (fdata_get_dead(ftick->tk_data)) { 538241519Sattilio return; 539241519Sattilio } 540241519Sattilio fuse_lck_mtx_lock(ftick->tk_data->ms_mtx); 541241519Sattilio fuse_ms_push(ftick); 542241519Sattilio wakeup_one(ftick->tk_data); 543241519Sattilio selwakeuppri(&ftick->tk_data->ks_rsel, PZERO + 1); 544241519Sattilio fuse_lck_mtx_unlock(ftick->tk_data->ms_mtx); 545241519Sattilio} 546241519Sattilio 547241519Sattiliostatic int 548241519Sattiliofuse_body_audit(struct fuse_ticket *ftick, size_t blen) 549241519Sattilio{ 550241519Sattilio int err = 0; 551241519Sattilio enum fuse_opcode opcode; 552241519Sattilio 553241519Sattilio debug_printf("ftick=%p, blen = %zu\n", ftick, blen); 554241519Sattilio 555241519Sattilio opcode = fticket_opcode(ftick); 556241519Sattilio 557241519Sattilio switch (opcode) { 558241519Sattilio case FUSE_LOOKUP: 559241519Sattilio err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL; 560241519Sattilio break; 561241519Sattilio 562241519Sattilio case FUSE_FORGET: 563241519Sattilio panic("FUSE: a handler has been intalled for FUSE_FORGET"); 564241519Sattilio break; 565241519Sattilio 566241519Sattilio case FUSE_GETATTR: 567241519Sattilio err = (blen == sizeof(struct fuse_attr_out)) ? 0 : EINVAL; 568241519Sattilio break; 569241519Sattilio 570241519Sattilio case FUSE_SETATTR: 571241519Sattilio err = (blen == sizeof(struct fuse_attr_out)) ? 0 : EINVAL; 572241519Sattilio break; 573241519Sattilio 574241519Sattilio case FUSE_READLINK: 575241519Sattilio err = (PAGE_SIZE >= blen) ? 0 : EINVAL; 576241519Sattilio break; 577241519Sattilio 578241519Sattilio case FUSE_SYMLINK: 579241519Sattilio err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL; 580241519Sattilio break; 581241519Sattilio 582241519Sattilio case FUSE_MKNOD: 583241519Sattilio err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL; 584241519Sattilio break; 585241519Sattilio 586241519Sattilio case FUSE_MKDIR: 587241519Sattilio err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL; 588241519Sattilio break; 589241519Sattilio 590241519Sattilio case FUSE_UNLINK: 591241519Sattilio err = (blen == 0) ? 0 : EINVAL; 592241519Sattilio break; 593241519Sattilio 594241519Sattilio case FUSE_RMDIR: 595241519Sattilio err = (blen == 0) ? 0 : EINVAL; 596241519Sattilio break; 597241519Sattilio 598241519Sattilio case FUSE_RENAME: 599241519Sattilio err = (blen == 0) ? 0 : EINVAL; 600241519Sattilio break; 601241519Sattilio 602241519Sattilio case FUSE_LINK: 603241519Sattilio err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL; 604241519Sattilio break; 605241519Sattilio 606241519Sattilio case FUSE_OPEN: 607241519Sattilio err = (blen == sizeof(struct fuse_open_out)) ? 0 : EINVAL; 608241519Sattilio break; 609241519Sattilio 610241519Sattilio case FUSE_READ: 611241519Sattilio err = (((struct fuse_read_in *)( 612241519Sattilio (char *)ftick->tk_ms_fiov.base + 613241519Sattilio sizeof(struct fuse_in_header) 614241519Sattilio ))->size >= blen) ? 0 : EINVAL; 615241519Sattilio break; 616241519Sattilio 617241519Sattilio case FUSE_WRITE: 618241519Sattilio err = (blen == sizeof(struct fuse_write_out)) ? 0 : EINVAL; 619241519Sattilio break; 620241519Sattilio 621241519Sattilio case FUSE_STATFS: 622241519Sattilio if (fuse_libabi_geq(ftick->tk_data, 7, 4)) { 623241519Sattilio err = (blen == sizeof(struct fuse_statfs_out)) ? 624241519Sattilio 0 : EINVAL; 625241519Sattilio } else { 626241519Sattilio err = (blen == FUSE_COMPAT_STATFS_SIZE) ? 0 : EINVAL; 627241519Sattilio } 628241519Sattilio break; 629241519Sattilio 630241519Sattilio case FUSE_RELEASE: 631241519Sattilio err = (blen == 0) ? 0 : EINVAL; 632241519Sattilio break; 633241519Sattilio 634241519Sattilio case FUSE_FSYNC: 635241519Sattilio err = (blen == 0) ? 0 : EINVAL; 636241519Sattilio break; 637241519Sattilio 638241519Sattilio case FUSE_SETXATTR: 639325164Spfg err = (blen == 0) ? 0 : EINVAL; 640241519Sattilio break; 641241519Sattilio 642241519Sattilio case FUSE_GETXATTR: 643241519Sattilio case FUSE_LISTXATTR: 644325164Spfg /* 645325164Spfg * These can have varying response lengths, and 0 length 646325164Spfg * isn't necessarily invalid. 647325164Spfg */ 648325164Spfg err = 0; 649241519Sattilio break; 650241519Sattilio 651241519Sattilio case FUSE_REMOVEXATTR: 652325164Spfg err = (blen == 0) ? 0 : EINVAL; 653241519Sattilio break; 654241519Sattilio 655241519Sattilio case FUSE_FLUSH: 656241519Sattilio err = (blen == 0) ? 0 : EINVAL; 657241519Sattilio break; 658241519Sattilio 659241519Sattilio case FUSE_INIT: 660241519Sattilio if (blen == sizeof(struct fuse_init_out) || blen == 8) { 661241519Sattilio err = 0; 662241519Sattilio } else { 663241519Sattilio err = EINVAL; 664241519Sattilio } 665241519Sattilio break; 666241519Sattilio 667241519Sattilio case FUSE_OPENDIR: 668241519Sattilio err = (blen == sizeof(struct fuse_open_out)) ? 0 : EINVAL; 669241519Sattilio break; 670241519Sattilio 671241519Sattilio case FUSE_READDIR: 672241519Sattilio err = (((struct fuse_read_in *)( 673241519Sattilio (char *)ftick->tk_ms_fiov.base + 674241519Sattilio sizeof(struct fuse_in_header) 675241519Sattilio ))->size >= blen) ? 0 : EINVAL; 676241519Sattilio break; 677241519Sattilio 678241519Sattilio case FUSE_RELEASEDIR: 679241519Sattilio err = (blen == 0) ? 0 : EINVAL; 680241519Sattilio break; 681241519Sattilio 682241519Sattilio case FUSE_FSYNCDIR: 683241519Sattilio err = (blen == 0) ? 0 : EINVAL; 684241519Sattilio break; 685241519Sattilio 686241519Sattilio case FUSE_GETLK: 687241519Sattilio panic("FUSE: no response body format check for FUSE_GETLK"); 688241519Sattilio break; 689241519Sattilio 690241519Sattilio case FUSE_SETLK: 691241519Sattilio panic("FUSE: no response body format check for FUSE_SETLK"); 692241519Sattilio break; 693241519Sattilio 694241519Sattilio case FUSE_SETLKW: 695241519Sattilio panic("FUSE: no response body format check for FUSE_SETLKW"); 696241519Sattilio break; 697241519Sattilio 698241519Sattilio case FUSE_ACCESS: 699241519Sattilio err = (blen == 0) ? 0 : EINVAL; 700241519Sattilio break; 701241519Sattilio 702241519Sattilio case FUSE_CREATE: 703241519Sattilio err = (blen == sizeof(struct fuse_entry_out) + 704241519Sattilio sizeof(struct fuse_open_out)) ? 0 : EINVAL; 705241519Sattilio break; 706241519Sattilio 707241519Sattilio case FUSE_DESTROY: 708241519Sattilio err = (blen == 0) ? 0 : EINVAL; 709241519Sattilio break; 710241519Sattilio 711241519Sattilio default: 712241519Sattilio panic("FUSE: opcodes out of sync (%d)\n", opcode); 713241519Sattilio } 714241519Sattilio 715241519Sattilio return err; 716241519Sattilio} 717241519Sattilio 718241519Sattiliostatic void 719241519Sattiliofuse_setup_ihead(struct fuse_in_header *ihead, 720241519Sattilio struct fuse_ticket *ftick, 721241519Sattilio uint64_t nid, 722241519Sattilio enum fuse_opcode op, 723241519Sattilio size_t blen, 724241519Sattilio pid_t pid, 725241519Sattilio struct ucred *cred) 726241519Sattilio{ 727241519Sattilio ihead->len = sizeof(*ihead) + blen; 728241519Sattilio ihead->unique = ftick->tk_unique; 729241519Sattilio ihead->nodeid = nid; 730241519Sattilio ihead->opcode = op; 731241519Sattilio 732241519Sattilio debug_printf("ihead=%p, ftick=%p, nid=%ju, op=%d, blen=%zu\n", 733241519Sattilio ihead, ftick, (uintmax_t)nid, op, blen); 734241519Sattilio 735241519Sattilio ihead->pid = pid; 736241519Sattilio ihead->uid = cred->cr_uid; 737241519Sattilio ihead->gid = cred->cr_rgid; 738241519Sattilio} 739241519Sattilio 740241519Sattilio/* 741241519Sattilio * fuse_standard_handler just pulls indata and wakes up pretender. 742241519Sattilio * Doesn't try to interpret data, that's left for the pretender. 743241519Sattilio * Though might do a basic size verification before the pull-in takes place 744241519Sattilio */ 745241519Sattilio 746241519Sattiliostatic int 747241519Sattiliofuse_standard_handler(struct fuse_ticket *ftick, struct uio *uio) 748241519Sattilio{ 749241519Sattilio int err = 0; 750241519Sattilio 751241519Sattilio debug_printf("ftick=%p, uio=%p\n", ftick, uio); 752241519Sattilio 753241519Sattilio err = fticket_pull(ftick, uio); 754241519Sattilio 755241519Sattilio fuse_lck_mtx_lock(ftick->tk_aw_mtx); 756241519Sattilio 757241519Sattilio if (!fticket_answered(ftick)) { 758241519Sattilio fticket_set_answered(ftick); 759241519Sattilio ftick->tk_aw_errno = err; 760241519Sattilio wakeup(ftick); 761241519Sattilio } 762241519Sattilio fuse_lck_mtx_unlock(ftick->tk_aw_mtx); 763241519Sattilio 764241519Sattilio return err; 765241519Sattilio} 766241519Sattilio 767241519Sattiliovoid 768241519Sattiliofdisp_make_pid(struct fuse_dispatcher *fdip, 769241519Sattilio enum fuse_opcode op, 770241519Sattilio struct mount *mp, 771241519Sattilio uint64_t nid, 772241519Sattilio pid_t pid, 773241519Sattilio struct ucred *cred) 774241519Sattilio{ 775241519Sattilio struct fuse_data *data = fuse_get_mpdata(mp); 776241519Sattilio 777241519Sattilio debug_printf("fdip=%p, op=%d, mp=%p, nid=%ju\n", 778241519Sattilio fdip, op, mp, (uintmax_t)nid); 779241519Sattilio 780241519Sattilio if (fdip->tick) { 781241519Sattilio fticket_refresh(fdip->tick); 782241519Sattilio } else { 783241519Sattilio fdip->tick = fuse_ticket_fetch(data); 784241519Sattilio } 785241519Sattilio 786241519Sattilio FUSE_DIMALLOC(&fdip->tick->tk_ms_fiov, fdip->finh, 787241519Sattilio fdip->indata, fdip->iosize); 788241519Sattilio 789241519Sattilio fuse_setup_ihead(fdip->finh, fdip->tick, nid, op, fdip->iosize, pid, cred); 790241519Sattilio} 791241519Sattilio 792241519Sattiliovoid 793241519Sattiliofdisp_make(struct fuse_dispatcher *fdip, 794241519Sattilio enum fuse_opcode op, 795241519Sattilio struct mount *mp, 796241519Sattilio uint64_t nid, 797241519Sattilio struct thread *td, 798241519Sattilio struct ucred *cred) 799241519Sattilio{ 800241519Sattilio RECTIFY_TDCR(td, cred); 801241519Sattilio 802241519Sattilio return fdisp_make_pid(fdip, op, mp, nid, td->td_proc->p_pid, cred); 803241519Sattilio} 804241519Sattilio 805241519Sattiliovoid 806241519Sattiliofdisp_make_vp(struct fuse_dispatcher *fdip, 807241519Sattilio enum fuse_opcode op, 808241519Sattilio struct vnode *vp, 809241519Sattilio struct thread *td, 810241519Sattilio struct ucred *cred) 811241519Sattilio{ 812241519Sattilio debug_printf("fdip=%p, op=%d, vp=%p\n", fdip, op, vp); 813241519Sattilio RECTIFY_TDCR(td, cred); 814241519Sattilio return fdisp_make_pid(fdip, op, vnode_mount(vp), VTOI(vp), 815241519Sattilio td->td_proc->p_pid, cred); 816241519Sattilio} 817241519Sattilio 818241519Sattilioint 819241519Sattiliofdisp_wait_answ(struct fuse_dispatcher *fdip) 820241519Sattilio{ 821241519Sattilio int err = 0; 822241519Sattilio 823241519Sattilio fdip->answ_stat = 0; 824241519Sattilio fuse_insert_callback(fdip->tick, fuse_standard_handler); 825241519Sattilio fuse_insert_message(fdip->tick); 826241519Sattilio 827241519Sattilio if ((err = fticket_wait_answer(fdip->tick))) { 828241519Sattilio debug_printf("IPC: interrupted, err = %d\n", err); 829241519Sattilio 830241519Sattilio fuse_lck_mtx_lock(fdip->tick->tk_aw_mtx); 831241519Sattilio 832241519Sattilio if (fticket_answered(fdip->tick)) { 833241519Sattilio /* 834241519Sattilio * Just between noticing the interrupt and getting here, 835241519Sattilio * the standard handler has completed his job. 836241519Sattilio * So we drop the ticket and exit as usual. 837241519Sattilio */ 838241519Sattilio debug_printf("IPC: already answered\n"); 839241519Sattilio fuse_lck_mtx_unlock(fdip->tick->tk_aw_mtx); 840241519Sattilio goto out; 841241519Sattilio } else { 842241519Sattilio /* 843241519Sattilio * So we were faster than the standard handler. 844241519Sattilio * Then by setting the answered flag we get *him* 845241519Sattilio * to drop the ticket. 846241519Sattilio */ 847241519Sattilio debug_printf("IPC: setting to answered\n"); 848241519Sattilio fticket_set_answered(fdip->tick); 849241519Sattilio fuse_lck_mtx_unlock(fdip->tick->tk_aw_mtx); 850241519Sattilio return err; 851241519Sattilio } 852241519Sattilio } 853241519Sattilio debug_printf("IPC: not interrupted, err = %d\n", err); 854241519Sattilio 855241519Sattilio if (fdip->tick->tk_aw_errno) { 856241519Sattilio debug_printf("IPC: explicit EIO-ing, tk_aw_errno = %d\n", 857241519Sattilio fdip->tick->tk_aw_errno); 858241519Sattilio err = EIO; 859241519Sattilio goto out; 860241519Sattilio } 861241519Sattilio if ((err = fdip->tick->tk_aw_ohead.error)) { 862241519Sattilio debug_printf("IPC: setting status to %d\n", 863241519Sattilio fdip->tick->tk_aw_ohead.error); 864241519Sattilio /* 865241519Sattilio * This means a "proper" fuse syscall error. 866241519Sattilio * We record this value so the caller will 867241519Sattilio * be able to know it's not a boring messaging 868241519Sattilio * failure, if she wishes so (and if not, she can 869241519Sattilio * just simply propagate the return value of this routine). 870241519Sattilio * [XXX Maybe a bitflag would do the job too, 871241519Sattilio * if other flags needed, this will be converted thusly.] 872241519Sattilio */ 873241519Sattilio fdip->answ_stat = err; 874241519Sattilio goto out; 875241519Sattilio } 876241519Sattilio fdip->answ = fticket_resp(fdip->tick)->base; 877241519Sattilio fdip->iosize = fticket_resp(fdip->tick)->len; 878241519Sattilio 879241519Sattilio debug_printf("IPC: all is well\n"); 880241519Sattilio 881241519Sattilio return 0; 882241519Sattilio 883241519Sattilioout: 884241519Sattilio debug_printf("IPC: dropping ticket, err = %d\n", err); 885241519Sattilio 886241519Sattilio return err; 887241519Sattilio} 888241519Sattilio 889241519Sattiliovoid 890241519Sattiliofuse_ipc_init(void) 891241519Sattilio{ 892241519Sattilio ticket_zone = uma_zcreate("fuse_ticket", sizeof(struct fuse_ticket), 893241519Sattilio fticket_ctor, fticket_dtor, fticket_init, fticket_fini, 894241519Sattilio UMA_ALIGN_PTR, 0); 895241519Sattilio} 896241519Sattilio 897241519Sattiliovoid 898241519Sattiliofuse_ipc_destroy(void) 899241519Sattilio{ 900241519Sattilio uma_zdestroy(ticket_zone); 901241519Sattilio} 902