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