15812c3ccSTomohiro Kusumi /*-
25812c3ccSTomohiro Kusumi * Copyright (c) 2019 Tomohiro Kusumi <tkusumi@netbsd.org>
35812c3ccSTomohiro Kusumi * Copyright (c) 2019 The DragonFly Project
45812c3ccSTomohiro Kusumi * All rights reserved.
55812c3ccSTomohiro Kusumi *
65812c3ccSTomohiro Kusumi * Redistribution and use in source and binary forms, with or without
75812c3ccSTomohiro Kusumi * modification, are permitted provided that the following conditions
85812c3ccSTomohiro Kusumi * are met:
95812c3ccSTomohiro Kusumi * 1. Redistributions of source code must retain the above copyright
105812c3ccSTomohiro Kusumi * notice, this list of conditions and the following disclaimer.
115812c3ccSTomohiro Kusumi * 2. Redistributions in binary form must reproduce the above copyright
125812c3ccSTomohiro Kusumi * notice, this list of conditions and the following disclaimer in the
135812c3ccSTomohiro Kusumi * documentation and/or other materials provided with the distribution.
145812c3ccSTomohiro Kusumi *
155812c3ccSTomohiro Kusumi * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
165812c3ccSTomohiro Kusumi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
175812c3ccSTomohiro Kusumi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
185812c3ccSTomohiro Kusumi * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
195812c3ccSTomohiro Kusumi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
205812c3ccSTomohiro Kusumi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
215812c3ccSTomohiro Kusumi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
225812c3ccSTomohiro Kusumi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
235812c3ccSTomohiro Kusumi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
245812c3ccSTomohiro Kusumi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
255812c3ccSTomohiro Kusumi * SUCH DAMAGE.
265812c3ccSTomohiro Kusumi */
275812c3ccSTomohiro Kusumi
285812c3ccSTomohiro Kusumi #include "fuse.h"
295812c3ccSTomohiro Kusumi
305812c3ccSTomohiro Kusumi #include <sys/signalvar.h>
315812c3ccSTomohiro Kusumi #include <sys/kern_syscall.h>
325812c3ccSTomohiro Kusumi
335812c3ccSTomohiro Kusumi static MALLOC_DEFINE(M_FUSE_BUF, "fuse_buf", "FUSE buf");
345812c3ccSTomohiro Kusumi static MALLOC_DEFINE(M_FUSE_IPC, "fuse_ipc", "FUSE ipc");
355812c3ccSTomohiro Kusumi
365812c3ccSTomohiro Kusumi static struct objcache *fuse_ipc_objcache = NULL;
375812c3ccSTomohiro Kusumi static struct objcache_malloc_args fuse_ipc_args = {
385812c3ccSTomohiro Kusumi sizeof(struct fuse_ipc), M_FUSE_IPC,
395812c3ccSTomohiro Kusumi };
405812c3ccSTomohiro Kusumi
41*1a8e5e4cSMatthew Dillon #if 0
425812c3ccSTomohiro Kusumi static int
435812c3ccSTomohiro Kusumi fuse_block_sigs(sigset_t *oldset)
445812c3ccSTomohiro Kusumi {
455812c3ccSTomohiro Kusumi if (curproc) {
465812c3ccSTomohiro Kusumi sigset_t newset;
475812c3ccSTomohiro Kusumi int error;
485812c3ccSTomohiro Kusumi
495812c3ccSTomohiro Kusumi SIGFILLSET(newset);
505812c3ccSTomohiro Kusumi SIGDELSET(newset, SIGKILL);
515812c3ccSTomohiro Kusumi
525812c3ccSTomohiro Kusumi error = kern_sigprocmask(SIG_BLOCK, &newset, oldset);
535812c3ccSTomohiro Kusumi KKASSERT(!error);
545812c3ccSTomohiro Kusumi return error;
555812c3ccSTomohiro Kusumi }
565812c3ccSTomohiro Kusumi
575812c3ccSTomohiro Kusumi return -1;
585812c3ccSTomohiro Kusumi }
595812c3ccSTomohiro Kusumi
605812c3ccSTomohiro Kusumi static int
615812c3ccSTomohiro Kusumi fuse_restore_sigs(sigset_t *oldset)
625812c3ccSTomohiro Kusumi {
635812c3ccSTomohiro Kusumi if (curproc) {
645812c3ccSTomohiro Kusumi int error = kern_sigprocmask(SIG_SETMASK, oldset, NULL);
655812c3ccSTomohiro Kusumi KKASSERT(!error);
665812c3ccSTomohiro Kusumi return error;
675812c3ccSTomohiro Kusumi }
685812c3ccSTomohiro Kusumi
695812c3ccSTomohiro Kusumi return -1;
705812c3ccSTomohiro Kusumi }
71*1a8e5e4cSMatthew Dillon #endif
725812c3ccSTomohiro Kusumi
735812c3ccSTomohiro Kusumi void
fuse_buf_alloc(struct fuse_buf * fbp,size_t len)745812c3ccSTomohiro Kusumi fuse_buf_alloc(struct fuse_buf *fbp, size_t len)
755812c3ccSTomohiro Kusumi {
765812c3ccSTomohiro Kusumi fbp->buf = kmalloc(len, M_FUSE_BUF, M_WAITOK | M_ZERO);
775812c3ccSTomohiro Kusumi KKASSERT(fbp->buf);
785812c3ccSTomohiro Kusumi fbp->len = len;
795812c3ccSTomohiro Kusumi }
805812c3ccSTomohiro Kusumi
815812c3ccSTomohiro Kusumi void
fuse_buf_free(struct fuse_buf * fbp)825812c3ccSTomohiro Kusumi fuse_buf_free(struct fuse_buf *fbp)
835812c3ccSTomohiro Kusumi {
845812c3ccSTomohiro Kusumi if (fbp->buf) {
855812c3ccSTomohiro Kusumi kfree(fbp->buf, M_FUSE_BUF);
865812c3ccSTomohiro Kusumi fbp->buf = NULL;
875812c3ccSTomohiro Kusumi }
885812c3ccSTomohiro Kusumi fbp->len = 0;
895812c3ccSTomohiro Kusumi }
905812c3ccSTomohiro Kusumi
915812c3ccSTomohiro Kusumi struct fuse_ipc*
fuse_ipc_get(struct fuse_mount * fmp,size_t len)925812c3ccSTomohiro Kusumi fuse_ipc_get(struct fuse_mount *fmp, size_t len)
935812c3ccSTomohiro Kusumi {
945812c3ccSTomohiro Kusumi struct fuse_ipc *fip;
955812c3ccSTomohiro Kusumi
965812c3ccSTomohiro Kusumi fip = objcache_get(fuse_ipc_objcache, M_WAITOK);
975d0d0bafSMatthew Dillon bzero(fip, sizeof(*fip));
985812c3ccSTomohiro Kusumi refcount_init(&fip->refcnt, 1);
995812c3ccSTomohiro Kusumi fip->fmp = fmp;
1005812c3ccSTomohiro Kusumi fip->unique = atomic_fetchadd_long(&fmp->unique, 1);
1015812c3ccSTomohiro Kusumi fip->done = 0;
1025812c3ccSTomohiro Kusumi
1035812c3ccSTomohiro Kusumi fuse_buf_alloc(&fip->request, sizeof(struct fuse_in_header) + len);
1045812c3ccSTomohiro Kusumi fip->reply.buf = NULL;
1055812c3ccSTomohiro Kusumi
1065812c3ccSTomohiro Kusumi return fip;
1075812c3ccSTomohiro Kusumi }
1085812c3ccSTomohiro Kusumi
1095812c3ccSTomohiro Kusumi void
fuse_ipc_put(struct fuse_ipc * fip)1105812c3ccSTomohiro Kusumi fuse_ipc_put(struct fuse_ipc *fip)
1115812c3ccSTomohiro Kusumi {
1125812c3ccSTomohiro Kusumi if (refcount_release(&fip->refcnt)) {
1135812c3ccSTomohiro Kusumi fuse_buf_free(&fip->request);
1145812c3ccSTomohiro Kusumi fuse_buf_free(&fip->reply);
1155812c3ccSTomohiro Kusumi objcache_put(fuse_ipc_objcache, fip);
1165812c3ccSTomohiro Kusumi }
1175812c3ccSTomohiro Kusumi }
1185812c3ccSTomohiro Kusumi
1195812c3ccSTomohiro Kusumi static void
fuse_ipc_remove(struct fuse_ipc * fip)1205812c3ccSTomohiro Kusumi fuse_ipc_remove(struct fuse_ipc *fip)
1215812c3ccSTomohiro Kusumi {
1225812c3ccSTomohiro Kusumi struct fuse_mount *fmp = fip->fmp;
1230d020c7bSTomohiro Kusumi struct fuse_ipc *p;
1245812c3ccSTomohiro Kusumi
1255812c3ccSTomohiro Kusumi mtx_lock(&fmp->ipc_lock);
1260d020c7bSTomohiro Kusumi TAILQ_FOREACH(p, &fmp->request_head, request_entry) {
1275812c3ccSTomohiro Kusumi if (fip == p) {
1285812c3ccSTomohiro Kusumi TAILQ_REMOVE(&fmp->request_head, p, request_entry);
129*1a8e5e4cSMatthew Dillon if (atomic_swap_int(&fip->sent, 1) == -1)
130*1a8e5e4cSMatthew Dillon wakeup(fip);
1315812c3ccSTomohiro Kusumi break;
1325812c3ccSTomohiro Kusumi }
1335812c3ccSTomohiro Kusumi }
1340d020c7bSTomohiro Kusumi TAILQ_FOREACH(p, &fmp->reply_head, reply_entry) {
1355812c3ccSTomohiro Kusumi if (fip == p) {
1365812c3ccSTomohiro Kusumi TAILQ_REMOVE(&fmp->reply_head, p, reply_entry);
1375812c3ccSTomohiro Kusumi break;
1385812c3ccSTomohiro Kusumi }
1395812c3ccSTomohiro Kusumi }
1405812c3ccSTomohiro Kusumi mtx_unlock(&fmp->ipc_lock);
1415812c3ccSTomohiro Kusumi }
1425812c3ccSTomohiro Kusumi
1435812c3ccSTomohiro Kusumi void*
fuse_ipc_fill(struct fuse_ipc * fip,int op,uint64_t ino,struct ucred * cred)1445812c3ccSTomohiro Kusumi fuse_ipc_fill(struct fuse_ipc *fip, int op, uint64_t ino, struct ucred *cred)
1455812c3ccSTomohiro Kusumi {
1465812c3ccSTomohiro Kusumi if (!cred)
1475812c3ccSTomohiro Kusumi cred = curthread->td_ucred;
1485812c3ccSTomohiro Kusumi
1495812c3ccSTomohiro Kusumi fuse_fill_in_header(fuse_in(fip), fuse_in_size(fip), op, fip->unique,
1505812c3ccSTomohiro Kusumi ino, cred->cr_uid, cred->cr_rgid,
1515812c3ccSTomohiro Kusumi curthread->td_proc ? curthread->td_proc->p_pid : 0);
1525812c3ccSTomohiro Kusumi
1535812c3ccSTomohiro Kusumi fuse_dbgipc(fip, 0, "");
1545812c3ccSTomohiro Kusumi
1555812c3ccSTomohiro Kusumi return fuse_in_data(fip);
1565812c3ccSTomohiro Kusumi }
1575812c3ccSTomohiro Kusumi
1585812c3ccSTomohiro Kusumi static int
fuse_ipc_wait(struct fuse_ipc * fip)1595812c3ccSTomohiro Kusumi fuse_ipc_wait(struct fuse_ipc *fip)
1605812c3ccSTomohiro Kusumi {
1615812c3ccSTomohiro Kusumi int error, retry = 0;
1625812c3ccSTomohiro Kusumi
1635812c3ccSTomohiro Kusumi if (fuse_test_dead(fip->fmp)) {
1645812c3ccSTomohiro Kusumi KKASSERT(!fuse_ipc_test_replied(fip));
1655812c3ccSTomohiro Kusumi fuse_ipc_set_replied(fip);
1665812c3ccSTomohiro Kusumi return ENOTCONN;
1675812c3ccSTomohiro Kusumi }
1685812c3ccSTomohiro Kusumi
1695812c3ccSTomohiro Kusumi if (fuse_ipc_test_replied(fip))
1705812c3ccSTomohiro Kusumi return 0;
1715812c3ccSTomohiro Kusumi again:
172*1a8e5e4cSMatthew Dillon tsleep_interlock(fip, 0);
173*1a8e5e4cSMatthew Dillon if (fuse_ipc_test_replied(fip))
174*1a8e5e4cSMatthew Dillon return 0;
175*1a8e5e4cSMatthew Dillon error = tsleep(fip, PINTERLOCKED, "ftxp", 5 * hz);
1765812c3ccSTomohiro Kusumi if (!error)
177419ae2abSTomohiro Kusumi KKASSERT(fuse_ipc_test_replied(fip));
1785812c3ccSTomohiro Kusumi
1795812c3ccSTomohiro Kusumi if (error == EWOULDBLOCK) {
1805812c3ccSTomohiro Kusumi if (!fuse_ipc_test_replied(fip)) {
1815812c3ccSTomohiro Kusumi if (!retry)
1825812c3ccSTomohiro Kusumi fuse_print("timeout/retry\n");
1835812c3ccSTomohiro Kusumi if (retry++ < 6)
1845812c3ccSTomohiro Kusumi goto again;
1855812c3ccSTomohiro Kusumi fuse_print("timeout\n");
1865812c3ccSTomohiro Kusumi fuse_ipc_remove(fip);
1875812c3ccSTomohiro Kusumi fuse_ipc_set_replied(fip);
1885812c3ccSTomohiro Kusumi return ETIMEDOUT;
1895812c3ccSTomohiro Kusumi } else
1905812c3ccSTomohiro Kusumi fuse_dbg("EWOULDBLOCK lost race\n");
1915812c3ccSTomohiro Kusumi } else if (error) {
1925812c3ccSTomohiro Kusumi fuse_print("error=%d\n", error);
1935812c3ccSTomohiro Kusumi fuse_ipc_remove(fip);
1945812c3ccSTomohiro Kusumi fuse_ipc_set_replied(fip);
1955812c3ccSTomohiro Kusumi return error;
1965812c3ccSTomohiro Kusumi }
1975812c3ccSTomohiro Kusumi
1985812c3ccSTomohiro Kusumi if (fuse_test_dead(fip->fmp)) {
1995812c3ccSTomohiro Kusumi KKASSERT(fuse_ipc_test_replied(fip));
2005812c3ccSTomohiro Kusumi return ENOTCONN;
2015812c3ccSTomohiro Kusumi }
2025812c3ccSTomohiro Kusumi
2035812c3ccSTomohiro Kusumi return 0;
2045812c3ccSTomohiro Kusumi }
2055812c3ccSTomohiro Kusumi
206*1a8e5e4cSMatthew Dillon static int
fuse_ipc_wait_sent(struct fuse_ipc * fip)207*1a8e5e4cSMatthew Dillon fuse_ipc_wait_sent(struct fuse_ipc *fip)
208*1a8e5e4cSMatthew Dillon {
209*1a8e5e4cSMatthew Dillon int error, retry = 0;
210*1a8e5e4cSMatthew Dillon
211*1a8e5e4cSMatthew Dillon if (fuse_test_dead(fip->fmp)) {
212*1a8e5e4cSMatthew Dillon KKASSERT(!fuse_ipc_test_replied(fip));
213*1a8e5e4cSMatthew Dillon fuse_ipc_remove(fip);
214*1a8e5e4cSMatthew Dillon fuse_ipc_set_replied(fip);
215*1a8e5e4cSMatthew Dillon return ENOTCONN;
216*1a8e5e4cSMatthew Dillon }
217*1a8e5e4cSMatthew Dillon
218*1a8e5e4cSMatthew Dillon error = 0;
219*1a8e5e4cSMatthew Dillon
220*1a8e5e4cSMatthew Dillon for (;;) {
221*1a8e5e4cSMatthew Dillon tsleep_interlock(fip, 0);
222*1a8e5e4cSMatthew Dillon if (atomic_swap_int(&fip->sent, -1) == 1) {
223*1a8e5e4cSMatthew Dillon error = 0;
224*1a8e5e4cSMatthew Dillon break;
225*1a8e5e4cSMatthew Dillon }
226*1a8e5e4cSMatthew Dillon error = tsleep(fip, PINTERLOCKED, "ftxp", 5 * hz);
227*1a8e5e4cSMatthew Dillon if (error == EWOULDBLOCK) {
228*1a8e5e4cSMatthew Dillon ++retry;
229*1a8e5e4cSMatthew Dillon if (retry == 6) {
230*1a8e5e4cSMatthew Dillon fuse_print("timeout\n");
231*1a8e5e4cSMatthew Dillon error = ETIMEDOUT;
232*1a8e5e4cSMatthew Dillon break;
233*1a8e5e4cSMatthew Dillon }
234*1a8e5e4cSMatthew Dillon fuse_print("timeout/retry\n");
235*1a8e5e4cSMatthew Dillon }
236*1a8e5e4cSMatthew Dillon }
237*1a8e5e4cSMatthew Dillon if (fuse_test_dead(fip->fmp))
238*1a8e5e4cSMatthew Dillon error = ENOTCONN;
239*1a8e5e4cSMatthew Dillon if (error) {
240*1a8e5e4cSMatthew Dillon fuse_ipc_remove(fip);
241*1a8e5e4cSMatthew Dillon fuse_ipc_set_replied(fip);
242*1a8e5e4cSMatthew Dillon }
243*1a8e5e4cSMatthew Dillon return error;
244*1a8e5e4cSMatthew Dillon }
245*1a8e5e4cSMatthew Dillon
2465812c3ccSTomohiro Kusumi int
fuse_ipc_tx(struct fuse_ipc * fip)2475812c3ccSTomohiro Kusumi fuse_ipc_tx(struct fuse_ipc *fip)
2485812c3ccSTomohiro Kusumi {
2495812c3ccSTomohiro Kusumi struct fuse_mount *fmp = fip->fmp;
2505812c3ccSTomohiro Kusumi struct fuse_out_header *ohd;
2515812c3ccSTomohiro Kusumi int error;
2525812c3ccSTomohiro Kusumi
2535812c3ccSTomohiro Kusumi if (fuse_test_dead(fmp)) {
2545812c3ccSTomohiro Kusumi fuse_ipc_put(fip);
2555812c3ccSTomohiro Kusumi return ENOTCONN;
2565812c3ccSTomohiro Kusumi }
2575812c3ccSTomohiro Kusumi
2585812c3ccSTomohiro Kusumi mtx_lock(&fmp->ipc_lock);
2595812c3ccSTomohiro Kusumi TAILQ_INSERT_TAIL(&fmp->reply_head, fip, reply_entry);
2605812c3ccSTomohiro Kusumi TAILQ_INSERT_TAIL(&fmp->request_head, fip, request_entry);
2615812c3ccSTomohiro Kusumi mtx_unlock(&fmp->ipc_lock);
2625812c3ccSTomohiro Kusumi
2635812c3ccSTomohiro Kusumi wakeup(fmp);
2645812c3ccSTomohiro Kusumi KNOTE(&fmp->kq.ki_note, 0);
2655812c3ccSTomohiro Kusumi
2665812c3ccSTomohiro Kusumi error = fuse_ipc_wait(fip);
2675812c3ccSTomohiro Kusumi KKASSERT(fuse_ipc_test_replied(fip));
2685812c3ccSTomohiro Kusumi if (error) {
2695812c3ccSTomohiro Kusumi fuse_dbgipc(fip, error, "ipc_wait");
2705812c3ccSTomohiro Kusumi fuse_ipc_put(fip);
2715812c3ccSTomohiro Kusumi return error;
2725812c3ccSTomohiro Kusumi }
2735812c3ccSTomohiro Kusumi
2745812c3ccSTomohiro Kusumi ohd = fuse_out(fip);
2755812c3ccSTomohiro Kusumi KKASSERT(ohd);
2765812c3ccSTomohiro Kusumi error = ohd->error;
2775812c3ccSTomohiro Kusumi if (error) {
2785812c3ccSTomohiro Kusumi fuse_dbgipc(fip, error, "ipc_error");
2795812c3ccSTomohiro Kusumi fuse_ipc_put(fip);
2805812c3ccSTomohiro Kusumi if (error < 0)
2815812c3ccSTomohiro Kusumi error = -error;
2825812c3ccSTomohiro Kusumi return error;
2835812c3ccSTomohiro Kusumi }
2845812c3ccSTomohiro Kusumi fuse_dbgipc(fip, 0, "done");
2855812c3ccSTomohiro Kusumi
2865812c3ccSTomohiro Kusumi return 0;
2875812c3ccSTomohiro Kusumi }
2885812c3ccSTomohiro Kusumi
289*1a8e5e4cSMatthew Dillon int
fuse_ipc_tx_noreply(struct fuse_ipc * fip)290*1a8e5e4cSMatthew Dillon fuse_ipc_tx_noreply(struct fuse_ipc *fip)
291*1a8e5e4cSMatthew Dillon {
292*1a8e5e4cSMatthew Dillon struct fuse_mount *fmp = fip->fmp;
293*1a8e5e4cSMatthew Dillon int error;
294*1a8e5e4cSMatthew Dillon
295*1a8e5e4cSMatthew Dillon if (fuse_test_dead(fmp)) {
296*1a8e5e4cSMatthew Dillon fuse_ipc_put(fip);
297*1a8e5e4cSMatthew Dillon return ENOTCONN;
298*1a8e5e4cSMatthew Dillon }
299*1a8e5e4cSMatthew Dillon
300*1a8e5e4cSMatthew Dillon mtx_lock(&fmp->ipc_lock);
301*1a8e5e4cSMatthew Dillon TAILQ_INSERT_TAIL(&fmp->request_head, fip, request_entry);
302*1a8e5e4cSMatthew Dillon mtx_unlock(&fmp->ipc_lock);
303*1a8e5e4cSMatthew Dillon
304*1a8e5e4cSMatthew Dillon wakeup(fmp);
305*1a8e5e4cSMatthew Dillon KNOTE(&fmp->kq.ki_note, 0);
306*1a8e5e4cSMatthew Dillon
307*1a8e5e4cSMatthew Dillon error = fuse_ipc_wait_sent(fip);
308*1a8e5e4cSMatthew Dillon if (error)
309*1a8e5e4cSMatthew Dillon fuse_ipc_put(fip);
310*1a8e5e4cSMatthew Dillon return error;
311*1a8e5e4cSMatthew Dillon }
312*1a8e5e4cSMatthew Dillon
3135812c3ccSTomohiro Kusumi void
fuse_ipc_init(void)3145812c3ccSTomohiro Kusumi fuse_ipc_init(void)
3155812c3ccSTomohiro Kusumi {
3165812c3ccSTomohiro Kusumi fuse_ipc_objcache = objcache_create("fuse_ipc", 0, 0,
3175812c3ccSTomohiro Kusumi NULL, NULL, NULL,
3185812c3ccSTomohiro Kusumi objcache_malloc_alloc_zero, objcache_malloc_free, &fuse_ipc_args);
3195812c3ccSTomohiro Kusumi }
3205812c3ccSTomohiro Kusumi
3215812c3ccSTomohiro Kusumi void
fuse_ipc_cleanup(void)3225812c3ccSTomohiro Kusumi fuse_ipc_cleanup(void)
3235812c3ccSTomohiro Kusumi {
3245812c3ccSTomohiro Kusumi objcache_destroy(fuse_ipc_objcache);
3255812c3ccSTomohiro Kusumi }
326