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