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
31 #include <sys/device.h>
32 #include <sys/devfs.h>
35 static int fuse_cdevpriv_close(struct fuse_mount
*);
36 static struct cdev
*fuse_dev
;
39 fuse_cdevpriv_dtor(void *data
)
41 struct fuse_mount
*fmp
= data
;
43 if (!fuse_cdevpriv_close(fmp
))
48 fuse_device_open(struct dev_open_args
*ap
)
50 struct fuse_mount
*fmp
;
51 struct file
*fp
= ap
->a_fpp
? *ap
->a_fpp
: NULL
;
53 fmp
= kmalloc(sizeof(*fmp
), M_TEMP
, M_WAITOK
| M_ZERO
);
56 refcount_init(&fmp
->refcnt
, 1);
57 devfs_set_cdevpriv(fp
, fmp
, fuse_cdevpriv_dtor
);
58 fuse_dbg("open %s\n", ap
->a_head
.a_dev
->si_name
);
64 fuse_device_close(struct dev_close_args
*ap
)
66 struct fuse_mount
*fmp
;
69 error
= devfs_get_cdevpriv(ap
->a_fp
, (void**)&fmp
);
74 /* XXX Can't call this on device close due to devfs bug... */
75 //fuse_cdevpriv_close(fmp);
76 fuse_dbg("close %s\n", ap
->a_head
.a_dev
->si_name
);
82 fuse_cdevpriv_close(struct fuse_mount
*fmp
)
85 fuse_print("/dev/%s not associated with FUSE mount\n",
90 mtx_lock(&fmp
->mnt_lock
);
91 if (fuse_mount_kill(fmp
) == -1)
92 KNOTE(&fmp
->kq
.ki_note
, 0);
94 mtx_unlock(&fmp
->mnt_lock
);
99 /* Call with ->ipc_lock held. */
101 fuse_device_clear(struct fuse_mount
*fmp
)
103 struct fuse_ipc
*fip
;
105 while ((fip
= TAILQ_FIRST(&fmp
->request_head
))) {
106 TAILQ_REMOVE(&fmp
->request_head
, fip
, request_entry
);
107 if (atomic_swap_int(&fip
->sent
, 1) == -1)
111 while ((fip
= TAILQ_FIRST(&fmp
->reply_head
))) {
112 TAILQ_REMOVE(&fmp
->reply_head
, fip
, reply_entry
);
113 if (fuse_ipc_test_and_set_replied(fip
))
119 fuse_device_read(struct dev_read_args
*ap
)
121 struct uio
*uio
= ap
->a_uio
;
122 struct fuse_mount
*fmp
;
123 struct fuse_ipc
*fip
;
126 error
= devfs_get_cdevpriv(ap
->a_fp
, (void**)&fmp
);
130 if (fuse_test_dead(fmp
))
133 mtx_lock(&fmp
->ipc_lock
);
134 while (!(fip
= TAILQ_FIRST(&fmp
->request_head
))) {
135 error
= mtxsleep(fmp
, &fmp
->ipc_lock
, PCATCH
, "ftxc", 0);
136 if (fuse_test_dead(fmp
)) {
137 fuse_device_clear(fmp
);
138 mtx_unlock(&fmp
->ipc_lock
);
139 fuse_dbg("error=%d dead\n", error
);
143 mtx_unlock(&fmp
->ipc_lock
);
144 fuse_dbg("error=%d\n", error
);
148 TAILQ_REMOVE(&fmp
->request_head
, fip
, request_entry
);
149 mtx_unlock(&fmp
->ipc_lock
);
151 fuse_dbgipc(fip
, 0, "");
153 if (uio
->uio_resid
< fuse_in_size(fip
))
156 error
= uiomove(fuse_in(fip
), fuse_in_size(fip
), uio
);
158 if (atomic_swap_int(&fip
->sent
, 1) == -1)
165 fuse_device_write(struct dev_write_args
*ap
)
167 struct uio
*uio
= ap
->a_uio
;
168 struct fuse_mount
*fmp
;
169 struct fuse_ipc
*fip
;
171 struct fuse_in_header
*ihd
;
172 struct fuse_out_header
*ohd
;
175 error
= devfs_get_cdevpriv(ap
->a_fp
, (void**)&fmp
);
179 if (uio
->uio_resid
< sizeof(*ohd
))
182 fuse_buf_alloc(&fb
, uio
->uio_resid
);
183 error
= uiomove(fb
.buf
, uio
->uio_resid
, uio
);
190 mtx_lock(&fmp
->ipc_lock
);
191 TAILQ_FOREACH(fip
, &fmp
->reply_head
, reply_entry
) {
192 if (fip
->unique
== ohd
->unique
) {
193 TAILQ_REMOVE(&fmp
->reply_head
, fip
, reply_entry
);
197 mtx_unlock(&fmp
->ipc_lock
);
200 fuse_dbg("unique=%ju not found\n", ohd
->unique
);
208 /* Non zero ohd->error is not /dev/fuse write error. */
209 if (ohd
->error
== -ENOSYS
) {
210 fuse_set_nosys(fmp
, ihd
->opcode
);
211 fuse_dbgipc(fip
, ohd
->error
, "ENOSYS");
212 } else if (!ohd
->error
&& fuse_audit_length(ihd
, ohd
)) {
214 fuse_dbgipc(fip
, error
, "audit");
216 fuse_dbgipc(fip
, 0, "");
218 /* Complete the IPC regardless of above result. */
219 if (fuse_ipc_test_and_set_replied(fip
))
225 static void filt_fusedevdetach(struct knote
*);
226 static int filt_fusedevread(struct knote
*, long);
227 static int filt_fusedevwrite(struct knote
*, long);
229 static struct filterops fusedevread_filterops
=
231 NULL
, filt_fusedevdetach
, filt_fusedevread
};
232 static struct filterops fusedevwrite_filterops
=
234 NULL
, filt_fusedevdetach
, filt_fusedevwrite
};
237 fuse_device_kqfilter(struct dev_kqfilter_args
*ap
)
239 struct knote
*kn
= ap
->a_kn
;
241 struct fuse_mount
*fmp
;
244 error
= devfs_get_cdevpriv(ap
->a_fp
, (void**)&fmp
);
246 ap
->a_result
= error
;
252 switch (kn
->kn_filter
) {
254 kn
->kn_fop
= &fusedevread_filterops
;
255 kn
->kn_hook
= (caddr_t
)fmp
;
258 kn
->kn_fop
= &fusedevwrite_filterops
;
259 kn
->kn_hook
= (caddr_t
)fmp
;
262 ap
->a_result
= EOPNOTSUPP
;
266 klist
= &fmp
->kq
.ki_note
;
267 knote_insert(klist
, kn
);
273 filt_fusedevdetach(struct knote
*kn
)
275 struct fuse_mount
*fmp
= (struct fuse_mount
*)kn
->kn_hook
;
276 struct klist
*klist
= &fmp
->kq
.ki_note
;
278 knote_remove(klist
, kn
);
282 filt_fusedevread(struct knote
*kn
, long hint
)
284 struct fuse_mount
*fmp
= (struct fuse_mount
*)kn
->kn_hook
;
287 mtx_lock(&fmp
->ipc_lock
);
288 if (!TAILQ_EMPTY(&fmp
->request_head
))
290 mtx_unlock(&fmp
->ipc_lock
);
296 filt_fusedevwrite(struct knote
*kn
, long hint
)
301 static struct dev_ops fuse_device_cdevsw
= {
302 { "fuse", 0, D_MPSAFE
, },
303 .d_open
= fuse_device_open
,
304 .d_close
= fuse_device_close
,
305 .d_read
= fuse_device_read
,
306 .d_write
= fuse_device_write
,
307 .d_kqfilter
= fuse_device_kqfilter
,
311 fuse_device_init(void)
313 fuse_dev
= make_dev(&fuse_device_cdevsw
, 0, UID_ROOT
, GID_OPERATOR
,
314 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IWGRP
, "fuse");
323 fuse_device_cleanup(void)
326 destroy_dev(fuse_dev
);