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
,
43 fuse_block_sigs(sigset_t
*oldset
)
50 SIGDELSET(newset
, SIGKILL
);
52 error
= kern_sigprocmask(SIG_BLOCK
, &newset
, oldset
);
61 fuse_restore_sigs(sigset_t
*oldset
)
64 int error
= kern_sigprocmask(SIG_SETMASK
, oldset
, NULL
);
74 fuse_buf_alloc(struct fuse_buf
*fbp
, size_t len
)
76 fbp
->buf
= kmalloc(len
, M_FUSE_BUF
, M_WAITOK
| M_ZERO
);
82 fuse_buf_free(struct fuse_buf
*fbp
)
85 kfree(fbp
->buf
, M_FUSE_BUF
);
92 fuse_ipc_get(struct fuse_mount
*fmp
, size_t len
)
96 fip
= objcache_get(fuse_ipc_objcache
, M_WAITOK
);
97 bzero(fip
, sizeof(*fip
));
98 refcount_init(&fip
->refcnt
, 1);
100 fip
->unique
= atomic_fetchadd_long(&fmp
->unique
, 1);
103 fuse_buf_alloc(&fip
->request
, sizeof(struct fuse_in_header
) + len
);
104 fip
->reply
.buf
= NULL
;
110 fuse_ipc_put(struct fuse_ipc
*fip
)
112 if (refcount_release(&fip
->refcnt
)) {
113 fuse_buf_free(&fip
->request
);
114 fuse_buf_free(&fip
->reply
);
115 objcache_put(fuse_ipc_objcache
, fip
);
120 fuse_ipc_remove(struct fuse_ipc
*fip
)
122 struct fuse_mount
*fmp
= fip
->fmp
;
125 mtx_lock(&fmp
->ipc_lock
);
126 TAILQ_FOREACH(p
, &fmp
->request_head
, request_entry
) {
128 TAILQ_REMOVE(&fmp
->request_head
, p
, request_entry
);
129 if (atomic_swap_int(&fip
->sent
, 1) == -1)
134 TAILQ_FOREACH(p
, &fmp
->reply_head
, reply_entry
) {
136 TAILQ_REMOVE(&fmp
->reply_head
, p
, reply_entry
);
140 mtx_unlock(&fmp
->ipc_lock
);
144 fuse_ipc_fill(struct fuse_ipc
*fip
, int op
, uint64_t ino
, struct ucred
*cred
)
147 cred
= curthread
->td_ucred
;
149 fuse_fill_in_header(fuse_in(fip
), fuse_in_size(fip
), op
, fip
->unique
,
150 ino
, cred
->cr_uid
, cred
->cr_rgid
,
151 curthread
->td_proc
? curthread
->td_proc
->p_pid
: 0);
153 fuse_dbgipc(fip
, 0, "");
155 return fuse_in_data(fip
);
159 fuse_ipc_wait(struct fuse_ipc
*fip
)
161 int error
, retry
= 0;
163 if (fuse_test_dead(fip
->fmp
)) {
164 KKASSERT(!fuse_ipc_test_replied(fip
));
165 fuse_ipc_set_replied(fip
);
169 if (fuse_ipc_test_replied(fip
))
172 tsleep_interlock(fip
, 0);
173 if (fuse_ipc_test_replied(fip
))
175 error
= tsleep(fip
, PINTERLOCKED
, "ftxp", 5 * hz
);
177 KKASSERT(fuse_ipc_test_replied(fip
));
179 if (error
== EWOULDBLOCK
) {
180 if (!fuse_ipc_test_replied(fip
)) {
182 fuse_print("timeout/retry\n");
185 fuse_print("timeout\n");
186 fuse_ipc_remove(fip
);
187 fuse_ipc_set_replied(fip
);
190 fuse_dbg("EWOULDBLOCK lost race\n");
192 fuse_print("error=%d\n", error
);
193 fuse_ipc_remove(fip
);
194 fuse_ipc_set_replied(fip
);
198 if (fuse_test_dead(fip
->fmp
)) {
199 KKASSERT(fuse_ipc_test_replied(fip
));
207 fuse_ipc_wait_sent(struct fuse_ipc
*fip
)
209 int error
, retry
= 0;
211 if (fuse_test_dead(fip
->fmp
)) {
212 KKASSERT(!fuse_ipc_test_replied(fip
));
213 fuse_ipc_remove(fip
);
214 fuse_ipc_set_replied(fip
);
221 tsleep_interlock(fip
, 0);
222 if (atomic_swap_int(&fip
->sent
, -1) == 1) {
226 error
= tsleep(fip
, PINTERLOCKED
, "ftxp", 5 * hz
);
227 if (error
== EWOULDBLOCK
) {
230 fuse_print("timeout\n");
234 fuse_print("timeout/retry\n");
237 if (fuse_test_dead(fip
->fmp
))
240 fuse_ipc_remove(fip
);
241 fuse_ipc_set_replied(fip
);
247 fuse_ipc_tx(struct fuse_ipc
*fip
)
249 struct fuse_mount
*fmp
= fip
->fmp
;
250 struct fuse_out_header
*ohd
;
253 if (fuse_test_dead(fmp
)) {
258 mtx_lock(&fmp
->ipc_lock
);
259 TAILQ_INSERT_TAIL(&fmp
->reply_head
, fip
, reply_entry
);
260 TAILQ_INSERT_TAIL(&fmp
->request_head
, fip
, request_entry
);
261 mtx_unlock(&fmp
->ipc_lock
);
264 KNOTE(&fmp
->kq
.ki_note
, 0);
266 error
= fuse_ipc_wait(fip
);
267 KKASSERT(fuse_ipc_test_replied(fip
));
269 fuse_dbgipc(fip
, error
, "ipc_wait");
278 fuse_dbgipc(fip
, error
, "ipc_error");
284 fuse_dbgipc(fip
, 0, "done");
290 fuse_ipc_tx_noreply(struct fuse_ipc
*fip
)
292 struct fuse_mount
*fmp
= fip
->fmp
;
295 if (fuse_test_dead(fmp
)) {
300 mtx_lock(&fmp
->ipc_lock
);
301 TAILQ_INSERT_TAIL(&fmp
->request_head
, fip
, request_entry
);
302 mtx_unlock(&fmp
->ipc_lock
);
305 KNOTE(&fmp
->kq
.ki_note
, 0);
307 error
= fuse_ipc_wait_sent(fip
);
316 fuse_ipc_objcache
= objcache_create("fuse_ipc", 0, 0,
318 objcache_malloc_alloc_zero
, objcache_malloc_free
, &fuse_ipc_args
);
322 fuse_ipc_cleanup(void)
324 objcache_destroy(fuse_ipc_objcache
);