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