1fa0f6e62SHans Petter Selasky /*- 25e59b273SHans Petter Selasky * Copyright (c) 2010-2022 Hans Petter Selasky 3fa0f6e62SHans Petter Selasky * 4fa0f6e62SHans Petter Selasky * Redistribution and use in source and binary forms, with or without 5fa0f6e62SHans Petter Selasky * modification, are permitted provided that the following conditions 6fa0f6e62SHans Petter Selasky * are met: 7fa0f6e62SHans Petter Selasky * 1. Redistributions of source code must retain the above copyright 8fa0f6e62SHans Petter Selasky * notice, this list of conditions and the following disclaimer. 9fa0f6e62SHans Petter Selasky * 2. Redistributions in binary form must reproduce the above copyright 10fa0f6e62SHans Petter Selasky * notice, this list of conditions and the following disclaimer in the 11fa0f6e62SHans Petter Selasky * documentation and/or other materials provided with the distribution. 12fa0f6e62SHans Petter Selasky * 13fa0f6e62SHans Petter Selasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14fa0f6e62SHans Petter Selasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15fa0f6e62SHans Petter Selasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16fa0f6e62SHans Petter Selasky * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17fa0f6e62SHans Petter Selasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18fa0f6e62SHans Petter Selasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19fa0f6e62SHans Petter Selasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20fa0f6e62SHans Petter Selasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21fa0f6e62SHans Petter Selasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22fa0f6e62SHans Petter Selasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23fa0f6e62SHans Petter Selasky * SUCH DAMAGE. 24fa0f6e62SHans Petter Selasky */ 25fa0f6e62SHans Petter Selasky 26fa0f6e62SHans Petter Selasky #include <sys/stdint.h> 27fa0f6e62SHans Petter Selasky #include <sys/stddef.h> 28fa0f6e62SHans Petter Selasky #include <sys/param.h> 29fa0f6e62SHans Petter Selasky #include <sys/types.h> 30fa0f6e62SHans Petter Selasky #include <sys/systm.h> 31fa0f6e62SHans Petter Selasky #include <sys/conf.h> 32fa0f6e62SHans Petter Selasky #include <sys/kernel.h> 33fa0f6e62SHans Petter Selasky #include <sys/bus.h> 34fa0f6e62SHans Petter Selasky #include <sys/linker_set.h> 35fa0f6e62SHans Petter Selasky #include <sys/module.h> 36fa0f6e62SHans Petter Selasky #include <sys/lock.h> 37fa0f6e62SHans Petter Selasky #include <sys/mutex.h> 38fa0f6e62SHans Petter Selasky #include <sys/condvar.h> 39fa0f6e62SHans Petter Selasky #include <sys/sysctl.h> 40fa0f6e62SHans Petter Selasky #include <sys/unistd.h> 41fa0f6e62SHans Petter Selasky #include <sys/malloc.h> 42fa0f6e62SHans Petter Selasky #include <sys/priv.h> 43fa0f6e62SHans Petter Selasky #include <sys/uio.h> 44fa0f6e62SHans Petter Selasky #include <sys/poll.h> 45fa0f6e62SHans Petter Selasky #include <sys/sx.h> 4656c49c63SHans Petter Selasky #include <sys/rwlock.h> 47fa0f6e62SHans Petter Selasky #include <sys/queue.h> 48fa0f6e62SHans Petter Selasky #include <sys/fcntl.h> 49fa0f6e62SHans Petter Selasky #include <sys/proc.h> 50fa0f6e62SHans Petter Selasky #include <sys/vnode.h> 51fa0f6e62SHans Petter Selasky #include <sys/selinfo.h> 52fa0f6e62SHans Petter Selasky #include <sys/ptrace.h> 53db92a6cdSHans Petter Selasky #include <sys/sysent.h> 54fa0f6e62SHans Petter Selasky 55fa0f6e62SHans Petter Selasky #include <machine/bus.h> 56fa0f6e62SHans Petter Selasky 57fa0f6e62SHans Petter Selasky #include <vm/vm.h> 58fa0f6e62SHans Petter Selasky #include <vm/pmap.h> 5956c49c63SHans Petter Selasky #include <vm/vm_object.h> 6056c49c63SHans Petter Selasky #include <vm/vm_page.h> 6156c49c63SHans Petter Selasky #include <vm/vm_pager.h> 62fa0f6e62SHans Petter Selasky 63fa0f6e62SHans Petter Selasky #include <fs/cuse/cuse_defs.h> 64fa0f6e62SHans Petter Selasky #include <fs/cuse/cuse_ioctl.h> 65fa0f6e62SHans Petter Selasky 665e59b273SHans Petter Selasky /* set this define to zero to disable this feature */ 675e59b273SHans Petter Selasky #define CUSE_COPY_BUFFER_MAX \ 685e59b273SHans Petter Selasky CUSE_BUFFER_MAX 695e59b273SHans Petter Selasky 702c28cd09SHans Petter Selasky #define CUSE_ALLOC_PAGES_MAX \ 712c28cd09SHans Petter Selasky (CUSE_ALLOC_BYTES_MAX / PAGE_SIZE) 722c28cd09SHans Petter Selasky 732c28cd09SHans Petter Selasky #if (CUSE_ALLOC_PAGES_MAX == 0) 742c28cd09SHans Petter Selasky #error "PAGE_SIZE is too big!" 752c28cd09SHans Petter Selasky #endif 762c28cd09SHans Petter Selasky 77a71074e0SHans Petter Selasky static int 78a71074e0SHans Petter Selasky cuse_modevent(module_t mod, int type, void *data) 79a71074e0SHans Petter Selasky { 80a71074e0SHans Petter Selasky switch (type) { 81a71074e0SHans Petter Selasky case MOD_LOAD: 82a71074e0SHans Petter Selasky case MOD_UNLOAD: 83a71074e0SHans Petter Selasky return (0); 84a71074e0SHans Petter Selasky default: 85a71074e0SHans Petter Selasky return (EOPNOTSUPP); 86a71074e0SHans Petter Selasky } 87a71074e0SHans Petter Selasky } 88a71074e0SHans Petter Selasky 89a71074e0SHans Petter Selasky static moduledata_t cuse_mod = { 90a71074e0SHans Petter Selasky .name = "cuse", 91a71074e0SHans Petter Selasky .evhand = &cuse_modevent, 92a71074e0SHans Petter Selasky }; 93a71074e0SHans Petter Selasky 94a71074e0SHans Petter Selasky DECLARE_MODULE(cuse, cuse_mod, SI_SUB_DEVFS, SI_ORDER_FIRST); 95fa0f6e62SHans Petter Selasky MODULE_VERSION(cuse, 1); 96fa0f6e62SHans Petter Selasky 9719f1b6fbSHans Petter Selasky /* 9819f1b6fbSHans Petter Selasky * Prevent cuse4bsd.ko and cuse.ko from loading at the same time by 9919f1b6fbSHans Petter Selasky * declaring support for the cuse4bsd interface in cuse.ko: 10019f1b6fbSHans Petter Selasky */ 10119f1b6fbSHans Petter Selasky MODULE_VERSION(cuse4bsd, 1); 10219f1b6fbSHans Petter Selasky 103fa0f6e62SHans Petter Selasky #ifdef FEATURE 104fa0f6e62SHans Petter Selasky FEATURE(cuse, "Userspace character devices"); 105fa0f6e62SHans Petter Selasky #endif 106fa0f6e62SHans Petter Selasky 107fa0f6e62SHans Petter Selasky struct cuse_command; 108fa0f6e62SHans Petter Selasky struct cuse_server; 109fa0f6e62SHans Petter Selasky struct cuse_client; 110fa0f6e62SHans Petter Selasky 111fa0f6e62SHans Petter Selasky struct cuse_client_command { 112fa0f6e62SHans Petter Selasky TAILQ_ENTRY(cuse_client_command) entry; 113fa0f6e62SHans Petter Selasky struct cuse_command sub; 114fa0f6e62SHans Petter Selasky struct sx sx; 115fa0f6e62SHans Petter Selasky struct cv cv; 116fa0f6e62SHans Petter Selasky struct thread *entered; 117fa0f6e62SHans Petter Selasky struct cuse_client *client; 118fa0f6e62SHans Petter Selasky struct proc *proc_curr; 119fa0f6e62SHans Petter Selasky int proc_refs; 120fa0f6e62SHans Petter Selasky int got_signal; 121fa0f6e62SHans Petter Selasky int error; 122fa0f6e62SHans Petter Selasky int command; 123fa0f6e62SHans Petter Selasky }; 124fa0f6e62SHans Petter Selasky 125fa0f6e62SHans Petter Selasky struct cuse_memory { 12656c49c63SHans Petter Selasky TAILQ_ENTRY(cuse_memory) entry; 12756c49c63SHans Petter Selasky vm_object_t object; 128fa0f6e62SHans Petter Selasky uint32_t page_count; 12956c49c63SHans Petter Selasky uint32_t alloc_nr; 130fa0f6e62SHans Petter Selasky }; 131fa0f6e62SHans Petter Selasky 132fa0f6e62SHans Petter Selasky struct cuse_server_dev { 133fa0f6e62SHans Petter Selasky TAILQ_ENTRY(cuse_server_dev) entry; 134fa0f6e62SHans Petter Selasky struct cuse_server *server; 135fa0f6e62SHans Petter Selasky struct cdev *kern_dev; 136fa0f6e62SHans Petter Selasky struct cuse_dev *user_dev; 137fa0f6e62SHans Petter Selasky }; 138fa0f6e62SHans Petter Selasky 139fa0f6e62SHans Petter Selasky struct cuse_server { 140fa0f6e62SHans Petter Selasky TAILQ_ENTRY(cuse_server) entry; 141fa0f6e62SHans Petter Selasky TAILQ_HEAD(, cuse_client_command) head; 142fa0f6e62SHans Petter Selasky TAILQ_HEAD(, cuse_server_dev) hdev; 143fa0f6e62SHans Petter Selasky TAILQ_HEAD(, cuse_client) hcli; 14456c49c63SHans Petter Selasky TAILQ_HEAD(, cuse_memory) hmem; 14598029019SHans Petter Selasky struct mtx mtx; 146fa0f6e62SHans Petter Selasky struct cv cv; 147fa0f6e62SHans Petter Selasky struct selinfo selinfo; 148ac60e801SHans Petter Selasky pid_t pid; 149fa0f6e62SHans Petter Selasky int is_closing; 150fa0f6e62SHans Petter Selasky int refs; 151fa0f6e62SHans Petter Selasky }; 152fa0f6e62SHans Petter Selasky 153fa0f6e62SHans Petter Selasky struct cuse_client { 154fa0f6e62SHans Petter Selasky TAILQ_ENTRY(cuse_client) entry; 155fa0f6e62SHans Petter Selasky TAILQ_ENTRY(cuse_client) entry_ref; 156fa0f6e62SHans Petter Selasky struct cuse_client_command cmds[CUSE_CMD_MAX]; 157fa0f6e62SHans Petter Selasky struct cuse_server *server; 158fa0f6e62SHans Petter Selasky struct cuse_server_dev *server_dev; 159fa0f6e62SHans Petter Selasky 1605e59b273SHans Petter Selasky uintptr_t read_base; 1615e59b273SHans Petter Selasky uintptr_t write_base; 1625e59b273SHans Petter Selasky int read_length; 1635e59b273SHans Petter Selasky int write_length; 1645e59b273SHans Petter Selasky uint8_t read_buffer[CUSE_COPY_BUFFER_MAX] __aligned(4); 1655e59b273SHans Petter Selasky uint8_t write_buffer[CUSE_COPY_BUFFER_MAX] __aligned(4); 166fa0f6e62SHans Petter Selasky uint8_t ioctl_buffer[CUSE_BUFFER_MAX] __aligned(4); 167fa0f6e62SHans Petter Selasky 168fa0f6e62SHans Petter Selasky int fflags; /* file flags */ 169fa0f6e62SHans Petter Selasky int cflags; /* client flags */ 170fa0f6e62SHans Petter Selasky #define CUSE_CLI_IS_CLOSING 0x01 171fa0f6e62SHans Petter Selasky #define CUSE_CLI_KNOTE_NEED_READ 0x02 172fa0f6e62SHans Petter Selasky #define CUSE_CLI_KNOTE_NEED_WRITE 0x04 173fa0f6e62SHans Petter Selasky #define CUSE_CLI_KNOTE_HAS_READ 0x08 174fa0f6e62SHans Petter Selasky #define CUSE_CLI_KNOTE_HAS_WRITE 0x10 175fa0f6e62SHans Petter Selasky }; 176fa0f6e62SHans Petter Selasky 177fa0f6e62SHans Petter Selasky #define CUSE_CLIENT_CLOSING(pcc) \ 178fa0f6e62SHans Petter Selasky ((pcc)->cflags & CUSE_CLI_IS_CLOSING) 179fa0f6e62SHans Petter Selasky 180fa0f6e62SHans Petter Selasky static MALLOC_DEFINE(M_CUSE, "cuse", "CUSE memory"); 181fa0f6e62SHans Petter Selasky 182fa0f6e62SHans Petter Selasky static TAILQ_HEAD(, cuse_server) cuse_server_head; 18398029019SHans Petter Selasky static struct mtx cuse_global_mtx; 184fa0f6e62SHans Petter Selasky static struct cdev *cuse_dev; 185fa0f6e62SHans Petter Selasky static struct cuse_server *cuse_alloc_unit[CUSE_DEVICES_MAX]; 186fa0f6e62SHans Petter Selasky static int cuse_alloc_unit_id[CUSE_DEVICES_MAX]; 187fa0f6e62SHans Petter Selasky 18895700043SHans Petter Selasky static void cuse_server_wakeup_all_client_locked(struct cuse_server *pcs); 189fa0f6e62SHans Petter Selasky static void cuse_client_kqfilter_read_detach(struct knote *kn); 190fa0f6e62SHans Petter Selasky static void cuse_client_kqfilter_write_detach(struct knote *kn); 191fa0f6e62SHans Petter Selasky static int cuse_client_kqfilter_read_event(struct knote *kn, long hint); 192fa0f6e62SHans Petter Selasky static int cuse_client_kqfilter_write_event(struct knote *kn, long hint); 193fa0f6e62SHans Petter Selasky 194ef9ffb85SMark Johnston static const struct filterops cuse_client_kqfilter_read_ops = { 195fa0f6e62SHans Petter Selasky .f_isfd = 1, 196fa0f6e62SHans Petter Selasky .f_detach = cuse_client_kqfilter_read_detach, 197fa0f6e62SHans Petter Selasky .f_event = cuse_client_kqfilter_read_event, 198fa0f6e62SHans Petter Selasky }; 199fa0f6e62SHans Petter Selasky 200ef9ffb85SMark Johnston static const struct filterops cuse_client_kqfilter_write_ops = { 201fa0f6e62SHans Petter Selasky .f_isfd = 1, 202fa0f6e62SHans Petter Selasky .f_detach = cuse_client_kqfilter_write_detach, 203fa0f6e62SHans Petter Selasky .f_event = cuse_client_kqfilter_write_event, 204fa0f6e62SHans Petter Selasky }; 205fa0f6e62SHans Petter Selasky 206fa0f6e62SHans Petter Selasky static d_open_t cuse_client_open; 207fa0f6e62SHans Petter Selasky static d_close_t cuse_client_close; 208fa0f6e62SHans Petter Selasky static d_ioctl_t cuse_client_ioctl; 209fa0f6e62SHans Petter Selasky static d_read_t cuse_client_read; 210fa0f6e62SHans Petter Selasky static d_write_t cuse_client_write; 211fa0f6e62SHans Petter Selasky static d_poll_t cuse_client_poll; 21256c49c63SHans Petter Selasky static d_mmap_single_t cuse_client_mmap_single; 213fa0f6e62SHans Petter Selasky static d_kqfilter_t cuse_client_kqfilter; 214fa0f6e62SHans Petter Selasky 215fa0f6e62SHans Petter Selasky static struct cdevsw cuse_client_devsw = { 216fa0f6e62SHans Petter Selasky .d_version = D_VERSION, 217fa0f6e62SHans Petter Selasky .d_open = cuse_client_open, 218fa0f6e62SHans Petter Selasky .d_close = cuse_client_close, 219fa0f6e62SHans Petter Selasky .d_ioctl = cuse_client_ioctl, 220fa0f6e62SHans Petter Selasky .d_name = "cuse_client", 221fa0f6e62SHans Petter Selasky .d_flags = D_TRACKCLOSE, 222fa0f6e62SHans Petter Selasky .d_read = cuse_client_read, 223fa0f6e62SHans Petter Selasky .d_write = cuse_client_write, 224fa0f6e62SHans Petter Selasky .d_poll = cuse_client_poll, 22556c49c63SHans Petter Selasky .d_mmap_single = cuse_client_mmap_single, 226fa0f6e62SHans Petter Selasky .d_kqfilter = cuse_client_kqfilter, 227fa0f6e62SHans Petter Selasky }; 228fa0f6e62SHans Petter Selasky 229fa0f6e62SHans Petter Selasky static d_open_t cuse_server_open; 230fa0f6e62SHans Petter Selasky static d_close_t cuse_server_close; 231fa0f6e62SHans Petter Selasky static d_ioctl_t cuse_server_ioctl; 232fa0f6e62SHans Petter Selasky static d_read_t cuse_server_read; 233fa0f6e62SHans Petter Selasky static d_write_t cuse_server_write; 234fa0f6e62SHans Petter Selasky static d_poll_t cuse_server_poll; 23556c49c63SHans Petter Selasky static d_mmap_single_t cuse_server_mmap_single; 236fa0f6e62SHans Petter Selasky 237fa0f6e62SHans Petter Selasky static struct cdevsw cuse_server_devsw = { 238fa0f6e62SHans Petter Selasky .d_version = D_VERSION, 239fa0f6e62SHans Petter Selasky .d_open = cuse_server_open, 240fa0f6e62SHans Petter Selasky .d_close = cuse_server_close, 241fa0f6e62SHans Petter Selasky .d_ioctl = cuse_server_ioctl, 242fa0f6e62SHans Petter Selasky .d_name = "cuse_server", 243fa0f6e62SHans Petter Selasky .d_flags = D_TRACKCLOSE, 244fa0f6e62SHans Petter Selasky .d_read = cuse_server_read, 245fa0f6e62SHans Petter Selasky .d_write = cuse_server_write, 246fa0f6e62SHans Petter Selasky .d_poll = cuse_server_poll, 24756c49c63SHans Petter Selasky .d_mmap_single = cuse_server_mmap_single, 248fa0f6e62SHans Petter Selasky }; 249fa0f6e62SHans Petter Selasky 250fa0f6e62SHans Petter Selasky static void cuse_client_is_closing(struct cuse_client *); 251fa0f6e62SHans Petter Selasky static int cuse_free_unit_by_id_locked(struct cuse_server *, int); 252fa0f6e62SHans Petter Selasky 253fa0f6e62SHans Petter Selasky static void 25498029019SHans Petter Selasky cuse_global_lock(void) 255fa0f6e62SHans Petter Selasky { 25698029019SHans Petter Selasky mtx_lock(&cuse_global_mtx); 257fa0f6e62SHans Petter Selasky } 258fa0f6e62SHans Petter Selasky 259fa0f6e62SHans Petter Selasky static void 26098029019SHans Petter Selasky cuse_global_unlock(void) 261fa0f6e62SHans Petter Selasky { 26298029019SHans Petter Selasky mtx_unlock(&cuse_global_mtx); 26398029019SHans Petter Selasky } 26498029019SHans Petter Selasky 26598029019SHans Petter Selasky static void 26698029019SHans Petter Selasky cuse_server_lock(struct cuse_server *pcs) 26798029019SHans Petter Selasky { 26898029019SHans Petter Selasky mtx_lock(&pcs->mtx); 26998029019SHans Petter Selasky } 27098029019SHans Petter Selasky 27198029019SHans Petter Selasky static void 27298029019SHans Petter Selasky cuse_server_unlock(struct cuse_server *pcs) 27398029019SHans Petter Selasky { 27498029019SHans Petter Selasky mtx_unlock(&pcs->mtx); 275fa0f6e62SHans Petter Selasky } 276fa0f6e62SHans Petter Selasky 2775e59b273SHans Petter Selasky static bool 2785e59b273SHans Petter Selasky cuse_server_is_locked(struct cuse_server *pcs) 2795e59b273SHans Petter Selasky { 2805e59b273SHans Petter Selasky return (mtx_owned(&pcs->mtx)); 2815e59b273SHans Petter Selasky } 2825e59b273SHans Petter Selasky 283fa0f6e62SHans Petter Selasky static void 284fa0f6e62SHans Petter Selasky cuse_cmd_lock(struct cuse_client_command *pccmd) 285fa0f6e62SHans Petter Selasky { 286fa0f6e62SHans Petter Selasky sx_xlock(&pccmd->sx); 287fa0f6e62SHans Petter Selasky } 288fa0f6e62SHans Petter Selasky 289fa0f6e62SHans Petter Selasky static void 290fa0f6e62SHans Petter Selasky cuse_cmd_unlock(struct cuse_client_command *pccmd) 291fa0f6e62SHans Petter Selasky { 292fa0f6e62SHans Petter Selasky sx_xunlock(&pccmd->sx); 293fa0f6e62SHans Petter Selasky } 294fa0f6e62SHans Petter Selasky 295fa0f6e62SHans Petter Selasky static void 296fa0f6e62SHans Petter Selasky cuse_kern_init(void *arg) 297fa0f6e62SHans Petter Selasky { 298fa0f6e62SHans Petter Selasky TAILQ_INIT(&cuse_server_head); 299fa0f6e62SHans Petter Selasky 30098029019SHans Petter Selasky mtx_init(&cuse_global_mtx, "cuse-global-mtx", NULL, MTX_DEF); 301fa0f6e62SHans Petter Selasky 302fa0f6e62SHans Petter Selasky cuse_dev = make_dev(&cuse_server_devsw, 0, 303fa0f6e62SHans Petter Selasky UID_ROOT, GID_OPERATOR, 0600, "cuse"); 304fa0f6e62SHans Petter Selasky 305fa0f6e62SHans Petter Selasky printf("Cuse v%d.%d.%d @ /dev/cuse\n", 306fa0f6e62SHans Petter Selasky (CUSE_VERSION >> 16) & 0xFF, (CUSE_VERSION >> 8) & 0xFF, 307fa0f6e62SHans Petter Selasky (CUSE_VERSION >> 0) & 0xFF); 308fa0f6e62SHans Petter Selasky } 309891cf3edSEd Maste SYSINIT(cuse_kern_init, SI_SUB_DEVFS, SI_ORDER_ANY, cuse_kern_init, NULL); 310fa0f6e62SHans Petter Selasky 311fa0f6e62SHans Petter Selasky static void 312fa0f6e62SHans Petter Selasky cuse_kern_uninit(void *arg) 313fa0f6e62SHans Petter Selasky { 314fa0f6e62SHans Petter Selasky void *ptr; 315fa0f6e62SHans Petter Selasky 316fa0f6e62SHans Petter Selasky while (1) { 317fa0f6e62SHans Petter Selasky printf("Cuse: Please exit all /dev/cuse instances " 318fa0f6e62SHans Petter Selasky "and processes which have used this device.\n"); 319fa0f6e62SHans Petter Selasky 320fa0f6e62SHans Petter Selasky pause("DRAIN", 2 * hz); 321fa0f6e62SHans Petter Selasky 32298029019SHans Petter Selasky cuse_global_lock(); 323fa0f6e62SHans Petter Selasky ptr = TAILQ_FIRST(&cuse_server_head); 32498029019SHans Petter Selasky cuse_global_unlock(); 325fa0f6e62SHans Petter Selasky 326fa0f6e62SHans Petter Selasky if (ptr == NULL) 327fa0f6e62SHans Petter Selasky break; 328fa0f6e62SHans Petter Selasky } 329fa0f6e62SHans Petter Selasky 330fa0f6e62SHans Petter Selasky if (cuse_dev != NULL) 331fa0f6e62SHans Petter Selasky destroy_dev(cuse_dev); 332fa0f6e62SHans Petter Selasky 33398029019SHans Petter Selasky mtx_destroy(&cuse_global_mtx); 334fa0f6e62SHans Petter Selasky } 335*6854a148SZhenlei Huang SYSUNINIT(cuse_kern_uninit, SI_SUB_DEVFS, SI_ORDER_ANY, cuse_kern_uninit, NULL); 336fa0f6e62SHans Petter Selasky 337fa0f6e62SHans Petter Selasky static int 338fa0f6e62SHans Petter Selasky cuse_server_get(struct cuse_server **ppcs) 339fa0f6e62SHans Petter Selasky { 340fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 341fa0f6e62SHans Petter Selasky int error; 342fa0f6e62SHans Petter Selasky 343fa0f6e62SHans Petter Selasky error = devfs_get_cdevpriv((void **)&pcs); 344fa0f6e62SHans Petter Selasky if (error != 0) { 345fa0f6e62SHans Petter Selasky *ppcs = NULL; 346fa0f6e62SHans Petter Selasky return (error); 347fa0f6e62SHans Petter Selasky } 348fa0f6e62SHans Petter Selasky if (pcs->is_closing) { 349fa0f6e62SHans Petter Selasky *ppcs = NULL; 350fa0f6e62SHans Petter Selasky return (EINVAL); 351fa0f6e62SHans Petter Selasky } 352fa0f6e62SHans Petter Selasky *ppcs = pcs; 353fa0f6e62SHans Petter Selasky return (0); 354fa0f6e62SHans Petter Selasky } 355fa0f6e62SHans Petter Selasky 356fa0f6e62SHans Petter Selasky static void 357fa0f6e62SHans Petter Selasky cuse_server_is_closing(struct cuse_server *pcs) 358fa0f6e62SHans Petter Selasky { 359fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 360fa0f6e62SHans Petter Selasky 361fa0f6e62SHans Petter Selasky if (pcs->is_closing) 362fa0f6e62SHans Petter Selasky return; 363fa0f6e62SHans Petter Selasky 364fa0f6e62SHans Petter Selasky pcs->is_closing = 1; 365fa0f6e62SHans Petter Selasky 366fa0f6e62SHans Petter Selasky TAILQ_FOREACH(pcc, &pcs->hcli, entry) { 367fa0f6e62SHans Petter Selasky cuse_client_is_closing(pcc); 368fa0f6e62SHans Petter Selasky } 369fa0f6e62SHans Petter Selasky } 370fa0f6e62SHans Petter Selasky 371fa0f6e62SHans Petter Selasky static struct cuse_client_command * 372fa0f6e62SHans Petter Selasky cuse_server_find_command(struct cuse_server *pcs, struct thread *td) 373fa0f6e62SHans Petter Selasky { 374fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 375fa0f6e62SHans Petter Selasky int n; 376fa0f6e62SHans Petter Selasky 377fa0f6e62SHans Petter Selasky if (pcs->is_closing) 378fa0f6e62SHans Petter Selasky goto done; 379fa0f6e62SHans Petter Selasky 380fa0f6e62SHans Petter Selasky TAILQ_FOREACH(pcc, &pcs->hcli, entry) { 381fa0f6e62SHans Petter Selasky if (CUSE_CLIENT_CLOSING(pcc)) 382fa0f6e62SHans Petter Selasky continue; 383fa0f6e62SHans Petter Selasky for (n = 0; n != CUSE_CMD_MAX; n++) { 384fa0f6e62SHans Petter Selasky if (pcc->cmds[n].entered == td) 385fa0f6e62SHans Petter Selasky return (&pcc->cmds[n]); 386fa0f6e62SHans Petter Selasky } 387fa0f6e62SHans Petter Selasky } 388fa0f6e62SHans Petter Selasky done: 389fa0f6e62SHans Petter Selasky return (NULL); 390fa0f6e62SHans Petter Selasky } 391fa0f6e62SHans Petter Selasky 392fa0f6e62SHans Petter Selasky static void 393fa0f6e62SHans Petter Selasky cuse_str_filter(char *ptr) 394fa0f6e62SHans Petter Selasky { 395fa0f6e62SHans Petter Selasky int c; 396fa0f6e62SHans Petter Selasky 397fa0f6e62SHans Petter Selasky while (((c = *ptr) != 0)) { 398fa0f6e62SHans Petter Selasky if ((c >= 'a') && (c <= 'z')) { 399fa0f6e62SHans Petter Selasky ptr++; 400fa0f6e62SHans Petter Selasky continue; 401fa0f6e62SHans Petter Selasky } 402fa0f6e62SHans Petter Selasky if ((c >= 'A') && (c <= 'Z')) { 403fa0f6e62SHans Petter Selasky ptr++; 404fa0f6e62SHans Petter Selasky continue; 405fa0f6e62SHans Petter Selasky } 406fa0f6e62SHans Petter Selasky if ((c >= '0') && (c <= '9')) { 407fa0f6e62SHans Petter Selasky ptr++; 408fa0f6e62SHans Petter Selasky continue; 409fa0f6e62SHans Petter Selasky } 410fa0f6e62SHans Petter Selasky if ((c == '.') || (c == '_') || (c == '/')) { 411fa0f6e62SHans Petter Selasky ptr++; 412fa0f6e62SHans Petter Selasky continue; 413fa0f6e62SHans Petter Selasky } 414fa0f6e62SHans Petter Selasky *ptr = '_'; 415fa0f6e62SHans Petter Selasky 416fa0f6e62SHans Petter Selasky ptr++; 417fa0f6e62SHans Petter Selasky } 418fa0f6e62SHans Petter Selasky } 419fa0f6e62SHans Petter Selasky 420fa0f6e62SHans Petter Selasky static int 421fa0f6e62SHans Petter Selasky cuse_convert_error(int error) 422fa0f6e62SHans Petter Selasky { 423fa0f6e62SHans Petter Selasky ; /* indent fix */ 424fa0f6e62SHans Petter Selasky switch (error) { 425fa0f6e62SHans Petter Selasky case CUSE_ERR_NONE: 426fa0f6e62SHans Petter Selasky return (0); 427fa0f6e62SHans Petter Selasky case CUSE_ERR_BUSY: 428fa0f6e62SHans Petter Selasky return (EBUSY); 429fa0f6e62SHans Petter Selasky case CUSE_ERR_WOULDBLOCK: 430fa0f6e62SHans Petter Selasky return (EWOULDBLOCK); 431fa0f6e62SHans Petter Selasky case CUSE_ERR_INVALID: 432fa0f6e62SHans Petter Selasky return (EINVAL); 433fa0f6e62SHans Petter Selasky case CUSE_ERR_NO_MEMORY: 434fa0f6e62SHans Petter Selasky return (ENOMEM); 435fa0f6e62SHans Petter Selasky case CUSE_ERR_FAULT: 436fa0f6e62SHans Petter Selasky return (EFAULT); 437fa0f6e62SHans Petter Selasky case CUSE_ERR_SIGNAL: 438fa0f6e62SHans Petter Selasky return (EINTR); 4399f16d9c9SHans Petter Selasky case CUSE_ERR_NO_DEVICE: 4409f16d9c9SHans Petter Selasky return (ENODEV); 441fa0f6e62SHans Petter Selasky default: 442fa0f6e62SHans Petter Selasky return (ENXIO); 443fa0f6e62SHans Petter Selasky } 444fa0f6e62SHans Petter Selasky } 445fa0f6e62SHans Petter Selasky 446fa0f6e62SHans Petter Selasky static void 44756c49c63SHans Petter Selasky cuse_vm_memory_free(struct cuse_memory *mem) 448fa0f6e62SHans Petter Selasky { 44956c49c63SHans Petter Selasky /* last user is gone - free */ 45056c49c63SHans Petter Selasky vm_object_deallocate(mem->object); 451fa0f6e62SHans Petter Selasky 45256c49c63SHans Petter Selasky /* free CUSE memory */ 45356c49c63SHans Petter Selasky free(mem, M_CUSE); 454fa0f6e62SHans Petter Selasky } 455fa0f6e62SHans Petter Selasky 456fa0f6e62SHans Petter Selasky static int 45756c49c63SHans Petter Selasky cuse_server_alloc_memory(struct cuse_server *pcs, uint32_t alloc_nr, 45856c49c63SHans Petter Selasky uint32_t page_count) 459fa0f6e62SHans Petter Selasky { 46056c49c63SHans Petter Selasky struct cuse_memory *temp; 46156c49c63SHans Petter Selasky struct cuse_memory *mem; 46256c49c63SHans Petter Selasky vm_object_t object; 463fa0f6e62SHans Petter Selasky int error; 464fa0f6e62SHans Petter Selasky 46556c49c63SHans Petter Selasky mem = malloc(sizeof(*mem), M_CUSE, M_WAITOK | M_ZERO); 466fa0f6e62SHans Petter Selasky 46756c49c63SHans Petter Selasky object = vm_pager_allocate(OBJT_SWAP, NULL, PAGE_SIZE * page_count, 46856c49c63SHans Petter Selasky VM_PROT_DEFAULT, 0, curthread->td_ucred); 46956c49c63SHans Petter Selasky if (object == NULL) { 470fa0f6e62SHans Petter Selasky error = ENOMEM; 47156c49c63SHans Petter Selasky goto error_0; 47256c49c63SHans Petter Selasky } 473fa0f6e62SHans Petter Selasky 47498029019SHans Petter Selasky cuse_server_lock(pcs); 47556c49c63SHans Petter Selasky /* check if allocation number already exists */ 47656c49c63SHans Petter Selasky TAILQ_FOREACH(temp, &pcs->hmem, entry) { 47756c49c63SHans Petter Selasky if (temp->alloc_nr == alloc_nr) 47856c49c63SHans Petter Selasky break; 47956c49c63SHans Petter Selasky } 48056c49c63SHans Petter Selasky if (temp != NULL) { 48198029019SHans Petter Selasky cuse_server_unlock(pcs); 48256c49c63SHans Petter Selasky error = EBUSY; 48356c49c63SHans Petter Selasky goto error_1; 48456c49c63SHans Petter Selasky } 48556c49c63SHans Petter Selasky mem->object = object; 48656c49c63SHans Petter Selasky mem->page_count = page_count; 48756c49c63SHans Petter Selasky mem->alloc_nr = alloc_nr; 48856c49c63SHans Petter Selasky TAILQ_INSERT_TAIL(&pcs->hmem, mem, entry); 48998029019SHans Petter Selasky cuse_server_unlock(pcs); 49056c49c63SHans Petter Selasky 49156c49c63SHans Petter Selasky return (0); 49256c49c63SHans Petter Selasky 49356c49c63SHans Petter Selasky error_1: 49456c49c63SHans Petter Selasky vm_object_deallocate(object); 49556c49c63SHans Petter Selasky error_0: 49656c49c63SHans Petter Selasky free(mem, M_CUSE); 497fa0f6e62SHans Petter Selasky return (error); 498fa0f6e62SHans Petter Selasky } 49956c49c63SHans Petter Selasky 50056c49c63SHans Petter Selasky static int 50156c49c63SHans Petter Selasky cuse_server_free_memory(struct cuse_server *pcs, uint32_t alloc_nr) 50256c49c63SHans Petter Selasky { 50356c49c63SHans Petter Selasky struct cuse_memory *mem; 50456c49c63SHans Petter Selasky 50598029019SHans Petter Selasky cuse_server_lock(pcs); 50656c49c63SHans Petter Selasky TAILQ_FOREACH(mem, &pcs->hmem, entry) { 50756c49c63SHans Petter Selasky if (mem->alloc_nr == alloc_nr) 50856c49c63SHans Petter Selasky break; 50956c49c63SHans Petter Selasky } 51056c49c63SHans Petter Selasky if (mem == NULL) { 51198029019SHans Petter Selasky cuse_server_unlock(pcs); 51256c49c63SHans Petter Selasky return (EINVAL); 51356c49c63SHans Petter Selasky } 51456c49c63SHans Petter Selasky TAILQ_REMOVE(&pcs->hmem, mem, entry); 51598029019SHans Petter Selasky cuse_server_unlock(pcs); 51656c49c63SHans Petter Selasky 51756c49c63SHans Petter Selasky cuse_vm_memory_free(mem); 518fa0f6e62SHans Petter Selasky 519fa0f6e62SHans Petter Selasky return (0); 520fa0f6e62SHans Petter Selasky } 521fa0f6e62SHans Petter Selasky 522fa0f6e62SHans Petter Selasky static int 523fa0f6e62SHans Petter Selasky cuse_client_get(struct cuse_client **ppcc) 524fa0f6e62SHans Petter Selasky { 525fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 526fa0f6e62SHans Petter Selasky int error; 527fa0f6e62SHans Petter Selasky 528fa0f6e62SHans Petter Selasky /* try to get private data */ 529fa0f6e62SHans Petter Selasky error = devfs_get_cdevpriv((void **)&pcc); 530fa0f6e62SHans Petter Selasky if (error != 0) { 531fa0f6e62SHans Petter Selasky *ppcc = NULL; 532fa0f6e62SHans Petter Selasky return (error); 533fa0f6e62SHans Petter Selasky } 534fa0f6e62SHans Petter Selasky if (CUSE_CLIENT_CLOSING(pcc) || pcc->server->is_closing) { 535fa0f6e62SHans Petter Selasky *ppcc = NULL; 536fa0f6e62SHans Petter Selasky return (EINVAL); 537fa0f6e62SHans Petter Selasky } 538fa0f6e62SHans Petter Selasky *ppcc = pcc; 539fa0f6e62SHans Petter Selasky return (0); 540fa0f6e62SHans Petter Selasky } 541fa0f6e62SHans Petter Selasky 542fa0f6e62SHans Petter Selasky static void 543fa0f6e62SHans Petter Selasky cuse_client_is_closing(struct cuse_client *pcc) 544fa0f6e62SHans Petter Selasky { 545fa0f6e62SHans Petter Selasky struct cuse_client_command *pccmd; 546fa0f6e62SHans Petter Selasky uint32_t n; 547fa0f6e62SHans Petter Selasky 548fa0f6e62SHans Petter Selasky if (CUSE_CLIENT_CLOSING(pcc)) 549fa0f6e62SHans Petter Selasky return; 550fa0f6e62SHans Petter Selasky 551fa0f6e62SHans Petter Selasky pcc->cflags |= CUSE_CLI_IS_CLOSING; 552fa0f6e62SHans Petter Selasky pcc->server_dev = NULL; 553fa0f6e62SHans Petter Selasky 554fa0f6e62SHans Petter Selasky for (n = 0; n != CUSE_CMD_MAX; n++) { 555fa0f6e62SHans Petter Selasky pccmd = &pcc->cmds[n]; 556fa0f6e62SHans Petter Selasky 557fa0f6e62SHans Petter Selasky if (pccmd->entry.tqe_prev != NULL) { 558fa0f6e62SHans Petter Selasky TAILQ_REMOVE(&pcc->server->head, pccmd, entry); 559fa0f6e62SHans Petter Selasky pccmd->entry.tqe_prev = NULL; 560fa0f6e62SHans Petter Selasky } 561fa0f6e62SHans Petter Selasky cv_broadcast(&pccmd->cv); 562fa0f6e62SHans Petter Selasky } 563fa0f6e62SHans Petter Selasky } 564fa0f6e62SHans Petter Selasky 565fa0f6e62SHans Petter Selasky static void 566fa0f6e62SHans Petter Selasky cuse_client_send_command_locked(struct cuse_client_command *pccmd, 567beebd9aaSHans Petter Selasky uintptr_t data_ptr, unsigned long arg, int fflags, int ioflag) 568fa0f6e62SHans Petter Selasky { 569fa0f6e62SHans Petter Selasky unsigned long cuse_fflags = 0; 570fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 571fa0f6e62SHans Petter Selasky 572fa0f6e62SHans Petter Selasky if (fflags & FREAD) 573fa0f6e62SHans Petter Selasky cuse_fflags |= CUSE_FFLAG_READ; 574fa0f6e62SHans Petter Selasky 575fa0f6e62SHans Petter Selasky if (fflags & FWRITE) 576fa0f6e62SHans Petter Selasky cuse_fflags |= CUSE_FFLAG_WRITE; 577fa0f6e62SHans Petter Selasky 578fa0f6e62SHans Petter Selasky if (ioflag & IO_NDELAY) 579fa0f6e62SHans Petter Selasky cuse_fflags |= CUSE_FFLAG_NONBLOCK; 580db92a6cdSHans Petter Selasky #if defined(__LP64__) 581db92a6cdSHans Petter Selasky if (SV_CURPROC_FLAG(SV_ILP32)) 582db92a6cdSHans Petter Selasky cuse_fflags |= CUSE_FFLAG_COMPAT32; 583db92a6cdSHans Petter Selasky #endif 584fa0f6e62SHans Petter Selasky pccmd->sub.fflags = cuse_fflags; 585fa0f6e62SHans Petter Selasky pccmd->sub.data_pointer = data_ptr; 586fa0f6e62SHans Petter Selasky pccmd->sub.argument = arg; 587fa0f6e62SHans Petter Selasky 588fa0f6e62SHans Petter Selasky pcs = pccmd->client->server; 589fa0f6e62SHans Petter Selasky 590fa0f6e62SHans Petter Selasky if ((pccmd->entry.tqe_prev == NULL) && 591fa0f6e62SHans Petter Selasky (CUSE_CLIENT_CLOSING(pccmd->client) == 0) && 592fa0f6e62SHans Petter Selasky (pcs->is_closing == 0)) { 593fa0f6e62SHans Petter Selasky TAILQ_INSERT_TAIL(&pcs->head, pccmd, entry); 594fa0f6e62SHans Petter Selasky cv_signal(&pcs->cv); 595fa0f6e62SHans Petter Selasky } 596fa0f6e62SHans Petter Selasky } 597fa0f6e62SHans Petter Selasky 598fa0f6e62SHans Petter Selasky static void 599fa0f6e62SHans Petter Selasky cuse_client_got_signal(struct cuse_client_command *pccmd) 600fa0f6e62SHans Petter Selasky { 601fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 602fa0f6e62SHans Petter Selasky 603fa0f6e62SHans Petter Selasky pccmd->got_signal = 1; 604fa0f6e62SHans Petter Selasky 605fa0f6e62SHans Petter Selasky pccmd = &pccmd->client->cmds[CUSE_CMD_SIGNAL]; 606fa0f6e62SHans Petter Selasky 607fa0f6e62SHans Petter Selasky pcs = pccmd->client->server; 608fa0f6e62SHans Petter Selasky 609fa0f6e62SHans Petter Selasky if ((pccmd->entry.tqe_prev == NULL) && 610fa0f6e62SHans Petter Selasky (CUSE_CLIENT_CLOSING(pccmd->client) == 0) && 611fa0f6e62SHans Petter Selasky (pcs->is_closing == 0)) { 612fa0f6e62SHans Petter Selasky TAILQ_INSERT_TAIL(&pcs->head, pccmd, entry); 613fa0f6e62SHans Petter Selasky cv_signal(&pcs->cv); 614fa0f6e62SHans Petter Selasky } 615fa0f6e62SHans Petter Selasky } 616fa0f6e62SHans Petter Selasky 617fa0f6e62SHans Petter Selasky static int 618fa0f6e62SHans Petter Selasky cuse_client_receive_command_locked(struct cuse_client_command *pccmd, 619fa0f6e62SHans Petter Selasky uint8_t *arg_ptr, uint32_t arg_len) 620fa0f6e62SHans Petter Selasky { 62198029019SHans Petter Selasky struct cuse_server *pcs; 622fa0f6e62SHans Petter Selasky int error; 623fa0f6e62SHans Petter Selasky 62498029019SHans Petter Selasky pcs = pccmd->client->server; 625fa0f6e62SHans Petter Selasky error = 0; 626fa0f6e62SHans Petter Selasky 627fa0f6e62SHans Petter Selasky pccmd->proc_curr = curthread->td_proc; 628fa0f6e62SHans Petter Selasky 62998029019SHans Petter Selasky if (CUSE_CLIENT_CLOSING(pccmd->client) || pcs->is_closing) { 630fa0f6e62SHans Petter Selasky error = CUSE_ERR_OTHER; 631fa0f6e62SHans Petter Selasky goto done; 632fa0f6e62SHans Petter Selasky } 633fa0f6e62SHans Petter Selasky while (pccmd->command == CUSE_CMD_NONE) { 634fa0f6e62SHans Petter Selasky if (error != 0) { 63598029019SHans Petter Selasky cv_wait(&pccmd->cv, &pcs->mtx); 636fa0f6e62SHans Petter Selasky } else { 63798029019SHans Petter Selasky error = cv_wait_sig(&pccmd->cv, &pcs->mtx); 638fa0f6e62SHans Petter Selasky 639fa0f6e62SHans Petter Selasky if (error != 0) 640fa0f6e62SHans Petter Selasky cuse_client_got_signal(pccmd); 641fa0f6e62SHans Petter Selasky } 64298029019SHans Petter Selasky if (CUSE_CLIENT_CLOSING(pccmd->client) || pcs->is_closing) { 643fa0f6e62SHans Petter Selasky error = CUSE_ERR_OTHER; 644fa0f6e62SHans Petter Selasky goto done; 645fa0f6e62SHans Petter Selasky } 646fa0f6e62SHans Petter Selasky } 647fa0f6e62SHans Petter Selasky 648fa0f6e62SHans Petter Selasky error = pccmd->error; 649fa0f6e62SHans Petter Selasky pccmd->command = CUSE_CMD_NONE; 650fa0f6e62SHans Petter Selasky cv_signal(&pccmd->cv); 651fa0f6e62SHans Petter Selasky 652fa0f6e62SHans Petter Selasky done: 653fa0f6e62SHans Petter Selasky 654fa0f6e62SHans Petter Selasky /* wait until all process references are gone */ 655fa0f6e62SHans Petter Selasky 656fa0f6e62SHans Petter Selasky pccmd->proc_curr = NULL; 657fa0f6e62SHans Petter Selasky 658fa0f6e62SHans Petter Selasky while (pccmd->proc_refs != 0) 65998029019SHans Petter Selasky cv_wait(&pccmd->cv, &pcs->mtx); 660fa0f6e62SHans Petter Selasky 661fa0f6e62SHans Petter Selasky return (error); 662fa0f6e62SHans Petter Selasky } 663fa0f6e62SHans Petter Selasky 664fa0f6e62SHans Petter Selasky /*------------------------------------------------------------------------* 665fa0f6e62SHans Petter Selasky * CUSE SERVER PART 666fa0f6e62SHans Petter Selasky *------------------------------------------------------------------------*/ 667fa0f6e62SHans Petter Selasky 668fa0f6e62SHans Petter Selasky static void 669fa0f6e62SHans Petter Selasky cuse_server_free_dev(struct cuse_server_dev *pcsd) 670fa0f6e62SHans Petter Selasky { 671fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 672fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 673fa0f6e62SHans Petter Selasky 674fa0f6e62SHans Petter Selasky /* get server pointer */ 675fa0f6e62SHans Petter Selasky pcs = pcsd->server; 676fa0f6e62SHans Petter Selasky 677fa0f6e62SHans Petter Selasky /* prevent creation of more devices */ 67898029019SHans Petter Selasky cuse_server_lock(pcs); 679fa0f6e62SHans Petter Selasky if (pcsd->kern_dev != NULL) 680fa0f6e62SHans Petter Selasky pcsd->kern_dev->si_drv1 = NULL; 681fa0f6e62SHans Petter Selasky 682fa0f6e62SHans Petter Selasky TAILQ_FOREACH(pcc, &pcs->hcli, entry) { 683fa0f6e62SHans Petter Selasky if (pcc->server_dev == pcsd) 684fa0f6e62SHans Petter Selasky cuse_client_is_closing(pcc); 685fa0f6e62SHans Petter Selasky } 68698029019SHans Petter Selasky cuse_server_unlock(pcs); 687fa0f6e62SHans Petter Selasky 688fa0f6e62SHans Petter Selasky /* destroy device, if any */ 689fa0f6e62SHans Petter Selasky if (pcsd->kern_dev != NULL) { 690fa0f6e62SHans Petter Selasky /* destroy device synchronously */ 691fa0f6e62SHans Petter Selasky destroy_dev(pcsd->kern_dev); 692fa0f6e62SHans Petter Selasky } 693fa0f6e62SHans Petter Selasky free(pcsd, M_CUSE); 694fa0f6e62SHans Petter Selasky } 695fa0f6e62SHans Petter Selasky 696fa0f6e62SHans Petter Selasky static void 69756c49c63SHans Petter Selasky cuse_server_unref(struct cuse_server *pcs) 698fa0f6e62SHans Petter Selasky { 699fa0f6e62SHans Petter Selasky struct cuse_server_dev *pcsd; 70056c49c63SHans Petter Selasky struct cuse_memory *mem; 701fa0f6e62SHans Petter Selasky 70298029019SHans Petter Selasky cuse_server_lock(pcs); 70398029019SHans Petter Selasky if (--(pcs->refs) != 0) { 70498029019SHans Petter Selasky cuse_server_unlock(pcs); 705fa0f6e62SHans Petter Selasky return; 706fa0f6e62SHans Petter Selasky } 707fa0f6e62SHans Petter Selasky cuse_server_is_closing(pcs); 70895700043SHans Petter Selasky /* final client wakeup, if any */ 70995700043SHans Petter Selasky cuse_server_wakeup_all_client_locked(pcs); 710fa0f6e62SHans Petter Selasky 71198029019SHans Petter Selasky cuse_global_lock(); 712fa0f6e62SHans Petter Selasky TAILQ_REMOVE(&cuse_server_head, pcs, entry); 71398029019SHans Petter Selasky cuse_global_unlock(); 714fa0f6e62SHans Petter Selasky 715fa0f6e62SHans Petter Selasky while ((pcsd = TAILQ_FIRST(&pcs->hdev)) != NULL) { 716fa0f6e62SHans Petter Selasky TAILQ_REMOVE(&pcs->hdev, pcsd, entry); 71798029019SHans Petter Selasky cuse_server_unlock(pcs); 718fa0f6e62SHans Petter Selasky cuse_server_free_dev(pcsd); 71998029019SHans Petter Selasky cuse_server_lock(pcs); 720fa0f6e62SHans Petter Selasky } 721fa0f6e62SHans Petter Selasky 72243a9329eSHans Petter Selasky cuse_free_unit_by_id_locked(pcs, -1); 72343a9329eSHans Petter Selasky 72456c49c63SHans Petter Selasky while ((mem = TAILQ_FIRST(&pcs->hmem)) != NULL) { 72556c49c63SHans Petter Selasky TAILQ_REMOVE(&pcs->hmem, mem, entry); 72698029019SHans Petter Selasky cuse_server_unlock(pcs); 72756c49c63SHans Petter Selasky cuse_vm_memory_free(mem); 72898029019SHans Petter Selasky cuse_server_lock(pcs); 72956c49c63SHans Petter Selasky } 730fa0f6e62SHans Petter Selasky 731fa0f6e62SHans Petter Selasky knlist_clear(&pcs->selinfo.si_note, 1); 732fa0f6e62SHans Petter Selasky knlist_destroy(&pcs->selinfo.si_note); 733fa0f6e62SHans Petter Selasky 73498029019SHans Petter Selasky cuse_server_unlock(pcs); 735fa0f6e62SHans Petter Selasky 736fa0f6e62SHans Petter Selasky seldrain(&pcs->selinfo); 737fa0f6e62SHans Petter Selasky 738fa0f6e62SHans Petter Selasky cv_destroy(&pcs->cv); 739fa0f6e62SHans Petter Selasky 74098029019SHans Petter Selasky mtx_destroy(&pcs->mtx); 74198029019SHans Petter Selasky 742fa0f6e62SHans Petter Selasky free(pcs, M_CUSE); 743fa0f6e62SHans Petter Selasky } 744fa0f6e62SHans Petter Selasky 745c7ffaed9SHans Petter Selasky static int 746c7ffaed9SHans Petter Selasky cuse_server_do_close(struct cuse_server *pcs) 747c7ffaed9SHans Petter Selasky { 748c7ffaed9SHans Petter Selasky int retval; 749c7ffaed9SHans Petter Selasky 75098029019SHans Petter Selasky cuse_server_lock(pcs); 751c7ffaed9SHans Petter Selasky cuse_server_is_closing(pcs); 752c7ffaed9SHans Petter Selasky /* final client wakeup, if any */ 753c7ffaed9SHans Petter Selasky cuse_server_wakeup_all_client_locked(pcs); 754c7ffaed9SHans Petter Selasky 755c7ffaed9SHans Petter Selasky knlist_clear(&pcs->selinfo.si_note, 1); 756c7ffaed9SHans Petter Selasky 757c7ffaed9SHans Petter Selasky retval = pcs->refs; 75898029019SHans Petter Selasky cuse_server_unlock(pcs); 759c7ffaed9SHans Petter Selasky 760c7ffaed9SHans Petter Selasky return (retval); 761c7ffaed9SHans Petter Selasky } 762c7ffaed9SHans Petter Selasky 76356c49c63SHans Petter Selasky static void 76456c49c63SHans Petter Selasky cuse_server_free(void *arg) 76556c49c63SHans Petter Selasky { 76656c49c63SHans Petter Selasky struct cuse_server *pcs = arg; 76756c49c63SHans Petter Selasky 768c7ffaed9SHans Petter Selasky /* 769c7ffaed9SHans Petter Selasky * The final server unref should be done by the server thread 770c7ffaed9SHans Petter Selasky * to prevent deadlock in the client cdevpriv destructor, 771c7ffaed9SHans Petter Selasky * which cannot destroy itself. 772c7ffaed9SHans Petter Selasky */ 773c7ffaed9SHans Petter Selasky while (cuse_server_do_close(pcs) != 1) 774c7ffaed9SHans Petter Selasky pause("W", hz); 775c7ffaed9SHans Petter Selasky 776c7ffaed9SHans Petter Selasky /* drop final refcount */ 77756c49c63SHans Petter Selasky cuse_server_unref(pcs); 77856c49c63SHans Petter Selasky } 77956c49c63SHans Petter Selasky 780fa0f6e62SHans Petter Selasky static int 781fa0f6e62SHans Petter Selasky cuse_server_open(struct cdev *dev, int fflags, int devtype, struct thread *td) 782fa0f6e62SHans Petter Selasky { 783fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 784fa0f6e62SHans Petter Selasky 785fa0f6e62SHans Petter Selasky pcs = malloc(sizeof(*pcs), M_CUSE, M_WAITOK | M_ZERO); 786fa0f6e62SHans Petter Selasky 787fa0f6e62SHans Petter Selasky if (devfs_set_cdevpriv(pcs, &cuse_server_free)) { 788fa0f6e62SHans Petter Selasky printf("Cuse: Cannot set cdevpriv.\n"); 789fa0f6e62SHans Petter Selasky free(pcs, M_CUSE); 790fa0f6e62SHans Petter Selasky return (ENOMEM); 791fa0f6e62SHans Petter Selasky } 792ac60e801SHans Petter Selasky /* store current process ID */ 793ac60e801SHans Petter Selasky pcs->pid = curproc->p_pid; 794ac60e801SHans Petter Selasky 795fa0f6e62SHans Petter Selasky TAILQ_INIT(&pcs->head); 796fa0f6e62SHans Petter Selasky TAILQ_INIT(&pcs->hdev); 797fa0f6e62SHans Petter Selasky TAILQ_INIT(&pcs->hcli); 79856c49c63SHans Petter Selasky TAILQ_INIT(&pcs->hmem); 799fa0f6e62SHans Petter Selasky 800fa0f6e62SHans Petter Selasky cv_init(&pcs->cv, "cuse-server-cv"); 801fa0f6e62SHans Petter Selasky 80298029019SHans Petter Selasky mtx_init(&pcs->mtx, "cuse-server-mtx", NULL, MTX_DEF); 803fa0f6e62SHans Petter Selasky 80498029019SHans Petter Selasky knlist_init_mtx(&pcs->selinfo.si_note, &pcs->mtx); 80598029019SHans Petter Selasky 80698029019SHans Petter Selasky cuse_global_lock(); 807fa0f6e62SHans Petter Selasky pcs->refs++; 808fa0f6e62SHans Petter Selasky TAILQ_INSERT_TAIL(&cuse_server_head, pcs, entry); 80998029019SHans Petter Selasky cuse_global_unlock(); 810fa0f6e62SHans Petter Selasky 811fa0f6e62SHans Petter Selasky return (0); 812fa0f6e62SHans Petter Selasky } 813fa0f6e62SHans Petter Selasky 814fa0f6e62SHans Petter Selasky static int 815fa0f6e62SHans Petter Selasky cuse_server_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 816fa0f6e62SHans Petter Selasky { 817fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 818fa0f6e62SHans Petter Selasky 819c7ffaed9SHans Petter Selasky if (cuse_server_get(&pcs) == 0) 820c7ffaed9SHans Petter Selasky cuse_server_do_close(pcs); 821fa0f6e62SHans Petter Selasky 822fa0f6e62SHans Petter Selasky return (0); 823fa0f6e62SHans Petter Selasky } 824fa0f6e62SHans Petter Selasky 825fa0f6e62SHans Petter Selasky static int 826fa0f6e62SHans Petter Selasky cuse_server_read(struct cdev *dev, struct uio *uio, int ioflag) 827fa0f6e62SHans Petter Selasky { 828fa0f6e62SHans Petter Selasky return (ENXIO); 829fa0f6e62SHans Petter Selasky } 830fa0f6e62SHans Petter Selasky 831fa0f6e62SHans Petter Selasky static int 832fa0f6e62SHans Petter Selasky cuse_server_write(struct cdev *dev, struct uio *uio, int ioflag) 833fa0f6e62SHans Petter Selasky { 834fa0f6e62SHans Petter Selasky return (ENXIO); 835fa0f6e62SHans Petter Selasky } 836fa0f6e62SHans Petter Selasky 837fa0f6e62SHans Petter Selasky static int 83898029019SHans Petter Selasky cuse_server_ioctl_copy_locked(struct cuse_server *pcs, 83998029019SHans Petter Selasky struct cuse_client_command *pccmd, 8408f0a3c9cSHans Petter Selasky struct cuse_data_chunk *pchk, bool isread) 841fa0f6e62SHans Petter Selasky { 842fa0f6e62SHans Petter Selasky struct proc *p_proc; 843fa0f6e62SHans Petter Selasky uint32_t offset; 844fa0f6e62SHans Petter Selasky int error; 845fa0f6e62SHans Petter Selasky 846fa0f6e62SHans Petter Selasky offset = pchk->peer_ptr - CUSE_BUF_MIN_PTR; 847fa0f6e62SHans Petter Selasky 848fa0f6e62SHans Petter Selasky if (pchk->length > CUSE_BUFFER_MAX) 849fa0f6e62SHans Petter Selasky return (EFAULT); 850fa0f6e62SHans Petter Selasky 851fa0f6e62SHans Petter Selasky if (offset >= CUSE_BUFFER_MAX) 852fa0f6e62SHans Petter Selasky return (EFAULT); 853fa0f6e62SHans Petter Selasky 854fa0f6e62SHans Petter Selasky if ((offset + pchk->length) > CUSE_BUFFER_MAX) 855fa0f6e62SHans Petter Selasky return (EFAULT); 856fa0f6e62SHans Petter Selasky 857fa0f6e62SHans Petter Selasky p_proc = pccmd->proc_curr; 858fa0f6e62SHans Petter Selasky if (p_proc == NULL) 859fa0f6e62SHans Petter Selasky return (ENXIO); 860fa0f6e62SHans Petter Selasky 861fa0f6e62SHans Petter Selasky if (pccmd->proc_refs < 0) 862fa0f6e62SHans Petter Selasky return (ENOMEM); 863fa0f6e62SHans Petter Selasky 864fa0f6e62SHans Petter Selasky pccmd->proc_refs++; 865fa0f6e62SHans Petter Selasky 86698029019SHans Petter Selasky cuse_server_unlock(pcs); 867fa0f6e62SHans Petter Selasky 8682ae08612SHans Petter Selasky if (!isread) { 869fa0f6e62SHans Petter Selasky error = copyin( 870fa0f6e62SHans Petter Selasky (void *)pchk->local_ptr, 871fa0f6e62SHans Petter Selasky pccmd->client->ioctl_buffer + offset, 872fa0f6e62SHans Petter Selasky pchk->length); 873fa0f6e62SHans Petter Selasky } else { 874fa0f6e62SHans Petter Selasky error = copyout( 875fa0f6e62SHans Petter Selasky pccmd->client->ioctl_buffer + offset, 876fa0f6e62SHans Petter Selasky (void *)pchk->local_ptr, 877fa0f6e62SHans Petter Selasky pchk->length); 878fa0f6e62SHans Petter Selasky } 879fa0f6e62SHans Petter Selasky 88098029019SHans Petter Selasky cuse_server_lock(pcs); 881fa0f6e62SHans Petter Selasky 882fa0f6e62SHans Petter Selasky pccmd->proc_refs--; 883fa0f6e62SHans Petter Selasky 884fa0f6e62SHans Petter Selasky if (pccmd->proc_curr == NULL) 885fa0f6e62SHans Petter Selasky cv_signal(&pccmd->cv); 886fa0f6e62SHans Petter Selasky 887fa0f6e62SHans Petter Selasky return (error); 888fa0f6e62SHans Petter Selasky } 889fa0f6e62SHans Petter Selasky 890fa0f6e62SHans Petter Selasky static int 891fa0f6e62SHans Petter Selasky cuse_proc2proc_copy(struct proc *proc_s, vm_offset_t data_s, 892fa0f6e62SHans Petter Selasky struct proc *proc_d, vm_offset_t data_d, size_t len) 893fa0f6e62SHans Petter Selasky { 894fa0f6e62SHans Petter Selasky struct thread *td; 895fa0f6e62SHans Petter Selasky struct proc *proc_cur; 896fa0f6e62SHans Petter Selasky int error; 897fa0f6e62SHans Petter Selasky 898fa0f6e62SHans Petter Selasky td = curthread; 899fa0f6e62SHans Petter Selasky proc_cur = td->td_proc; 900fa0f6e62SHans Petter Selasky 901fa0f6e62SHans Petter Selasky if (proc_cur == proc_d) { 902fa0f6e62SHans Petter Selasky struct iovec iov = { 903fa0f6e62SHans Petter Selasky .iov_base = (caddr_t)data_d, 904fa0f6e62SHans Petter Selasky .iov_len = len, 905fa0f6e62SHans Petter Selasky }; 906fa0f6e62SHans Petter Selasky struct uio uio = { 907fa0f6e62SHans Petter Selasky .uio_iov = &iov, 908fa0f6e62SHans Petter Selasky .uio_iovcnt = 1, 909fa0f6e62SHans Petter Selasky .uio_offset = (off_t)data_s, 910fa0f6e62SHans Petter Selasky .uio_resid = len, 911fa0f6e62SHans Petter Selasky .uio_segflg = UIO_USERSPACE, 912fa0f6e62SHans Petter Selasky .uio_rw = UIO_READ, 913fa0f6e62SHans Petter Selasky .uio_td = td, 914fa0f6e62SHans Petter Selasky }; 915fa0f6e62SHans Petter Selasky 9165928e3b9SHans Petter Selasky PHOLD(proc_s); 917fa0f6e62SHans Petter Selasky error = proc_rwmem(proc_s, &uio); 9185928e3b9SHans Petter Selasky PRELE(proc_s); 919fa0f6e62SHans Petter Selasky 920fa0f6e62SHans Petter Selasky } else if (proc_cur == proc_s) { 921fa0f6e62SHans Petter Selasky struct iovec iov = { 922fa0f6e62SHans Petter Selasky .iov_base = (caddr_t)data_s, 923fa0f6e62SHans Petter Selasky .iov_len = len, 924fa0f6e62SHans Petter Selasky }; 925fa0f6e62SHans Petter Selasky struct uio uio = { 926fa0f6e62SHans Petter Selasky .uio_iov = &iov, 927fa0f6e62SHans Petter Selasky .uio_iovcnt = 1, 928fa0f6e62SHans Petter Selasky .uio_offset = (off_t)data_d, 929fa0f6e62SHans Petter Selasky .uio_resid = len, 930fa0f6e62SHans Petter Selasky .uio_segflg = UIO_USERSPACE, 931fa0f6e62SHans Petter Selasky .uio_rw = UIO_WRITE, 932fa0f6e62SHans Petter Selasky .uio_td = td, 933fa0f6e62SHans Petter Selasky }; 934fa0f6e62SHans Petter Selasky 9355928e3b9SHans Petter Selasky PHOLD(proc_d); 936fa0f6e62SHans Petter Selasky error = proc_rwmem(proc_d, &uio); 9375928e3b9SHans Petter Selasky PRELE(proc_d); 938fa0f6e62SHans Petter Selasky } else { 939fa0f6e62SHans Petter Selasky error = EINVAL; 940fa0f6e62SHans Petter Selasky } 941fa0f6e62SHans Petter Selasky return (error); 942fa0f6e62SHans Petter Selasky } 943fa0f6e62SHans Petter Selasky 944fa0f6e62SHans Petter Selasky static int 94598029019SHans Petter Selasky cuse_server_data_copy_locked(struct cuse_server *pcs, 94698029019SHans Petter Selasky struct cuse_client_command *pccmd, 9478f0a3c9cSHans Petter Selasky struct cuse_data_chunk *pchk, bool isread) 948fa0f6e62SHans Petter Selasky { 949fa0f6e62SHans Petter Selasky struct proc *p_proc; 950fa0f6e62SHans Petter Selasky int error; 951fa0f6e62SHans Petter Selasky 952fa0f6e62SHans Petter Selasky p_proc = pccmd->proc_curr; 953fa0f6e62SHans Petter Selasky if (p_proc == NULL) 954fa0f6e62SHans Petter Selasky return (ENXIO); 955fa0f6e62SHans Petter Selasky 956fa0f6e62SHans Petter Selasky if (pccmd->proc_refs < 0) 957fa0f6e62SHans Petter Selasky return (ENOMEM); 958fa0f6e62SHans Petter Selasky 959fa0f6e62SHans Petter Selasky pccmd->proc_refs++; 960fa0f6e62SHans Petter Selasky 96198029019SHans Petter Selasky cuse_server_unlock(pcs); 962fa0f6e62SHans Petter Selasky 9632ae08612SHans Petter Selasky if (!isread) { 964fa0f6e62SHans Petter Selasky error = cuse_proc2proc_copy( 965fa0f6e62SHans Petter Selasky curthread->td_proc, pchk->local_ptr, 966fa0f6e62SHans Petter Selasky p_proc, pchk->peer_ptr, 967fa0f6e62SHans Petter Selasky pchk->length); 968fa0f6e62SHans Petter Selasky } else { 969fa0f6e62SHans Petter Selasky error = cuse_proc2proc_copy( 970fa0f6e62SHans Petter Selasky p_proc, pchk->peer_ptr, 971fa0f6e62SHans Petter Selasky curthread->td_proc, pchk->local_ptr, 972fa0f6e62SHans Petter Selasky pchk->length); 973fa0f6e62SHans Petter Selasky } 974fa0f6e62SHans Petter Selasky 97598029019SHans Petter Selasky cuse_server_lock(pcs); 976fa0f6e62SHans Petter Selasky 977fa0f6e62SHans Petter Selasky pccmd->proc_refs--; 978fa0f6e62SHans Petter Selasky 979fa0f6e62SHans Petter Selasky if (pccmd->proc_curr == NULL) 980fa0f6e62SHans Petter Selasky cv_signal(&pccmd->cv); 981fa0f6e62SHans Petter Selasky 982fa0f6e62SHans Petter Selasky return (error); 983fa0f6e62SHans Petter Selasky } 984fa0f6e62SHans Petter Selasky 985fa0f6e62SHans Petter Selasky static int 9865e59b273SHans Petter Selasky cuse_server_data_copy_optimized_locked(struct cuse_server *pcs, 9875e59b273SHans Petter Selasky struct cuse_client_command *pccmd, 9885e59b273SHans Petter Selasky struct cuse_data_chunk *pchk, bool isread) 9895e59b273SHans Petter Selasky { 9905e59b273SHans Petter Selasky uintptr_t offset; 9915e59b273SHans Petter Selasky int error; 9925e59b273SHans Petter Selasky 9935e59b273SHans Petter Selasky /* 9945e59b273SHans Petter Selasky * Check if data is stored locally to avoid accessing 9955e59b273SHans Petter Selasky * other process's data space: 9965e59b273SHans Petter Selasky */ 9975e59b273SHans Petter Selasky if (isread) { 9985e59b273SHans Petter Selasky offset = pchk->peer_ptr - pccmd->client->write_base; 9995e59b273SHans Petter Selasky 10005e59b273SHans Petter Selasky if (offset < (uintptr_t)pccmd->client->write_length && 10015e59b273SHans Petter Selasky pchk->length <= (unsigned long)pccmd->client->write_length && 10025e59b273SHans Petter Selasky offset + pchk->length <= (uintptr_t)pccmd->client->write_length) { 10035e59b273SHans Petter Selasky cuse_server_unlock(pcs); 10045e59b273SHans Petter Selasky error = copyout(pccmd->client->write_buffer + offset, 10055e59b273SHans Petter Selasky (void *)pchk->local_ptr, pchk->length); 10065e59b273SHans Petter Selasky goto done; 10075e59b273SHans Petter Selasky } 10085e59b273SHans Petter Selasky } else { 10095e59b273SHans Petter Selasky offset = pchk->peer_ptr - pccmd->client->read_base; 10105e59b273SHans Petter Selasky 10115e59b273SHans Petter Selasky if (offset < (uintptr_t)pccmd->client->read_length && 10125e59b273SHans Petter Selasky pchk->length <= (unsigned long)pccmd->client->read_length && 10135e59b273SHans Petter Selasky offset + pchk->length <= (uintptr_t)pccmd->client->read_length) { 10145e59b273SHans Petter Selasky cuse_server_unlock(pcs); 10155e59b273SHans Petter Selasky error = copyin((void *)pchk->local_ptr, 10165e59b273SHans Petter Selasky pccmd->client->read_buffer + offset, pchk->length); 10175e59b273SHans Petter Selasky goto done; 10185e59b273SHans Petter Selasky } 10195e59b273SHans Petter Selasky } 10205e59b273SHans Petter Selasky 10215e59b273SHans Petter Selasky /* use process to process copy function */ 10225e59b273SHans Petter Selasky error = cuse_server_data_copy_locked(pcs, pccmd, pchk, isread); 10235e59b273SHans Petter Selasky done: 10245e59b273SHans Petter Selasky return (error); 10255e59b273SHans Petter Selasky } 10265e59b273SHans Petter Selasky 10275e59b273SHans Petter Selasky static int 1028fa0f6e62SHans Petter Selasky cuse_alloc_unit_by_id_locked(struct cuse_server *pcs, int id) 1029fa0f6e62SHans Petter Selasky { 1030fa0f6e62SHans Petter Selasky int n; 1031fa0f6e62SHans Petter Selasky int x = 0; 1032fa0f6e62SHans Petter Selasky int match; 1033fa0f6e62SHans Petter Selasky 1034fa0f6e62SHans Petter Selasky do { 1035fa0f6e62SHans Petter Selasky for (match = n = 0; n != CUSE_DEVICES_MAX; n++) { 1036fa0f6e62SHans Petter Selasky if (cuse_alloc_unit[n] != NULL) { 1037fa0f6e62SHans Petter Selasky if ((cuse_alloc_unit_id[n] ^ id) & CUSE_ID_MASK) 1038fa0f6e62SHans Petter Selasky continue; 1039fa0f6e62SHans Petter Selasky if ((cuse_alloc_unit_id[n] & ~CUSE_ID_MASK) == x) { 1040fa0f6e62SHans Petter Selasky x++; 1041fa0f6e62SHans Petter Selasky match = 1; 1042fa0f6e62SHans Petter Selasky } 1043fa0f6e62SHans Petter Selasky } 1044fa0f6e62SHans Petter Selasky } 1045fa0f6e62SHans Petter Selasky } while (match); 1046fa0f6e62SHans Petter Selasky 1047fa0f6e62SHans Petter Selasky if (x < 256) { 1048fa0f6e62SHans Petter Selasky for (n = 0; n != CUSE_DEVICES_MAX; n++) { 1049fa0f6e62SHans Petter Selasky if (cuse_alloc_unit[n] == NULL) { 1050fa0f6e62SHans Petter Selasky cuse_alloc_unit[n] = pcs; 1051fa0f6e62SHans Petter Selasky cuse_alloc_unit_id[n] = id | x; 1052fa0f6e62SHans Petter Selasky return (x); 1053fa0f6e62SHans Petter Selasky } 1054fa0f6e62SHans Petter Selasky } 1055fa0f6e62SHans Petter Selasky } 1056fa0f6e62SHans Petter Selasky return (-1); 1057fa0f6e62SHans Petter Selasky } 1058fa0f6e62SHans Petter Selasky 1059fa0f6e62SHans Petter Selasky static void 1060fa0f6e62SHans Petter Selasky cuse_server_wakeup_locked(struct cuse_server *pcs) 1061fa0f6e62SHans Petter Selasky { 1062fa0f6e62SHans Petter Selasky selwakeup(&pcs->selinfo); 1063fa0f6e62SHans Petter Selasky KNOTE_LOCKED(&pcs->selinfo.si_note, 0); 1064fa0f6e62SHans Petter Selasky } 1065fa0f6e62SHans Petter Selasky 106695700043SHans Petter Selasky static void 106795700043SHans Petter Selasky cuse_server_wakeup_all_client_locked(struct cuse_server *pcs) 106895700043SHans Petter Selasky { 106995700043SHans Petter Selasky struct cuse_client *pcc; 107095700043SHans Petter Selasky 107195700043SHans Petter Selasky TAILQ_FOREACH(pcc, &pcs->hcli, entry) { 107295700043SHans Petter Selasky pcc->cflags |= (CUSE_CLI_KNOTE_NEED_READ | 107395700043SHans Petter Selasky CUSE_CLI_KNOTE_NEED_WRITE); 107495700043SHans Petter Selasky } 107595700043SHans Petter Selasky cuse_server_wakeup_locked(pcs); 107695700043SHans Petter Selasky } 107795700043SHans Petter Selasky 1078fa0f6e62SHans Petter Selasky static int 1079fa0f6e62SHans Petter Selasky cuse_free_unit_by_id_locked(struct cuse_server *pcs, int id) 1080fa0f6e62SHans Petter Selasky { 1081fa0f6e62SHans Petter Selasky int n; 1082fa0f6e62SHans Petter Selasky int found = 0; 1083fa0f6e62SHans Petter Selasky 1084fa0f6e62SHans Petter Selasky for (n = 0; n != CUSE_DEVICES_MAX; n++) { 1085fa0f6e62SHans Petter Selasky if (cuse_alloc_unit[n] == pcs) { 1086fa0f6e62SHans Petter Selasky if (cuse_alloc_unit_id[n] == id || id == -1) { 1087fa0f6e62SHans Petter Selasky cuse_alloc_unit[n] = NULL; 1088fa0f6e62SHans Petter Selasky cuse_alloc_unit_id[n] = 0; 1089fa0f6e62SHans Petter Selasky found = 1; 1090fa0f6e62SHans Petter Selasky } 1091fa0f6e62SHans Petter Selasky } 1092fa0f6e62SHans Petter Selasky } 1093fa0f6e62SHans Petter Selasky 1094fa0f6e62SHans Petter Selasky return (found ? 0 : EINVAL); 1095fa0f6e62SHans Petter Selasky } 1096fa0f6e62SHans Petter Selasky 1097fa0f6e62SHans Petter Selasky static int 1098fa0f6e62SHans Petter Selasky cuse_server_ioctl(struct cdev *dev, unsigned long cmd, 1099fa0f6e62SHans Petter Selasky caddr_t data, int fflag, struct thread *td) 1100fa0f6e62SHans Petter Selasky { 1101fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 1102fa0f6e62SHans Petter Selasky int error; 1103fa0f6e62SHans Petter Selasky 1104fa0f6e62SHans Petter Selasky error = cuse_server_get(&pcs); 1105fa0f6e62SHans Petter Selasky if (error != 0) 1106fa0f6e62SHans Petter Selasky return (error); 1107fa0f6e62SHans Petter Selasky 1108fa0f6e62SHans Petter Selasky switch (cmd) { 1109fa0f6e62SHans Petter Selasky struct cuse_client_command *pccmd; 1110fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 1111fa0f6e62SHans Petter Selasky struct cuse_command *pcmd; 1112fa0f6e62SHans Petter Selasky struct cuse_alloc_info *pai; 1113fa0f6e62SHans Petter Selasky struct cuse_create_dev *pcd; 1114fa0f6e62SHans Petter Selasky struct cuse_server_dev *pcsd; 1115fa0f6e62SHans Petter Selasky struct cuse_data_chunk *pchk; 1116fa0f6e62SHans Petter Selasky int n; 1117fa0f6e62SHans Petter Selasky 1118fa0f6e62SHans Petter Selasky case CUSE_IOCTL_GET_COMMAND: 1119fa0f6e62SHans Petter Selasky pcmd = (void *)data; 1120fa0f6e62SHans Petter Selasky 112198029019SHans Petter Selasky cuse_server_lock(pcs); 1122fa0f6e62SHans Petter Selasky 1123fa0f6e62SHans Petter Selasky while ((pccmd = TAILQ_FIRST(&pcs->head)) == NULL) { 112498029019SHans Petter Selasky error = cv_wait_sig(&pcs->cv, &pcs->mtx); 1125fa0f6e62SHans Petter Selasky 1126fa0f6e62SHans Petter Selasky if (pcs->is_closing) 1127fa0f6e62SHans Petter Selasky error = ENXIO; 1128fa0f6e62SHans Petter Selasky 1129fa0f6e62SHans Petter Selasky if (error) { 113098029019SHans Petter Selasky cuse_server_unlock(pcs); 1131fa0f6e62SHans Petter Selasky return (error); 1132fa0f6e62SHans Petter Selasky } 1133fa0f6e62SHans Petter Selasky } 1134fa0f6e62SHans Petter Selasky 1135fa0f6e62SHans Petter Selasky TAILQ_REMOVE(&pcs->head, pccmd, entry); 1136fa0f6e62SHans Petter Selasky pccmd->entry.tqe_prev = NULL; 1137fa0f6e62SHans Petter Selasky 1138fa0f6e62SHans Petter Selasky pccmd->entered = curthread; 1139fa0f6e62SHans Petter Selasky 1140fa0f6e62SHans Petter Selasky *pcmd = pccmd->sub; 1141fa0f6e62SHans Petter Selasky 114298029019SHans Petter Selasky cuse_server_unlock(pcs); 1143fa0f6e62SHans Petter Selasky 1144fa0f6e62SHans Petter Selasky break; 1145fa0f6e62SHans Petter Selasky 1146fa0f6e62SHans Petter Selasky case CUSE_IOCTL_SYNC_COMMAND: 1147fa0f6e62SHans Petter Selasky 114898029019SHans Petter Selasky cuse_server_lock(pcs); 1149fa0f6e62SHans Petter Selasky while ((pccmd = cuse_server_find_command(pcs, curthread)) != NULL) { 1150fa0f6e62SHans Petter Selasky /* send sync command */ 1151fa0f6e62SHans Petter Selasky pccmd->entered = NULL; 1152fa0f6e62SHans Petter Selasky pccmd->error = *(int *)data; 1153fa0f6e62SHans Petter Selasky pccmd->command = CUSE_CMD_SYNC; 1154fa0f6e62SHans Petter Selasky 1155fa0f6e62SHans Petter Selasky /* signal peer, if any */ 1156fa0f6e62SHans Petter Selasky cv_signal(&pccmd->cv); 1157fa0f6e62SHans Petter Selasky } 115898029019SHans Petter Selasky cuse_server_unlock(pcs); 1159fa0f6e62SHans Petter Selasky 1160fa0f6e62SHans Petter Selasky break; 1161fa0f6e62SHans Petter Selasky 1162fa0f6e62SHans Petter Selasky case CUSE_IOCTL_ALLOC_UNIT: 1163fa0f6e62SHans Petter Selasky 116498029019SHans Petter Selasky cuse_server_lock(pcs); 1165fa0f6e62SHans Petter Selasky n = cuse_alloc_unit_by_id_locked(pcs, 1166fa0f6e62SHans Petter Selasky CUSE_ID_DEFAULT(0)); 116798029019SHans Petter Selasky cuse_server_unlock(pcs); 1168fa0f6e62SHans Petter Selasky 1169fa0f6e62SHans Petter Selasky if (n < 0) 1170fa0f6e62SHans Petter Selasky error = ENOMEM; 1171fa0f6e62SHans Petter Selasky else 1172fa0f6e62SHans Petter Selasky *(int *)data = n; 1173fa0f6e62SHans Petter Selasky break; 1174fa0f6e62SHans Petter Selasky 1175fa0f6e62SHans Petter Selasky case CUSE_IOCTL_ALLOC_UNIT_BY_ID: 1176fa0f6e62SHans Petter Selasky 1177fa0f6e62SHans Petter Selasky n = *(int *)data; 1178fa0f6e62SHans Petter Selasky 1179fa0f6e62SHans Petter Selasky n = (n & CUSE_ID_MASK); 1180fa0f6e62SHans Petter Selasky 118198029019SHans Petter Selasky cuse_server_lock(pcs); 1182fa0f6e62SHans Petter Selasky n = cuse_alloc_unit_by_id_locked(pcs, n); 118398029019SHans Petter Selasky cuse_server_unlock(pcs); 1184fa0f6e62SHans Petter Selasky 1185fa0f6e62SHans Petter Selasky if (n < 0) 1186fa0f6e62SHans Petter Selasky error = ENOMEM; 1187fa0f6e62SHans Petter Selasky else 1188fa0f6e62SHans Petter Selasky *(int *)data = n; 1189fa0f6e62SHans Petter Selasky break; 1190fa0f6e62SHans Petter Selasky 1191fa0f6e62SHans Petter Selasky case CUSE_IOCTL_FREE_UNIT: 1192fa0f6e62SHans Petter Selasky 1193fa0f6e62SHans Petter Selasky n = *(int *)data; 1194fa0f6e62SHans Petter Selasky 1195fa0f6e62SHans Petter Selasky n = CUSE_ID_DEFAULT(n); 1196fa0f6e62SHans Petter Selasky 119798029019SHans Petter Selasky cuse_server_lock(pcs); 1198fa0f6e62SHans Petter Selasky error = cuse_free_unit_by_id_locked(pcs, n); 119998029019SHans Petter Selasky cuse_server_unlock(pcs); 1200fa0f6e62SHans Petter Selasky break; 1201fa0f6e62SHans Petter Selasky 1202fa0f6e62SHans Petter Selasky case CUSE_IOCTL_FREE_UNIT_BY_ID: 1203fa0f6e62SHans Petter Selasky 1204fa0f6e62SHans Petter Selasky n = *(int *)data; 1205fa0f6e62SHans Petter Selasky 120698029019SHans Petter Selasky cuse_server_lock(pcs); 1207fa0f6e62SHans Petter Selasky error = cuse_free_unit_by_id_locked(pcs, n); 120898029019SHans Petter Selasky cuse_server_unlock(pcs); 1209fa0f6e62SHans Petter Selasky break; 1210fa0f6e62SHans Petter Selasky 1211fa0f6e62SHans Petter Selasky case CUSE_IOCTL_ALLOC_MEMORY: 1212fa0f6e62SHans Petter Selasky 1213fa0f6e62SHans Petter Selasky pai = (void *)data; 1214fa0f6e62SHans Petter Selasky 1215fa0f6e62SHans Petter Selasky if (pai->alloc_nr >= CUSE_ALLOC_UNIT_MAX) { 1216fa0f6e62SHans Petter Selasky error = ENOMEM; 1217fa0f6e62SHans Petter Selasky break; 1218fa0f6e62SHans Petter Selasky } 12190996dd7dSHans Petter Selasky if (pai->page_count > CUSE_ALLOC_PAGES_MAX) { 1220fa0f6e62SHans Petter Selasky error = ENOMEM; 1221fa0f6e62SHans Petter Selasky break; 1222fa0f6e62SHans Petter Selasky } 1223fa0f6e62SHans Petter Selasky error = cuse_server_alloc_memory(pcs, 122456c49c63SHans Petter Selasky pai->alloc_nr, pai->page_count); 1225fa0f6e62SHans Petter Selasky break; 1226fa0f6e62SHans Petter Selasky 1227fa0f6e62SHans Petter Selasky case CUSE_IOCTL_FREE_MEMORY: 1228fa0f6e62SHans Petter Selasky pai = (void *)data; 1229fa0f6e62SHans Petter Selasky 1230fa0f6e62SHans Petter Selasky if (pai->alloc_nr >= CUSE_ALLOC_UNIT_MAX) { 1231fa0f6e62SHans Petter Selasky error = ENOMEM; 1232fa0f6e62SHans Petter Selasky break; 1233fa0f6e62SHans Petter Selasky } 123456c49c63SHans Petter Selasky error = cuse_server_free_memory(pcs, pai->alloc_nr); 1235fa0f6e62SHans Petter Selasky break; 1236fa0f6e62SHans Petter Selasky 1237fa0f6e62SHans Petter Selasky case CUSE_IOCTL_GET_SIG: 1238fa0f6e62SHans Petter Selasky 123998029019SHans Petter Selasky cuse_server_lock(pcs); 1240fa0f6e62SHans Petter Selasky pccmd = cuse_server_find_command(pcs, curthread); 1241fa0f6e62SHans Petter Selasky 1242fa0f6e62SHans Petter Selasky if (pccmd != NULL) { 1243fa0f6e62SHans Petter Selasky n = pccmd->got_signal; 1244fa0f6e62SHans Petter Selasky pccmd->got_signal = 0; 1245fa0f6e62SHans Petter Selasky } else { 1246fa0f6e62SHans Petter Selasky n = 0; 1247fa0f6e62SHans Petter Selasky } 124898029019SHans Petter Selasky cuse_server_unlock(pcs); 1249fa0f6e62SHans Petter Selasky 1250fa0f6e62SHans Petter Selasky *(int *)data = n; 1251fa0f6e62SHans Petter Selasky 1252fa0f6e62SHans Petter Selasky break; 1253fa0f6e62SHans Petter Selasky 1254fa0f6e62SHans Petter Selasky case CUSE_IOCTL_SET_PFH: 1255fa0f6e62SHans Petter Selasky 125698029019SHans Petter Selasky cuse_server_lock(pcs); 1257fa0f6e62SHans Petter Selasky pccmd = cuse_server_find_command(pcs, curthread); 1258fa0f6e62SHans Petter Selasky 1259fa0f6e62SHans Petter Selasky if (pccmd != NULL) { 1260fa0f6e62SHans Petter Selasky pcc = pccmd->client; 1261fa0f6e62SHans Petter Selasky for (n = 0; n != CUSE_CMD_MAX; n++) { 12629fb69c9dSHans Petter Selasky pcc->cmds[n].sub.per_file_handle = *(uintptr_t *)data; 1263fa0f6e62SHans Petter Selasky } 1264fa0f6e62SHans Petter Selasky } else { 1265fa0f6e62SHans Petter Selasky error = ENXIO; 1266fa0f6e62SHans Petter Selasky } 126798029019SHans Petter Selasky cuse_server_unlock(pcs); 1268fa0f6e62SHans Petter Selasky break; 1269fa0f6e62SHans Petter Selasky 1270fa0f6e62SHans Petter Selasky case CUSE_IOCTL_CREATE_DEV: 1271fa0f6e62SHans Petter Selasky 1272fa0f6e62SHans Petter Selasky error = priv_check(curthread, PRIV_DRIVER); 1273fa0f6e62SHans Petter Selasky if (error) 1274fa0f6e62SHans Petter Selasky break; 1275fa0f6e62SHans Petter Selasky 1276fa0f6e62SHans Petter Selasky pcd = (void *)data; 1277fa0f6e62SHans Petter Selasky 1278fa0f6e62SHans Petter Selasky /* filter input */ 1279fa0f6e62SHans Petter Selasky 1280fa0f6e62SHans Petter Selasky pcd->devname[sizeof(pcd->devname) - 1] = 0; 1281fa0f6e62SHans Petter Selasky 1282fa0f6e62SHans Petter Selasky if (pcd->devname[0] == 0) { 1283fa0f6e62SHans Petter Selasky error = EINVAL; 1284fa0f6e62SHans Petter Selasky break; 1285fa0f6e62SHans Petter Selasky } 1286fa0f6e62SHans Petter Selasky cuse_str_filter(pcd->devname); 1287fa0f6e62SHans Petter Selasky 1288fa0f6e62SHans Petter Selasky pcd->permissions &= 0777; 1289fa0f6e62SHans Petter Selasky 1290fa0f6e62SHans Petter Selasky /* try to allocate a character device */ 1291fa0f6e62SHans Petter Selasky 1292fa0f6e62SHans Petter Selasky pcsd = malloc(sizeof(*pcsd), M_CUSE, M_WAITOK | M_ZERO); 1293fa0f6e62SHans Petter Selasky 1294fa0f6e62SHans Petter Selasky pcsd->server = pcs; 1295fa0f6e62SHans Petter Selasky 1296fa0f6e62SHans Petter Selasky pcsd->user_dev = pcd->dev; 1297fa0f6e62SHans Petter Selasky 1298fa0f6e62SHans Petter Selasky pcsd->kern_dev = make_dev_credf(MAKEDEV_CHECKNAME, 1299fa0f6e62SHans Petter Selasky &cuse_client_devsw, 0, NULL, pcd->user_id, pcd->group_id, 1300fa0f6e62SHans Petter Selasky pcd->permissions, "%s", pcd->devname); 1301fa0f6e62SHans Petter Selasky 1302fa0f6e62SHans Petter Selasky if (pcsd->kern_dev == NULL) { 1303fa0f6e62SHans Petter Selasky free(pcsd, M_CUSE); 1304fa0f6e62SHans Petter Selasky error = ENOMEM; 1305fa0f6e62SHans Petter Selasky break; 1306fa0f6e62SHans Petter Selasky } 1307fa0f6e62SHans Petter Selasky pcsd->kern_dev->si_drv1 = pcsd; 1308fa0f6e62SHans Petter Selasky 130998029019SHans Petter Selasky cuse_server_lock(pcs); 1310fa0f6e62SHans Petter Selasky TAILQ_INSERT_TAIL(&pcs->hdev, pcsd, entry); 131198029019SHans Petter Selasky cuse_server_unlock(pcs); 1312fa0f6e62SHans Petter Selasky 1313fa0f6e62SHans Petter Selasky break; 1314fa0f6e62SHans Petter Selasky 1315fa0f6e62SHans Petter Selasky case CUSE_IOCTL_DESTROY_DEV: 1316fa0f6e62SHans Petter Selasky 1317fa0f6e62SHans Petter Selasky error = priv_check(curthread, PRIV_DRIVER); 1318fa0f6e62SHans Petter Selasky if (error) 1319fa0f6e62SHans Petter Selasky break; 1320fa0f6e62SHans Petter Selasky 132198029019SHans Petter Selasky cuse_server_lock(pcs); 1322fa0f6e62SHans Petter Selasky 1323fa0f6e62SHans Petter Selasky error = EINVAL; 1324fa0f6e62SHans Petter Selasky 1325fa0f6e62SHans Petter Selasky pcsd = TAILQ_FIRST(&pcs->hdev); 1326fa0f6e62SHans Petter Selasky while (pcsd != NULL) { 1327fa0f6e62SHans Petter Selasky if (pcsd->user_dev == *(struct cuse_dev **)data) { 1328fa0f6e62SHans Petter Selasky TAILQ_REMOVE(&pcs->hdev, pcsd, entry); 132998029019SHans Petter Selasky cuse_server_unlock(pcs); 1330fa0f6e62SHans Petter Selasky cuse_server_free_dev(pcsd); 133198029019SHans Petter Selasky cuse_server_lock(pcs); 1332fa0f6e62SHans Petter Selasky error = 0; 1333fa0f6e62SHans Petter Selasky pcsd = TAILQ_FIRST(&pcs->hdev); 1334fa0f6e62SHans Petter Selasky } else { 1335fa0f6e62SHans Petter Selasky pcsd = TAILQ_NEXT(pcsd, entry); 1336fa0f6e62SHans Petter Selasky } 1337fa0f6e62SHans Petter Selasky } 1338fa0f6e62SHans Petter Selasky 133998029019SHans Petter Selasky cuse_server_unlock(pcs); 1340fa0f6e62SHans Petter Selasky break; 1341fa0f6e62SHans Petter Selasky 1342fa0f6e62SHans Petter Selasky case CUSE_IOCTL_WRITE_DATA: 1343fa0f6e62SHans Petter Selasky case CUSE_IOCTL_READ_DATA: 1344fa0f6e62SHans Petter Selasky 134598029019SHans Petter Selasky cuse_server_lock(pcs); 1346fa0f6e62SHans Petter Selasky pchk = (struct cuse_data_chunk *)data; 1347fa0f6e62SHans Petter Selasky 1348fa0f6e62SHans Petter Selasky pccmd = cuse_server_find_command(pcs, curthread); 1349fa0f6e62SHans Petter Selasky 1350fa0f6e62SHans Petter Selasky if (pccmd == NULL) { 1351fa0f6e62SHans Petter Selasky error = ENXIO; /* invalid request */ 1352fa0f6e62SHans Petter Selasky } else if (pchk->peer_ptr < CUSE_BUF_MIN_PTR) { 1353fa0f6e62SHans Petter Selasky error = EFAULT; /* NULL pointer */ 13545e59b273SHans Petter Selasky } else if (pchk->length == 0) { 13555e59b273SHans Petter Selasky /* NOP */ 1356fa0f6e62SHans Petter Selasky } else if (pchk->peer_ptr < CUSE_BUF_MAX_PTR) { 135798029019SHans Petter Selasky error = cuse_server_ioctl_copy_locked(pcs, pccmd, 1358fa0f6e62SHans Petter Selasky pchk, cmd == CUSE_IOCTL_READ_DATA); 1359fa0f6e62SHans Petter Selasky } else { 13605e59b273SHans Petter Selasky error = cuse_server_data_copy_optimized_locked( 13615e59b273SHans Petter Selasky pcs, pccmd, pchk, cmd == CUSE_IOCTL_READ_DATA); 1362fa0f6e62SHans Petter Selasky } 13635e59b273SHans Petter Selasky 13645e59b273SHans Petter Selasky /* 13655e59b273SHans Petter Selasky * Sometimes the functions above drop the server lock 13665e59b273SHans Petter Selasky * early as an optimization: 13675e59b273SHans Petter Selasky */ 13685e59b273SHans Petter Selasky if (cuse_server_is_locked(pcs)) 136998029019SHans Petter Selasky cuse_server_unlock(pcs); 1370fa0f6e62SHans Petter Selasky break; 1371fa0f6e62SHans Petter Selasky 1372fa0f6e62SHans Petter Selasky case CUSE_IOCTL_SELWAKEUP: 137398029019SHans Petter Selasky cuse_server_lock(pcs); 1374fa0f6e62SHans Petter Selasky /* 1375fa0f6e62SHans Petter Selasky * We don't know which direction caused the event. 1376fa0f6e62SHans Petter Selasky * Wakeup both! 1377fa0f6e62SHans Petter Selasky */ 137895700043SHans Petter Selasky cuse_server_wakeup_all_client_locked(pcs); 137998029019SHans Petter Selasky cuse_server_unlock(pcs); 1380fa0f6e62SHans Petter Selasky break; 1381fa0f6e62SHans Petter Selasky 1382fa0f6e62SHans Petter Selasky default: 1383fa0f6e62SHans Petter Selasky error = ENXIO; 1384fa0f6e62SHans Petter Selasky break; 1385fa0f6e62SHans Petter Selasky } 1386fa0f6e62SHans Petter Selasky return (error); 1387fa0f6e62SHans Petter Selasky } 1388fa0f6e62SHans Petter Selasky 1389fa0f6e62SHans Petter Selasky static int 1390fa0f6e62SHans Petter Selasky cuse_server_poll(struct cdev *dev, int events, struct thread *td) 1391fa0f6e62SHans Petter Selasky { 1392fa0f6e62SHans Petter Selasky return (events & (POLLHUP | POLLPRI | POLLIN | 1393fa0f6e62SHans Petter Selasky POLLRDNORM | POLLOUT | POLLWRNORM)); 1394fa0f6e62SHans Petter Selasky } 1395fa0f6e62SHans Petter Selasky 1396fa0f6e62SHans Petter Selasky static int 1397d14b53eeSHans Petter Selasky cuse_common_mmap_single(struct cuse_server *pcs, 1398d14b53eeSHans Petter Selasky vm_ooffset_t *offset, vm_size_t size, struct vm_object **object) 1399d14b53eeSHans Petter Selasky { 1400d14b53eeSHans Petter Selasky struct cuse_memory *mem; 1401d14b53eeSHans Petter Selasky int error; 1402d14b53eeSHans Petter Selasky 1403d14b53eeSHans Petter Selasky /* verify size */ 1404d14b53eeSHans Petter Selasky if ((size % PAGE_SIZE) != 0 || (size < PAGE_SIZE)) 1405d14b53eeSHans Petter Selasky return (EINVAL); 1406d14b53eeSHans Petter Selasky 1407d14b53eeSHans Petter Selasky cuse_server_lock(pcs); 1408d14b53eeSHans Petter Selasky error = ENOMEM; 1409d14b53eeSHans Petter Selasky 1410d14b53eeSHans Petter Selasky /* lookup memory structure, if any */ 1411d14b53eeSHans Petter Selasky TAILQ_FOREACH(mem, &pcs->hmem, entry) { 1412d14b53eeSHans Petter Selasky vm_ooffset_t min_off; 1413d14b53eeSHans Petter Selasky vm_ooffset_t max_off; 1414d14b53eeSHans Petter Selasky 1415d14b53eeSHans Petter Selasky min_off = (mem->alloc_nr << CUSE_ALLOC_UNIT_SHIFT); 1416d14b53eeSHans Petter Selasky max_off = min_off + (PAGE_SIZE * mem->page_count); 1417d14b53eeSHans Petter Selasky 1418d14b53eeSHans Petter Selasky if (*offset >= min_off && *offset < max_off) { 1419d14b53eeSHans Petter Selasky /* range check size */ 1420d14b53eeSHans Petter Selasky if (size > (max_off - *offset)) { 1421d14b53eeSHans Petter Selasky error = EINVAL; 1422d14b53eeSHans Petter Selasky } else { 1423d14b53eeSHans Petter Selasky /* get new VM object offset to use */ 1424d14b53eeSHans Petter Selasky *offset -= min_off; 1425d14b53eeSHans Petter Selasky vm_object_reference(mem->object); 1426d14b53eeSHans Petter Selasky *object = mem->object; 1427d14b53eeSHans Petter Selasky error = 0; 1428d14b53eeSHans Petter Selasky } 1429d14b53eeSHans Petter Selasky break; 1430d14b53eeSHans Petter Selasky } 1431d14b53eeSHans Petter Selasky } 1432d14b53eeSHans Petter Selasky cuse_server_unlock(pcs); 1433d14b53eeSHans Petter Selasky return (error); 1434d14b53eeSHans Petter Selasky } 1435d14b53eeSHans Petter Selasky 1436d14b53eeSHans Petter Selasky static int 143756c49c63SHans Petter Selasky cuse_server_mmap_single(struct cdev *dev, vm_ooffset_t *offset, 143856c49c63SHans Petter Selasky vm_size_t size, struct vm_object **object, int nprot) 1439fa0f6e62SHans Petter Selasky { 1440fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 1441fa0f6e62SHans Petter Selasky int error; 1442fa0f6e62SHans Petter Selasky 1443fa0f6e62SHans Petter Selasky error = cuse_server_get(&pcs); 1444fa0f6e62SHans Petter Selasky if (error != 0) 144556c49c63SHans Petter Selasky return (error); 1446fa0f6e62SHans Petter Selasky 1447d14b53eeSHans Petter Selasky return (cuse_common_mmap_single(pcs, offset, size, object)); 1448fa0f6e62SHans Petter Selasky } 1449fa0f6e62SHans Petter Selasky 1450fa0f6e62SHans Petter Selasky /*------------------------------------------------------------------------* 1451fa0f6e62SHans Petter Selasky * CUSE CLIENT PART 1452fa0f6e62SHans Petter Selasky *------------------------------------------------------------------------*/ 1453fa0f6e62SHans Petter Selasky static void 1454fa0f6e62SHans Petter Selasky cuse_client_free(void *arg) 1455fa0f6e62SHans Petter Selasky { 1456fa0f6e62SHans Petter Selasky struct cuse_client *pcc = arg; 1457fa0f6e62SHans Petter Selasky struct cuse_client_command *pccmd; 1458fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 1459fa0f6e62SHans Petter Selasky int n; 1460fa0f6e62SHans Petter Selasky 146198029019SHans Petter Selasky pcs = pcc->server; 146298029019SHans Petter Selasky 146398029019SHans Petter Selasky cuse_server_lock(pcs); 1464fa0f6e62SHans Petter Selasky cuse_client_is_closing(pcc); 146598029019SHans Petter Selasky TAILQ_REMOVE(&pcs->hcli, pcc, entry); 146698029019SHans Petter Selasky cuse_server_unlock(pcs); 1467fa0f6e62SHans Petter Selasky 1468fa0f6e62SHans Petter Selasky for (n = 0; n != CUSE_CMD_MAX; n++) { 1469fa0f6e62SHans Petter Selasky pccmd = &pcc->cmds[n]; 1470fa0f6e62SHans Petter Selasky 1471fa0f6e62SHans Petter Selasky sx_destroy(&pccmd->sx); 1472fa0f6e62SHans Petter Selasky cv_destroy(&pccmd->cv); 1473fa0f6e62SHans Petter Selasky } 1474fa0f6e62SHans Petter Selasky 1475fa0f6e62SHans Petter Selasky free(pcc, M_CUSE); 1476fa0f6e62SHans Petter Selasky 1477fa0f6e62SHans Petter Selasky /* drop reference on server */ 147856c49c63SHans Petter Selasky cuse_server_unref(pcs); 1479fa0f6e62SHans Petter Selasky } 1480fa0f6e62SHans Petter Selasky 1481fa0f6e62SHans Petter Selasky static int 1482fa0f6e62SHans Petter Selasky cuse_client_open(struct cdev *dev, int fflags, int devtype, struct thread *td) 1483fa0f6e62SHans Petter Selasky { 1484fa0f6e62SHans Petter Selasky struct cuse_client_command *pccmd; 1485fa0f6e62SHans Petter Selasky struct cuse_server_dev *pcsd; 1486fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 1487fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 1488fa0f6e62SHans Petter Selasky struct cuse_dev *pcd; 1489fa0f6e62SHans Petter Selasky int error; 1490fa0f6e62SHans Petter Selasky int n; 1491fa0f6e62SHans Petter Selasky 1492fa0f6e62SHans Petter Selasky pcsd = dev->si_drv1; 1493fa0f6e62SHans Petter Selasky if (pcsd != NULL) { 1494fa0f6e62SHans Petter Selasky pcs = pcsd->server; 1495fa0f6e62SHans Petter Selasky pcd = pcsd->user_dev; 149698029019SHans Petter Selasky 149798029019SHans Petter Selasky cuse_server_lock(pcs); 1498ac60e801SHans Petter Selasky /* 1499ac60e801SHans Petter Selasky * Check that the refcount didn't wrap and that the 1500ac60e801SHans Petter Selasky * same process is not both client and server. This 1501ac60e801SHans Petter Selasky * can easily lead to deadlocks when destroying the 1502ac60e801SHans Petter Selasky * CUSE character device nodes: 1503ac60e801SHans Petter Selasky */ 1504fa0f6e62SHans Petter Selasky pcs->refs++; 1505ac60e801SHans Petter Selasky if (pcs->refs < 0 || pcs->pid == curproc->p_pid) { 1506ac60e801SHans Petter Selasky /* overflow or wrong PID */ 1507fa0f6e62SHans Petter Selasky pcs->refs--; 150898029019SHans Petter Selasky cuse_server_unlock(pcs); 1509fa0f6e62SHans Petter Selasky return (EINVAL); 151098029019SHans Petter Selasky } 151198029019SHans Petter Selasky cuse_server_unlock(pcs); 151298029019SHans Petter Selasky } else { 151398029019SHans Petter Selasky return (EINVAL); 151498029019SHans Petter Selasky } 1515fa0f6e62SHans Petter Selasky 1516fa0f6e62SHans Petter Selasky pcc = malloc(sizeof(*pcc), M_CUSE, M_WAITOK | M_ZERO); 1517fa0f6e62SHans Petter Selasky if (devfs_set_cdevpriv(pcc, &cuse_client_free)) { 1518fa0f6e62SHans Petter Selasky printf("Cuse: Cannot set cdevpriv.\n"); 1519fa0f6e62SHans Petter Selasky /* drop reference on server */ 152056c49c63SHans Petter Selasky cuse_server_unref(pcs); 1521fa0f6e62SHans Petter Selasky free(pcc, M_CUSE); 1522fa0f6e62SHans Petter Selasky return (ENOMEM); 1523fa0f6e62SHans Petter Selasky } 1524fa0f6e62SHans Petter Selasky pcc->fflags = fflags; 1525fa0f6e62SHans Petter Selasky pcc->server_dev = pcsd; 1526fa0f6e62SHans Petter Selasky pcc->server = pcs; 1527fa0f6e62SHans Petter Selasky 1528fa0f6e62SHans Petter Selasky for (n = 0; n != CUSE_CMD_MAX; n++) { 1529fa0f6e62SHans Petter Selasky pccmd = &pcc->cmds[n]; 1530fa0f6e62SHans Petter Selasky 1531fa0f6e62SHans Petter Selasky pccmd->sub.dev = pcd; 1532fa0f6e62SHans Petter Selasky pccmd->sub.command = n; 1533fa0f6e62SHans Petter Selasky pccmd->client = pcc; 1534fa0f6e62SHans Petter Selasky 1535fa0f6e62SHans Petter Selasky sx_init(&pccmd->sx, "cuse-client-sx"); 1536fa0f6e62SHans Petter Selasky cv_init(&pccmd->cv, "cuse-client-cv"); 1537fa0f6e62SHans Petter Selasky } 1538fa0f6e62SHans Petter Selasky 153998029019SHans Petter Selasky cuse_server_lock(pcs); 1540fa0f6e62SHans Petter Selasky 1541fa0f6e62SHans Petter Selasky /* cuse_client_free() assumes that the client is listed somewhere! */ 1542fa0f6e62SHans Petter Selasky /* always enqueue */ 1543fa0f6e62SHans Petter Selasky 1544fa0f6e62SHans Petter Selasky TAILQ_INSERT_TAIL(&pcs->hcli, pcc, entry); 1545fa0f6e62SHans Petter Selasky 1546fa0f6e62SHans Petter Selasky /* check if server is closing */ 1547fa0f6e62SHans Petter Selasky if ((pcs->is_closing != 0) || (dev->si_drv1 == NULL)) { 1548fa0f6e62SHans Petter Selasky error = EINVAL; 1549fa0f6e62SHans Petter Selasky } else { 1550fa0f6e62SHans Petter Selasky error = 0; 1551fa0f6e62SHans Petter Selasky } 155298029019SHans Petter Selasky cuse_server_unlock(pcs); 1553fa0f6e62SHans Petter Selasky 1554fa0f6e62SHans Petter Selasky if (error) { 1555fa0f6e62SHans Petter Selasky devfs_clear_cdevpriv(); /* XXX bugfix */ 1556fa0f6e62SHans Petter Selasky return (error); 1557fa0f6e62SHans Petter Selasky } 1558fa0f6e62SHans Petter Selasky pccmd = &pcc->cmds[CUSE_CMD_OPEN]; 1559fa0f6e62SHans Petter Selasky 1560fa0f6e62SHans Petter Selasky cuse_cmd_lock(pccmd); 1561fa0f6e62SHans Petter Selasky 156298029019SHans Petter Selasky cuse_server_lock(pcs); 1563fa0f6e62SHans Petter Selasky cuse_client_send_command_locked(pccmd, 0, 0, pcc->fflags, 0); 1564fa0f6e62SHans Petter Selasky 1565fa0f6e62SHans Petter Selasky error = cuse_client_receive_command_locked(pccmd, 0, 0); 156698029019SHans Petter Selasky cuse_server_unlock(pcs); 1567fa0f6e62SHans Petter Selasky 1568fa0f6e62SHans Petter Selasky if (error < 0) { 1569fa0f6e62SHans Petter Selasky error = cuse_convert_error(error); 1570fa0f6e62SHans Petter Selasky } else { 1571fa0f6e62SHans Petter Selasky error = 0; 1572fa0f6e62SHans Petter Selasky } 1573fa0f6e62SHans Petter Selasky 1574fa0f6e62SHans Petter Selasky cuse_cmd_unlock(pccmd); 1575fa0f6e62SHans Petter Selasky 1576fa0f6e62SHans Petter Selasky if (error) 1577fa0f6e62SHans Petter Selasky devfs_clear_cdevpriv(); /* XXX bugfix */ 1578fa0f6e62SHans Petter Selasky 1579fa0f6e62SHans Petter Selasky return (error); 1580fa0f6e62SHans Petter Selasky } 1581fa0f6e62SHans Petter Selasky 1582fa0f6e62SHans Petter Selasky static int 1583fa0f6e62SHans Petter Selasky cuse_client_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 1584fa0f6e62SHans Petter Selasky { 1585fa0f6e62SHans Petter Selasky struct cuse_client_command *pccmd; 1586fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 158798029019SHans Petter Selasky struct cuse_server *pcs; 1588fa0f6e62SHans Petter Selasky int error; 1589fa0f6e62SHans Petter Selasky 1590fa0f6e62SHans Petter Selasky error = cuse_client_get(&pcc); 1591fa0f6e62SHans Petter Selasky if (error != 0) 1592fa0f6e62SHans Petter Selasky return (0); 1593fa0f6e62SHans Petter Selasky 1594fa0f6e62SHans Petter Selasky pccmd = &pcc->cmds[CUSE_CMD_CLOSE]; 159598029019SHans Petter Selasky pcs = pcc->server; 1596fa0f6e62SHans Petter Selasky 1597fa0f6e62SHans Petter Selasky cuse_cmd_lock(pccmd); 1598fa0f6e62SHans Petter Selasky 159998029019SHans Petter Selasky cuse_server_lock(pcs); 1600fa0f6e62SHans Petter Selasky cuse_client_send_command_locked(pccmd, 0, 0, pcc->fflags, 0); 1601fa0f6e62SHans Petter Selasky 1602fa0f6e62SHans Petter Selasky error = cuse_client_receive_command_locked(pccmd, 0, 0); 1603fa0f6e62SHans Petter Selasky cuse_cmd_unlock(pccmd); 1604fa0f6e62SHans Petter Selasky 1605fa0f6e62SHans Petter Selasky cuse_client_is_closing(pcc); 160698029019SHans Petter Selasky cuse_server_unlock(pcs); 1607fa0f6e62SHans Petter Selasky 1608fa0f6e62SHans Petter Selasky return (0); 1609fa0f6e62SHans Petter Selasky } 1610fa0f6e62SHans Petter Selasky 1611fa0f6e62SHans Petter Selasky static void 1612fa0f6e62SHans Petter Selasky cuse_client_kqfilter_poll(struct cdev *dev, struct cuse_client *pcc) 1613fa0f6e62SHans Petter Selasky { 161498029019SHans Petter Selasky struct cuse_server *pcs = pcc->server; 1615fa0f6e62SHans Petter Selasky int temp; 1616fa0f6e62SHans Petter Selasky 161798029019SHans Petter Selasky cuse_server_lock(pcs); 1618fa0f6e62SHans Petter Selasky temp = (pcc->cflags & (CUSE_CLI_KNOTE_HAS_READ | 1619fa0f6e62SHans Petter Selasky CUSE_CLI_KNOTE_HAS_WRITE)); 1620fa0f6e62SHans Petter Selasky pcc->cflags &= ~(CUSE_CLI_KNOTE_NEED_READ | 1621fa0f6e62SHans Petter Selasky CUSE_CLI_KNOTE_NEED_WRITE); 162298029019SHans Petter Selasky cuse_server_unlock(pcs); 1623fa0f6e62SHans Petter Selasky 1624fa0f6e62SHans Petter Selasky if (temp != 0) { 1625fa0f6e62SHans Petter Selasky /* get the latest polling state from the server */ 1626fa0f6e62SHans Petter Selasky temp = cuse_client_poll(dev, POLLIN | POLLOUT, NULL); 1627fa0f6e62SHans Petter Selasky 1628fa0f6e62SHans Petter Selasky if (temp & (POLLIN | POLLOUT)) { 162998029019SHans Petter Selasky cuse_server_lock(pcs); 1630fa0f6e62SHans Petter Selasky if (temp & POLLIN) 1631fa0f6e62SHans Petter Selasky pcc->cflags |= CUSE_CLI_KNOTE_NEED_READ; 1632fa0f6e62SHans Petter Selasky if (temp & POLLOUT) 1633fa0f6e62SHans Petter Selasky pcc->cflags |= CUSE_CLI_KNOTE_NEED_WRITE; 1634fa0f6e62SHans Petter Selasky 1635fa0f6e62SHans Petter Selasky /* make sure the "knote" gets woken up */ 1636fa0f6e62SHans Petter Selasky cuse_server_wakeup_locked(pcc->server); 163798029019SHans Petter Selasky cuse_server_unlock(pcs); 1638fa0f6e62SHans Petter Selasky } 1639fa0f6e62SHans Petter Selasky } 16409a83b097SHans Petter Selasky } 1641fa0f6e62SHans Petter Selasky 1642fa0f6e62SHans Petter Selasky static int 1643fa0f6e62SHans Petter Selasky cuse_client_read(struct cdev *dev, struct uio *uio, int ioflag) 1644fa0f6e62SHans Petter Selasky { 1645fa0f6e62SHans Petter Selasky struct cuse_client_command *pccmd; 1646fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 164798029019SHans Petter Selasky struct cuse_server *pcs; 1648fa0f6e62SHans Petter Selasky int error; 16495e59b273SHans Petter Selasky int temp; 1650fa0f6e62SHans Petter Selasky int len; 1651fa0f6e62SHans Petter Selasky 1652fa0f6e62SHans Petter Selasky error = cuse_client_get(&pcc); 1653fa0f6e62SHans Petter Selasky if (error != 0) 1654fa0f6e62SHans Petter Selasky return (error); 1655fa0f6e62SHans Petter Selasky 1656fa0f6e62SHans Petter Selasky pccmd = &pcc->cmds[CUSE_CMD_READ]; 165798029019SHans Petter Selasky pcs = pcc->server; 1658fa0f6e62SHans Petter Selasky 1659fa0f6e62SHans Petter Selasky if (uio->uio_segflg != UIO_USERSPACE) { 1660fa0f6e62SHans Petter Selasky return (EINVAL); 1661fa0f6e62SHans Petter Selasky } 1662fa0f6e62SHans Petter Selasky uio->uio_segflg = UIO_NOCOPY; 1663fa0f6e62SHans Petter Selasky 1664fa0f6e62SHans Petter Selasky cuse_cmd_lock(pccmd); 1665fa0f6e62SHans Petter Selasky 1666fa0f6e62SHans Petter Selasky while (uio->uio_resid != 0) { 1667fa0f6e62SHans Petter Selasky if (uio->uio_iov->iov_len > CUSE_LENGTH_MAX) { 1668fa0f6e62SHans Petter Selasky error = ENOMEM; 1669fa0f6e62SHans Petter Selasky break; 1670fa0f6e62SHans Petter Selasky } 1671fa0f6e62SHans Petter Selasky len = uio->uio_iov->iov_len; 1672fa0f6e62SHans Petter Selasky 167398029019SHans Petter Selasky cuse_server_lock(pcs); 16745e59b273SHans Petter Selasky if (len <= CUSE_COPY_BUFFER_MAX) { 16755e59b273SHans Petter Selasky /* set read buffer region for small reads */ 16765e59b273SHans Petter Selasky pcc->read_base = (uintptr_t)uio->uio_iov->iov_base; 16775e59b273SHans Petter Selasky pcc->read_length = len; 16785e59b273SHans Petter Selasky } 1679fa0f6e62SHans Petter Selasky cuse_client_send_command_locked(pccmd, 1680beebd9aaSHans Petter Selasky (uintptr_t)uio->uio_iov->iov_base, 1681fa0f6e62SHans Petter Selasky (unsigned long)(unsigned int)len, pcc->fflags, ioflag); 1682fa0f6e62SHans Petter Selasky 1683fa0f6e62SHans Petter Selasky error = cuse_client_receive_command_locked(pccmd, 0, 0); 16845e59b273SHans Petter Selasky /* 16855e59b273SHans Petter Selasky * After finishing reading data, disable the read 16865e59b273SHans Petter Selasky * region for the cuse_server_data_copy_optimized_locked() 16875e59b273SHans Petter Selasky * function: 16885e59b273SHans Petter Selasky */ 16895e59b273SHans Petter Selasky pcc->read_base = 0; 16905e59b273SHans Petter Selasky pcc->read_length = 0; 169198029019SHans Petter Selasky cuse_server_unlock(pcs); 1692fa0f6e62SHans Petter Selasky 16935e59b273SHans Petter Selasky /* 16945e59b273SHans Petter Selasky * The return value indicates the read length, when 16955e59b273SHans Petter Selasky * not negative. Range check it just in case to avoid 16965e59b273SHans Petter Selasky * passing invalid length values to uiomove(). 16975e59b273SHans Petter Selasky */ 16985e59b273SHans Petter Selasky if (error > len) { 16995e59b273SHans Petter Selasky error = ERANGE; 17005e59b273SHans Petter Selasky break; 17015e59b273SHans Petter Selasky } else if (error > 0 && len <= CUSE_COPY_BUFFER_MAX) { 17025e59b273SHans Petter Selasky temp = copyout(pcc->read_buffer, 17035e59b273SHans Petter Selasky uio->uio_iov->iov_base, error); 17045e59b273SHans Petter Selasky if (temp != 0) { 17055e59b273SHans Petter Selasky error = temp; 17065e59b273SHans Petter Selasky break; 17075e59b273SHans Petter Selasky } 17085e59b273SHans Petter Selasky } 1709fa0f6e62SHans Petter Selasky if (error < 0) { 1710fa0f6e62SHans Petter Selasky error = cuse_convert_error(error); 1711fa0f6e62SHans Petter Selasky break; 1712fa0f6e62SHans Petter Selasky } else if (error == len) { 1713fa0f6e62SHans Petter Selasky error = uiomove(NULL, error, uio); 1714fa0f6e62SHans Petter Selasky if (error) 1715fa0f6e62SHans Petter Selasky break; 1716fa0f6e62SHans Petter Selasky } else { 1717fa0f6e62SHans Petter Selasky error = uiomove(NULL, error, uio); 1718fa0f6e62SHans Petter Selasky break; 1719fa0f6e62SHans Petter Selasky } 1720fa0f6e62SHans Petter Selasky } 1721fa0f6e62SHans Petter Selasky cuse_cmd_unlock(pccmd); 1722fa0f6e62SHans Petter Selasky 1723fa0f6e62SHans Petter Selasky uio->uio_segflg = UIO_USERSPACE;/* restore segment flag */ 1724fa0f6e62SHans Petter Selasky 1725fa0f6e62SHans Petter Selasky if (error == EWOULDBLOCK) 1726fa0f6e62SHans Petter Selasky cuse_client_kqfilter_poll(dev, pcc); 1727fa0f6e62SHans Petter Selasky 1728fa0f6e62SHans Petter Selasky return (error); 1729fa0f6e62SHans Petter Selasky } 1730fa0f6e62SHans Petter Selasky 1731fa0f6e62SHans Petter Selasky static int 1732fa0f6e62SHans Petter Selasky cuse_client_write(struct cdev *dev, struct uio *uio, int ioflag) 1733fa0f6e62SHans Petter Selasky { 1734fa0f6e62SHans Petter Selasky struct cuse_client_command *pccmd; 1735fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 173698029019SHans Petter Selasky struct cuse_server *pcs; 1737fa0f6e62SHans Petter Selasky int error; 1738fa0f6e62SHans Petter Selasky int len; 1739fa0f6e62SHans Petter Selasky 1740fa0f6e62SHans Petter Selasky error = cuse_client_get(&pcc); 1741fa0f6e62SHans Petter Selasky if (error != 0) 1742fa0f6e62SHans Petter Selasky return (error); 1743fa0f6e62SHans Petter Selasky 1744fa0f6e62SHans Petter Selasky pccmd = &pcc->cmds[CUSE_CMD_WRITE]; 174598029019SHans Petter Selasky pcs = pcc->server; 1746fa0f6e62SHans Petter Selasky 1747fa0f6e62SHans Petter Selasky if (uio->uio_segflg != UIO_USERSPACE) { 1748fa0f6e62SHans Petter Selasky return (EINVAL); 1749fa0f6e62SHans Petter Selasky } 1750fa0f6e62SHans Petter Selasky uio->uio_segflg = UIO_NOCOPY; 1751fa0f6e62SHans Petter Selasky 1752fa0f6e62SHans Petter Selasky cuse_cmd_lock(pccmd); 1753fa0f6e62SHans Petter Selasky 1754fa0f6e62SHans Petter Selasky while (uio->uio_resid != 0) { 1755fa0f6e62SHans Petter Selasky if (uio->uio_iov->iov_len > CUSE_LENGTH_MAX) { 1756fa0f6e62SHans Petter Selasky error = ENOMEM; 1757fa0f6e62SHans Petter Selasky break; 1758fa0f6e62SHans Petter Selasky } 1759fa0f6e62SHans Petter Selasky len = uio->uio_iov->iov_len; 1760fa0f6e62SHans Petter Selasky 17615e59b273SHans Petter Selasky if (len <= CUSE_COPY_BUFFER_MAX) { 17625e59b273SHans Petter Selasky error = copyin(uio->uio_iov->iov_base, 17635e59b273SHans Petter Selasky pcc->write_buffer, len); 17645e59b273SHans Petter Selasky if (error != 0) 17655e59b273SHans Petter Selasky break; 17665e59b273SHans Petter Selasky } 17675e59b273SHans Petter Selasky 176898029019SHans Petter Selasky cuse_server_lock(pcs); 17695e59b273SHans Petter Selasky if (len <= CUSE_COPY_BUFFER_MAX) { 17705e59b273SHans Petter Selasky /* set write buffer region for small writes */ 17715e59b273SHans Petter Selasky pcc->write_base = (uintptr_t)uio->uio_iov->iov_base; 17725e59b273SHans Petter Selasky pcc->write_length = len; 17735e59b273SHans Petter Selasky } 1774fa0f6e62SHans Petter Selasky cuse_client_send_command_locked(pccmd, 1775beebd9aaSHans Petter Selasky (uintptr_t)uio->uio_iov->iov_base, 1776fa0f6e62SHans Petter Selasky (unsigned long)(unsigned int)len, pcc->fflags, ioflag); 1777fa0f6e62SHans Petter Selasky 1778fa0f6e62SHans Petter Selasky error = cuse_client_receive_command_locked(pccmd, 0, 0); 17795e59b273SHans Petter Selasky 17805e59b273SHans Petter Selasky /* 17815e59b273SHans Petter Selasky * After finishing writing data, disable the write 17825e59b273SHans Petter Selasky * region for the cuse_server_data_copy_optimized_locked() 17835e59b273SHans Petter Selasky * function: 17845e59b273SHans Petter Selasky */ 17855e59b273SHans Petter Selasky pcc->write_base = 0; 17865e59b273SHans Petter Selasky pcc->write_length = 0; 178798029019SHans Petter Selasky cuse_server_unlock(pcs); 1788fa0f6e62SHans Petter Selasky 17895e59b273SHans Petter Selasky /* 17905e59b273SHans Petter Selasky * The return value indicates the write length, when 17915e59b273SHans Petter Selasky * not negative. Range check it just in case to avoid 17925e59b273SHans Petter Selasky * passing invalid length values to uiomove(). 17935e59b273SHans Petter Selasky */ 17945e59b273SHans Petter Selasky if (error > len) { 17955e59b273SHans Petter Selasky error = ERANGE; 17965e59b273SHans Petter Selasky break; 17975e59b273SHans Petter Selasky } else if (error < 0) { 1798fa0f6e62SHans Petter Selasky error = cuse_convert_error(error); 1799fa0f6e62SHans Petter Selasky break; 1800fa0f6e62SHans Petter Selasky } else if (error == len) { 1801fa0f6e62SHans Petter Selasky error = uiomove(NULL, error, uio); 1802fa0f6e62SHans Petter Selasky if (error) 1803fa0f6e62SHans Petter Selasky break; 1804fa0f6e62SHans Petter Selasky } else { 1805fa0f6e62SHans Petter Selasky error = uiomove(NULL, error, uio); 1806fa0f6e62SHans Petter Selasky break; 1807fa0f6e62SHans Petter Selasky } 1808fa0f6e62SHans Petter Selasky } 1809fa0f6e62SHans Petter Selasky cuse_cmd_unlock(pccmd); 1810fa0f6e62SHans Petter Selasky 18115e59b273SHans Petter Selasky /* restore segment flag */ 18125e59b273SHans Petter Selasky uio->uio_segflg = UIO_USERSPACE; 1813fa0f6e62SHans Petter Selasky 1814fa0f6e62SHans Petter Selasky if (error == EWOULDBLOCK) 1815fa0f6e62SHans Petter Selasky cuse_client_kqfilter_poll(dev, pcc); 1816fa0f6e62SHans Petter Selasky 1817fa0f6e62SHans Petter Selasky return (error); 1818fa0f6e62SHans Petter Selasky } 1819fa0f6e62SHans Petter Selasky 1820fa0f6e62SHans Petter Selasky int 1821fa0f6e62SHans Petter Selasky cuse_client_ioctl(struct cdev *dev, unsigned long cmd, 1822fa0f6e62SHans Petter Selasky caddr_t data, int fflag, struct thread *td) 1823fa0f6e62SHans Petter Selasky { 1824fa0f6e62SHans Petter Selasky struct cuse_client_command *pccmd; 1825fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 182698029019SHans Petter Selasky struct cuse_server *pcs; 1827fa0f6e62SHans Petter Selasky int error; 1828fa0f6e62SHans Petter Selasky int len; 1829fa0f6e62SHans Petter Selasky 1830fa0f6e62SHans Petter Selasky error = cuse_client_get(&pcc); 1831fa0f6e62SHans Petter Selasky if (error != 0) 1832fa0f6e62SHans Petter Selasky return (error); 1833fa0f6e62SHans Petter Selasky 1834fa0f6e62SHans Petter Selasky len = IOCPARM_LEN(cmd); 1835fa0f6e62SHans Petter Selasky if (len > CUSE_BUFFER_MAX) 1836fa0f6e62SHans Petter Selasky return (ENOMEM); 1837fa0f6e62SHans Petter Selasky 1838fa0f6e62SHans Petter Selasky pccmd = &pcc->cmds[CUSE_CMD_IOCTL]; 183998029019SHans Petter Selasky pcs = pcc->server; 1840fa0f6e62SHans Petter Selasky 1841fa0f6e62SHans Petter Selasky cuse_cmd_lock(pccmd); 1842fa0f6e62SHans Petter Selasky 1843010638abSHans Petter Selasky if (cmd & (IOC_IN | IOC_VOID)) 1844fa0f6e62SHans Petter Selasky memcpy(pcc->ioctl_buffer, data, len); 1845fa0f6e62SHans Petter Selasky 1846fa0f6e62SHans Petter Selasky /* 1847fa0f6e62SHans Petter Selasky * When the ioctl-length is zero drivers can pass information 1848fa0f6e62SHans Petter Selasky * through the data pointer of the ioctl. Make sure this information 1849fa0f6e62SHans Petter Selasky * is forwarded to the driver. 1850fa0f6e62SHans Petter Selasky */ 1851fa0f6e62SHans Petter Selasky 185298029019SHans Petter Selasky cuse_server_lock(pcs); 1853fa0f6e62SHans Petter Selasky cuse_client_send_command_locked(pccmd, 1854fa0f6e62SHans Petter Selasky (len == 0) ? *(long *)data : CUSE_BUF_MIN_PTR, 1855fa0f6e62SHans Petter Selasky (unsigned long)cmd, pcc->fflags, 1856fa0f6e62SHans Petter Selasky (fflag & O_NONBLOCK) ? IO_NDELAY : 0); 1857fa0f6e62SHans Petter Selasky 1858fa0f6e62SHans Petter Selasky error = cuse_client_receive_command_locked(pccmd, data, len); 185998029019SHans Petter Selasky cuse_server_unlock(pcs); 1860fa0f6e62SHans Petter Selasky 1861fa0f6e62SHans Petter Selasky if (error < 0) { 1862fa0f6e62SHans Petter Selasky error = cuse_convert_error(error); 1863fa0f6e62SHans Petter Selasky } else { 1864fa0f6e62SHans Petter Selasky error = 0; 1865fa0f6e62SHans Petter Selasky } 1866fa0f6e62SHans Petter Selasky 1867fa0f6e62SHans Petter Selasky if (cmd & IOC_OUT) 1868fa0f6e62SHans Petter Selasky memcpy(data, pcc->ioctl_buffer, len); 1869fa0f6e62SHans Petter Selasky 1870fa0f6e62SHans Petter Selasky cuse_cmd_unlock(pccmd); 1871fa0f6e62SHans Petter Selasky 1872fa0f6e62SHans Petter Selasky if (error == EWOULDBLOCK) 1873fa0f6e62SHans Petter Selasky cuse_client_kqfilter_poll(dev, pcc); 1874fa0f6e62SHans Petter Selasky 1875fa0f6e62SHans Petter Selasky return (error); 1876fa0f6e62SHans Petter Selasky } 1877fa0f6e62SHans Petter Selasky 1878fa0f6e62SHans Petter Selasky static int 1879fa0f6e62SHans Petter Selasky cuse_client_poll(struct cdev *dev, int events, struct thread *td) 1880fa0f6e62SHans Petter Selasky { 1881fa0f6e62SHans Petter Selasky struct cuse_client_command *pccmd; 1882fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 188398029019SHans Petter Selasky struct cuse_server *pcs; 1884fa0f6e62SHans Petter Selasky unsigned long temp; 1885fa0f6e62SHans Petter Selasky int error; 1886fa0f6e62SHans Petter Selasky int revents; 1887fa0f6e62SHans Petter Selasky 1888fa0f6e62SHans Petter Selasky error = cuse_client_get(&pcc); 1889fa0f6e62SHans Petter Selasky if (error != 0) 189095700043SHans Petter Selasky goto pollnval; 1891fa0f6e62SHans Petter Selasky 1892fa0f6e62SHans Petter Selasky temp = 0; 189398029019SHans Petter Selasky pcs = pcc->server; 1894fa0f6e62SHans Petter Selasky 1895fa0f6e62SHans Petter Selasky if (events & (POLLPRI | POLLIN | POLLRDNORM)) 1896fa0f6e62SHans Petter Selasky temp |= CUSE_POLL_READ; 1897fa0f6e62SHans Petter Selasky 1898fa0f6e62SHans Petter Selasky if (events & (POLLOUT | POLLWRNORM)) 1899fa0f6e62SHans Petter Selasky temp |= CUSE_POLL_WRITE; 1900fa0f6e62SHans Petter Selasky 1901fa0f6e62SHans Petter Selasky if (events & POLLHUP) 1902fa0f6e62SHans Petter Selasky temp |= CUSE_POLL_ERROR; 1903fa0f6e62SHans Petter Selasky 1904fa0f6e62SHans Petter Selasky pccmd = &pcc->cmds[CUSE_CMD_POLL]; 1905fa0f6e62SHans Petter Selasky 1906fa0f6e62SHans Petter Selasky cuse_cmd_lock(pccmd); 1907fa0f6e62SHans Petter Selasky 1908fa0f6e62SHans Petter Selasky /* Need to selrecord() first to not loose any events. */ 1909fa0f6e62SHans Petter Selasky if (temp != 0 && td != NULL) 191098029019SHans Petter Selasky selrecord(td, &pcs->selinfo); 1911fa0f6e62SHans Petter Selasky 191298029019SHans Petter Selasky cuse_server_lock(pcs); 1913fa0f6e62SHans Petter Selasky cuse_client_send_command_locked(pccmd, 1914fa0f6e62SHans Petter Selasky 0, temp, pcc->fflags, IO_NDELAY); 1915fa0f6e62SHans Petter Selasky 1916fa0f6e62SHans Petter Selasky error = cuse_client_receive_command_locked(pccmd, 0, 0); 191798029019SHans Petter Selasky cuse_server_unlock(pcs); 1918fa0f6e62SHans Petter Selasky 191995700043SHans Petter Selasky cuse_cmd_unlock(pccmd); 192095700043SHans Petter Selasky 1921fa0f6e62SHans Petter Selasky if (error < 0) { 192295700043SHans Petter Selasky goto pollnval; 1923fa0f6e62SHans Petter Selasky } else { 1924fa0f6e62SHans Petter Selasky revents = 0; 1925fa0f6e62SHans Petter Selasky if (error & CUSE_POLL_READ) 1926fa0f6e62SHans Petter Selasky revents |= (events & (POLLPRI | POLLIN | POLLRDNORM)); 1927fa0f6e62SHans Petter Selasky if (error & CUSE_POLL_WRITE) 1928fa0f6e62SHans Petter Selasky revents |= (events & (POLLOUT | POLLWRNORM)); 1929fa0f6e62SHans Petter Selasky if (error & CUSE_POLL_ERROR) 1930fa0f6e62SHans Petter Selasky revents |= (events & POLLHUP); 1931fa0f6e62SHans Petter Selasky } 1932fa0f6e62SHans Petter Selasky return (revents); 193395700043SHans Petter Selasky 193495700043SHans Petter Selasky pollnval: 193595700043SHans Petter Selasky /* XXX many clients don't understand POLLNVAL */ 193695700043SHans Petter Selasky return (events & (POLLHUP | POLLPRI | POLLIN | 193795700043SHans Petter Selasky POLLRDNORM | POLLOUT | POLLWRNORM)); 1938fa0f6e62SHans Petter Selasky } 1939fa0f6e62SHans Petter Selasky 1940fa0f6e62SHans Petter Selasky static int 194156c49c63SHans Petter Selasky cuse_client_mmap_single(struct cdev *dev, vm_ooffset_t *offset, 194256c49c63SHans Petter Selasky vm_size_t size, struct vm_object **object, int nprot) 1943fa0f6e62SHans Petter Selasky { 1944fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 1945fa0f6e62SHans Petter Selasky int error; 1946fa0f6e62SHans Petter Selasky 1947fa0f6e62SHans Petter Selasky error = cuse_client_get(&pcc); 1948fa0f6e62SHans Petter Selasky if (error != 0) 194956c49c63SHans Petter Selasky return (error); 1950fa0f6e62SHans Petter Selasky 1951d14b53eeSHans Petter Selasky return (cuse_common_mmap_single(pcc->server, offset, size, object)); 1952fa0f6e62SHans Petter Selasky } 1953fa0f6e62SHans Petter Selasky 1954fa0f6e62SHans Petter Selasky static void 1955fa0f6e62SHans Petter Selasky cuse_client_kqfilter_read_detach(struct knote *kn) 1956fa0f6e62SHans Petter Selasky { 1957fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 195898029019SHans Petter Selasky struct cuse_server *pcs; 1959fa0f6e62SHans Petter Selasky 1960fa0f6e62SHans Petter Selasky pcc = kn->kn_hook; 196198029019SHans Petter Selasky pcs = pcc->server; 196298029019SHans Petter Selasky 196398029019SHans Petter Selasky cuse_server_lock(pcs); 196498029019SHans Petter Selasky knlist_remove(&pcs->selinfo.si_note, kn, 1); 196598029019SHans Petter Selasky cuse_server_unlock(pcs); 1966fa0f6e62SHans Petter Selasky } 1967fa0f6e62SHans Petter Selasky 1968fa0f6e62SHans Petter Selasky static void 1969fa0f6e62SHans Petter Selasky cuse_client_kqfilter_write_detach(struct knote *kn) 1970fa0f6e62SHans Petter Selasky { 1971fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 197298029019SHans Petter Selasky struct cuse_server *pcs; 1973fa0f6e62SHans Petter Selasky 1974fa0f6e62SHans Petter Selasky pcc = kn->kn_hook; 197598029019SHans Petter Selasky pcs = pcc->server; 197698029019SHans Petter Selasky 197798029019SHans Petter Selasky cuse_server_lock(pcs); 197898029019SHans Petter Selasky knlist_remove(&pcs->selinfo.si_note, kn, 1); 197998029019SHans Petter Selasky cuse_server_unlock(pcs); 1980fa0f6e62SHans Petter Selasky } 1981fa0f6e62SHans Petter Selasky 1982fa0f6e62SHans Petter Selasky static int 1983fa0f6e62SHans Petter Selasky cuse_client_kqfilter_read_event(struct knote *kn, long hint) 1984fa0f6e62SHans Petter Selasky { 1985fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 1986fa0f6e62SHans Petter Selasky 1987fa0f6e62SHans Petter Selasky pcc = kn->kn_hook; 198898029019SHans Petter Selasky 198998029019SHans Petter Selasky mtx_assert(&pcc->server->mtx, MA_OWNED); 199098029019SHans Petter Selasky 1991fa0f6e62SHans Petter Selasky return ((pcc->cflags & CUSE_CLI_KNOTE_NEED_READ) ? 1 : 0); 1992fa0f6e62SHans Petter Selasky } 1993fa0f6e62SHans Petter Selasky 1994fa0f6e62SHans Petter Selasky static int 1995fa0f6e62SHans Petter Selasky cuse_client_kqfilter_write_event(struct knote *kn, long hint) 1996fa0f6e62SHans Petter Selasky { 1997fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 1998fa0f6e62SHans Petter Selasky 1999fa0f6e62SHans Petter Selasky pcc = kn->kn_hook; 200098029019SHans Petter Selasky 200198029019SHans Petter Selasky mtx_assert(&pcc->server->mtx, MA_OWNED); 200298029019SHans Petter Selasky 2003fa0f6e62SHans Petter Selasky return ((pcc->cflags & CUSE_CLI_KNOTE_NEED_WRITE) ? 1 : 0); 2004fa0f6e62SHans Petter Selasky } 2005fa0f6e62SHans Petter Selasky 2006fa0f6e62SHans Petter Selasky static int 2007fa0f6e62SHans Petter Selasky cuse_client_kqfilter(struct cdev *dev, struct knote *kn) 2008fa0f6e62SHans Petter Selasky { 2009fa0f6e62SHans Petter Selasky struct cuse_client *pcc; 2010fa0f6e62SHans Petter Selasky struct cuse_server *pcs; 2011fa0f6e62SHans Petter Selasky int error; 2012fa0f6e62SHans Petter Selasky 2013fa0f6e62SHans Petter Selasky error = cuse_client_get(&pcc); 2014fa0f6e62SHans Petter Selasky if (error != 0) 2015fa0f6e62SHans Petter Selasky return (error); 2016fa0f6e62SHans Petter Selasky 2017fa0f6e62SHans Petter Selasky pcs = pcc->server; 201898029019SHans Petter Selasky 201998029019SHans Petter Selasky cuse_server_lock(pcs); 2020fa0f6e62SHans Petter Selasky switch (kn->kn_filter) { 2021fa0f6e62SHans Petter Selasky case EVFILT_READ: 2022fa0f6e62SHans Petter Selasky pcc->cflags |= CUSE_CLI_KNOTE_HAS_READ; 2023fa0f6e62SHans Petter Selasky kn->kn_hook = pcc; 2024fa0f6e62SHans Petter Selasky kn->kn_fop = &cuse_client_kqfilter_read_ops; 2025fa0f6e62SHans Petter Selasky knlist_add(&pcs->selinfo.si_note, kn, 1); 2026fa0f6e62SHans Petter Selasky break; 2027fa0f6e62SHans Petter Selasky case EVFILT_WRITE: 2028fa0f6e62SHans Petter Selasky pcc->cflags |= CUSE_CLI_KNOTE_HAS_WRITE; 2029fa0f6e62SHans Petter Selasky kn->kn_hook = pcc; 2030fa0f6e62SHans Petter Selasky kn->kn_fop = &cuse_client_kqfilter_write_ops; 2031fa0f6e62SHans Petter Selasky knlist_add(&pcs->selinfo.si_note, kn, 1); 2032fa0f6e62SHans Petter Selasky break; 2033fa0f6e62SHans Petter Selasky default: 2034fa0f6e62SHans Petter Selasky error = EINVAL; 2035fa0f6e62SHans Petter Selasky break; 2036fa0f6e62SHans Petter Selasky } 203798029019SHans Petter Selasky cuse_server_unlock(pcs); 2038fa0f6e62SHans Petter Selasky 2039fa0f6e62SHans Petter Selasky if (error == 0) 2040fa0f6e62SHans Petter Selasky cuse_client_kqfilter_poll(dev, pcc); 2041fa0f6e62SHans Petter Selasky return (error); 2042fa0f6e62SHans Petter Selasky } 2043