xref: /dflybsd-src/sys/vfs/fuse/fuse_device.c (revision 1a8e5e4cf0cfbe16676810f7edca73f98bb9b8f5)
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/conf.h>
315812c3ccSTomohiro Kusumi #include <sys/device.h>
325812c3ccSTomohiro Kusumi #include <sys/devfs.h>
335812c3ccSTomohiro Kusumi #include <sys/uio.h>
345812c3ccSTomohiro Kusumi 
355812c3ccSTomohiro Kusumi static int fuse_cdevpriv_close(struct fuse_mount*);
365812c3ccSTomohiro Kusumi static struct cdev *fuse_dev;
375812c3ccSTomohiro Kusumi 
385812c3ccSTomohiro Kusumi static void
fuse_cdevpriv_dtor(void * data)395812c3ccSTomohiro Kusumi fuse_cdevpriv_dtor(void *data)
405812c3ccSTomohiro Kusumi {
415812c3ccSTomohiro Kusumi 	struct fuse_mount *fmp = data;
425812c3ccSTomohiro Kusumi 
435812c3ccSTomohiro Kusumi 	if (!fuse_cdevpriv_close(fmp))
445812c3ccSTomohiro Kusumi 		fuse_mount_free(fmp);
455812c3ccSTomohiro Kusumi }
465812c3ccSTomohiro Kusumi 
475812c3ccSTomohiro Kusumi static int
fuse_device_open(struct dev_open_args * ap)485812c3ccSTomohiro Kusumi fuse_device_open(struct dev_open_args *ap)
495812c3ccSTomohiro Kusumi {
505812c3ccSTomohiro Kusumi 	struct fuse_mount *fmp;
515bd45597SMatthew Dillon 	struct file *fp = ap->a_fpp ? *ap->a_fpp : NULL;
525812c3ccSTomohiro Kusumi 
535812c3ccSTomohiro Kusumi 	fmp = kmalloc(sizeof(*fmp), M_TEMP, M_WAITOK | M_ZERO);
545812c3ccSTomohiro Kusumi 	KKASSERT(fmp);
555812c3ccSTomohiro Kusumi 
565812c3ccSTomohiro Kusumi 	refcount_init(&fmp->refcnt, 1);
575bd45597SMatthew Dillon 	devfs_set_cdevpriv(fp, fmp, fuse_cdevpriv_dtor);
585812c3ccSTomohiro Kusumi 	fuse_dbg("open %s\n", ap->a_head.a_dev->si_name);
595812c3ccSTomohiro Kusumi 
605812c3ccSTomohiro Kusumi 	return 0;
615812c3ccSTomohiro Kusumi }
625812c3ccSTomohiro Kusumi 
635812c3ccSTomohiro Kusumi static int
fuse_device_close(struct dev_close_args * ap)645812c3ccSTomohiro Kusumi fuse_device_close(struct dev_close_args *ap)
655812c3ccSTomohiro Kusumi {
665812c3ccSTomohiro Kusumi 	struct fuse_mount *fmp;
675812c3ccSTomohiro Kusumi 	int error;
685812c3ccSTomohiro Kusumi 
695812c3ccSTomohiro Kusumi 	error = devfs_get_cdevpriv(ap->a_fp, (void**)&fmp);
705812c3ccSTomohiro Kusumi 	if (error)
715812c3ccSTomohiro Kusumi 		return error;
725812c3ccSTomohiro Kusumi 	KKASSERT(fmp);
735812c3ccSTomohiro Kusumi 
745812c3ccSTomohiro Kusumi 	/* XXX Can't call this on device close due to devfs bug... */
755812c3ccSTomohiro Kusumi 	//fuse_cdevpriv_close(fmp);
765812c3ccSTomohiro Kusumi 	fuse_dbg("close %s\n", ap->a_head.a_dev->si_name);
775812c3ccSTomohiro Kusumi 
785812c3ccSTomohiro Kusumi 	return 0;
795812c3ccSTomohiro Kusumi }
805812c3ccSTomohiro Kusumi 
815812c3ccSTomohiro Kusumi static int
fuse_cdevpriv_close(struct fuse_mount * fmp)825812c3ccSTomohiro Kusumi fuse_cdevpriv_close(struct fuse_mount *fmp)
835812c3ccSTomohiro Kusumi {
845812c3ccSTomohiro Kusumi 	if (!fmp->devvp) {
855812c3ccSTomohiro Kusumi 		fuse_print("/dev/%s not associated with FUSE mount\n",
865812c3ccSTomohiro Kusumi 		    fuse_dev->si_name);
875812c3ccSTomohiro Kusumi 		return ENODEV;
885812c3ccSTomohiro Kusumi 	}
895812c3ccSTomohiro Kusumi 
905812c3ccSTomohiro Kusumi 	mtx_lock(&fmp->mnt_lock);
915812c3ccSTomohiro Kusumi 	if (fuse_mount_kill(fmp) == -1)
925812c3ccSTomohiro Kusumi 		KNOTE(&fmp->kq.ki_note, 0);
935812c3ccSTomohiro Kusumi 	KKASSERT(fmp->devvp);
945812c3ccSTomohiro Kusumi 	mtx_unlock(&fmp->mnt_lock);
955812c3ccSTomohiro Kusumi 
965812c3ccSTomohiro Kusumi 	return 0;
975812c3ccSTomohiro Kusumi }
985812c3ccSTomohiro Kusumi 
995812c3ccSTomohiro Kusumi /* Call with ->ipc_lock held. */
1005812c3ccSTomohiro Kusumi static void
fuse_device_clear(struct fuse_mount * fmp)1015812c3ccSTomohiro Kusumi fuse_device_clear(struct fuse_mount *fmp)
1025812c3ccSTomohiro Kusumi {
1035812c3ccSTomohiro Kusumi 	struct fuse_ipc *fip;
1045812c3ccSTomohiro Kusumi 
105*1a8e5e4cSMatthew Dillon 	while ((fip = TAILQ_FIRST(&fmp->request_head))) {
1065812c3ccSTomohiro Kusumi 		TAILQ_REMOVE(&fmp->request_head, fip, request_entry);
107*1a8e5e4cSMatthew Dillon 		if (atomic_swap_int(&fip->sent, 1) == -1)
108*1a8e5e4cSMatthew Dillon 			wakeup(fip);
109*1a8e5e4cSMatthew Dillon 	}
1105812c3ccSTomohiro Kusumi 
1115812c3ccSTomohiro Kusumi 	while ((fip = TAILQ_FIRST(&fmp->reply_head))) {
1125812c3ccSTomohiro Kusumi 		TAILQ_REMOVE(&fmp->reply_head, fip, reply_entry);
1135812c3ccSTomohiro Kusumi 		if (fuse_ipc_test_and_set_replied(fip))
1145812c3ccSTomohiro Kusumi 			wakeup(fip);
1155812c3ccSTomohiro Kusumi 	}
1165812c3ccSTomohiro Kusumi }
1175812c3ccSTomohiro Kusumi 
1185812c3ccSTomohiro Kusumi static int
fuse_device_read(struct dev_read_args * ap)1195812c3ccSTomohiro Kusumi fuse_device_read(struct dev_read_args *ap)
1205812c3ccSTomohiro Kusumi {
1215812c3ccSTomohiro Kusumi 	struct uio *uio = ap->a_uio;
1225812c3ccSTomohiro Kusumi 	struct fuse_mount *fmp;
1235812c3ccSTomohiro Kusumi 	struct fuse_ipc *fip;
1245812c3ccSTomohiro Kusumi 	int error;
1255812c3ccSTomohiro Kusumi 
1265812c3ccSTomohiro Kusumi 	error = devfs_get_cdevpriv(ap->a_fp, (void**)&fmp);
1275812c3ccSTomohiro Kusumi 	if (error)
1285812c3ccSTomohiro Kusumi 		return error;
1295812c3ccSTomohiro Kusumi 
1305812c3ccSTomohiro Kusumi 	if (fuse_test_dead(fmp))
1315812c3ccSTomohiro Kusumi 		return ENOTCONN;
1325812c3ccSTomohiro Kusumi 
1335812c3ccSTomohiro Kusumi 	mtx_lock(&fmp->ipc_lock);
1345812c3ccSTomohiro Kusumi 	while (!(fip = TAILQ_FIRST(&fmp->request_head))) {
1355812c3ccSTomohiro Kusumi 		error = mtxsleep(fmp, &fmp->ipc_lock, PCATCH, "ftxc", 0);
1365812c3ccSTomohiro Kusumi 		if (fuse_test_dead(fmp)) {
1375812c3ccSTomohiro Kusumi 			fuse_device_clear(fmp);
1385812c3ccSTomohiro Kusumi 			mtx_unlock(&fmp->ipc_lock);
1395812c3ccSTomohiro Kusumi 			fuse_dbg("error=%d dead\n", error);
1405812c3ccSTomohiro Kusumi 			return ENOTCONN;
1415812c3ccSTomohiro Kusumi 		}
1425812c3ccSTomohiro Kusumi 		if (error) {
1435812c3ccSTomohiro Kusumi 			mtx_unlock(&fmp->ipc_lock);
1445812c3ccSTomohiro Kusumi 			fuse_dbg("error=%d\n", error);
1455812c3ccSTomohiro Kusumi 			return error;
1465812c3ccSTomohiro Kusumi 		}
1475812c3ccSTomohiro Kusumi 	}
1485812c3ccSTomohiro Kusumi 	TAILQ_REMOVE(&fmp->request_head, fip, request_entry);
1495812c3ccSTomohiro Kusumi 	mtx_unlock(&fmp->ipc_lock);
1505812c3ccSTomohiro Kusumi 
1515812c3ccSTomohiro Kusumi 	fuse_dbgipc(fip, 0, "");
1525812c3ccSTomohiro Kusumi 
1535812c3ccSTomohiro Kusumi 	if (uio->uio_resid < fuse_in_size(fip))
154*1a8e5e4cSMatthew Dillon 		error = EILSEQ;
155*1a8e5e4cSMatthew Dillon 	else
156*1a8e5e4cSMatthew Dillon 		error = uiomove(fuse_in(fip), fuse_in_size(fip), uio);
1575812c3ccSTomohiro Kusumi 
158*1a8e5e4cSMatthew Dillon 	if (atomic_swap_int(&fip->sent, 1) == -1)
159*1a8e5e4cSMatthew Dillon 		wakeup(fip);
160*1a8e5e4cSMatthew Dillon 
161*1a8e5e4cSMatthew Dillon 	return error;
1625812c3ccSTomohiro Kusumi }
1635812c3ccSTomohiro Kusumi 
1645812c3ccSTomohiro Kusumi static int
fuse_device_write(struct dev_write_args * ap)1655812c3ccSTomohiro Kusumi fuse_device_write(struct dev_write_args *ap)
1665812c3ccSTomohiro Kusumi {
1675812c3ccSTomohiro Kusumi 	struct uio *uio = ap->a_uio;
1685812c3ccSTomohiro Kusumi 	struct fuse_mount *fmp;
1690d020c7bSTomohiro Kusumi 	struct fuse_ipc *fip;
1705812c3ccSTomohiro Kusumi 	struct fuse_buf fb;
1715812c3ccSTomohiro Kusumi 	struct fuse_in_header *ihd;
1725812c3ccSTomohiro Kusumi 	struct fuse_out_header *ohd;
1735812c3ccSTomohiro Kusumi 	int error;
1745812c3ccSTomohiro Kusumi 
1755812c3ccSTomohiro Kusumi 	error = devfs_get_cdevpriv(ap->a_fp, (void**)&fmp);
1765812c3ccSTomohiro Kusumi 	if (error)
1775812c3ccSTomohiro Kusumi 		return error;
1785812c3ccSTomohiro Kusumi 
1795812c3ccSTomohiro Kusumi 	if (uio->uio_resid < sizeof(*ohd))
1805812c3ccSTomohiro Kusumi 		return EILSEQ;
1815812c3ccSTomohiro Kusumi 
1825812c3ccSTomohiro Kusumi 	fuse_buf_alloc(&fb, uio->uio_resid);
1835812c3ccSTomohiro Kusumi 	error = uiomove(fb.buf, uio->uio_resid, uio);
1845812c3ccSTomohiro Kusumi 	if (error) {
1855812c3ccSTomohiro Kusumi 		fuse_buf_free(&fb);
1865812c3ccSTomohiro Kusumi 		return error;
1875812c3ccSTomohiro Kusumi 	}
1885812c3ccSTomohiro Kusumi 	ohd = fb.buf;
1895812c3ccSTomohiro Kusumi 
1905812c3ccSTomohiro Kusumi 	mtx_lock(&fmp->ipc_lock);
1910d020c7bSTomohiro Kusumi 	TAILQ_FOREACH(fip, &fmp->reply_head, reply_entry) {
1925812c3ccSTomohiro Kusumi 		if (fip->unique == ohd->unique) {
1935812c3ccSTomohiro Kusumi 			TAILQ_REMOVE(&fmp->reply_head, fip, reply_entry);
1945812c3ccSTomohiro Kusumi 			break;
1955812c3ccSTomohiro Kusumi 		}
1965812c3ccSTomohiro Kusumi 	}
1975812c3ccSTomohiro Kusumi 	mtx_unlock(&fmp->ipc_lock);
1985812c3ccSTomohiro Kusumi 
1990d020c7bSTomohiro Kusumi 	if (!fip) {
2005812c3ccSTomohiro Kusumi 		fuse_dbg("unique=%ju not found\n", ohd->unique);
2015812c3ccSTomohiro Kusumi 		fuse_buf_free(&fb);
2025812c3ccSTomohiro Kusumi 		return ENOMSG;
2035812c3ccSTomohiro Kusumi 	}
2045812c3ccSTomohiro Kusumi 
2055812c3ccSTomohiro Kusumi 	fip->reply = fb;
2065812c3ccSTomohiro Kusumi 	ihd = fuse_in(fip);
2075812c3ccSTomohiro Kusumi 
2085812c3ccSTomohiro Kusumi 	/* Non zero ohd->error is not /dev/fuse write error. */
2095812c3ccSTomohiro Kusumi 	if (ohd->error == -ENOSYS) {
2105812c3ccSTomohiro Kusumi 		fuse_set_nosys(fmp, ihd->opcode);
2115812c3ccSTomohiro Kusumi 		fuse_dbgipc(fip, ohd->error, "ENOSYS");
2125812c3ccSTomohiro Kusumi 	} else if (!ohd->error && fuse_audit_length(ihd, ohd)) {
2135812c3ccSTomohiro Kusumi 		error = EPROTO;
2145812c3ccSTomohiro Kusumi 		fuse_dbgipc(fip, error, "audit");
2155812c3ccSTomohiro Kusumi 	} else
2165812c3ccSTomohiro Kusumi 		fuse_dbgipc(fip, 0, "");
2175812c3ccSTomohiro Kusumi 
2185812c3ccSTomohiro Kusumi 	/* Complete the IPC regardless of above result. */
2195812c3ccSTomohiro Kusumi 	if (fuse_ipc_test_and_set_replied(fip))
2205812c3ccSTomohiro Kusumi 		wakeup(fip);
2215812c3ccSTomohiro Kusumi 
2225812c3ccSTomohiro Kusumi 	return error;
2235812c3ccSTomohiro Kusumi }
2245812c3ccSTomohiro Kusumi 
2255812c3ccSTomohiro Kusumi static void filt_fusedevdetach(struct knote*);
2265812c3ccSTomohiro Kusumi static int filt_fusedevread(struct knote*, long);
2275812c3ccSTomohiro Kusumi static int filt_fusedevwrite(struct knote*, long);
2285812c3ccSTomohiro Kusumi 
2295812c3ccSTomohiro Kusumi static struct filterops fusedevread_filterops =
2305812c3ccSTomohiro Kusumi 	{ FILTEROP_ISFD,
2315812c3ccSTomohiro Kusumi 	  NULL, filt_fusedevdetach, filt_fusedevread };
2325812c3ccSTomohiro Kusumi static struct filterops fusedevwrite_filterops =
2335812c3ccSTomohiro Kusumi 	{ FILTEROP_ISFD,
2345812c3ccSTomohiro Kusumi 	  NULL, filt_fusedevdetach, filt_fusedevwrite };
2355812c3ccSTomohiro Kusumi 
2365812c3ccSTomohiro Kusumi static int
fuse_device_kqfilter(struct dev_kqfilter_args * ap)2375812c3ccSTomohiro Kusumi fuse_device_kqfilter(struct dev_kqfilter_args *ap)
2385812c3ccSTomohiro Kusumi {
2395812c3ccSTomohiro Kusumi 	struct knote *kn = ap->a_kn;
2405812c3ccSTomohiro Kusumi 	struct klist *klist;
2415812c3ccSTomohiro Kusumi 	struct fuse_mount *fmp;
2425812c3ccSTomohiro Kusumi 	int error;
2435812c3ccSTomohiro Kusumi 
2445812c3ccSTomohiro Kusumi 	error = devfs_get_cdevpriv(ap->a_fp, (void**)&fmp);
2455812c3ccSTomohiro Kusumi 	if (error) {
2465812c3ccSTomohiro Kusumi 		ap->a_result = error;
2475812c3ccSTomohiro Kusumi 		return 0;
2485812c3ccSTomohiro Kusumi 	}
2495812c3ccSTomohiro Kusumi 
2505812c3ccSTomohiro Kusumi 	ap->a_result = 0;
2515812c3ccSTomohiro Kusumi 
2525812c3ccSTomohiro Kusumi 	switch (kn->kn_filter) {
2535812c3ccSTomohiro Kusumi 	case EVFILT_READ:
2545812c3ccSTomohiro Kusumi 		kn->kn_fop = &fusedevread_filterops;
2555812c3ccSTomohiro Kusumi 		kn->kn_hook = (caddr_t)fmp;
2565812c3ccSTomohiro Kusumi 		break;
2575812c3ccSTomohiro Kusumi 	case EVFILT_WRITE:
2585812c3ccSTomohiro Kusumi 		kn->kn_fop = &fusedevwrite_filterops;
2595812c3ccSTomohiro Kusumi 		kn->kn_hook = (caddr_t)fmp;
2605812c3ccSTomohiro Kusumi 		break;
2615812c3ccSTomohiro Kusumi 	default:
2625812c3ccSTomohiro Kusumi 		ap->a_result = EOPNOTSUPP;
2635812c3ccSTomohiro Kusumi 		return 0;
2645812c3ccSTomohiro Kusumi 	}
2655812c3ccSTomohiro Kusumi 
2665812c3ccSTomohiro Kusumi 	klist = &fmp->kq.ki_note;
2675812c3ccSTomohiro Kusumi 	knote_insert(klist, kn);
2685812c3ccSTomohiro Kusumi 
2695812c3ccSTomohiro Kusumi 	return 0;
2705812c3ccSTomohiro Kusumi }
2715812c3ccSTomohiro Kusumi 
2725812c3ccSTomohiro Kusumi static void
filt_fusedevdetach(struct knote * kn)2735812c3ccSTomohiro Kusumi filt_fusedevdetach(struct knote *kn)
2745812c3ccSTomohiro Kusumi {
2755812c3ccSTomohiro Kusumi 	struct fuse_mount *fmp = (struct fuse_mount*)kn->kn_hook;
2765812c3ccSTomohiro Kusumi 	struct klist *klist = &fmp->kq.ki_note;
2775812c3ccSTomohiro Kusumi 
2785812c3ccSTomohiro Kusumi 	knote_remove(klist, kn);
2795812c3ccSTomohiro Kusumi }
2805812c3ccSTomohiro Kusumi 
2815812c3ccSTomohiro Kusumi static int
filt_fusedevread(struct knote * kn,long hint)2825812c3ccSTomohiro Kusumi filt_fusedevread(struct knote *kn, long hint)
2835812c3ccSTomohiro Kusumi {
2845812c3ccSTomohiro Kusumi 	struct fuse_mount *fmp = (struct fuse_mount*)kn->kn_hook;
2855812c3ccSTomohiro Kusumi 	int ready = 0;
2865812c3ccSTomohiro Kusumi 
2875812c3ccSTomohiro Kusumi 	mtx_lock(&fmp->ipc_lock);
2885812c3ccSTomohiro Kusumi 	if (!TAILQ_EMPTY(&fmp->request_head))
2895812c3ccSTomohiro Kusumi 		ready = 1;
2905812c3ccSTomohiro Kusumi 	mtx_unlock(&fmp->ipc_lock);
2915812c3ccSTomohiro Kusumi 
2925812c3ccSTomohiro Kusumi 	return ready;
2935812c3ccSTomohiro Kusumi }
2945812c3ccSTomohiro Kusumi 
2955812c3ccSTomohiro Kusumi static int
filt_fusedevwrite(struct knote * kn,long hint)2965812c3ccSTomohiro Kusumi filt_fusedevwrite(struct knote *kn, long hint)
2975812c3ccSTomohiro Kusumi {
2985812c3ccSTomohiro Kusumi 	return 1;
2995812c3ccSTomohiro Kusumi }
3005812c3ccSTomohiro Kusumi 
3015812c3ccSTomohiro Kusumi static struct dev_ops fuse_device_cdevsw = {
3025812c3ccSTomohiro Kusumi 	{ "fuse", 0, D_MPSAFE, },
3035812c3ccSTomohiro Kusumi 	.d_open = fuse_device_open,
3045812c3ccSTomohiro Kusumi 	.d_close = fuse_device_close,
3055812c3ccSTomohiro Kusumi 	.d_read = fuse_device_read,
3065812c3ccSTomohiro Kusumi 	.d_write = fuse_device_write,
3075812c3ccSTomohiro Kusumi 	.d_kqfilter = fuse_device_kqfilter,
3085812c3ccSTomohiro Kusumi };
3095812c3ccSTomohiro Kusumi 
3105812c3ccSTomohiro Kusumi int
fuse_device_init(void)3115812c3ccSTomohiro Kusumi fuse_device_init(void)
3125812c3ccSTomohiro Kusumi {
3135812c3ccSTomohiro Kusumi 	fuse_dev = make_dev(&fuse_device_cdevsw, 0, UID_ROOT, GID_OPERATOR,
3145812c3ccSTomohiro Kusumi 	    S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, "fuse");
3155812c3ccSTomohiro Kusumi 
3165812c3ccSTomohiro Kusumi 	if (!fuse_dev)
3175812c3ccSTomohiro Kusumi 		return ENOMEM;
3185812c3ccSTomohiro Kusumi 
3195812c3ccSTomohiro Kusumi 	return 0;
3205812c3ccSTomohiro Kusumi }
3215812c3ccSTomohiro Kusumi 
3225812c3ccSTomohiro Kusumi void
fuse_device_cleanup(void)3235812c3ccSTomohiro Kusumi fuse_device_cleanup(void)
3245812c3ccSTomohiro Kusumi {
3255812c3ccSTomohiro Kusumi 	KKASSERT(fuse_dev);
3265812c3ccSTomohiro Kusumi 	destroy_dev(fuse_dev);
3275812c3ccSTomohiro Kusumi }
328