1*fa0f6e62SHans Petter Selasky /* $FreeBSD$ */ 2*fa0f6e62SHans Petter Selasky /*- 3*fa0f6e62SHans Petter Selasky * Copyright (c) 2010-2013 Hans Petter Selasky. All rights reserved. 4*fa0f6e62SHans Petter Selasky * 5*fa0f6e62SHans Petter Selasky * Redistribution and use in source and binary forms, with or without 6*fa0f6e62SHans Petter Selasky * modification, are permitted provided that the following conditions 7*fa0f6e62SHans Petter Selasky * are met: 8*fa0f6e62SHans Petter Selasky * 1. Redistributions of source code must retain the above copyright 9*fa0f6e62SHans Petter Selasky * notice, this list of conditions and the following disclaimer. 10*fa0f6e62SHans Petter Selasky * 2. Redistributions in binary form must reproduce the above copyright 11*fa0f6e62SHans Petter Selasky * notice, this list of conditions and the following disclaimer in the 12*fa0f6e62SHans Petter Selasky * documentation and/or other materials provided with the distribution. 13*fa0f6e62SHans Petter Selasky * 14*fa0f6e62SHans Petter Selasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*fa0f6e62SHans Petter Selasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*fa0f6e62SHans Petter Selasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*fa0f6e62SHans Petter Selasky * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*fa0f6e62SHans Petter Selasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*fa0f6e62SHans Petter Selasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*fa0f6e62SHans Petter Selasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*fa0f6e62SHans Petter Selasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*fa0f6e62SHans Petter Selasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*fa0f6e62SHans Petter Selasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*fa0f6e62SHans Petter Selasky * SUCH DAMAGE. 25*fa0f6e62SHans Petter Selasky */ 26*fa0f6e62SHans Petter Selasky 27*fa0f6e62SHans Petter Selasky #include "opt_compat.h" 28*fa0f6e62SHans Petter Selasky 29*fa0f6e62SHans Petter Selasky #include <sys/stdint.h> 30*fa0f6e62SHans Petter Selasky #include <sys/stddef.h> 31*fa0f6e62SHans Petter Selasky #include <sys/param.h> 32*fa0f6e62SHans Petter Selasky #include <sys/types.h> 33*fa0f6e62SHans Petter Selasky #include <sys/systm.h> 34*fa0f6e62SHans Petter Selasky #include <sys/conf.h> 35*fa0f6e62SHans Petter Selasky #include <sys/kernel.h> 36*fa0f6e62SHans Petter Selasky #include <sys/bus.h> 37*fa0f6e62SHans Petter Selasky #include <sys/linker_set.h> 38*fa0f6e62SHans Petter Selasky #include <sys/module.h> 39*fa0f6e62SHans Petter Selasky #include <sys/lock.h> 40*fa0f6e62SHans Petter Selasky #include <sys/mutex.h> 41*fa0f6e62SHans Petter Selasky #include <sys/condvar.h> 42*fa0f6e62SHans Petter Selasky #include <sys/sysctl.h> 43*fa0f6e62SHans Petter Selasky #include <sys/unistd.h> 44*fa0f6e62SHans Petter Selasky #include <sys/malloc.h> 45*fa0f6e62SHans Petter Selasky #include <sys/priv.h> 46*fa0f6e62SHans Petter Selasky #include <sys/uio.h> 47*fa0f6e62SHans Petter Selasky #include <sys/poll.h> 48*fa0f6e62SHans Petter Selasky #include <sys/sx.h> 49*fa0f6e62SHans Petter Selasky #include <sys/queue.h> 50*fa0f6e62SHans Petter Selasky #include <sys/fcntl.h> 51*fa0f6e62SHans Petter Selasky #include <sys/proc.h> 52*fa0f6e62SHans Petter Selasky #include <sys/vnode.h> 53*fa0f6e62SHans Petter Selasky #include <sys/selinfo.h> 54*fa0f6e62SHans Petter Selasky #include <sys/ptrace.h> 55*fa0f6e62SHans Petter Selasky 56*fa0f6e62SHans Petter Selasky #include <machine/bus.h> 57*fa0f6e62SHans Petter Selasky 58*fa0f6e62SHans Petter Selasky #include <vm/vm.h> 59*fa0f6e62SHans Petter Selasky #include <vm/pmap.h> 60*fa0f6e62SHans Petter Selasky 61*fa0f6e62SHans Petter Selasky #include <fs/cuse/cuse_defs.h> 62*fa0f6e62SHans Petter Selasky #include <fs/cuse/cuse_ioctl.h> 63*fa0f6e62SHans Petter Selasky 64*fa0f6e62SHans Petter Selasky MODULE_VERSION(cuse, 1); 65*fa0f6e62SHans Petter Selasky 66*fa0f6e62SHans Petter Selasky #define NBUSY ((uint8_t *)1) 67*fa0f6e62SHans Petter Selasky 68*fa0f6e62SHans Petter Selasky #ifdef FEATURE 69*fa0f6e62SHans Petter Selasky FEATURE(cuse, "Userspace character devices"); 70*fa0f6e62SHans Petter Selasky #endif 71*fa0f6e62SHans Petter Selasky 72*fa0f6e62SHans Petter Selasky struct cuse_command; 73*fa0f6e62SHans Petter Selasky struct cuse_server; 74*fa0f6e62SHans Petter Selasky struct cuse_client; 75*fa0f6e62SHans Petter Selasky 76*fa0f6e62SHans Petter Selasky struct cuse_client_command { 77*fa0f6e62SHans Petter Selasky TAILQ_ENTRY(cuse_client_command) entry; 78*fa0f6e62SHans Petter Selasky struct cuse_command sub; 79*fa0f6e62SHans Petter Selasky struct sx sx; 80*fa0f6e62SHans Petter Selasky struct cv cv; 81*fa0f6e62SHans Petter Selasky struct thread *entered; 82*fa0f6e62SHans Petter Selasky struct cuse_client *client; 83*fa0f6e62SHans Petter Selasky struct proc *proc_curr; 84*fa0f6e62SHans Petter Selasky int proc_refs; 85*fa0f6e62SHans Petter Selasky int got_signal; 86*fa0f6e62SHans Petter Selasky int error; 87*fa0f6e62SHans Petter Selasky int command; 88*fa0f6e62SHans Petter Selasky }; 89*fa0f6e62SHans Petter Selasky 90*fa0f6e62SHans Petter Selasky struct cuse_memory { 91*fa0f6e62SHans Petter Selasky struct cuse_server *owner; 92*fa0f6e62SHans Petter Selasky uint8_t *virtaddr; 93*fa0f6e62SHans Petter Selasky uint32_t page_count; 94*fa0f6e62SHans Petter Selasky uint32_t is_allocated; 95*fa0f6e62SHans Petter Selasky }; 96*fa0f6e62SHans Petter Selasky 97*fa0f6e62SHans Petter Selasky struct cuse_server_dev { 98*fa0f6e62SHans Petter Selasky TAILQ_ENTRY(cuse_server_dev) entry; 99*fa0f6e62SHans Petter Selasky struct cuse_server *server; 100*fa0f6e62SHans Petter Selasky struct cdev *kern_dev; 101*fa0f6e62SHans Petter Selasky struct cuse_dev *user_dev; 102*fa0f6e62SHans Petter Selasky }; 103*fa0f6e62SHans Petter Selasky 104*fa0f6e62SHans Petter Selasky struct cuse_server { 105*fa0f6e62SHans Petter Selasky TAILQ_ENTRY(cuse_server) entry; 106*fa0f6e62SHans Petter Selasky TAILQ_HEAD(, cuse_client_command) head; 107*fa0f6e62SHans Petter Selasky TAILQ_HEAD(, cuse_server_dev) hdev; 108*fa0f6e62SHans Petter Selasky TAILQ_HEAD(, cuse_client) hcli; 109*fa0f6e62SHans Petter Selasky struct cv cv; 110*fa0f6e62SHans Petter Selasky struct selinfo selinfo; 111*fa0f6e62SHans Petter Selasky int is_closing; 112*fa0f6e62SHans Petter Selasky int refs; 113*fa0f6e62SHans Petter Selasky }; 114*fa0f6e62SHans Petter Selasky 115*fa0f6e62SHans Petter Selasky struct cuse_client { 116*fa0f6e62SHans Petter Selasky TAILQ_ENTRY(cuse_client) entry; 117*fa0f6e62SHans Petter Selasky TAILQ_ENTRY(cuse_client) entry_ref; 118*fa0f6e62SHans Petter Selasky struct cuse_client_command cmds[CUSE_CMD_MAX]; 119*fa0f6e62SHans Petter Selasky struct cuse_server *server; 120*fa0f6e62SHans Petter Selasky struct cuse_server_dev *server_dev; 121*fa0f6e62SHans Petter Selasky 122*fa0f6e62SHans Petter Selasky uint8_t ioctl_buffer[CUSE_BUFFER_MAX] __aligned(4); 123*fa0f6e62SHans Petter Selasky 124*fa0f6e62SHans Petter Selasky int fflags; /* file flags */ 125*fa0f6e62SHans Petter Selasky int cflags; /* client flags */ 126*fa0f6e62SHans Petter Selasky #define CUSE_CLI_IS_CLOSING 0x01 127*fa0f6e62SHans Petter Selasky #define CUSE_CLI_KNOTE_NEED_READ 0x02 128*fa0f6e62SHans Petter Selasky #define CUSE_CLI_KNOTE_NEED_WRITE 0x04 129*fa0f6e62SHans Petter Selasky #define CUSE_CLI_KNOTE_HAS_READ 0x08 130*fa0f6e62SHans Petter Selasky #define CUSE_CLI_KNOTE_HAS_WRITE 0x10 131*fa0f6e62SHans Petter Selasky }; 132*fa0f6e62SHans Petter Selasky 133*fa0f6e62SHans Petter Selasky #define CUSE_CLIENT_CLOSING(pcc) \ 134*fa0f6e62SHans Petter Selasky ((pcc)->cflags & CUSE_CLI_IS_CLOSING) 135*fa0f6e62SHans Petter Selasky 136*fa0f6e62SHans Petter Selasky static MALLOC_DEFINE(M_CUSE, "cuse", "CUSE memory"); 137*fa0f6e62SHans Petter Selasky 138*fa0f6e62SHans Petter Selasky static TAILQ_HEAD(, cuse_server) cuse_server_head; 139*fa0f6e62SHans Petter Selasky static struct mtx cuse_mtx; 140*fa0f6e62SHans Petter Selasky static struct cdev *cuse_dev; 141*fa0f6e62SHans Petter Selasky static struct cuse_server *cuse_alloc_unit[CUSE_DEVICES_MAX]; 142*fa0f6e62SHans Petter Selasky static int cuse_alloc_unit_id[CUSE_DEVICES_MAX]; 143*fa0f6e62SHans Petter Selasky static struct cuse_memory cuse_mem[CUSE_ALLOC_UNIT_MAX]; 144*fa0f6e62SHans Petter Selasky 145*fa0f6e62SHans Petter Selasky static void cuse_client_kqfilter_read_detach(struct knote *kn); 146*fa0f6e62SHans Petter Selasky static void cuse_client_kqfilter_write_detach(struct knote *kn); 147*fa0f6e62SHans Petter Selasky static int cuse_client_kqfilter_read_event(struct knote *kn, long hint); 148*fa0f6e62SHans Petter Selasky static int cuse_client_kqfilter_write_event(struct knote *kn, long hint); 149*fa0f6e62SHans Petter Selasky 150*fa0f6e62SHans Petter Selasky static struct filterops cuse_client_kqfilter_read_ops = { 151*fa0f6e62SHans Petter Selasky .f_isfd = 1, 152*fa0f6e62SHans Petter Selasky .f_detach = cuse_client_kqfilter_read_detach, 153*fa0f6e62SHans Petter Selasky .f_event = cuse_client_kqfilter_read_event, 154*fa0f6e62SHans Petter Selasky }; 155*fa0f6e62SHans Petter Selasky 156*fa0f6e62SHans Petter Selasky static struct filterops cuse_client_kqfilter_write_ops = { 157*fa0f6e62SHans Petter Selasky .f_isfd = 1, 158*fa0f6e62SHans Petter Selasky .f_detach = cuse_client_kqfilter_write_detach, 159*fa0f6e62SHans Petter Selasky .f_event = cuse_client_kqfilter_write_event, 160*fa0f6e62SHans Petter Selasky }; 161*fa0f6e62SHans Petter Selasky 162*fa0f6e62SHans Petter Selasky static d_open_t cuse_client_open; 163*fa0f6e62SHans Petter Selasky static d_close_t cuse_client_close; 164*fa0f6e62SHans Petter Selasky static d_ioctl_t cuse_client_ioctl; 165*fa0f6e62SHans Petter Selasky static d_read_t cuse_client_read; 166*fa0f6e62SHans Petter Selasky static d_write_t cuse_client_write; 167*fa0f6e62SHans Petter Selasky static d_poll_t cuse_client_poll; 168*fa0f6e62SHans Petter Selasky static d_mmap_t cuse_client_mmap; 169*fa0f6e62SHans Petter Selasky static d_kqfilter_t cuse_client_kqfilter; 170*fa0f6e62SHans Petter Selasky 171*fa0f6e62SHans Petter Selasky static struct cdevsw cuse_client_devsw = { 172*fa0f6e62SHans Petter Selasky .d_version = D_VERSION, 173*fa0f6e62SHans Petter Selasky .d_open = cuse_client_open, 174*fa0f6e62SHans Petter Selasky .d_close = cuse_client_close, 175*fa0f6e62SHans Petter Selasky .d_ioctl = cuse_client_ioctl, 176*fa0f6e62SHans Petter Selasky .d_name = "cuse_client", 177*fa0f6e62SHans Petter Selasky .d_flags = D_TRACKCLOSE, 178*fa0f6e62SHans Petter Selasky .d_read = cuse_client_read, 179*fa0f6e62SHans Petter Selasky .d_write = cuse_client_write, 180*fa0f6e62SHans Petter Selasky .d_poll = cuse_client_poll, 181*fa0f6e62SHans Petter Selasky .d_mmap = cuse_client_mmap, 182*fa0f6e62SHans Petter Selasky .d_kqfilter = cuse_client_kqfilter, 183*fa0f6e62SHans Petter Selasky }; 184*fa0f6e62SHans Petter Selasky 185*fa0f6e62SHans Petter Selasky static d_open_t cuse_server_open; 186*fa0f6e62SHans Petter Selasky static d_close_t cuse_server_close; 187*fa0f6e62SHans Petter Selasky static d_ioctl_t cuse_server_ioctl; 188*fa0f6e62SHans Petter Selasky static d_read_t cuse_server_read; 189*fa0f6e62SHans Petter Selasky static d_write_t cuse_server_write; 190*fa0f6e62SHans Petter Selasky static d_poll_t cuse_server_poll; 191*fa0f6e62SHans Petter Selasky static d_mmap_t cuse_server_mmap; 192*fa0f6e62SHans Petter Selasky 193*fa0f6e62SHans Petter Selasky static struct cdevsw cuse_server_devsw = { 194*fa0f6e62SHans Petter Selasky .d_version = D_VERSION, 195*fa0f6e62SHans Petter Selasky .d_open = cuse_server_open, 196*fa0f6e62SHans Petter Selasky .d_close = cuse_server_close, 197*fa0f6e62SHans Petter Selasky .d_ioctl = cuse_server_ioctl, 198*fa0f6e62SHans Petter Selasky .d_name = "cuse_server", 199*fa0f6e62SHans Petter Selasky .d_flags = D_TRACKCLOSE, 200*fa0f6e62SHans Petter Selasky .d_read = cuse_server_read, 201*fa0f6e62SHans Petter Selasky .d_write = cuse_server_write, 202*fa0f6e62SHans Petter Selasky .d_poll = cuse_server_poll, 203*fa0f6e62SHans Petter Selasky .d_mmap = cuse_server_mmap, 204*fa0f6e62SHans Petter Selasky }; 205*fa0f6e62SHans Petter Selasky 206*fa0f6e62SHans Petter Selasky static void cuse_client_is_closing(struct cuse_client *); 207*fa0f6e62SHans Petter Selasky static int cuse_free_unit_by_id_locked(struct cuse_server *, int); 208*fa0f6e62SHans Petter Selasky 209*fa0f6e62SHans Petter Selasky static void 210*fa0f6e62SHans Petter Selasky cuse_lock(void) 211*fa0f6e62SHans Petter Selasky { 212*fa0f6e62SHans Petter Selasky mtx_lock(&cuse_mtx); 213*fa0f6e62SHans Petter Selasky } 214*fa0f6e62SHans Petter Selasky 215*fa0f6e62SHans Petter Selasky static void 216*fa0f6e62SHans Petter Selasky cuse_unlock(void) 217*fa0f6e62SHans Petter Selasky { 218*fa0f6e62SHans Petter Selasky mtx_unlock(&cuse_mtx); 219*fa0f6e62SHans Petter Selasky } 220*fa0f6e62SHans Petter Selasky 221*fa0f6e62SHans Petter Selasky static void 222*fa0f6e62SHans Petter Selasky cuse_cmd_lock(struct cuse_client_command *pccmd) 223*fa0f6e62SHans Petter Selasky { 224*fa0f6e62SHans Petter Selasky sx_xlock(&pccmd->sx); 225*fa0f6e62SHans Petter Selasky } 226*fa0f6e62SHans Petter Selasky 227*fa0f6e62SHans Petter Selasky static void 228*fa0f6e62SHans Petter Selasky cuse_cmd_unlock(struct cuse_client_command *pccmd) 229*fa0f6e62SHans Petter Selasky { 230*fa0f6e62SHans Petter Selasky sx_xunlock(&pccmd->sx); 231*fa0f6e62SHans Petter Selasky } 232*fa0f6e62SHans Petter Selasky 233*fa0f6e62SHans Petter Selasky static void 234*fa0f6e62SHans Petter Selasky cuse_kern_init(void *arg) 235*fa0f6e62SHans Petter Selasky { 236*fa0f6e62SHans Petter Selasky TAILQ_INIT(&cuse_server_head); 237*fa0f6e62SHans Petter Selasky 238*fa0f6e62SHans Petter Selasky mtx_init(&cuse_mtx, "cuse-mtx", NULL, MTX_DEF); 239*fa0f6e62SHans Petter Selasky 240*fa0f6e62SHans Petter Selasky cuse_dev = make_dev(&cuse_server_devsw, 0, 241*fa0f6e62SHans Petter Selasky UID_ROOT, GID_OPERATOR, 0600, "cuse"); 242*fa0f6e62SHans Petter Selasky 243*fa0f6e62SHans Petter Selasky printf("Cuse v%d.%d.%d @ /dev/cuse\n", 244*fa0f6e62SHans Petter Selasky (CUSE_VERSION >> 16) & 0xFF, (CUSE_VERSION >> 8) & 0xFF, 245*fa0f6e62SHans Petter Selasky (CUSE_VERSION >> 0) & 0xFF); 246*fa0f6e62SHans Petter Selasky } 247*fa0f6e62SHans Petter Selasky 248*fa0f6e62SHans Petter Selasky SYSINIT(cuse_kern_init, SI_SUB_DEVFS, SI_ORDER_ANY, cuse_kern_init, 0); 249*fa0f6e62SHans Petter Selasky 250*fa0f6e62SHans Petter Selasky static void 251*fa0f6e62SHans Petter Selasky cuse_kern_uninit(void *arg) 252*fa0f6e62SHans Petter Selasky { 253*fa0f6e62SHans Petter Selasky void *ptr; 254*fa0f6e62SHans Petter Selasky 255*fa0f6e62SHans Petter Selasky while (1) { 256*fa0f6e62SHans Petter Selasky 257*fa0f6e62SHans Petter Selasky printf("Cuse: Please exit all /dev/cuse instances " 258*fa0f6e62SHans Petter Selasky "and processes which have used this device.\n"); 259*fa0f6e62SHans Petter Selasky 260*fa0f6e62SHans Petter Selasky pause("DRAIN", 2 * hz); 261*fa0f6e62SHans Petter Selasky 262*fa0f6e62SHans Petter Selasky cuse_lock(); 263*fa0f6e62SHans Petter Selasky ptr = TAILQ_FIRST(&cuse_server_head); 264*fa0f6e62SHans Petter Selasky cuse_unlock(); 265*fa0f6e62SHans Petter Selasky 266*fa0f6e62SHans Petter Selasky if (ptr == NULL) 267*fa0f6e62SHans Petter Selasky break; 268*fa0f6e62SHans Petter Selasky } 269*fa0f6e62SHans Petter Selasky 270*fa0f6e62SHans Petter Selasky if (cuse_dev != NULL) 271*fa0f6e62SHans Petter Selasky destroy_dev(cuse_dev); 272*fa0f6e62SHans Petter Selasky 273*fa0f6e62SHans Petter Selasky mtx_destroy(&cuse_mtx); 274*fa0f6e62SHans Petter Selasky } 275*fa0f6e62SHans Petter Selasky 276*fa0f6e62SHans Petter Selasky SYSUNINIT(cuse_kern_uninit, SI_SUB_DEVFS, SI_ORDER_ANY, cuse_kern_uninit, 0); 277*fa0f6e62SHans Petter Selasky 278*fa0f6e62SHans Petter Selasky static int 279*fa0f6e62SHans Petter Selasky cuse_server_get(struct cuse_server **ppcs) 280*fa0f6e62SHans Petter Selasky { 281*fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 282*fa0f6e62SHans Petter Selasky int error; 283*fa0f6e62SHans Petter Selasky 284*fa0f6e62SHans Petter Selasky error = devfs_get_cdevpriv((void **)&pcs); 285*fa0f6e62SHans Petter Selasky if (error != 0) { 286*fa0f6e62SHans Petter Selasky *ppcs = NULL; 287*fa0f6e62SHans Petter Selasky return (error); 288*fa0f6e62SHans Petter Selasky } 289*fa0f6e62SHans Petter Selasky /* check if closing */ 290*fa0f6e62SHans Petter Selasky cuse_lock(); 291*fa0f6e62SHans Petter Selasky if (pcs->is_closing) { 292*fa0f6e62SHans Petter Selasky cuse_unlock(); 293*fa0f6e62SHans Petter Selasky *ppcs = NULL; 294*fa0f6e62SHans Petter Selasky return (EINVAL); 295*fa0f6e62SHans Petter Selasky } 296*fa0f6e62SHans Petter Selasky cuse_unlock(); 297*fa0f6e62SHans Petter Selasky *ppcs = pcs; 298*fa0f6e62SHans Petter Selasky return (0); 299*fa0f6e62SHans Petter Selasky } 300*fa0f6e62SHans Petter Selasky 301*fa0f6e62SHans Petter Selasky static void 302*fa0f6e62SHans Petter Selasky cuse_server_is_closing(struct cuse_server *pcs) 303*fa0f6e62SHans Petter Selasky { 304*fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 305*fa0f6e62SHans Petter Selasky 306*fa0f6e62SHans Petter Selasky if (pcs->is_closing) 307*fa0f6e62SHans Petter Selasky return; 308*fa0f6e62SHans Petter Selasky 309*fa0f6e62SHans Petter Selasky pcs->is_closing = 1; 310*fa0f6e62SHans Petter Selasky 311*fa0f6e62SHans Petter Selasky TAILQ_FOREACH(pcc, &pcs->hcli, entry) { 312*fa0f6e62SHans Petter Selasky cuse_client_is_closing(pcc); 313*fa0f6e62SHans Petter Selasky } 314*fa0f6e62SHans Petter Selasky } 315*fa0f6e62SHans Petter Selasky 316*fa0f6e62SHans Petter Selasky static struct cuse_client_command * 317*fa0f6e62SHans Petter Selasky cuse_server_find_command(struct cuse_server *pcs, struct thread *td) 318*fa0f6e62SHans Petter Selasky { 319*fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 320*fa0f6e62SHans Petter Selasky int n; 321*fa0f6e62SHans Petter Selasky 322*fa0f6e62SHans Petter Selasky if (pcs->is_closing) 323*fa0f6e62SHans Petter Selasky goto done; 324*fa0f6e62SHans Petter Selasky 325*fa0f6e62SHans Petter Selasky TAILQ_FOREACH(pcc, &pcs->hcli, entry) { 326*fa0f6e62SHans Petter Selasky if (CUSE_CLIENT_CLOSING(pcc)) 327*fa0f6e62SHans Petter Selasky continue; 328*fa0f6e62SHans Petter Selasky for (n = 0; n != CUSE_CMD_MAX; n++) { 329*fa0f6e62SHans Petter Selasky if (pcc->cmds[n].entered == td) 330*fa0f6e62SHans Petter Selasky return (&pcc->cmds[n]); 331*fa0f6e62SHans Petter Selasky } 332*fa0f6e62SHans Petter Selasky } 333*fa0f6e62SHans Petter Selasky done: 334*fa0f6e62SHans Petter Selasky return (NULL); 335*fa0f6e62SHans Petter Selasky } 336*fa0f6e62SHans Petter Selasky 337*fa0f6e62SHans Petter Selasky static void 338*fa0f6e62SHans Petter Selasky cuse_str_filter(char *ptr) 339*fa0f6e62SHans Petter Selasky { 340*fa0f6e62SHans Petter Selasky int c; 341*fa0f6e62SHans Petter Selasky 342*fa0f6e62SHans Petter Selasky while (((c = *ptr) != 0)) { 343*fa0f6e62SHans Petter Selasky 344*fa0f6e62SHans Petter Selasky if ((c >= 'a') && (c <= 'z')) { 345*fa0f6e62SHans Petter Selasky ptr++; 346*fa0f6e62SHans Petter Selasky continue; 347*fa0f6e62SHans Petter Selasky } 348*fa0f6e62SHans Petter Selasky if ((c >= 'A') && (c <= 'Z')) { 349*fa0f6e62SHans Petter Selasky ptr++; 350*fa0f6e62SHans Petter Selasky continue; 351*fa0f6e62SHans Petter Selasky } 352*fa0f6e62SHans Petter Selasky if ((c >= '0') && (c <= '9')) { 353*fa0f6e62SHans Petter Selasky ptr++; 354*fa0f6e62SHans Petter Selasky continue; 355*fa0f6e62SHans Petter Selasky } 356*fa0f6e62SHans Petter Selasky if ((c == '.') || (c == '_') || (c == '/')) { 357*fa0f6e62SHans Petter Selasky ptr++; 358*fa0f6e62SHans Petter Selasky continue; 359*fa0f6e62SHans Petter Selasky } 360*fa0f6e62SHans Petter Selasky *ptr = '_'; 361*fa0f6e62SHans Petter Selasky 362*fa0f6e62SHans Petter Selasky ptr++; 363*fa0f6e62SHans Petter Selasky } 364*fa0f6e62SHans Petter Selasky } 365*fa0f6e62SHans Petter Selasky 366*fa0f6e62SHans Petter Selasky static int 367*fa0f6e62SHans Petter Selasky cuse_convert_error(int error) 368*fa0f6e62SHans Petter Selasky { 369*fa0f6e62SHans Petter Selasky ; /* indent fix */ 370*fa0f6e62SHans Petter Selasky switch (error) { 371*fa0f6e62SHans Petter Selasky case CUSE_ERR_NONE: 372*fa0f6e62SHans Petter Selasky return (0); 373*fa0f6e62SHans Petter Selasky case CUSE_ERR_BUSY: 374*fa0f6e62SHans Petter Selasky return (EBUSY); 375*fa0f6e62SHans Petter Selasky case CUSE_ERR_WOULDBLOCK: 376*fa0f6e62SHans Petter Selasky return (EWOULDBLOCK); 377*fa0f6e62SHans Petter Selasky case CUSE_ERR_INVALID: 378*fa0f6e62SHans Petter Selasky return (EINVAL); 379*fa0f6e62SHans Petter Selasky case CUSE_ERR_NO_MEMORY: 380*fa0f6e62SHans Petter Selasky return (ENOMEM); 381*fa0f6e62SHans Petter Selasky case CUSE_ERR_FAULT: 382*fa0f6e62SHans Petter Selasky return (EFAULT); 383*fa0f6e62SHans Petter Selasky case CUSE_ERR_SIGNAL: 384*fa0f6e62SHans Petter Selasky return (EINTR); 385*fa0f6e62SHans Petter Selasky default: 386*fa0f6e62SHans Petter Selasky return (ENXIO); 387*fa0f6e62SHans Petter Selasky } 388*fa0f6e62SHans Petter Selasky } 389*fa0f6e62SHans Petter Selasky 390*fa0f6e62SHans Petter Selasky static void 391*fa0f6e62SHans Petter Selasky cuse_server_free_memory(struct cuse_server *pcs) 392*fa0f6e62SHans Petter Selasky { 393*fa0f6e62SHans Petter Selasky struct cuse_memory *mem; 394*fa0f6e62SHans Petter Selasky uint32_t n; 395*fa0f6e62SHans Petter Selasky 396*fa0f6e62SHans Petter Selasky for (n = 0; n != CUSE_ALLOC_UNIT_MAX; n++) { 397*fa0f6e62SHans Petter Selasky mem = &cuse_mem[n]; 398*fa0f6e62SHans Petter Selasky 399*fa0f6e62SHans Petter Selasky /* this memory is never freed */ 400*fa0f6e62SHans Petter Selasky if (mem->owner == pcs) { 401*fa0f6e62SHans Petter Selasky mem->owner = NULL; 402*fa0f6e62SHans Petter Selasky mem->is_allocated = 0; 403*fa0f6e62SHans Petter Selasky } 404*fa0f6e62SHans Petter Selasky } 405*fa0f6e62SHans Petter Selasky } 406*fa0f6e62SHans Petter Selasky 407*fa0f6e62SHans Petter Selasky static int 408*fa0f6e62SHans Petter Selasky cuse_server_alloc_memory(struct cuse_server *pcs, 409*fa0f6e62SHans Petter Selasky struct cuse_memory *mem, uint32_t page_count) 410*fa0f6e62SHans Petter Selasky { 411*fa0f6e62SHans Petter Selasky void *ptr; 412*fa0f6e62SHans Petter Selasky int error; 413*fa0f6e62SHans Petter Selasky 414*fa0f6e62SHans Petter Selasky cuse_lock(); 415*fa0f6e62SHans Petter Selasky 416*fa0f6e62SHans Petter Selasky if (mem->virtaddr == NBUSY) { 417*fa0f6e62SHans Petter Selasky cuse_unlock(); 418*fa0f6e62SHans Petter Selasky return (EBUSY); 419*fa0f6e62SHans Petter Selasky } 420*fa0f6e62SHans Petter Selasky if (mem->virtaddr != NULL) { 421*fa0f6e62SHans Petter Selasky if (mem->is_allocated != 0) { 422*fa0f6e62SHans Petter Selasky cuse_unlock(); 423*fa0f6e62SHans Petter Selasky return (EBUSY); 424*fa0f6e62SHans Petter Selasky } 425*fa0f6e62SHans Petter Selasky if (mem->page_count == page_count) { 426*fa0f6e62SHans Petter Selasky mem->is_allocated = 1; 427*fa0f6e62SHans Petter Selasky mem->owner = pcs; 428*fa0f6e62SHans Petter Selasky cuse_unlock(); 429*fa0f6e62SHans Petter Selasky return (0); 430*fa0f6e62SHans Petter Selasky } 431*fa0f6e62SHans Petter Selasky cuse_unlock(); 432*fa0f6e62SHans Petter Selasky return (EBUSY); 433*fa0f6e62SHans Petter Selasky } 434*fa0f6e62SHans Petter Selasky memset(mem, 0, sizeof(*mem)); 435*fa0f6e62SHans Petter Selasky 436*fa0f6e62SHans Petter Selasky mem->virtaddr = NBUSY; 437*fa0f6e62SHans Petter Selasky 438*fa0f6e62SHans Petter Selasky cuse_unlock(); 439*fa0f6e62SHans Petter Selasky 440*fa0f6e62SHans Petter Selasky ptr = malloc(page_count * PAGE_SIZE, M_CUSE, M_WAITOK | M_ZERO); 441*fa0f6e62SHans Petter Selasky if (ptr == NULL) 442*fa0f6e62SHans Petter Selasky error = ENOMEM; 443*fa0f6e62SHans Petter Selasky else 444*fa0f6e62SHans Petter Selasky error = 0; 445*fa0f6e62SHans Petter Selasky 446*fa0f6e62SHans Petter Selasky cuse_lock(); 447*fa0f6e62SHans Petter Selasky 448*fa0f6e62SHans Petter Selasky if (error) { 449*fa0f6e62SHans Petter Selasky mem->virtaddr = NULL; 450*fa0f6e62SHans Petter Selasky cuse_unlock(); 451*fa0f6e62SHans Petter Selasky return (error); 452*fa0f6e62SHans Petter Selasky } 453*fa0f6e62SHans Petter Selasky mem->virtaddr = ptr; 454*fa0f6e62SHans Petter Selasky mem->page_count = page_count; 455*fa0f6e62SHans Petter Selasky mem->is_allocated = 1; 456*fa0f6e62SHans Petter Selasky mem->owner = pcs; 457*fa0f6e62SHans Petter Selasky cuse_unlock(); 458*fa0f6e62SHans Petter Selasky 459*fa0f6e62SHans Petter Selasky return (0); 460*fa0f6e62SHans Petter Selasky } 461*fa0f6e62SHans Petter Selasky 462*fa0f6e62SHans Petter Selasky static int 463*fa0f6e62SHans Petter Selasky cuse_client_get(struct cuse_client **ppcc) 464*fa0f6e62SHans Petter Selasky { 465*fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 466*fa0f6e62SHans Petter Selasky int error; 467*fa0f6e62SHans Petter Selasky 468*fa0f6e62SHans Petter Selasky /* try to get private data */ 469*fa0f6e62SHans Petter Selasky error = devfs_get_cdevpriv((void **)&pcc); 470*fa0f6e62SHans Petter Selasky if (error != 0) { 471*fa0f6e62SHans Petter Selasky *ppcc = NULL; 472*fa0f6e62SHans Petter Selasky return (error); 473*fa0f6e62SHans Petter Selasky } 474*fa0f6e62SHans Petter Selasky /* check if closing */ 475*fa0f6e62SHans Petter Selasky cuse_lock(); 476*fa0f6e62SHans Petter Selasky if (CUSE_CLIENT_CLOSING(pcc) || pcc->server->is_closing) { 477*fa0f6e62SHans Petter Selasky cuse_unlock(); 478*fa0f6e62SHans Petter Selasky *ppcc = NULL; 479*fa0f6e62SHans Petter Selasky return (EINVAL); 480*fa0f6e62SHans Petter Selasky } 481*fa0f6e62SHans Petter Selasky cuse_unlock(); 482*fa0f6e62SHans Petter Selasky *ppcc = pcc; 483*fa0f6e62SHans Petter Selasky return (0); 484*fa0f6e62SHans Petter Selasky } 485*fa0f6e62SHans Petter Selasky 486*fa0f6e62SHans Petter Selasky static void 487*fa0f6e62SHans Petter Selasky cuse_client_is_closing(struct cuse_client *pcc) 488*fa0f6e62SHans Petter Selasky { 489*fa0f6e62SHans Petter Selasky struct cuse_client_command *pccmd; 490*fa0f6e62SHans Petter Selasky uint32_t n; 491*fa0f6e62SHans Petter Selasky 492*fa0f6e62SHans Petter Selasky if (CUSE_CLIENT_CLOSING(pcc)) 493*fa0f6e62SHans Petter Selasky return; 494*fa0f6e62SHans Petter Selasky 495*fa0f6e62SHans Petter Selasky pcc->cflags |= CUSE_CLI_IS_CLOSING; 496*fa0f6e62SHans Petter Selasky pcc->server_dev = NULL; 497*fa0f6e62SHans Petter Selasky 498*fa0f6e62SHans Petter Selasky for (n = 0; n != CUSE_CMD_MAX; n++) { 499*fa0f6e62SHans Petter Selasky 500*fa0f6e62SHans Petter Selasky pccmd = &pcc->cmds[n]; 501*fa0f6e62SHans Petter Selasky 502*fa0f6e62SHans Petter Selasky if (pccmd->entry.tqe_prev != NULL) { 503*fa0f6e62SHans Petter Selasky TAILQ_REMOVE(&pcc->server->head, pccmd, entry); 504*fa0f6e62SHans Petter Selasky pccmd->entry.tqe_prev = NULL; 505*fa0f6e62SHans Petter Selasky } 506*fa0f6e62SHans Petter Selasky cv_broadcast(&pccmd->cv); 507*fa0f6e62SHans Petter Selasky } 508*fa0f6e62SHans Petter Selasky } 509*fa0f6e62SHans Petter Selasky 510*fa0f6e62SHans Petter Selasky static void 511*fa0f6e62SHans Petter Selasky cuse_client_send_command_locked(struct cuse_client_command *pccmd, 512*fa0f6e62SHans Petter Selasky unsigned long data_ptr, unsigned long arg, int fflags, int ioflag) 513*fa0f6e62SHans Petter Selasky { 514*fa0f6e62SHans Petter Selasky unsigned long cuse_fflags = 0; 515*fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 516*fa0f6e62SHans Petter Selasky 517*fa0f6e62SHans Petter Selasky if (fflags & FREAD) 518*fa0f6e62SHans Petter Selasky cuse_fflags |= CUSE_FFLAG_READ; 519*fa0f6e62SHans Petter Selasky 520*fa0f6e62SHans Petter Selasky if (fflags & FWRITE) 521*fa0f6e62SHans Petter Selasky cuse_fflags |= CUSE_FFLAG_WRITE; 522*fa0f6e62SHans Petter Selasky 523*fa0f6e62SHans Petter Selasky if (ioflag & IO_NDELAY) 524*fa0f6e62SHans Petter Selasky cuse_fflags |= CUSE_FFLAG_NONBLOCK; 525*fa0f6e62SHans Petter Selasky 526*fa0f6e62SHans Petter Selasky pccmd->sub.fflags = cuse_fflags; 527*fa0f6e62SHans Petter Selasky pccmd->sub.data_pointer = data_ptr; 528*fa0f6e62SHans Petter Selasky pccmd->sub.argument = arg; 529*fa0f6e62SHans Petter Selasky 530*fa0f6e62SHans Petter Selasky pcs = pccmd->client->server; 531*fa0f6e62SHans Petter Selasky 532*fa0f6e62SHans Petter Selasky if ((pccmd->entry.tqe_prev == NULL) && 533*fa0f6e62SHans Petter Selasky (CUSE_CLIENT_CLOSING(pccmd->client) == 0) && 534*fa0f6e62SHans Petter Selasky (pcs->is_closing == 0)) { 535*fa0f6e62SHans Petter Selasky TAILQ_INSERT_TAIL(&pcs->head, pccmd, entry); 536*fa0f6e62SHans Petter Selasky cv_signal(&pcs->cv); 537*fa0f6e62SHans Petter Selasky } 538*fa0f6e62SHans Petter Selasky } 539*fa0f6e62SHans Petter Selasky 540*fa0f6e62SHans Petter Selasky static void 541*fa0f6e62SHans Petter Selasky cuse_client_got_signal(struct cuse_client_command *pccmd) 542*fa0f6e62SHans Petter Selasky { 543*fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 544*fa0f6e62SHans Petter Selasky 545*fa0f6e62SHans Petter Selasky pccmd->got_signal = 1; 546*fa0f6e62SHans Petter Selasky 547*fa0f6e62SHans Petter Selasky pccmd = &pccmd->client->cmds[CUSE_CMD_SIGNAL]; 548*fa0f6e62SHans Petter Selasky 549*fa0f6e62SHans Petter Selasky pcs = pccmd->client->server; 550*fa0f6e62SHans Petter Selasky 551*fa0f6e62SHans Petter Selasky if ((pccmd->entry.tqe_prev == NULL) && 552*fa0f6e62SHans Petter Selasky (CUSE_CLIENT_CLOSING(pccmd->client) == 0) && 553*fa0f6e62SHans Petter Selasky (pcs->is_closing == 0)) { 554*fa0f6e62SHans Petter Selasky TAILQ_INSERT_TAIL(&pcs->head, pccmd, entry); 555*fa0f6e62SHans Petter Selasky cv_signal(&pcs->cv); 556*fa0f6e62SHans Petter Selasky } 557*fa0f6e62SHans Petter Selasky } 558*fa0f6e62SHans Petter Selasky 559*fa0f6e62SHans Petter Selasky static int 560*fa0f6e62SHans Petter Selasky cuse_client_receive_command_locked(struct cuse_client_command *pccmd, 561*fa0f6e62SHans Petter Selasky uint8_t *arg_ptr, uint32_t arg_len) 562*fa0f6e62SHans Petter Selasky { 563*fa0f6e62SHans Petter Selasky int error; 564*fa0f6e62SHans Petter Selasky 565*fa0f6e62SHans Petter Selasky error = 0; 566*fa0f6e62SHans Petter Selasky 567*fa0f6e62SHans Petter Selasky pccmd->proc_curr = curthread->td_proc; 568*fa0f6e62SHans Petter Selasky 569*fa0f6e62SHans Petter Selasky if (CUSE_CLIENT_CLOSING(pccmd->client) || 570*fa0f6e62SHans Petter Selasky pccmd->client->server->is_closing) { 571*fa0f6e62SHans Petter Selasky error = CUSE_ERR_OTHER; 572*fa0f6e62SHans Petter Selasky goto done; 573*fa0f6e62SHans Petter Selasky } 574*fa0f6e62SHans Petter Selasky while (pccmd->command == CUSE_CMD_NONE) { 575*fa0f6e62SHans Petter Selasky if (error != 0) { 576*fa0f6e62SHans Petter Selasky cv_wait(&pccmd->cv, &cuse_mtx); 577*fa0f6e62SHans Petter Selasky } else { 578*fa0f6e62SHans Petter Selasky error = cv_wait_sig(&pccmd->cv, &cuse_mtx); 579*fa0f6e62SHans Petter Selasky 580*fa0f6e62SHans Petter Selasky if (error != 0) 581*fa0f6e62SHans Petter Selasky cuse_client_got_signal(pccmd); 582*fa0f6e62SHans Petter Selasky } 583*fa0f6e62SHans Petter Selasky if (CUSE_CLIENT_CLOSING(pccmd->client) || 584*fa0f6e62SHans Petter Selasky pccmd->client->server->is_closing) { 585*fa0f6e62SHans Petter Selasky error = CUSE_ERR_OTHER; 586*fa0f6e62SHans Petter Selasky goto done; 587*fa0f6e62SHans Petter Selasky } 588*fa0f6e62SHans Petter Selasky } 589*fa0f6e62SHans Petter Selasky 590*fa0f6e62SHans Petter Selasky error = pccmd->error; 591*fa0f6e62SHans Petter Selasky pccmd->command = CUSE_CMD_NONE; 592*fa0f6e62SHans Petter Selasky cv_signal(&pccmd->cv); 593*fa0f6e62SHans Petter Selasky 594*fa0f6e62SHans Petter Selasky done: 595*fa0f6e62SHans Petter Selasky 596*fa0f6e62SHans Petter Selasky /* wait until all process references are gone */ 597*fa0f6e62SHans Petter Selasky 598*fa0f6e62SHans Petter Selasky pccmd->proc_curr = NULL; 599*fa0f6e62SHans Petter Selasky 600*fa0f6e62SHans Petter Selasky while (pccmd->proc_refs != 0) 601*fa0f6e62SHans Petter Selasky cv_wait(&pccmd->cv, &cuse_mtx); 602*fa0f6e62SHans Petter Selasky 603*fa0f6e62SHans Petter Selasky return (error); 604*fa0f6e62SHans Petter Selasky } 605*fa0f6e62SHans Petter Selasky 606*fa0f6e62SHans Petter Selasky /*------------------------------------------------------------------------* 607*fa0f6e62SHans Petter Selasky * CUSE SERVER PART 608*fa0f6e62SHans Petter Selasky *------------------------------------------------------------------------*/ 609*fa0f6e62SHans Petter Selasky 610*fa0f6e62SHans Petter Selasky static void 611*fa0f6e62SHans Petter Selasky cuse_server_free_dev(struct cuse_server_dev *pcsd) 612*fa0f6e62SHans Petter Selasky { 613*fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 614*fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 615*fa0f6e62SHans Petter Selasky 616*fa0f6e62SHans Petter Selasky /* get server pointer */ 617*fa0f6e62SHans Petter Selasky pcs = pcsd->server; 618*fa0f6e62SHans Petter Selasky 619*fa0f6e62SHans Petter Selasky /* prevent creation of more devices */ 620*fa0f6e62SHans Petter Selasky cuse_lock(); 621*fa0f6e62SHans Petter Selasky if (pcsd->kern_dev != NULL) 622*fa0f6e62SHans Petter Selasky pcsd->kern_dev->si_drv1 = NULL; 623*fa0f6e62SHans Petter Selasky 624*fa0f6e62SHans Petter Selasky TAILQ_FOREACH(pcc, &pcs->hcli, entry) { 625*fa0f6e62SHans Petter Selasky if (pcc->server_dev == pcsd) 626*fa0f6e62SHans Petter Selasky cuse_client_is_closing(pcc); 627*fa0f6e62SHans Petter Selasky } 628*fa0f6e62SHans Petter Selasky cuse_unlock(); 629*fa0f6e62SHans Petter Selasky 630*fa0f6e62SHans Petter Selasky /* destroy device, if any */ 631*fa0f6e62SHans Petter Selasky if (pcsd->kern_dev != NULL) { 632*fa0f6e62SHans Petter Selasky /* destroy device synchronously */ 633*fa0f6e62SHans Petter Selasky destroy_dev(pcsd->kern_dev); 634*fa0f6e62SHans Petter Selasky } 635*fa0f6e62SHans Petter Selasky free(pcsd, M_CUSE); 636*fa0f6e62SHans Petter Selasky } 637*fa0f6e62SHans Petter Selasky 638*fa0f6e62SHans Petter Selasky static void 639*fa0f6e62SHans Petter Selasky cuse_server_free(void *arg) 640*fa0f6e62SHans Petter Selasky { 641*fa0f6e62SHans Petter Selasky struct cuse_server *pcs = arg; 642*fa0f6e62SHans Petter Selasky struct cuse_server_dev *pcsd; 643*fa0f6e62SHans Petter Selasky 644*fa0f6e62SHans Petter Selasky cuse_lock(); 645*fa0f6e62SHans Petter Selasky pcs->refs--; 646*fa0f6e62SHans Petter Selasky if (pcs->refs != 0) { 647*fa0f6e62SHans Petter Selasky cuse_unlock(); 648*fa0f6e62SHans Petter Selasky return; 649*fa0f6e62SHans Petter Selasky } 650*fa0f6e62SHans Petter Selasky cuse_server_is_closing(pcs); 651*fa0f6e62SHans Petter Selasky 652*fa0f6e62SHans Petter Selasky TAILQ_REMOVE(&cuse_server_head, pcs, entry); 653*fa0f6e62SHans Petter Selasky 654*fa0f6e62SHans Petter Selasky cuse_free_unit_by_id_locked(pcs, -1); 655*fa0f6e62SHans Petter Selasky 656*fa0f6e62SHans Petter Selasky while ((pcsd = TAILQ_FIRST(&pcs->hdev)) != NULL) { 657*fa0f6e62SHans Petter Selasky TAILQ_REMOVE(&pcs->hdev, pcsd, entry); 658*fa0f6e62SHans Petter Selasky cuse_unlock(); 659*fa0f6e62SHans Petter Selasky cuse_server_free_dev(pcsd); 660*fa0f6e62SHans Petter Selasky cuse_lock(); 661*fa0f6e62SHans Petter Selasky } 662*fa0f6e62SHans Petter Selasky 663*fa0f6e62SHans Petter Selasky cuse_server_free_memory(pcs); 664*fa0f6e62SHans Petter Selasky 665*fa0f6e62SHans Petter Selasky knlist_clear(&pcs->selinfo.si_note, 1); 666*fa0f6e62SHans Petter Selasky knlist_destroy(&pcs->selinfo.si_note); 667*fa0f6e62SHans Petter Selasky 668*fa0f6e62SHans Petter Selasky cuse_unlock(); 669*fa0f6e62SHans Petter Selasky 670*fa0f6e62SHans Petter Selasky seldrain(&pcs->selinfo); 671*fa0f6e62SHans Petter Selasky 672*fa0f6e62SHans Petter Selasky cv_destroy(&pcs->cv); 673*fa0f6e62SHans Petter Selasky 674*fa0f6e62SHans Petter Selasky free(pcs, M_CUSE); 675*fa0f6e62SHans Petter Selasky } 676*fa0f6e62SHans Petter Selasky 677*fa0f6e62SHans Petter Selasky static int 678*fa0f6e62SHans Petter Selasky cuse_server_open(struct cdev *dev, int fflags, int devtype, struct thread *td) 679*fa0f6e62SHans Petter Selasky { 680*fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 681*fa0f6e62SHans Petter Selasky 682*fa0f6e62SHans Petter Selasky pcs = malloc(sizeof(*pcs), M_CUSE, M_WAITOK | M_ZERO); 683*fa0f6e62SHans Petter Selasky if (pcs == NULL) 684*fa0f6e62SHans Petter Selasky return (ENOMEM); 685*fa0f6e62SHans Petter Selasky 686*fa0f6e62SHans Petter Selasky if (devfs_set_cdevpriv(pcs, &cuse_server_free)) { 687*fa0f6e62SHans Petter Selasky printf("Cuse: Cannot set cdevpriv.\n"); 688*fa0f6e62SHans Petter Selasky free(pcs, M_CUSE); 689*fa0f6e62SHans Petter Selasky return (ENOMEM); 690*fa0f6e62SHans Petter Selasky } 691*fa0f6e62SHans Petter Selasky TAILQ_INIT(&pcs->head); 692*fa0f6e62SHans Petter Selasky TAILQ_INIT(&pcs->hdev); 693*fa0f6e62SHans Petter Selasky TAILQ_INIT(&pcs->hcli); 694*fa0f6e62SHans Petter Selasky 695*fa0f6e62SHans Petter Selasky cv_init(&pcs->cv, "cuse-server-cv"); 696*fa0f6e62SHans Petter Selasky 697*fa0f6e62SHans Petter Selasky knlist_init_mtx(&pcs->selinfo.si_note, &cuse_mtx); 698*fa0f6e62SHans Petter Selasky 699*fa0f6e62SHans Petter Selasky cuse_lock(); 700*fa0f6e62SHans Petter Selasky pcs->refs++; 701*fa0f6e62SHans Petter Selasky TAILQ_INSERT_TAIL(&cuse_server_head, pcs, entry); 702*fa0f6e62SHans Petter Selasky cuse_unlock(); 703*fa0f6e62SHans Petter Selasky 704*fa0f6e62SHans Petter Selasky return (0); 705*fa0f6e62SHans Petter Selasky } 706*fa0f6e62SHans Petter Selasky 707*fa0f6e62SHans Petter Selasky static int 708*fa0f6e62SHans Petter Selasky cuse_server_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 709*fa0f6e62SHans Petter Selasky { 710*fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 711*fa0f6e62SHans Petter Selasky int error; 712*fa0f6e62SHans Petter Selasky 713*fa0f6e62SHans Petter Selasky error = cuse_server_get(&pcs); 714*fa0f6e62SHans Petter Selasky if (error != 0) 715*fa0f6e62SHans Petter Selasky goto done; 716*fa0f6e62SHans Petter Selasky 717*fa0f6e62SHans Petter Selasky cuse_lock(); 718*fa0f6e62SHans Petter Selasky cuse_server_is_closing(pcs); 719*fa0f6e62SHans Petter Selasky knlist_clear(&pcs->selinfo.si_note, 1); 720*fa0f6e62SHans Petter Selasky cuse_unlock(); 721*fa0f6e62SHans Petter Selasky 722*fa0f6e62SHans Petter Selasky done: 723*fa0f6e62SHans Petter Selasky return (0); 724*fa0f6e62SHans Petter Selasky } 725*fa0f6e62SHans Petter Selasky 726*fa0f6e62SHans Petter Selasky static int 727*fa0f6e62SHans Petter Selasky cuse_server_read(struct cdev *dev, struct uio *uio, int ioflag) 728*fa0f6e62SHans Petter Selasky { 729*fa0f6e62SHans Petter Selasky return (ENXIO); 730*fa0f6e62SHans Petter Selasky } 731*fa0f6e62SHans Petter Selasky 732*fa0f6e62SHans Petter Selasky static int 733*fa0f6e62SHans Petter Selasky cuse_server_write(struct cdev *dev, struct uio *uio, int ioflag) 734*fa0f6e62SHans Petter Selasky { 735*fa0f6e62SHans Petter Selasky return (ENXIO); 736*fa0f6e62SHans Petter Selasky } 737*fa0f6e62SHans Petter Selasky 738*fa0f6e62SHans Petter Selasky static int 739*fa0f6e62SHans Petter Selasky cuse_server_ioctl_copy_locked(struct cuse_client_command *pccmd, 740*fa0f6e62SHans Petter Selasky struct cuse_data_chunk *pchk, int isread) 741*fa0f6e62SHans Petter Selasky { 742*fa0f6e62SHans Petter Selasky struct proc *p_proc; 743*fa0f6e62SHans Petter Selasky uint32_t offset; 744*fa0f6e62SHans Petter Selasky int error; 745*fa0f6e62SHans Petter Selasky 746*fa0f6e62SHans Petter Selasky offset = pchk->peer_ptr - CUSE_BUF_MIN_PTR; 747*fa0f6e62SHans Petter Selasky 748*fa0f6e62SHans Petter Selasky if (pchk->length > CUSE_BUFFER_MAX) 749*fa0f6e62SHans Petter Selasky return (EFAULT); 750*fa0f6e62SHans Petter Selasky 751*fa0f6e62SHans Petter Selasky if (offset >= CUSE_BUFFER_MAX) 752*fa0f6e62SHans Petter Selasky return (EFAULT); 753*fa0f6e62SHans Petter Selasky 754*fa0f6e62SHans Petter Selasky if ((offset + pchk->length) > CUSE_BUFFER_MAX) 755*fa0f6e62SHans Petter Selasky return (EFAULT); 756*fa0f6e62SHans Petter Selasky 757*fa0f6e62SHans Petter Selasky p_proc = pccmd->proc_curr; 758*fa0f6e62SHans Petter Selasky if (p_proc == NULL) 759*fa0f6e62SHans Petter Selasky return (ENXIO); 760*fa0f6e62SHans Petter Selasky 761*fa0f6e62SHans Petter Selasky if (pccmd->proc_refs < 0) 762*fa0f6e62SHans Petter Selasky return (ENOMEM); 763*fa0f6e62SHans Petter Selasky 764*fa0f6e62SHans Petter Selasky pccmd->proc_refs++; 765*fa0f6e62SHans Petter Selasky 766*fa0f6e62SHans Petter Selasky cuse_unlock(); 767*fa0f6e62SHans Petter Selasky 768*fa0f6e62SHans Petter Selasky if (isread == 0) { 769*fa0f6e62SHans Petter Selasky error = copyin( 770*fa0f6e62SHans Petter Selasky (void *)pchk->local_ptr, 771*fa0f6e62SHans Petter Selasky pccmd->client->ioctl_buffer + offset, 772*fa0f6e62SHans Petter Selasky pchk->length); 773*fa0f6e62SHans Petter Selasky } else { 774*fa0f6e62SHans Petter Selasky error = copyout( 775*fa0f6e62SHans Petter Selasky pccmd->client->ioctl_buffer + offset, 776*fa0f6e62SHans Petter Selasky (void *)pchk->local_ptr, 777*fa0f6e62SHans Petter Selasky pchk->length); 778*fa0f6e62SHans Petter Selasky } 779*fa0f6e62SHans Petter Selasky 780*fa0f6e62SHans Petter Selasky cuse_lock(); 781*fa0f6e62SHans Petter Selasky 782*fa0f6e62SHans Petter Selasky pccmd->proc_refs--; 783*fa0f6e62SHans Petter Selasky 784*fa0f6e62SHans Petter Selasky if (pccmd->proc_curr == NULL) 785*fa0f6e62SHans Petter Selasky cv_signal(&pccmd->cv); 786*fa0f6e62SHans Petter Selasky 787*fa0f6e62SHans Petter Selasky return (error); 788*fa0f6e62SHans Petter Selasky } 789*fa0f6e62SHans Petter Selasky 790*fa0f6e62SHans Petter Selasky static int 791*fa0f6e62SHans Petter Selasky cuse_proc2proc_copy(struct proc *proc_s, vm_offset_t data_s, 792*fa0f6e62SHans Petter Selasky struct proc *proc_d, vm_offset_t data_d, size_t len) 793*fa0f6e62SHans Petter Selasky { 794*fa0f6e62SHans Petter Selasky struct thread *td; 795*fa0f6e62SHans Petter Selasky struct proc *proc_cur; 796*fa0f6e62SHans Petter Selasky int error; 797*fa0f6e62SHans Petter Selasky 798*fa0f6e62SHans Petter Selasky td = curthread; 799*fa0f6e62SHans Petter Selasky proc_cur = td->td_proc; 800*fa0f6e62SHans Petter Selasky 801*fa0f6e62SHans Petter Selasky if (proc_cur == proc_d) { 802*fa0f6e62SHans Petter Selasky struct iovec iov = { 803*fa0f6e62SHans Petter Selasky .iov_base = (caddr_t)data_d, 804*fa0f6e62SHans Petter Selasky .iov_len = len, 805*fa0f6e62SHans Petter Selasky }; 806*fa0f6e62SHans Petter Selasky struct uio uio = { 807*fa0f6e62SHans Petter Selasky .uio_iov = &iov, 808*fa0f6e62SHans Petter Selasky .uio_iovcnt = 1, 809*fa0f6e62SHans Petter Selasky .uio_offset = (off_t)data_s, 810*fa0f6e62SHans Petter Selasky .uio_resid = len, 811*fa0f6e62SHans Petter Selasky .uio_segflg = UIO_USERSPACE, 812*fa0f6e62SHans Petter Selasky .uio_rw = UIO_READ, 813*fa0f6e62SHans Petter Selasky .uio_td = td, 814*fa0f6e62SHans Petter Selasky }; 815*fa0f6e62SHans Petter Selasky 816*fa0f6e62SHans Petter Selasky PROC_LOCK(proc_s); 817*fa0f6e62SHans Petter Selasky _PHOLD(proc_s); 818*fa0f6e62SHans Petter Selasky PROC_UNLOCK(proc_s); 819*fa0f6e62SHans Petter Selasky 820*fa0f6e62SHans Petter Selasky error = proc_rwmem(proc_s, &uio); 821*fa0f6e62SHans Petter Selasky 822*fa0f6e62SHans Petter Selasky PROC_LOCK(proc_s); 823*fa0f6e62SHans Petter Selasky _PRELE(proc_s); 824*fa0f6e62SHans Petter Selasky PROC_UNLOCK(proc_s); 825*fa0f6e62SHans Petter Selasky 826*fa0f6e62SHans Petter Selasky } else if (proc_cur == proc_s) { 827*fa0f6e62SHans Petter Selasky struct iovec iov = { 828*fa0f6e62SHans Petter Selasky .iov_base = (caddr_t)data_s, 829*fa0f6e62SHans Petter Selasky .iov_len = len, 830*fa0f6e62SHans Petter Selasky }; 831*fa0f6e62SHans Petter Selasky struct uio uio = { 832*fa0f6e62SHans Petter Selasky .uio_iov = &iov, 833*fa0f6e62SHans Petter Selasky .uio_iovcnt = 1, 834*fa0f6e62SHans Petter Selasky .uio_offset = (off_t)data_d, 835*fa0f6e62SHans Petter Selasky .uio_resid = len, 836*fa0f6e62SHans Petter Selasky .uio_segflg = UIO_USERSPACE, 837*fa0f6e62SHans Petter Selasky .uio_rw = UIO_WRITE, 838*fa0f6e62SHans Petter Selasky .uio_td = td, 839*fa0f6e62SHans Petter Selasky }; 840*fa0f6e62SHans Petter Selasky 841*fa0f6e62SHans Petter Selasky PROC_LOCK(proc_d); 842*fa0f6e62SHans Petter Selasky _PHOLD(proc_d); 843*fa0f6e62SHans Petter Selasky PROC_UNLOCK(proc_d); 844*fa0f6e62SHans Petter Selasky 845*fa0f6e62SHans Petter Selasky error = proc_rwmem(proc_d, &uio); 846*fa0f6e62SHans Petter Selasky 847*fa0f6e62SHans Petter Selasky PROC_LOCK(proc_d); 848*fa0f6e62SHans Petter Selasky _PRELE(proc_d); 849*fa0f6e62SHans Petter Selasky PROC_UNLOCK(proc_d); 850*fa0f6e62SHans Petter Selasky } else { 851*fa0f6e62SHans Petter Selasky error = EINVAL; 852*fa0f6e62SHans Petter Selasky } 853*fa0f6e62SHans Petter Selasky return (error); 854*fa0f6e62SHans Petter Selasky } 855*fa0f6e62SHans Petter Selasky 856*fa0f6e62SHans Petter Selasky static int 857*fa0f6e62SHans Petter Selasky cuse_server_data_copy_locked(struct cuse_client_command *pccmd, 858*fa0f6e62SHans Petter Selasky struct cuse_data_chunk *pchk, int isread) 859*fa0f6e62SHans Petter Selasky { 860*fa0f6e62SHans Petter Selasky struct proc *p_proc; 861*fa0f6e62SHans Petter Selasky int error; 862*fa0f6e62SHans Petter Selasky 863*fa0f6e62SHans Petter Selasky p_proc = pccmd->proc_curr; 864*fa0f6e62SHans Petter Selasky if (p_proc == NULL) 865*fa0f6e62SHans Petter Selasky return (ENXIO); 866*fa0f6e62SHans Petter Selasky 867*fa0f6e62SHans Petter Selasky if (pccmd->proc_refs < 0) 868*fa0f6e62SHans Petter Selasky return (ENOMEM); 869*fa0f6e62SHans Petter Selasky 870*fa0f6e62SHans Petter Selasky pccmd->proc_refs++; 871*fa0f6e62SHans Petter Selasky 872*fa0f6e62SHans Petter Selasky cuse_unlock(); 873*fa0f6e62SHans Petter Selasky 874*fa0f6e62SHans Petter Selasky if (isread == 0) { 875*fa0f6e62SHans Petter Selasky error = cuse_proc2proc_copy( 876*fa0f6e62SHans Petter Selasky curthread->td_proc, pchk->local_ptr, 877*fa0f6e62SHans Petter Selasky p_proc, pchk->peer_ptr, 878*fa0f6e62SHans Petter Selasky pchk->length); 879*fa0f6e62SHans Petter Selasky } else { 880*fa0f6e62SHans Petter Selasky error = cuse_proc2proc_copy( 881*fa0f6e62SHans Petter Selasky p_proc, pchk->peer_ptr, 882*fa0f6e62SHans Petter Selasky curthread->td_proc, pchk->local_ptr, 883*fa0f6e62SHans Petter Selasky pchk->length); 884*fa0f6e62SHans Petter Selasky } 885*fa0f6e62SHans Petter Selasky 886*fa0f6e62SHans Petter Selasky cuse_lock(); 887*fa0f6e62SHans Petter Selasky 888*fa0f6e62SHans Petter Selasky pccmd->proc_refs--; 889*fa0f6e62SHans Petter Selasky 890*fa0f6e62SHans Petter Selasky if (pccmd->proc_curr == NULL) 891*fa0f6e62SHans Petter Selasky cv_signal(&pccmd->cv); 892*fa0f6e62SHans Petter Selasky 893*fa0f6e62SHans Petter Selasky return (error); 894*fa0f6e62SHans Petter Selasky } 895*fa0f6e62SHans Petter Selasky 896*fa0f6e62SHans Petter Selasky static int 897*fa0f6e62SHans Petter Selasky cuse_alloc_unit_by_id_locked(struct cuse_server *pcs, int id) 898*fa0f6e62SHans Petter Selasky { 899*fa0f6e62SHans Petter Selasky int n; 900*fa0f6e62SHans Petter Selasky int x = 0; 901*fa0f6e62SHans Petter Selasky int match; 902*fa0f6e62SHans Petter Selasky 903*fa0f6e62SHans Petter Selasky do { 904*fa0f6e62SHans Petter Selasky for (match = n = 0; n != CUSE_DEVICES_MAX; n++) { 905*fa0f6e62SHans Petter Selasky if (cuse_alloc_unit[n] != NULL) { 906*fa0f6e62SHans Petter Selasky if ((cuse_alloc_unit_id[n] ^ id) & CUSE_ID_MASK) 907*fa0f6e62SHans Petter Selasky continue; 908*fa0f6e62SHans Petter Selasky if ((cuse_alloc_unit_id[n] & ~CUSE_ID_MASK) == x) { 909*fa0f6e62SHans Petter Selasky x++; 910*fa0f6e62SHans Petter Selasky match = 1; 911*fa0f6e62SHans Petter Selasky } 912*fa0f6e62SHans Petter Selasky } 913*fa0f6e62SHans Petter Selasky } 914*fa0f6e62SHans Petter Selasky } while (match); 915*fa0f6e62SHans Petter Selasky 916*fa0f6e62SHans Petter Selasky if (x < 256) { 917*fa0f6e62SHans Petter Selasky for (n = 0; n != CUSE_DEVICES_MAX; n++) { 918*fa0f6e62SHans Petter Selasky if (cuse_alloc_unit[n] == NULL) { 919*fa0f6e62SHans Petter Selasky cuse_alloc_unit[n] = pcs; 920*fa0f6e62SHans Petter Selasky cuse_alloc_unit_id[n] = id | x; 921*fa0f6e62SHans Petter Selasky return (x); 922*fa0f6e62SHans Petter Selasky } 923*fa0f6e62SHans Petter Selasky } 924*fa0f6e62SHans Petter Selasky } 925*fa0f6e62SHans Petter Selasky return (-1); 926*fa0f6e62SHans Petter Selasky } 927*fa0f6e62SHans Petter Selasky 928*fa0f6e62SHans Petter Selasky static void 929*fa0f6e62SHans Petter Selasky cuse_server_wakeup_locked(struct cuse_server *pcs) 930*fa0f6e62SHans Petter Selasky { 931*fa0f6e62SHans Petter Selasky selwakeup(&pcs->selinfo); 932*fa0f6e62SHans Petter Selasky KNOTE_LOCKED(&pcs->selinfo.si_note, 0); 933*fa0f6e62SHans Petter Selasky } 934*fa0f6e62SHans Petter Selasky 935*fa0f6e62SHans Petter Selasky static int 936*fa0f6e62SHans Petter Selasky cuse_free_unit_by_id_locked(struct cuse_server *pcs, int id) 937*fa0f6e62SHans Petter Selasky { 938*fa0f6e62SHans Petter Selasky int n; 939*fa0f6e62SHans Petter Selasky int found = 0; 940*fa0f6e62SHans Petter Selasky 941*fa0f6e62SHans Petter Selasky for (n = 0; n != CUSE_DEVICES_MAX; n++) { 942*fa0f6e62SHans Petter Selasky if (cuse_alloc_unit[n] == pcs) { 943*fa0f6e62SHans Petter Selasky if (cuse_alloc_unit_id[n] == id || id == -1) { 944*fa0f6e62SHans Petter Selasky cuse_alloc_unit[n] = NULL; 945*fa0f6e62SHans Petter Selasky cuse_alloc_unit_id[n] = 0; 946*fa0f6e62SHans Petter Selasky found = 1; 947*fa0f6e62SHans Petter Selasky } 948*fa0f6e62SHans Petter Selasky } 949*fa0f6e62SHans Petter Selasky } 950*fa0f6e62SHans Petter Selasky 951*fa0f6e62SHans Petter Selasky return (found ? 0 : EINVAL); 952*fa0f6e62SHans Petter Selasky } 953*fa0f6e62SHans Petter Selasky 954*fa0f6e62SHans Petter Selasky static int 955*fa0f6e62SHans Petter Selasky cuse_server_ioctl(struct cdev *dev, unsigned long cmd, 956*fa0f6e62SHans Petter Selasky caddr_t data, int fflag, struct thread *td) 957*fa0f6e62SHans Petter Selasky { 958*fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 959*fa0f6e62SHans Petter Selasky int error; 960*fa0f6e62SHans Petter Selasky 961*fa0f6e62SHans Petter Selasky error = cuse_server_get(&pcs); 962*fa0f6e62SHans Petter Selasky if (error != 0) 963*fa0f6e62SHans Petter Selasky return (error); 964*fa0f6e62SHans Petter Selasky 965*fa0f6e62SHans Petter Selasky switch (cmd) { 966*fa0f6e62SHans Petter Selasky struct cuse_client_command *pccmd; 967*fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 968*fa0f6e62SHans Petter Selasky struct cuse_command *pcmd; 969*fa0f6e62SHans Petter Selasky struct cuse_alloc_info *pai; 970*fa0f6e62SHans Petter Selasky struct cuse_create_dev *pcd; 971*fa0f6e62SHans Petter Selasky struct cuse_server_dev *pcsd; 972*fa0f6e62SHans Petter Selasky struct cuse_data_chunk *pchk; 973*fa0f6e62SHans Petter Selasky int n; 974*fa0f6e62SHans Petter Selasky 975*fa0f6e62SHans Petter Selasky case CUSE_IOCTL_GET_COMMAND: 976*fa0f6e62SHans Petter Selasky pcmd = (void *)data; 977*fa0f6e62SHans Petter Selasky 978*fa0f6e62SHans Petter Selasky cuse_lock(); 979*fa0f6e62SHans Petter Selasky 980*fa0f6e62SHans Petter Selasky while ((pccmd = TAILQ_FIRST(&pcs->head)) == NULL) { 981*fa0f6e62SHans Petter Selasky error = cv_wait_sig(&pcs->cv, &cuse_mtx); 982*fa0f6e62SHans Petter Selasky 983*fa0f6e62SHans Petter Selasky if (pcs->is_closing) 984*fa0f6e62SHans Petter Selasky error = ENXIO; 985*fa0f6e62SHans Petter Selasky 986*fa0f6e62SHans Petter Selasky if (error) { 987*fa0f6e62SHans Petter Selasky cuse_unlock(); 988*fa0f6e62SHans Petter Selasky return (error); 989*fa0f6e62SHans Petter Selasky } 990*fa0f6e62SHans Petter Selasky } 991*fa0f6e62SHans Petter Selasky 992*fa0f6e62SHans Petter Selasky TAILQ_REMOVE(&pcs->head, pccmd, entry); 993*fa0f6e62SHans Petter Selasky pccmd->entry.tqe_prev = NULL; 994*fa0f6e62SHans Petter Selasky 995*fa0f6e62SHans Petter Selasky pccmd->entered = curthread; 996*fa0f6e62SHans Petter Selasky 997*fa0f6e62SHans Petter Selasky *pcmd = pccmd->sub; 998*fa0f6e62SHans Petter Selasky 999*fa0f6e62SHans Petter Selasky cuse_unlock(); 1000*fa0f6e62SHans Petter Selasky 1001*fa0f6e62SHans Petter Selasky break; 1002*fa0f6e62SHans Petter Selasky 1003*fa0f6e62SHans Petter Selasky case CUSE_IOCTL_SYNC_COMMAND: 1004*fa0f6e62SHans Petter Selasky 1005*fa0f6e62SHans Petter Selasky cuse_lock(); 1006*fa0f6e62SHans Petter Selasky while ((pccmd = cuse_server_find_command(pcs, curthread)) != NULL) { 1007*fa0f6e62SHans Petter Selasky 1008*fa0f6e62SHans Petter Selasky /* send sync command */ 1009*fa0f6e62SHans Petter Selasky pccmd->entered = NULL; 1010*fa0f6e62SHans Petter Selasky pccmd->error = *(int *)data; 1011*fa0f6e62SHans Petter Selasky pccmd->command = CUSE_CMD_SYNC; 1012*fa0f6e62SHans Petter Selasky 1013*fa0f6e62SHans Petter Selasky /* signal peer, if any */ 1014*fa0f6e62SHans Petter Selasky cv_signal(&pccmd->cv); 1015*fa0f6e62SHans Petter Selasky } 1016*fa0f6e62SHans Petter Selasky cuse_unlock(); 1017*fa0f6e62SHans Petter Selasky 1018*fa0f6e62SHans Petter Selasky break; 1019*fa0f6e62SHans Petter Selasky 1020*fa0f6e62SHans Petter Selasky case CUSE_IOCTL_ALLOC_UNIT: 1021*fa0f6e62SHans Petter Selasky 1022*fa0f6e62SHans Petter Selasky cuse_lock(); 1023*fa0f6e62SHans Petter Selasky n = cuse_alloc_unit_by_id_locked(pcs, 1024*fa0f6e62SHans Petter Selasky CUSE_ID_DEFAULT(0)); 1025*fa0f6e62SHans Petter Selasky cuse_unlock(); 1026*fa0f6e62SHans Petter Selasky 1027*fa0f6e62SHans Petter Selasky if (n < 0) 1028*fa0f6e62SHans Petter Selasky error = ENOMEM; 1029*fa0f6e62SHans Petter Selasky else 1030*fa0f6e62SHans Petter Selasky *(int *)data = n; 1031*fa0f6e62SHans Petter Selasky break; 1032*fa0f6e62SHans Petter Selasky 1033*fa0f6e62SHans Petter Selasky case CUSE_IOCTL_ALLOC_UNIT_BY_ID: 1034*fa0f6e62SHans Petter Selasky 1035*fa0f6e62SHans Petter Selasky n = *(int *)data; 1036*fa0f6e62SHans Petter Selasky 1037*fa0f6e62SHans Petter Selasky n = (n & CUSE_ID_MASK); 1038*fa0f6e62SHans Petter Selasky 1039*fa0f6e62SHans Petter Selasky cuse_lock(); 1040*fa0f6e62SHans Petter Selasky n = cuse_alloc_unit_by_id_locked(pcs, n); 1041*fa0f6e62SHans Petter Selasky cuse_unlock(); 1042*fa0f6e62SHans Petter Selasky 1043*fa0f6e62SHans Petter Selasky if (n < 0) 1044*fa0f6e62SHans Petter Selasky error = ENOMEM; 1045*fa0f6e62SHans Petter Selasky else 1046*fa0f6e62SHans Petter Selasky *(int *)data = n; 1047*fa0f6e62SHans Petter Selasky break; 1048*fa0f6e62SHans Petter Selasky 1049*fa0f6e62SHans Petter Selasky case CUSE_IOCTL_FREE_UNIT: 1050*fa0f6e62SHans Petter Selasky 1051*fa0f6e62SHans Petter Selasky n = *(int *)data; 1052*fa0f6e62SHans Petter Selasky 1053*fa0f6e62SHans Petter Selasky n = CUSE_ID_DEFAULT(n); 1054*fa0f6e62SHans Petter Selasky 1055*fa0f6e62SHans Petter Selasky cuse_lock(); 1056*fa0f6e62SHans Petter Selasky error = cuse_free_unit_by_id_locked(pcs, n); 1057*fa0f6e62SHans Petter Selasky cuse_unlock(); 1058*fa0f6e62SHans Petter Selasky break; 1059*fa0f6e62SHans Petter Selasky 1060*fa0f6e62SHans Petter Selasky case CUSE_IOCTL_FREE_UNIT_BY_ID: 1061*fa0f6e62SHans Petter Selasky 1062*fa0f6e62SHans Petter Selasky n = *(int *)data; 1063*fa0f6e62SHans Petter Selasky 1064*fa0f6e62SHans Petter Selasky cuse_lock(); 1065*fa0f6e62SHans Petter Selasky error = cuse_free_unit_by_id_locked(pcs, n); 1066*fa0f6e62SHans Petter Selasky cuse_unlock(); 1067*fa0f6e62SHans Petter Selasky break; 1068*fa0f6e62SHans Petter Selasky 1069*fa0f6e62SHans Petter Selasky case CUSE_IOCTL_ALLOC_MEMORY: 1070*fa0f6e62SHans Petter Selasky 1071*fa0f6e62SHans Petter Selasky pai = (void *)data; 1072*fa0f6e62SHans Petter Selasky 1073*fa0f6e62SHans Petter Selasky if (pai->alloc_nr >= CUSE_ALLOC_UNIT_MAX) { 1074*fa0f6e62SHans Petter Selasky error = ENOMEM; 1075*fa0f6e62SHans Petter Selasky break; 1076*fa0f6e62SHans Petter Selasky } 1077*fa0f6e62SHans Petter Selasky if (pai->page_count > CUSE_ALLOC_PAGES_MAX) { 1078*fa0f6e62SHans Petter Selasky error = ENOMEM; 1079*fa0f6e62SHans Petter Selasky break; 1080*fa0f6e62SHans Petter Selasky } 1081*fa0f6e62SHans Petter Selasky error = cuse_server_alloc_memory(pcs, 1082*fa0f6e62SHans Petter Selasky &cuse_mem[pai->alloc_nr], pai->page_count); 1083*fa0f6e62SHans Petter Selasky break; 1084*fa0f6e62SHans Petter Selasky 1085*fa0f6e62SHans Petter Selasky case CUSE_IOCTL_FREE_MEMORY: 1086*fa0f6e62SHans Petter Selasky pai = (void *)data; 1087*fa0f6e62SHans Petter Selasky 1088*fa0f6e62SHans Petter Selasky if (pai->alloc_nr >= CUSE_ALLOC_UNIT_MAX) { 1089*fa0f6e62SHans Petter Selasky error = ENOMEM; 1090*fa0f6e62SHans Petter Selasky break; 1091*fa0f6e62SHans Petter Selasky } 1092*fa0f6e62SHans Petter Selasky /* we trust the character device driver in this case */ 1093*fa0f6e62SHans Petter Selasky 1094*fa0f6e62SHans Petter Selasky cuse_lock(); 1095*fa0f6e62SHans Petter Selasky if (cuse_mem[pai->alloc_nr].owner == pcs) { 1096*fa0f6e62SHans Petter Selasky cuse_mem[pai->alloc_nr].is_allocated = 0; 1097*fa0f6e62SHans Petter Selasky cuse_mem[pai->alloc_nr].owner = NULL; 1098*fa0f6e62SHans Petter Selasky } else { 1099*fa0f6e62SHans Petter Selasky error = EINVAL; 1100*fa0f6e62SHans Petter Selasky } 1101*fa0f6e62SHans Petter Selasky cuse_unlock(); 1102*fa0f6e62SHans Petter Selasky break; 1103*fa0f6e62SHans Petter Selasky 1104*fa0f6e62SHans Petter Selasky case CUSE_IOCTL_GET_SIG: 1105*fa0f6e62SHans Petter Selasky 1106*fa0f6e62SHans Petter Selasky cuse_lock(); 1107*fa0f6e62SHans Petter Selasky pccmd = cuse_server_find_command(pcs, curthread); 1108*fa0f6e62SHans Petter Selasky 1109*fa0f6e62SHans Petter Selasky if (pccmd != NULL) { 1110*fa0f6e62SHans Petter Selasky n = pccmd->got_signal; 1111*fa0f6e62SHans Petter Selasky pccmd->got_signal = 0; 1112*fa0f6e62SHans Petter Selasky } else { 1113*fa0f6e62SHans Petter Selasky n = 0; 1114*fa0f6e62SHans Petter Selasky } 1115*fa0f6e62SHans Petter Selasky cuse_unlock(); 1116*fa0f6e62SHans Petter Selasky 1117*fa0f6e62SHans Petter Selasky *(int *)data = n; 1118*fa0f6e62SHans Petter Selasky 1119*fa0f6e62SHans Petter Selasky break; 1120*fa0f6e62SHans Petter Selasky 1121*fa0f6e62SHans Petter Selasky case CUSE_IOCTL_SET_PFH: 1122*fa0f6e62SHans Petter Selasky 1123*fa0f6e62SHans Petter Selasky cuse_lock(); 1124*fa0f6e62SHans Petter Selasky pccmd = cuse_server_find_command(pcs, curthread); 1125*fa0f6e62SHans Petter Selasky 1126*fa0f6e62SHans Petter Selasky if (pccmd != NULL) { 1127*fa0f6e62SHans Petter Selasky pcc = pccmd->client; 1128*fa0f6e62SHans Petter Selasky for (n = 0; n != CUSE_CMD_MAX; n++) { 1129*fa0f6e62SHans Petter Selasky pcc->cmds[n].sub.per_file_handle = *(unsigned long *)data; 1130*fa0f6e62SHans Petter Selasky } 1131*fa0f6e62SHans Petter Selasky } else { 1132*fa0f6e62SHans Petter Selasky error = ENXIO; 1133*fa0f6e62SHans Petter Selasky } 1134*fa0f6e62SHans Petter Selasky cuse_unlock(); 1135*fa0f6e62SHans Petter Selasky break; 1136*fa0f6e62SHans Petter Selasky 1137*fa0f6e62SHans Petter Selasky case CUSE_IOCTL_CREATE_DEV: 1138*fa0f6e62SHans Petter Selasky 1139*fa0f6e62SHans Petter Selasky error = priv_check(curthread, PRIV_DRIVER); 1140*fa0f6e62SHans Petter Selasky if (error) 1141*fa0f6e62SHans Petter Selasky break; 1142*fa0f6e62SHans Petter Selasky 1143*fa0f6e62SHans Petter Selasky pcd = (void *)data; 1144*fa0f6e62SHans Petter Selasky 1145*fa0f6e62SHans Petter Selasky /* filter input */ 1146*fa0f6e62SHans Petter Selasky 1147*fa0f6e62SHans Petter Selasky pcd->devname[sizeof(pcd->devname) - 1] = 0; 1148*fa0f6e62SHans Petter Selasky 1149*fa0f6e62SHans Petter Selasky if (pcd->devname[0] == 0) { 1150*fa0f6e62SHans Petter Selasky error = EINVAL; 1151*fa0f6e62SHans Petter Selasky break; 1152*fa0f6e62SHans Petter Selasky } 1153*fa0f6e62SHans Petter Selasky cuse_str_filter(pcd->devname); 1154*fa0f6e62SHans Petter Selasky 1155*fa0f6e62SHans Petter Selasky pcd->permissions &= 0777; 1156*fa0f6e62SHans Petter Selasky 1157*fa0f6e62SHans Petter Selasky /* try to allocate a character device */ 1158*fa0f6e62SHans Petter Selasky 1159*fa0f6e62SHans Petter Selasky pcsd = malloc(sizeof(*pcsd), M_CUSE, M_WAITOK | M_ZERO); 1160*fa0f6e62SHans Petter Selasky 1161*fa0f6e62SHans Petter Selasky if (pcsd == NULL) { 1162*fa0f6e62SHans Petter Selasky error = ENOMEM; 1163*fa0f6e62SHans Petter Selasky break; 1164*fa0f6e62SHans Petter Selasky } 1165*fa0f6e62SHans Petter Selasky pcsd->server = pcs; 1166*fa0f6e62SHans Petter Selasky 1167*fa0f6e62SHans Petter Selasky pcsd->user_dev = pcd->dev; 1168*fa0f6e62SHans Petter Selasky 1169*fa0f6e62SHans Petter Selasky pcsd->kern_dev = make_dev_credf(MAKEDEV_CHECKNAME, 1170*fa0f6e62SHans Petter Selasky &cuse_client_devsw, 0, NULL, pcd->user_id, pcd->group_id, 1171*fa0f6e62SHans Petter Selasky pcd->permissions, "%s", pcd->devname); 1172*fa0f6e62SHans Petter Selasky 1173*fa0f6e62SHans Petter Selasky if (pcsd->kern_dev == NULL) { 1174*fa0f6e62SHans Petter Selasky free(pcsd, M_CUSE); 1175*fa0f6e62SHans Petter Selasky error = ENOMEM; 1176*fa0f6e62SHans Petter Selasky break; 1177*fa0f6e62SHans Petter Selasky } 1178*fa0f6e62SHans Petter Selasky pcsd->kern_dev->si_drv1 = pcsd; 1179*fa0f6e62SHans Petter Selasky 1180*fa0f6e62SHans Petter Selasky cuse_lock(); 1181*fa0f6e62SHans Petter Selasky TAILQ_INSERT_TAIL(&pcs->hdev, pcsd, entry); 1182*fa0f6e62SHans Petter Selasky cuse_unlock(); 1183*fa0f6e62SHans Petter Selasky 1184*fa0f6e62SHans Petter Selasky break; 1185*fa0f6e62SHans Petter Selasky 1186*fa0f6e62SHans Petter Selasky case CUSE_IOCTL_DESTROY_DEV: 1187*fa0f6e62SHans Petter Selasky 1188*fa0f6e62SHans Petter Selasky error = priv_check(curthread, PRIV_DRIVER); 1189*fa0f6e62SHans Petter Selasky if (error) 1190*fa0f6e62SHans Petter Selasky break; 1191*fa0f6e62SHans Petter Selasky 1192*fa0f6e62SHans Petter Selasky cuse_lock(); 1193*fa0f6e62SHans Petter Selasky 1194*fa0f6e62SHans Petter Selasky error = EINVAL; 1195*fa0f6e62SHans Petter Selasky 1196*fa0f6e62SHans Petter Selasky pcsd = TAILQ_FIRST(&pcs->hdev); 1197*fa0f6e62SHans Petter Selasky while (pcsd != NULL) { 1198*fa0f6e62SHans Petter Selasky if (pcsd->user_dev == *(struct cuse_dev **)data) { 1199*fa0f6e62SHans Petter Selasky TAILQ_REMOVE(&pcs->hdev, pcsd, entry); 1200*fa0f6e62SHans Petter Selasky cuse_unlock(); 1201*fa0f6e62SHans Petter Selasky cuse_server_free_dev(pcsd); 1202*fa0f6e62SHans Petter Selasky cuse_lock(); 1203*fa0f6e62SHans Petter Selasky error = 0; 1204*fa0f6e62SHans Petter Selasky pcsd = TAILQ_FIRST(&pcs->hdev); 1205*fa0f6e62SHans Petter Selasky } else { 1206*fa0f6e62SHans Petter Selasky pcsd = TAILQ_NEXT(pcsd, entry); 1207*fa0f6e62SHans Petter Selasky } 1208*fa0f6e62SHans Petter Selasky } 1209*fa0f6e62SHans Petter Selasky 1210*fa0f6e62SHans Petter Selasky cuse_unlock(); 1211*fa0f6e62SHans Petter Selasky break; 1212*fa0f6e62SHans Petter Selasky 1213*fa0f6e62SHans Petter Selasky case CUSE_IOCTL_WRITE_DATA: 1214*fa0f6e62SHans Petter Selasky case CUSE_IOCTL_READ_DATA: 1215*fa0f6e62SHans Petter Selasky 1216*fa0f6e62SHans Petter Selasky cuse_lock(); 1217*fa0f6e62SHans Petter Selasky pchk = (struct cuse_data_chunk *)data; 1218*fa0f6e62SHans Petter Selasky 1219*fa0f6e62SHans Petter Selasky pccmd = cuse_server_find_command(pcs, curthread); 1220*fa0f6e62SHans Petter Selasky 1221*fa0f6e62SHans Petter Selasky if (pccmd == NULL) { 1222*fa0f6e62SHans Petter Selasky error = ENXIO; /* invalid request */ 1223*fa0f6e62SHans Petter Selasky } else if (pchk->peer_ptr < CUSE_BUF_MIN_PTR) { 1224*fa0f6e62SHans Petter Selasky error = EFAULT; /* NULL pointer */ 1225*fa0f6e62SHans Petter Selasky } else if (pchk->peer_ptr < CUSE_BUF_MAX_PTR) { 1226*fa0f6e62SHans Petter Selasky error = cuse_server_ioctl_copy_locked(pccmd, 1227*fa0f6e62SHans Petter Selasky pchk, cmd == CUSE_IOCTL_READ_DATA); 1228*fa0f6e62SHans Petter Selasky } else { 1229*fa0f6e62SHans Petter Selasky error = cuse_server_data_copy_locked(pccmd, 1230*fa0f6e62SHans Petter Selasky pchk, cmd == CUSE_IOCTL_READ_DATA); 1231*fa0f6e62SHans Petter Selasky } 1232*fa0f6e62SHans Petter Selasky cuse_unlock(); 1233*fa0f6e62SHans Petter Selasky break; 1234*fa0f6e62SHans Petter Selasky 1235*fa0f6e62SHans Petter Selasky case CUSE_IOCTL_SELWAKEUP: 1236*fa0f6e62SHans Petter Selasky cuse_lock(); 1237*fa0f6e62SHans Petter Selasky /* 1238*fa0f6e62SHans Petter Selasky * We don't know which direction caused the event. 1239*fa0f6e62SHans Petter Selasky * Wakeup both! 1240*fa0f6e62SHans Petter Selasky */ 1241*fa0f6e62SHans Petter Selasky TAILQ_FOREACH(pcc, &pcs->hcli, entry) { 1242*fa0f6e62SHans Petter Selasky pcc->cflags |= (CUSE_CLI_KNOTE_NEED_READ | 1243*fa0f6e62SHans Petter Selasky CUSE_CLI_KNOTE_NEED_WRITE); 1244*fa0f6e62SHans Petter Selasky } 1245*fa0f6e62SHans Petter Selasky cuse_server_wakeup_locked(pcs); 1246*fa0f6e62SHans Petter Selasky cuse_unlock(); 1247*fa0f6e62SHans Petter Selasky break; 1248*fa0f6e62SHans Petter Selasky 1249*fa0f6e62SHans Petter Selasky default: 1250*fa0f6e62SHans Petter Selasky error = ENXIO; 1251*fa0f6e62SHans Petter Selasky break; 1252*fa0f6e62SHans Petter Selasky } 1253*fa0f6e62SHans Petter Selasky return (error); 1254*fa0f6e62SHans Petter Selasky } 1255*fa0f6e62SHans Petter Selasky 1256*fa0f6e62SHans Petter Selasky static int 1257*fa0f6e62SHans Petter Selasky cuse_server_poll(struct cdev *dev, int events, struct thread *td) 1258*fa0f6e62SHans Petter Selasky { 1259*fa0f6e62SHans Petter Selasky return (events & (POLLHUP | POLLPRI | POLLIN | 1260*fa0f6e62SHans Petter Selasky POLLRDNORM | POLLOUT | POLLWRNORM)); 1261*fa0f6e62SHans Petter Selasky } 1262*fa0f6e62SHans Petter Selasky 1263*fa0f6e62SHans Petter Selasky static int 1264*fa0f6e62SHans Petter Selasky cuse_server_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, vm_memattr_t *memattr) 1265*fa0f6e62SHans Petter Selasky { 1266*fa0f6e62SHans Petter Selasky uint32_t page_nr = offset / PAGE_SIZE; 1267*fa0f6e62SHans Petter Selasky uint32_t alloc_nr = page_nr / CUSE_ALLOC_PAGES_MAX; 1268*fa0f6e62SHans Petter Selasky struct cuse_memory *mem; 1269*fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 1270*fa0f6e62SHans Petter Selasky uint8_t *ptr; 1271*fa0f6e62SHans Petter Selasky int error; 1272*fa0f6e62SHans Petter Selasky 1273*fa0f6e62SHans Petter Selasky if (alloc_nr >= CUSE_ALLOC_UNIT_MAX) 1274*fa0f6e62SHans Petter Selasky return (ENOMEM); 1275*fa0f6e62SHans Petter Selasky 1276*fa0f6e62SHans Petter Selasky error = cuse_server_get(&pcs); 1277*fa0f6e62SHans Petter Selasky if (error != 0) 1278*fa0f6e62SHans Petter Selasky pcs = NULL; 1279*fa0f6e62SHans Petter Selasky 1280*fa0f6e62SHans Petter Selasky cuse_lock(); 1281*fa0f6e62SHans Petter Selasky mem = &cuse_mem[alloc_nr]; 1282*fa0f6e62SHans Petter Selasky 1283*fa0f6e62SHans Petter Selasky /* try to enforce slight ownership */ 1284*fa0f6e62SHans Petter Selasky if ((pcs != NULL) && (mem->owner != pcs)) { 1285*fa0f6e62SHans Petter Selasky cuse_unlock(); 1286*fa0f6e62SHans Petter Selasky return (EINVAL); 1287*fa0f6e62SHans Petter Selasky } 1288*fa0f6e62SHans Petter Selasky if (mem->virtaddr == NULL) { 1289*fa0f6e62SHans Petter Selasky cuse_unlock(); 1290*fa0f6e62SHans Petter Selasky return (ENOMEM); 1291*fa0f6e62SHans Petter Selasky } 1292*fa0f6e62SHans Petter Selasky if (mem->virtaddr == NBUSY) { 1293*fa0f6e62SHans Petter Selasky cuse_unlock(); 1294*fa0f6e62SHans Petter Selasky return (ENOMEM); 1295*fa0f6e62SHans Petter Selasky } 1296*fa0f6e62SHans Petter Selasky page_nr %= CUSE_ALLOC_PAGES_MAX; 1297*fa0f6e62SHans Petter Selasky 1298*fa0f6e62SHans Petter Selasky if (page_nr >= mem->page_count) { 1299*fa0f6e62SHans Petter Selasky cuse_unlock(); 1300*fa0f6e62SHans Petter Selasky return (ENXIO); 1301*fa0f6e62SHans Petter Selasky } 1302*fa0f6e62SHans Petter Selasky ptr = mem->virtaddr + (page_nr * PAGE_SIZE); 1303*fa0f6e62SHans Petter Selasky cuse_unlock(); 1304*fa0f6e62SHans Petter Selasky 1305*fa0f6e62SHans Petter Selasky *paddr = vtophys(ptr); 1306*fa0f6e62SHans Petter Selasky 1307*fa0f6e62SHans Petter Selasky return (0); 1308*fa0f6e62SHans Petter Selasky } 1309*fa0f6e62SHans Petter Selasky 1310*fa0f6e62SHans Petter Selasky /*------------------------------------------------------------------------* 1311*fa0f6e62SHans Petter Selasky * CUSE CLIENT PART 1312*fa0f6e62SHans Petter Selasky *------------------------------------------------------------------------*/ 1313*fa0f6e62SHans Petter Selasky static void 1314*fa0f6e62SHans Petter Selasky cuse_client_free(void *arg) 1315*fa0f6e62SHans Petter Selasky { 1316*fa0f6e62SHans Petter Selasky struct cuse_client *pcc = arg; 1317*fa0f6e62SHans Petter Selasky struct cuse_client_command *pccmd; 1318*fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 1319*fa0f6e62SHans Petter Selasky int n; 1320*fa0f6e62SHans Petter Selasky 1321*fa0f6e62SHans Petter Selasky cuse_lock(); 1322*fa0f6e62SHans Petter Selasky cuse_client_is_closing(pcc); 1323*fa0f6e62SHans Petter Selasky TAILQ_REMOVE(&pcc->server->hcli, pcc, entry); 1324*fa0f6e62SHans Petter Selasky cuse_unlock(); 1325*fa0f6e62SHans Petter Selasky 1326*fa0f6e62SHans Petter Selasky for (n = 0; n != CUSE_CMD_MAX; n++) { 1327*fa0f6e62SHans Petter Selasky 1328*fa0f6e62SHans Petter Selasky pccmd = &pcc->cmds[n]; 1329*fa0f6e62SHans Petter Selasky 1330*fa0f6e62SHans Petter Selasky sx_destroy(&pccmd->sx); 1331*fa0f6e62SHans Petter Selasky cv_destroy(&pccmd->cv); 1332*fa0f6e62SHans Petter Selasky } 1333*fa0f6e62SHans Petter Selasky 1334*fa0f6e62SHans Petter Selasky pcs = pcc->server; 1335*fa0f6e62SHans Petter Selasky 1336*fa0f6e62SHans Petter Selasky free(pcc, M_CUSE); 1337*fa0f6e62SHans Petter Selasky 1338*fa0f6e62SHans Petter Selasky /* drop reference on server */ 1339*fa0f6e62SHans Petter Selasky cuse_server_free(pcs); 1340*fa0f6e62SHans Petter Selasky } 1341*fa0f6e62SHans Petter Selasky 1342*fa0f6e62SHans Petter Selasky static int 1343*fa0f6e62SHans Petter Selasky cuse_client_open(struct cdev *dev, int fflags, int devtype, struct thread *td) 1344*fa0f6e62SHans Petter Selasky { 1345*fa0f6e62SHans Petter Selasky struct cuse_client_command *pccmd; 1346*fa0f6e62SHans Petter Selasky struct cuse_server_dev *pcsd; 1347*fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 1348*fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 1349*fa0f6e62SHans Petter Selasky struct cuse_dev *pcd; 1350*fa0f6e62SHans Petter Selasky int error; 1351*fa0f6e62SHans Petter Selasky int n; 1352*fa0f6e62SHans Petter Selasky 1353*fa0f6e62SHans Petter Selasky cuse_lock(); 1354*fa0f6e62SHans Petter Selasky pcsd = dev->si_drv1; 1355*fa0f6e62SHans Petter Selasky if (pcsd != NULL) { 1356*fa0f6e62SHans Petter Selasky pcs = pcsd->server; 1357*fa0f6e62SHans Petter Selasky pcd = pcsd->user_dev; 1358*fa0f6e62SHans Petter Selasky pcs->refs++; 1359*fa0f6e62SHans Petter Selasky if (pcs->refs < 0) { 1360*fa0f6e62SHans Petter Selasky /* overflow */ 1361*fa0f6e62SHans Petter Selasky pcs->refs--; 1362*fa0f6e62SHans Petter Selasky pcsd = NULL; 1363*fa0f6e62SHans Petter Selasky } 1364*fa0f6e62SHans Petter Selasky } else { 1365*fa0f6e62SHans Petter Selasky pcs = NULL; 1366*fa0f6e62SHans Petter Selasky pcd = NULL; 1367*fa0f6e62SHans Petter Selasky } 1368*fa0f6e62SHans Petter Selasky cuse_unlock(); 1369*fa0f6e62SHans Petter Selasky 1370*fa0f6e62SHans Petter Selasky if (pcsd == NULL) 1371*fa0f6e62SHans Petter Selasky return (EINVAL); 1372*fa0f6e62SHans Petter Selasky 1373*fa0f6e62SHans Petter Selasky pcc = malloc(sizeof(*pcc), M_CUSE, M_WAITOK | M_ZERO); 1374*fa0f6e62SHans Petter Selasky if (pcc == NULL) { 1375*fa0f6e62SHans Petter Selasky /* drop reference on server */ 1376*fa0f6e62SHans Petter Selasky cuse_server_free(pcs); 1377*fa0f6e62SHans Petter Selasky return (ENOMEM); 1378*fa0f6e62SHans Petter Selasky } 1379*fa0f6e62SHans Petter Selasky if (devfs_set_cdevpriv(pcc, &cuse_client_free)) { 1380*fa0f6e62SHans Petter Selasky printf("Cuse: Cannot set cdevpriv.\n"); 1381*fa0f6e62SHans Petter Selasky /* drop reference on server */ 1382*fa0f6e62SHans Petter Selasky cuse_server_free(pcs); 1383*fa0f6e62SHans Petter Selasky free(pcc, M_CUSE); 1384*fa0f6e62SHans Petter Selasky return (ENOMEM); 1385*fa0f6e62SHans Petter Selasky } 1386*fa0f6e62SHans Petter Selasky pcc->fflags = fflags; 1387*fa0f6e62SHans Petter Selasky pcc->server_dev = pcsd; 1388*fa0f6e62SHans Petter Selasky pcc->server = pcs; 1389*fa0f6e62SHans Petter Selasky 1390*fa0f6e62SHans Petter Selasky for (n = 0; n != CUSE_CMD_MAX; n++) { 1391*fa0f6e62SHans Petter Selasky 1392*fa0f6e62SHans Petter Selasky pccmd = &pcc->cmds[n]; 1393*fa0f6e62SHans Petter Selasky 1394*fa0f6e62SHans Petter Selasky pccmd->sub.dev = pcd; 1395*fa0f6e62SHans Petter Selasky pccmd->sub.command = n; 1396*fa0f6e62SHans Petter Selasky pccmd->client = pcc; 1397*fa0f6e62SHans Petter Selasky 1398*fa0f6e62SHans Petter Selasky sx_init(&pccmd->sx, "cuse-client-sx"); 1399*fa0f6e62SHans Petter Selasky cv_init(&pccmd->cv, "cuse-client-cv"); 1400*fa0f6e62SHans Petter Selasky } 1401*fa0f6e62SHans Petter Selasky 1402*fa0f6e62SHans Petter Selasky cuse_lock(); 1403*fa0f6e62SHans Petter Selasky 1404*fa0f6e62SHans Petter Selasky /* cuse_client_free() assumes that the client is listed somewhere! */ 1405*fa0f6e62SHans Petter Selasky /* always enqueue */ 1406*fa0f6e62SHans Petter Selasky 1407*fa0f6e62SHans Petter Selasky TAILQ_INSERT_TAIL(&pcs->hcli, pcc, entry); 1408*fa0f6e62SHans Petter Selasky 1409*fa0f6e62SHans Petter Selasky /* check if server is closing */ 1410*fa0f6e62SHans Petter Selasky if ((pcs->is_closing != 0) || (dev->si_drv1 == NULL)) { 1411*fa0f6e62SHans Petter Selasky error = EINVAL; 1412*fa0f6e62SHans Petter Selasky } else { 1413*fa0f6e62SHans Petter Selasky error = 0; 1414*fa0f6e62SHans Petter Selasky } 1415*fa0f6e62SHans Petter Selasky cuse_unlock(); 1416*fa0f6e62SHans Petter Selasky 1417*fa0f6e62SHans Petter Selasky if (error) { 1418*fa0f6e62SHans Petter Selasky devfs_clear_cdevpriv(); /* XXX bugfix */ 1419*fa0f6e62SHans Petter Selasky return (error); 1420*fa0f6e62SHans Petter Selasky } 1421*fa0f6e62SHans Petter Selasky pccmd = &pcc->cmds[CUSE_CMD_OPEN]; 1422*fa0f6e62SHans Petter Selasky 1423*fa0f6e62SHans Petter Selasky cuse_cmd_lock(pccmd); 1424*fa0f6e62SHans Petter Selasky 1425*fa0f6e62SHans Petter Selasky cuse_lock(); 1426*fa0f6e62SHans Petter Selasky cuse_client_send_command_locked(pccmd, 0, 0, pcc->fflags, 0); 1427*fa0f6e62SHans Petter Selasky 1428*fa0f6e62SHans Petter Selasky error = cuse_client_receive_command_locked(pccmd, 0, 0); 1429*fa0f6e62SHans Petter Selasky cuse_unlock(); 1430*fa0f6e62SHans Petter Selasky 1431*fa0f6e62SHans Petter Selasky if (error < 0) { 1432*fa0f6e62SHans Petter Selasky error = cuse_convert_error(error); 1433*fa0f6e62SHans Petter Selasky } else { 1434*fa0f6e62SHans Petter Selasky error = 0; 1435*fa0f6e62SHans Petter Selasky } 1436*fa0f6e62SHans Petter Selasky 1437*fa0f6e62SHans Petter Selasky cuse_cmd_unlock(pccmd); 1438*fa0f6e62SHans Petter Selasky 1439*fa0f6e62SHans Petter Selasky if (error) 1440*fa0f6e62SHans Petter Selasky devfs_clear_cdevpriv(); /* XXX bugfix */ 1441*fa0f6e62SHans Petter Selasky 1442*fa0f6e62SHans Petter Selasky return (error); 1443*fa0f6e62SHans Petter Selasky } 1444*fa0f6e62SHans Petter Selasky 1445*fa0f6e62SHans Petter Selasky static int 1446*fa0f6e62SHans Petter Selasky cuse_client_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 1447*fa0f6e62SHans Petter Selasky { 1448*fa0f6e62SHans Petter Selasky struct cuse_client_command *pccmd; 1449*fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 1450*fa0f6e62SHans Petter Selasky int error; 1451*fa0f6e62SHans Petter Selasky 1452*fa0f6e62SHans Petter Selasky error = cuse_client_get(&pcc); 1453*fa0f6e62SHans Petter Selasky if (error != 0) 1454*fa0f6e62SHans Petter Selasky return (0); 1455*fa0f6e62SHans Petter Selasky 1456*fa0f6e62SHans Petter Selasky pccmd = &pcc->cmds[CUSE_CMD_CLOSE]; 1457*fa0f6e62SHans Petter Selasky 1458*fa0f6e62SHans Petter Selasky cuse_cmd_lock(pccmd); 1459*fa0f6e62SHans Petter Selasky 1460*fa0f6e62SHans Petter Selasky cuse_lock(); 1461*fa0f6e62SHans Petter Selasky cuse_client_send_command_locked(pccmd, 0, 0, pcc->fflags, 0); 1462*fa0f6e62SHans Petter Selasky 1463*fa0f6e62SHans Petter Selasky error = cuse_client_receive_command_locked(pccmd, 0, 0); 1464*fa0f6e62SHans Petter Selasky cuse_unlock(); 1465*fa0f6e62SHans Petter Selasky 1466*fa0f6e62SHans Petter Selasky cuse_cmd_unlock(pccmd); 1467*fa0f6e62SHans Petter Selasky 1468*fa0f6e62SHans Petter Selasky cuse_lock(); 1469*fa0f6e62SHans Petter Selasky cuse_client_is_closing(pcc); 1470*fa0f6e62SHans Petter Selasky cuse_unlock(); 1471*fa0f6e62SHans Petter Selasky 1472*fa0f6e62SHans Petter Selasky return (0); 1473*fa0f6e62SHans Petter Selasky } 1474*fa0f6e62SHans Petter Selasky 1475*fa0f6e62SHans Petter Selasky static void 1476*fa0f6e62SHans Petter Selasky cuse_client_kqfilter_poll(struct cdev *dev, struct cuse_client *pcc) 1477*fa0f6e62SHans Petter Selasky { 1478*fa0f6e62SHans Petter Selasky int temp; 1479*fa0f6e62SHans Petter Selasky 1480*fa0f6e62SHans Petter Selasky cuse_lock(); 1481*fa0f6e62SHans Petter Selasky temp = (pcc->cflags & (CUSE_CLI_KNOTE_HAS_READ | 1482*fa0f6e62SHans Petter Selasky CUSE_CLI_KNOTE_HAS_WRITE)); 1483*fa0f6e62SHans Petter Selasky pcc->cflags &= ~(CUSE_CLI_KNOTE_NEED_READ | 1484*fa0f6e62SHans Petter Selasky CUSE_CLI_KNOTE_NEED_WRITE); 1485*fa0f6e62SHans Petter Selasky cuse_unlock(); 1486*fa0f6e62SHans Petter Selasky 1487*fa0f6e62SHans Petter Selasky if (temp != 0) { 1488*fa0f6e62SHans Petter Selasky /* get the latest polling state from the server */ 1489*fa0f6e62SHans Petter Selasky temp = cuse_client_poll(dev, POLLIN | POLLOUT, NULL); 1490*fa0f6e62SHans Petter Selasky 1491*fa0f6e62SHans Petter Selasky cuse_lock(); 1492*fa0f6e62SHans Petter Selasky if (temp & (POLLIN | POLLOUT)) { 1493*fa0f6e62SHans Petter Selasky if (temp & POLLIN) 1494*fa0f6e62SHans Petter Selasky pcc->cflags |= CUSE_CLI_KNOTE_NEED_READ; 1495*fa0f6e62SHans Petter Selasky if (temp & POLLOUT) 1496*fa0f6e62SHans Petter Selasky pcc->cflags |= CUSE_CLI_KNOTE_NEED_WRITE; 1497*fa0f6e62SHans Petter Selasky 1498*fa0f6e62SHans Petter Selasky /* make sure the "knote" gets woken up */ 1499*fa0f6e62SHans Petter Selasky cuse_server_wakeup_locked(pcc->server); 1500*fa0f6e62SHans Petter Selasky } 1501*fa0f6e62SHans Petter Selasky cuse_unlock(); 1502*fa0f6e62SHans Petter Selasky } 1503*fa0f6e62SHans Petter Selasky } 1504*fa0f6e62SHans Petter Selasky 1505*fa0f6e62SHans Petter Selasky static int 1506*fa0f6e62SHans Petter Selasky cuse_client_read(struct cdev *dev, struct uio *uio, int ioflag) 1507*fa0f6e62SHans Petter Selasky { 1508*fa0f6e62SHans Petter Selasky struct cuse_client_command *pccmd; 1509*fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 1510*fa0f6e62SHans Petter Selasky int error; 1511*fa0f6e62SHans Petter Selasky int len; 1512*fa0f6e62SHans Petter Selasky 1513*fa0f6e62SHans Petter Selasky error = cuse_client_get(&pcc); 1514*fa0f6e62SHans Petter Selasky if (error != 0) 1515*fa0f6e62SHans Petter Selasky return (error); 1516*fa0f6e62SHans Petter Selasky 1517*fa0f6e62SHans Petter Selasky pccmd = &pcc->cmds[CUSE_CMD_READ]; 1518*fa0f6e62SHans Petter Selasky 1519*fa0f6e62SHans Petter Selasky if (uio->uio_segflg != UIO_USERSPACE) { 1520*fa0f6e62SHans Petter Selasky return (EINVAL); 1521*fa0f6e62SHans Petter Selasky } 1522*fa0f6e62SHans Petter Selasky uio->uio_segflg = UIO_NOCOPY; 1523*fa0f6e62SHans Petter Selasky 1524*fa0f6e62SHans Petter Selasky cuse_cmd_lock(pccmd); 1525*fa0f6e62SHans Petter Selasky 1526*fa0f6e62SHans Petter Selasky while (uio->uio_resid != 0) { 1527*fa0f6e62SHans Petter Selasky 1528*fa0f6e62SHans Petter Selasky if (uio->uio_iov->iov_len > CUSE_LENGTH_MAX) { 1529*fa0f6e62SHans Petter Selasky error = ENOMEM; 1530*fa0f6e62SHans Petter Selasky break; 1531*fa0f6e62SHans Petter Selasky } 1532*fa0f6e62SHans Petter Selasky 1533*fa0f6e62SHans Petter Selasky len = uio->uio_iov->iov_len; 1534*fa0f6e62SHans Petter Selasky 1535*fa0f6e62SHans Petter Selasky cuse_lock(); 1536*fa0f6e62SHans Petter Selasky cuse_client_send_command_locked(pccmd, 1537*fa0f6e62SHans Petter Selasky (unsigned long)uio->uio_iov->iov_base, 1538*fa0f6e62SHans Petter Selasky (unsigned long)(unsigned int)len, pcc->fflags, ioflag); 1539*fa0f6e62SHans Petter Selasky 1540*fa0f6e62SHans Petter Selasky error = cuse_client_receive_command_locked(pccmd, 0, 0); 1541*fa0f6e62SHans Petter Selasky cuse_unlock(); 1542*fa0f6e62SHans Petter Selasky 1543*fa0f6e62SHans Petter Selasky if (error < 0) { 1544*fa0f6e62SHans Petter Selasky error = cuse_convert_error(error); 1545*fa0f6e62SHans Petter Selasky break; 1546*fa0f6e62SHans Petter Selasky } else if (error == len) { 1547*fa0f6e62SHans Petter Selasky error = uiomove(NULL, error, uio); 1548*fa0f6e62SHans Petter Selasky if (error) 1549*fa0f6e62SHans Petter Selasky break; 1550*fa0f6e62SHans Petter Selasky } else { 1551*fa0f6e62SHans Petter Selasky error = uiomove(NULL, error, uio); 1552*fa0f6e62SHans Petter Selasky break; 1553*fa0f6e62SHans Petter Selasky } 1554*fa0f6e62SHans Petter Selasky } 1555*fa0f6e62SHans Petter Selasky cuse_cmd_unlock(pccmd); 1556*fa0f6e62SHans Petter Selasky 1557*fa0f6e62SHans Petter Selasky uio->uio_segflg = UIO_USERSPACE;/* restore segment flag */ 1558*fa0f6e62SHans Petter Selasky 1559*fa0f6e62SHans Petter Selasky if (error == EWOULDBLOCK) 1560*fa0f6e62SHans Petter Selasky cuse_client_kqfilter_poll(dev, pcc); 1561*fa0f6e62SHans Petter Selasky 1562*fa0f6e62SHans Petter Selasky return (error); 1563*fa0f6e62SHans Petter Selasky } 1564*fa0f6e62SHans Petter Selasky 1565*fa0f6e62SHans Petter Selasky static int 1566*fa0f6e62SHans Petter Selasky cuse_client_write(struct cdev *dev, struct uio *uio, int ioflag) 1567*fa0f6e62SHans Petter Selasky { 1568*fa0f6e62SHans Petter Selasky struct cuse_client_command *pccmd; 1569*fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 1570*fa0f6e62SHans Petter Selasky int error; 1571*fa0f6e62SHans Petter Selasky int len; 1572*fa0f6e62SHans Petter Selasky 1573*fa0f6e62SHans Petter Selasky error = cuse_client_get(&pcc); 1574*fa0f6e62SHans Petter Selasky if (error != 0) 1575*fa0f6e62SHans Petter Selasky return (error); 1576*fa0f6e62SHans Petter Selasky 1577*fa0f6e62SHans Petter Selasky pccmd = &pcc->cmds[CUSE_CMD_WRITE]; 1578*fa0f6e62SHans Petter Selasky 1579*fa0f6e62SHans Petter Selasky if (uio->uio_segflg != UIO_USERSPACE) { 1580*fa0f6e62SHans Petter Selasky return (EINVAL); 1581*fa0f6e62SHans Petter Selasky } 1582*fa0f6e62SHans Petter Selasky uio->uio_segflg = UIO_NOCOPY; 1583*fa0f6e62SHans Petter Selasky 1584*fa0f6e62SHans Petter Selasky cuse_cmd_lock(pccmd); 1585*fa0f6e62SHans Petter Selasky 1586*fa0f6e62SHans Petter Selasky while (uio->uio_resid != 0) { 1587*fa0f6e62SHans Petter Selasky 1588*fa0f6e62SHans Petter Selasky if (uio->uio_iov->iov_len > CUSE_LENGTH_MAX) { 1589*fa0f6e62SHans Petter Selasky error = ENOMEM; 1590*fa0f6e62SHans Petter Selasky break; 1591*fa0f6e62SHans Petter Selasky } 1592*fa0f6e62SHans Petter Selasky 1593*fa0f6e62SHans Petter Selasky len = uio->uio_iov->iov_len; 1594*fa0f6e62SHans Petter Selasky 1595*fa0f6e62SHans Petter Selasky cuse_lock(); 1596*fa0f6e62SHans Petter Selasky cuse_client_send_command_locked(pccmd, 1597*fa0f6e62SHans Petter Selasky (unsigned long)uio->uio_iov->iov_base, 1598*fa0f6e62SHans Petter Selasky (unsigned long)(unsigned int)len, pcc->fflags, ioflag); 1599*fa0f6e62SHans Petter Selasky 1600*fa0f6e62SHans Petter Selasky error = cuse_client_receive_command_locked(pccmd, 0, 0); 1601*fa0f6e62SHans Petter Selasky cuse_unlock(); 1602*fa0f6e62SHans Petter Selasky 1603*fa0f6e62SHans Petter Selasky if (error < 0) { 1604*fa0f6e62SHans Petter Selasky error = cuse_convert_error(error); 1605*fa0f6e62SHans Petter Selasky break; 1606*fa0f6e62SHans Petter Selasky } else if (error == len) { 1607*fa0f6e62SHans Petter Selasky error = uiomove(NULL, error, uio); 1608*fa0f6e62SHans Petter Selasky if (error) 1609*fa0f6e62SHans Petter Selasky break; 1610*fa0f6e62SHans Petter Selasky } else { 1611*fa0f6e62SHans Petter Selasky error = uiomove(NULL, error, uio); 1612*fa0f6e62SHans Petter Selasky break; 1613*fa0f6e62SHans Petter Selasky } 1614*fa0f6e62SHans Petter Selasky } 1615*fa0f6e62SHans Petter Selasky cuse_cmd_unlock(pccmd); 1616*fa0f6e62SHans Petter Selasky 1617*fa0f6e62SHans Petter Selasky uio->uio_segflg = UIO_USERSPACE;/* restore segment flag */ 1618*fa0f6e62SHans Petter Selasky 1619*fa0f6e62SHans Petter Selasky if (error == EWOULDBLOCK) 1620*fa0f6e62SHans Petter Selasky cuse_client_kqfilter_poll(dev, pcc); 1621*fa0f6e62SHans Petter Selasky 1622*fa0f6e62SHans Petter Selasky return (error); 1623*fa0f6e62SHans Petter Selasky } 1624*fa0f6e62SHans Petter Selasky 1625*fa0f6e62SHans Petter Selasky int 1626*fa0f6e62SHans Petter Selasky cuse_client_ioctl(struct cdev *dev, unsigned long cmd, 1627*fa0f6e62SHans Petter Selasky caddr_t data, int fflag, struct thread *td) 1628*fa0f6e62SHans Petter Selasky { 1629*fa0f6e62SHans Petter Selasky struct cuse_client_command *pccmd; 1630*fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 1631*fa0f6e62SHans Petter Selasky int error; 1632*fa0f6e62SHans Petter Selasky int len; 1633*fa0f6e62SHans Petter Selasky 1634*fa0f6e62SHans Petter Selasky error = cuse_client_get(&pcc); 1635*fa0f6e62SHans Petter Selasky if (error != 0) 1636*fa0f6e62SHans Petter Selasky return (error); 1637*fa0f6e62SHans Petter Selasky 1638*fa0f6e62SHans Petter Selasky len = IOCPARM_LEN(cmd); 1639*fa0f6e62SHans Petter Selasky if (len > CUSE_BUFFER_MAX) 1640*fa0f6e62SHans Petter Selasky return (ENOMEM); 1641*fa0f6e62SHans Petter Selasky 1642*fa0f6e62SHans Petter Selasky pccmd = &pcc->cmds[CUSE_CMD_IOCTL]; 1643*fa0f6e62SHans Petter Selasky 1644*fa0f6e62SHans Petter Selasky cuse_cmd_lock(pccmd); 1645*fa0f6e62SHans Petter Selasky 1646*fa0f6e62SHans Petter Selasky if (cmd & IOC_IN) 1647*fa0f6e62SHans Petter Selasky memcpy(pcc->ioctl_buffer, data, len); 1648*fa0f6e62SHans Petter Selasky 1649*fa0f6e62SHans Petter Selasky /* 1650*fa0f6e62SHans Petter Selasky * When the ioctl-length is zero drivers can pass information 1651*fa0f6e62SHans Petter Selasky * through the data pointer of the ioctl. Make sure this information 1652*fa0f6e62SHans Petter Selasky * is forwarded to the driver. 1653*fa0f6e62SHans Petter Selasky */ 1654*fa0f6e62SHans Petter Selasky 1655*fa0f6e62SHans Petter Selasky cuse_lock(); 1656*fa0f6e62SHans Petter Selasky cuse_client_send_command_locked(pccmd, 1657*fa0f6e62SHans Petter Selasky (len == 0) ? *(long *)data : CUSE_BUF_MIN_PTR, 1658*fa0f6e62SHans Petter Selasky (unsigned long)cmd, pcc->fflags, 1659*fa0f6e62SHans Petter Selasky (fflag & O_NONBLOCK) ? IO_NDELAY : 0); 1660*fa0f6e62SHans Petter Selasky 1661*fa0f6e62SHans Petter Selasky error = cuse_client_receive_command_locked(pccmd, data, len); 1662*fa0f6e62SHans Petter Selasky cuse_unlock(); 1663*fa0f6e62SHans Petter Selasky 1664*fa0f6e62SHans Petter Selasky if (error < 0) { 1665*fa0f6e62SHans Petter Selasky error = cuse_convert_error(error); 1666*fa0f6e62SHans Petter Selasky } else { 1667*fa0f6e62SHans Petter Selasky error = 0; 1668*fa0f6e62SHans Petter Selasky } 1669*fa0f6e62SHans Petter Selasky 1670*fa0f6e62SHans Petter Selasky if (cmd & IOC_OUT) 1671*fa0f6e62SHans Petter Selasky memcpy(data, pcc->ioctl_buffer, len); 1672*fa0f6e62SHans Petter Selasky 1673*fa0f6e62SHans Petter Selasky cuse_cmd_unlock(pccmd); 1674*fa0f6e62SHans Petter Selasky 1675*fa0f6e62SHans Petter Selasky if (error == EWOULDBLOCK) 1676*fa0f6e62SHans Petter Selasky cuse_client_kqfilter_poll(dev, pcc); 1677*fa0f6e62SHans Petter Selasky 1678*fa0f6e62SHans Petter Selasky return (error); 1679*fa0f6e62SHans Petter Selasky } 1680*fa0f6e62SHans Petter Selasky 1681*fa0f6e62SHans Petter Selasky static int 1682*fa0f6e62SHans Petter Selasky cuse_client_poll(struct cdev *dev, int events, struct thread *td) 1683*fa0f6e62SHans Petter Selasky { 1684*fa0f6e62SHans Petter Selasky struct cuse_client_command *pccmd; 1685*fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 1686*fa0f6e62SHans Petter Selasky unsigned long temp; 1687*fa0f6e62SHans Petter Selasky int error; 1688*fa0f6e62SHans Petter Selasky int revents; 1689*fa0f6e62SHans Petter Selasky 1690*fa0f6e62SHans Petter Selasky error = cuse_client_get(&pcc); 1691*fa0f6e62SHans Petter Selasky if (error != 0) 1692*fa0f6e62SHans Petter Selasky return (POLLNVAL); 1693*fa0f6e62SHans Petter Selasky 1694*fa0f6e62SHans Petter Selasky temp = 0; 1695*fa0f6e62SHans Petter Selasky 1696*fa0f6e62SHans Petter Selasky if (events & (POLLPRI | POLLIN | POLLRDNORM)) 1697*fa0f6e62SHans Petter Selasky temp |= CUSE_POLL_READ; 1698*fa0f6e62SHans Petter Selasky 1699*fa0f6e62SHans Petter Selasky if (events & (POLLOUT | POLLWRNORM)) 1700*fa0f6e62SHans Petter Selasky temp |= CUSE_POLL_WRITE; 1701*fa0f6e62SHans Petter Selasky 1702*fa0f6e62SHans Petter Selasky if (events & POLLHUP) 1703*fa0f6e62SHans Petter Selasky temp |= CUSE_POLL_ERROR; 1704*fa0f6e62SHans Petter Selasky 1705*fa0f6e62SHans Petter Selasky pccmd = &pcc->cmds[CUSE_CMD_POLL]; 1706*fa0f6e62SHans Petter Selasky 1707*fa0f6e62SHans Petter Selasky cuse_cmd_lock(pccmd); 1708*fa0f6e62SHans Petter Selasky 1709*fa0f6e62SHans Petter Selasky /* Need to selrecord() first to not loose any events. */ 1710*fa0f6e62SHans Petter Selasky if (temp != 0 && td != NULL) 1711*fa0f6e62SHans Petter Selasky selrecord(td, &pcc->server->selinfo); 1712*fa0f6e62SHans Petter Selasky 1713*fa0f6e62SHans Petter Selasky cuse_lock(); 1714*fa0f6e62SHans Petter Selasky cuse_client_send_command_locked(pccmd, 1715*fa0f6e62SHans Petter Selasky 0, temp, pcc->fflags, IO_NDELAY); 1716*fa0f6e62SHans Petter Selasky 1717*fa0f6e62SHans Petter Selasky error = cuse_client_receive_command_locked(pccmd, 0, 0); 1718*fa0f6e62SHans Petter Selasky cuse_unlock(); 1719*fa0f6e62SHans Petter Selasky 1720*fa0f6e62SHans Petter Selasky if (error < 0) { 1721*fa0f6e62SHans Petter Selasky revents = POLLNVAL; 1722*fa0f6e62SHans Petter Selasky } else { 1723*fa0f6e62SHans Petter Selasky revents = 0; 1724*fa0f6e62SHans Petter Selasky if (error & CUSE_POLL_READ) 1725*fa0f6e62SHans Petter Selasky revents |= (events & (POLLPRI | POLLIN | POLLRDNORM)); 1726*fa0f6e62SHans Petter Selasky if (error & CUSE_POLL_WRITE) 1727*fa0f6e62SHans Petter Selasky revents |= (events & (POLLOUT | POLLWRNORM)); 1728*fa0f6e62SHans Petter Selasky if (error & CUSE_POLL_ERROR) 1729*fa0f6e62SHans Petter Selasky revents |= (events & POLLHUP); 1730*fa0f6e62SHans Petter Selasky } 1731*fa0f6e62SHans Petter Selasky 1732*fa0f6e62SHans Petter Selasky cuse_cmd_unlock(pccmd); 1733*fa0f6e62SHans Petter Selasky 1734*fa0f6e62SHans Petter Selasky return (revents); 1735*fa0f6e62SHans Petter Selasky } 1736*fa0f6e62SHans Petter Selasky 1737*fa0f6e62SHans Petter Selasky static int 1738*fa0f6e62SHans Petter Selasky cuse_client_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, vm_memattr_t *memattr) 1739*fa0f6e62SHans Petter Selasky { 1740*fa0f6e62SHans Petter Selasky uint32_t page_nr = offset / PAGE_SIZE; 1741*fa0f6e62SHans Petter Selasky uint32_t alloc_nr = page_nr / CUSE_ALLOC_PAGES_MAX; 1742*fa0f6e62SHans Petter Selasky struct cuse_memory *mem; 1743*fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 1744*fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 1745*fa0f6e62SHans Petter Selasky uint8_t *ptr; 1746*fa0f6e62SHans Petter Selasky int error; 1747*fa0f6e62SHans Petter Selasky 1748*fa0f6e62SHans Petter Selasky if (alloc_nr >= CUSE_ALLOC_UNIT_MAX) 1749*fa0f6e62SHans Petter Selasky return (ENOMEM); 1750*fa0f6e62SHans Petter Selasky 1751*fa0f6e62SHans Petter Selasky error = cuse_client_get(&pcc); 1752*fa0f6e62SHans Petter Selasky if (error != 0) 1753*fa0f6e62SHans Petter Selasky pcs = NULL; 1754*fa0f6e62SHans Petter Selasky else 1755*fa0f6e62SHans Petter Selasky pcs = pcc->server; 1756*fa0f6e62SHans Petter Selasky 1757*fa0f6e62SHans Petter Selasky cuse_lock(); 1758*fa0f6e62SHans Petter Selasky mem = &cuse_mem[alloc_nr]; 1759*fa0f6e62SHans Petter Selasky 1760*fa0f6e62SHans Petter Selasky /* try to enforce slight ownership */ 1761*fa0f6e62SHans Petter Selasky if ((pcs != NULL) && (mem->owner != pcs)) { 1762*fa0f6e62SHans Petter Selasky cuse_unlock(); 1763*fa0f6e62SHans Petter Selasky return (EINVAL); 1764*fa0f6e62SHans Petter Selasky } 1765*fa0f6e62SHans Petter Selasky if (mem->virtaddr == NULL) { 1766*fa0f6e62SHans Petter Selasky cuse_unlock(); 1767*fa0f6e62SHans Petter Selasky return (ENOMEM); 1768*fa0f6e62SHans Petter Selasky } 1769*fa0f6e62SHans Petter Selasky if (mem->virtaddr == NBUSY) { 1770*fa0f6e62SHans Petter Selasky cuse_unlock(); 1771*fa0f6e62SHans Petter Selasky return (ENOMEM); 1772*fa0f6e62SHans Petter Selasky } 1773*fa0f6e62SHans Petter Selasky page_nr %= CUSE_ALLOC_PAGES_MAX; 1774*fa0f6e62SHans Petter Selasky 1775*fa0f6e62SHans Petter Selasky if (page_nr >= mem->page_count) { 1776*fa0f6e62SHans Petter Selasky cuse_unlock(); 1777*fa0f6e62SHans Petter Selasky return (ENXIO); 1778*fa0f6e62SHans Petter Selasky } 1779*fa0f6e62SHans Petter Selasky ptr = mem->virtaddr + (page_nr * PAGE_SIZE); 1780*fa0f6e62SHans Petter Selasky cuse_unlock(); 1781*fa0f6e62SHans Petter Selasky 1782*fa0f6e62SHans Petter Selasky *paddr = vtophys(ptr); 1783*fa0f6e62SHans Petter Selasky 1784*fa0f6e62SHans Petter Selasky return (0); 1785*fa0f6e62SHans Petter Selasky } 1786*fa0f6e62SHans Petter Selasky 1787*fa0f6e62SHans Petter Selasky static void 1788*fa0f6e62SHans Petter Selasky cuse_client_kqfilter_read_detach(struct knote *kn) 1789*fa0f6e62SHans Petter Selasky { 1790*fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 1791*fa0f6e62SHans Petter Selasky 1792*fa0f6e62SHans Petter Selasky cuse_lock(); 1793*fa0f6e62SHans Petter Selasky pcc = kn->kn_hook; 1794*fa0f6e62SHans Petter Selasky knlist_remove(&pcc->server->selinfo.si_note, kn, 1); 1795*fa0f6e62SHans Petter Selasky cuse_unlock(); 1796*fa0f6e62SHans Petter Selasky } 1797*fa0f6e62SHans Petter Selasky 1798*fa0f6e62SHans Petter Selasky static void 1799*fa0f6e62SHans Petter Selasky cuse_client_kqfilter_write_detach(struct knote *kn) 1800*fa0f6e62SHans Petter Selasky { 1801*fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 1802*fa0f6e62SHans Petter Selasky 1803*fa0f6e62SHans Petter Selasky cuse_lock(); 1804*fa0f6e62SHans Petter Selasky pcc = kn->kn_hook; 1805*fa0f6e62SHans Petter Selasky knlist_remove(&pcc->server->selinfo.si_note, kn, 1); 1806*fa0f6e62SHans Petter Selasky cuse_unlock(); 1807*fa0f6e62SHans Petter Selasky } 1808*fa0f6e62SHans Petter Selasky 1809*fa0f6e62SHans Petter Selasky static int 1810*fa0f6e62SHans Petter Selasky cuse_client_kqfilter_read_event(struct knote *kn, long hint) 1811*fa0f6e62SHans Petter Selasky { 1812*fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 1813*fa0f6e62SHans Petter Selasky 1814*fa0f6e62SHans Petter Selasky mtx_assert(&cuse_mtx, MA_OWNED); 1815*fa0f6e62SHans Petter Selasky 1816*fa0f6e62SHans Petter Selasky pcc = kn->kn_hook; 1817*fa0f6e62SHans Petter Selasky return ((pcc->cflags & CUSE_CLI_KNOTE_NEED_READ) ? 1 : 0); 1818*fa0f6e62SHans Petter Selasky } 1819*fa0f6e62SHans Petter Selasky 1820*fa0f6e62SHans Petter Selasky static int 1821*fa0f6e62SHans Petter Selasky cuse_client_kqfilter_write_event(struct knote *kn, long hint) 1822*fa0f6e62SHans Petter Selasky { 1823*fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 1824*fa0f6e62SHans Petter Selasky 1825*fa0f6e62SHans Petter Selasky mtx_assert(&cuse_mtx, MA_OWNED); 1826*fa0f6e62SHans Petter Selasky 1827*fa0f6e62SHans Petter Selasky pcc = kn->kn_hook; 1828*fa0f6e62SHans Petter Selasky return ((pcc->cflags & CUSE_CLI_KNOTE_NEED_WRITE) ? 1 : 0); 1829*fa0f6e62SHans Petter Selasky } 1830*fa0f6e62SHans Petter Selasky 1831*fa0f6e62SHans Petter Selasky static int 1832*fa0f6e62SHans Petter Selasky cuse_client_kqfilter(struct cdev *dev, struct knote *kn) 1833*fa0f6e62SHans Petter Selasky { 1834*fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 1835*fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 1836*fa0f6e62SHans Petter Selasky int error; 1837*fa0f6e62SHans Petter Selasky 1838*fa0f6e62SHans Petter Selasky error = cuse_client_get(&pcc); 1839*fa0f6e62SHans Petter Selasky if (error != 0) 1840*fa0f6e62SHans Petter Selasky return (error); 1841*fa0f6e62SHans Petter Selasky 1842*fa0f6e62SHans Petter Selasky cuse_lock(); 1843*fa0f6e62SHans Petter Selasky pcs = pcc->server; 1844*fa0f6e62SHans Petter Selasky switch (kn->kn_filter) { 1845*fa0f6e62SHans Petter Selasky case EVFILT_READ: 1846*fa0f6e62SHans Petter Selasky pcc->cflags |= CUSE_CLI_KNOTE_HAS_READ; 1847*fa0f6e62SHans Petter Selasky kn->kn_hook = pcc; 1848*fa0f6e62SHans Petter Selasky kn->kn_fop = &cuse_client_kqfilter_read_ops; 1849*fa0f6e62SHans Petter Selasky knlist_add(&pcs->selinfo.si_note, kn, 1); 1850*fa0f6e62SHans Petter Selasky break; 1851*fa0f6e62SHans Petter Selasky case EVFILT_WRITE: 1852*fa0f6e62SHans Petter Selasky pcc->cflags |= CUSE_CLI_KNOTE_HAS_WRITE; 1853*fa0f6e62SHans Petter Selasky kn->kn_hook = pcc; 1854*fa0f6e62SHans Petter Selasky kn->kn_fop = &cuse_client_kqfilter_write_ops; 1855*fa0f6e62SHans Petter Selasky knlist_add(&pcs->selinfo.si_note, kn, 1); 1856*fa0f6e62SHans Petter Selasky break; 1857*fa0f6e62SHans Petter Selasky default: 1858*fa0f6e62SHans Petter Selasky error = EINVAL; 1859*fa0f6e62SHans Petter Selasky break; 1860*fa0f6e62SHans Petter Selasky } 1861*fa0f6e62SHans Petter Selasky cuse_unlock(); 1862*fa0f6e62SHans Petter Selasky 1863*fa0f6e62SHans Petter Selasky if (error == 0) 1864*fa0f6e62SHans Petter Selasky cuse_client_kqfilter_poll(dev, pcc); 1865*fa0f6e62SHans Petter Selasky return (error); 1866*fa0f6e62SHans Petter Selasky } 1867