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