The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/cuse/cuse.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: a66e8b33715a4cb0f3e3a0479a19155e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.