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