2 * Copyright (c) 2019 Tomohiro Kusumi <tkusumi@netbsd.org>
3 * Copyright (c) 2019 The DragonFly Project
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/signalvar.h>
31 #include <sys/kern_syscall.h>
33 static MALLOC_DEFINE(M_FUSE_BUF, "fuse_buf", "FUSE buf");
34 static MALLOC_DEFINE(M_FUSE_IPC, "fuse_ipc", "FUSE ipc");
36 static struct objcache *fuse_ipc_objcache = NULL;
37 static struct objcache_malloc_args fuse_ipc_args = {
38 sizeof(struct fuse_ipc), M_FUSE_IPC,
42 fuse_block_sigs(sigset_t *oldset)
49 SIGDELSET(newset, SIGKILL);
51 error = kern_sigprocmask(SIG_BLOCK, &newset, oldset);
60 fuse_restore_sigs(sigset_t *oldset)
63 int error = kern_sigprocmask(SIG_SETMASK, oldset, NULL);
72 fuse_buf_alloc(struct fuse_buf *fbp, size_t len)
74 fbp->buf = kmalloc(len, M_FUSE_BUF, M_WAITOK | M_ZERO);
80 fuse_buf_free(struct fuse_buf *fbp)
83 kfree(fbp->buf, M_FUSE_BUF);
90 fuse_ipc_get(struct fuse_mount *fmp, size_t len)
94 fip = objcache_get(fuse_ipc_objcache, M_WAITOK);
95 refcount_init(&fip->refcnt, 1);
97 fip->unique = atomic_fetchadd_long(&fmp->unique, 1);
100 fuse_buf_alloc(&fip->request, sizeof(struct fuse_in_header) + len);
101 fip->reply.buf = NULL;
107 fuse_ipc_put(struct fuse_ipc *fip)
109 if (refcount_release(&fip->refcnt)) {
110 fuse_buf_free(&fip->request);
111 fuse_buf_free(&fip->reply);
112 objcache_put(fuse_ipc_objcache, fip);
117 fuse_ipc_remove(struct fuse_ipc *fip)
119 struct fuse_mount *fmp = fip->fmp;
122 mtx_lock(&fmp->ipc_lock);
123 TAILQ_FOREACH(p, &fmp->request_head, request_entry) {
125 TAILQ_REMOVE(&fmp->request_head, p, request_entry);
129 TAILQ_FOREACH(p, &fmp->reply_head, reply_entry) {
131 TAILQ_REMOVE(&fmp->reply_head, p, reply_entry);
135 mtx_unlock(&fmp->ipc_lock);
139 fuse_ipc_fill(struct fuse_ipc *fip, int op, uint64_t ino, struct ucred *cred)
142 cred = curthread->td_ucred;
144 fuse_fill_in_header(fuse_in(fip), fuse_in_size(fip), op, fip->unique,
145 ino, cred->cr_uid, cred->cr_rgid,
146 curthread->td_proc ? curthread->td_proc->p_pid : 0);
148 fuse_dbgipc(fip, 0, "");
150 return fuse_in_data(fip);
154 fuse_ipc_wait(struct fuse_ipc *fip)
157 int error, retry = 0;
159 if (fuse_test_dead(fip->fmp)) {
160 KKASSERT(!fuse_ipc_test_replied(fip));
161 fuse_ipc_set_replied(fip);
165 if (fuse_ipc_test_replied(fip))
168 fuse_block_sigs(&oldset);
169 error = tsleep(fip, 0, "ftxp", 5 * hz);
170 fuse_restore_sigs(&oldset);
172 KKASSERT(fuse_ipc_test_replied(fip));
174 if (error == EWOULDBLOCK) {
175 if (!fuse_ipc_test_replied(fip)) {
177 fuse_print("timeout/retry\n");
180 fuse_print("timeout\n");
181 fuse_ipc_remove(fip);
182 fuse_ipc_set_replied(fip);
185 fuse_dbg("EWOULDBLOCK lost race\n");
187 fuse_print("error=%d\n", error);
188 fuse_ipc_remove(fip);
189 fuse_ipc_set_replied(fip);
193 if (fuse_test_dead(fip->fmp)) {
194 KKASSERT(fuse_ipc_test_replied(fip));
202 fuse_ipc_tx(struct fuse_ipc *fip)
204 struct fuse_mount *fmp = fip->fmp;
205 struct fuse_out_header *ohd;
208 if (fuse_test_dead(fmp)) {
213 mtx_lock(&fmp->mnt_lock);
215 mtx_lock(&fmp->ipc_lock);
216 TAILQ_INSERT_TAIL(&fmp->reply_head, fip, reply_entry);
217 TAILQ_INSERT_TAIL(&fmp->request_head, fip, request_entry);
218 mtx_unlock(&fmp->ipc_lock);
221 KNOTE(&fmp->kq.ki_note, 0);
222 mtx_unlock(&fmp->mnt_lock);
224 error = fuse_ipc_wait(fip);
225 KKASSERT(fuse_ipc_test_replied(fip));
227 fuse_dbgipc(fip, error, "ipc_wait");
236 fuse_dbgipc(fip, error, "ipc_error");
242 fuse_dbgipc(fip, 0, "done");
250 fuse_ipc_objcache = objcache_create("fuse_ipc", 0, 0,
252 objcache_malloc_alloc_zero, objcache_malloc_free, &fuse_ipc_args);
256 fuse_ipc_cleanup(void)
258 objcache_destroy(fuse_ipc_objcache);