]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libcuse/cuse_lib.c
Add two missing eventhandler.h headers
[FreeBSD/FreeBSD.git] / lib / libcuse / cuse_lib.c
1 /* $FreeBSD$ */
2 /*-
3  * Copyright (c) 2010-2012 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 <stdio.h>
28 #include <stdint.h>
29 #include <pthread.h>
30 #include <signal.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <stdlib.h>
35 #include <stdarg.h>
36
37 #include <sys/types.h>
38 #include <sys/queue.h>
39 #include <sys/fcntl.h>
40 #include <sys/mman.h>
41 #include <sys/param.h>
42
43 #include <fs/cuse/cuse_ioctl.h>
44
45 #include "cuse.h"
46
47 int     cuse_debug_level;
48
49 #ifdef HAVE_DEBUG
50 static const char *cuse_cmd_str(int cmd);
51
52 #define DPRINTF(...) do {                       \
53         if (cuse_debug_level != 0)              \
54                 printf(__VA_ARGS__);            \
55 } while (0)
56 #else
57 #define DPRINTF(...) do { } while (0)
58 #endif
59
60 struct cuse_vm_allocation {
61         uint8_t *ptr;
62         uint32_t size;
63 };
64
65 struct cuse_dev_entered {
66         TAILQ_ENTRY(cuse_dev_entered) entry;
67         pthread_t thread;
68         void   *per_file_handle;
69         struct cuse_dev *cdev;
70         int     cmd;
71         int     is_local;
72         int     got_signal;
73 };
74
75 struct cuse_dev {
76         TAILQ_ENTRY(cuse_dev) entry;
77         const struct cuse_methods *mtod;
78         void   *priv0;
79         void   *priv1;
80 };
81
82 static int f_cuse = -1;
83
84 static pthread_mutex_t m_cuse;
85 static TAILQ_HEAD(, cuse_dev) h_cuse __guarded_by(m_cuse);
86 static TAILQ_HEAD(, cuse_dev_entered) h_cuse_entered __guarded_by(m_cuse);
87 static struct cuse_vm_allocation a_cuse[CUSE_ALLOC_UNIT_MAX]
88     __guarded_by(m_cuse);
89
90 #define CUSE_LOCK() \
91         pthread_mutex_lock(&m_cuse)
92
93 #define CUSE_UNLOCK() \
94         pthread_mutex_unlock(&m_cuse)
95
96 int
97 cuse_init(void)
98 {
99         pthread_mutexattr_t attr;
100
101         f_cuse = open("/dev/cuse", O_RDWR);
102         if (f_cuse < 0) {
103                 if (feature_present("cuse") == 0)
104                         return (CUSE_ERR_NOT_LOADED);
105                 else
106                         return (CUSE_ERR_INVALID);
107         }
108         pthread_mutexattr_init(&attr);
109         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
110         pthread_mutex_init(&m_cuse, &attr);
111
112         TAILQ_INIT(&h_cuse);
113         TAILQ_INIT(&h_cuse_entered);
114
115         return (0);
116 }
117
118 int
119 cuse_uninit(void)
120 {
121         int f;
122
123         if (f_cuse < 0)
124                 return (CUSE_ERR_INVALID);
125
126         f = f_cuse;
127         f_cuse = -1;
128
129         close(f);
130
131         pthread_mutex_destroy(&m_cuse);
132
133         memset(a_cuse, 0, sizeof(a_cuse));
134
135         return (0);
136 }
137
138 unsigned long
139 cuse_vmoffset(void *_ptr)
140 {
141         uint8_t *ptr_min;
142         uint8_t *ptr_max;
143         uint8_t *ptr = _ptr;
144         unsigned long remainder;
145         int n;
146
147         CUSE_LOCK();
148         for (n = 0; n != CUSE_ALLOC_UNIT_MAX; n++) {
149                 if (a_cuse[n].ptr == NULL)
150                         continue;
151
152                 ptr_min = a_cuse[n].ptr;
153                 ptr_max = a_cuse[n].ptr + a_cuse[n].size - 1;
154
155                 if ((ptr >= ptr_min) && (ptr <= ptr_max)) {
156
157                         CUSE_UNLOCK();
158
159                         remainder = (ptr - ptr_min);
160
161                         remainder -= remainder % PAGE_SIZE;
162
163                         return ((n * PAGE_SIZE * CUSE_ALLOC_PAGES_MAX) + remainder);
164                 }
165         }
166         CUSE_UNLOCK();
167
168         return (0x80000000UL);          /* failure */
169 }
170
171 void   *
172 cuse_vmalloc(int size)
173 {
174         struct cuse_alloc_info info;
175         void *ptr;
176         int error;
177         int n;
178
179         if (f_cuse < 0)
180                 return (NULL);
181
182         memset(&info, 0, sizeof(info));
183
184         if (size < 1)
185                 return (NULL);
186
187         info.page_count = howmany(size, PAGE_SIZE);
188
189         CUSE_LOCK();
190         for (n = 0; n != CUSE_ALLOC_UNIT_MAX; n++) {
191
192                 if (a_cuse[n].ptr != NULL)
193                         continue;
194
195                 a_cuse[n].ptr = ((uint8_t *)1); /* reserve */
196                 a_cuse[n].size = 0;
197
198                 CUSE_UNLOCK();
199
200                 info.alloc_nr = n;
201
202                 error = ioctl(f_cuse, CUSE_IOCTL_ALLOC_MEMORY, &info);
203
204                 if (error) {
205
206                         CUSE_LOCK();
207
208                         a_cuse[n].ptr = NULL;
209
210                         if (errno == EBUSY)
211                                 continue;
212                         else
213                                 break;
214                 }
215                 ptr = mmap(NULL, info.page_count * PAGE_SIZE,
216                     PROT_READ | PROT_WRITE,
217                     MAP_SHARED, f_cuse, CUSE_ALLOC_PAGES_MAX *
218                     PAGE_SIZE * n);
219
220                 if (ptr == MAP_FAILED) {
221
222                         error = ioctl(f_cuse, CUSE_IOCTL_FREE_MEMORY, &info);
223
224                         if (error) {
225                                 /* ignore */
226                         }
227                         CUSE_LOCK();
228
229                         a_cuse[n].ptr = NULL;
230
231                         break;
232                 }
233                 CUSE_LOCK();
234                 a_cuse[n].ptr = ptr;
235                 a_cuse[n].size = size;
236                 CUSE_UNLOCK();
237
238                 return (ptr);           /* success */
239         }
240         CUSE_UNLOCK();
241         return (NULL);                  /* failure */
242 }
243
244 int
245 cuse_is_vmalloc_addr(void *ptr)
246 {
247         int n;
248
249         if (f_cuse < 0 || ptr == NULL)
250                 return (0);             /* false */
251
252         CUSE_LOCK();
253         for (n = 0; n != CUSE_ALLOC_UNIT_MAX; n++) {
254                 if (a_cuse[n].ptr == ptr)
255                         break;
256         }
257         CUSE_UNLOCK();
258
259         return (n != CUSE_ALLOC_UNIT_MAX);
260 }
261
262 void
263 cuse_vmfree(void *ptr)
264 {
265         struct cuse_vm_allocation temp;
266         struct cuse_alloc_info info;
267         int error;
268         int n;
269
270         if (f_cuse < 0)
271                 return;
272
273         CUSE_LOCK();
274         for (n = 0; n != CUSE_ALLOC_UNIT_MAX; n++) {
275                 if (a_cuse[n].ptr != ptr)
276                         continue;
277
278                 temp = a_cuse[n];
279
280                 CUSE_UNLOCK();
281
282                 munmap(temp.ptr, temp.size);
283
284                 memset(&info, 0, sizeof(info));
285
286                 info.alloc_nr = n;
287
288                 error = ioctl(f_cuse, CUSE_IOCTL_FREE_MEMORY, &info);
289
290                 if (error != 0) {
291                         /* ignore any errors */
292                         DPRINTF("Freeing memory failed: %d\n", errno);
293                 }
294                 CUSE_LOCK();
295
296                 a_cuse[n].ptr = NULL;
297                 a_cuse[n].size = 0;
298
299                 break;
300         }
301         CUSE_UNLOCK();
302 }
303
304 int
305 cuse_alloc_unit_number_by_id(int *pnum, int id)
306 {
307         int error;
308
309         if (f_cuse < 0)
310                 return (CUSE_ERR_INVALID);
311
312         *pnum = (id & CUSE_ID_MASK);
313
314         error = ioctl(f_cuse, CUSE_IOCTL_ALLOC_UNIT_BY_ID, pnum);
315         if (error)
316                 return (CUSE_ERR_NO_MEMORY);
317
318         return (0);
319
320 }
321
322 int
323 cuse_free_unit_number_by_id(int num, int id)
324 {
325         int error;
326
327         if (f_cuse < 0)
328                 return (CUSE_ERR_INVALID);
329
330         if (num != -1 || id != -1)
331                 num = (id & CUSE_ID_MASK) | (num & 0xFF);
332
333         error = ioctl(f_cuse, CUSE_IOCTL_FREE_UNIT_BY_ID, &num);
334         if (error)
335                 return (CUSE_ERR_NO_MEMORY);
336
337         return (0);
338 }
339
340 int
341 cuse_alloc_unit_number(int *pnum)
342 {
343         int error;
344
345         if (f_cuse < 0)
346                 return (CUSE_ERR_INVALID);
347
348         error = ioctl(f_cuse, CUSE_IOCTL_ALLOC_UNIT, pnum);
349         if (error)
350                 return (CUSE_ERR_NO_MEMORY);
351
352         return (0);
353 }
354
355 int
356 cuse_free_unit_number(int num)
357 {
358         int error;
359
360         if (f_cuse < 0)
361                 return (CUSE_ERR_INVALID);
362
363         error = ioctl(f_cuse, CUSE_IOCTL_FREE_UNIT, &num);
364         if (error)
365                 return (CUSE_ERR_NO_MEMORY);
366
367         return (0);
368 }
369
370 struct cuse_dev *
371 cuse_dev_create(const struct cuse_methods *mtod, void *priv0, void *priv1,
372     uid_t _uid, gid_t _gid, int _perms, const char *_fmt,...)
373 {
374         struct cuse_create_dev info;
375         struct cuse_dev *cdev;
376         va_list args;
377         int error;
378
379         if (f_cuse < 0)
380                 return (NULL);
381
382         cdev = malloc(sizeof(*cdev));
383         if (cdev == NULL)
384                 return (NULL);
385
386         memset(cdev, 0, sizeof(*cdev));
387
388         cdev->mtod = mtod;
389         cdev->priv0 = priv0;
390         cdev->priv1 = priv1;
391
392         memset(&info, 0, sizeof(info));
393
394         info.dev = cdev;
395         info.user_id = _uid;
396         info.group_id = _gid;
397         info.permissions = _perms;
398
399         va_start(args, _fmt);
400         vsnprintf(info.devname, sizeof(info.devname), _fmt, args);
401         va_end(args);
402
403         error = ioctl(f_cuse, CUSE_IOCTL_CREATE_DEV, &info);
404         if (error) {
405                 free(cdev);
406                 return (NULL);
407         }
408         CUSE_LOCK();
409         TAILQ_INSERT_TAIL(&h_cuse, cdev, entry);
410         CUSE_UNLOCK();
411
412         return (cdev);
413 }
414
415
416 void
417 cuse_dev_destroy(struct cuse_dev *cdev)
418 {
419         int error;
420
421         if (f_cuse < 0)
422                 return;
423
424         CUSE_LOCK();
425         TAILQ_REMOVE(&h_cuse, cdev, entry);
426         CUSE_UNLOCK();
427
428         error = ioctl(f_cuse, CUSE_IOCTL_DESTROY_DEV, &cdev);
429         if (error)
430                 return;
431
432         free(cdev);
433 }
434
435 void   *
436 cuse_dev_get_priv0(struct cuse_dev *cdev)
437 {
438         return (cdev->priv0);
439 }
440
441 void   *
442 cuse_dev_get_priv1(struct cuse_dev *cdev)
443 {
444         return (cdev->priv1);
445 }
446
447 void
448 cuse_dev_set_priv0(struct cuse_dev *cdev, void *priv)
449 {
450         cdev->priv0 = priv;
451 }
452
453 void
454 cuse_dev_set_priv1(struct cuse_dev *cdev, void *priv)
455 {
456         cdev->priv1 = priv;
457 }
458
459 int
460 cuse_wait_and_process(void)
461 {
462         pthread_t curr = pthread_self();
463         struct cuse_dev_entered *pe;
464         struct cuse_dev_entered enter;
465         struct cuse_command info;
466         struct cuse_dev *cdev;
467         int error;
468
469         if (f_cuse < 0)
470                 return (CUSE_ERR_INVALID);
471
472         error = ioctl(f_cuse, CUSE_IOCTL_GET_COMMAND, &info);
473         if (error)
474                 return (CUSE_ERR_OTHER);
475
476         cdev = info.dev;
477
478         CUSE_LOCK();
479         enter.thread = curr;
480         enter.per_file_handle = (void *)info.per_file_handle;
481         enter.cmd = info.command;
482         enter.is_local = 0;
483         enter.got_signal = 0;
484         enter.cdev = cdev;
485         TAILQ_INSERT_TAIL(&h_cuse_entered, &enter, entry);
486         CUSE_UNLOCK();
487
488         DPRINTF("cuse: Command = %d = %s, flags = %d, arg = 0x%08x, ptr = 0x%08x\n",
489             (int)info.command, cuse_cmd_str(info.command), (int)info.fflags,
490             (int)info.argument, (int)info.data_pointer);
491
492         switch (info.command) {
493         case CUSE_CMD_OPEN:
494                 if (cdev->mtod->cm_open != NULL)
495                         error = (cdev->mtod->cm_open) (cdev, (int)info.fflags);
496                 else
497                         error = 0;
498                 break;
499
500         case CUSE_CMD_CLOSE:
501
502                 /* wait for other threads to stop */
503
504                 while (1) {
505
506                         error = 0;
507
508                         CUSE_LOCK();
509                         TAILQ_FOREACH(pe, &h_cuse_entered, entry) {
510                                 if (pe->cdev != cdev)
511                                         continue;
512                                 if (pe->thread == curr)
513                                         continue;
514                                 if (pe->per_file_handle !=
515                                     enter.per_file_handle)
516                                         continue;
517                                 pe->got_signal = 1;
518                                 pthread_kill(pe->thread, SIGHUP);
519                                 error = CUSE_ERR_BUSY;
520                         }
521                         CUSE_UNLOCK();
522
523                         if (error == 0)
524                                 break;
525                         else
526                                 usleep(10000);
527                 }
528
529                 if (cdev->mtod->cm_close != NULL)
530                         error = (cdev->mtod->cm_close) (cdev, (int)info.fflags);
531                 else
532                         error = 0;
533                 break;
534
535         case CUSE_CMD_READ:
536                 if (cdev->mtod->cm_read != NULL) {
537                         error = (cdev->mtod->cm_read) (cdev, (int)info.fflags,
538                             (void *)info.data_pointer, (int)info.argument);
539                 } else {
540                         error = CUSE_ERR_INVALID;
541                 }
542                 break;
543
544         case CUSE_CMD_WRITE:
545                 if (cdev->mtod->cm_write != NULL) {
546                         error = (cdev->mtod->cm_write) (cdev, (int)info.fflags,
547                             (void *)info.data_pointer, (int)info.argument);
548                 } else {
549                         error = CUSE_ERR_INVALID;
550                 }
551                 break;
552
553         case CUSE_CMD_IOCTL:
554                 if (cdev->mtod->cm_ioctl != NULL) {
555                         error = (cdev->mtod->cm_ioctl) (cdev, (int)info.fflags,
556                             (unsigned int)info.argument, (void *)info.data_pointer);
557                 } else {
558                         error = CUSE_ERR_INVALID;
559                 }
560                 break;
561
562         case CUSE_CMD_POLL:
563                 if (cdev->mtod->cm_poll != NULL) {
564                         error = (cdev->mtod->cm_poll) (cdev, (int)info.fflags,
565                             (int)info.argument);
566                 } else {
567                         error = CUSE_POLL_ERROR;
568                 }
569                 break;
570
571         case CUSE_CMD_SIGNAL:
572                 CUSE_LOCK();
573                 TAILQ_FOREACH(pe, &h_cuse_entered, entry) {
574                         if (pe->cdev != cdev)
575                                 continue;
576                         if (pe->thread == curr)
577                                 continue;
578                         if (pe->per_file_handle !=
579                             enter.per_file_handle)
580                                 continue;
581                         pe->got_signal = 1;
582                         pthread_kill(pe->thread, SIGHUP);
583                 }
584                 CUSE_UNLOCK();
585                 break;
586
587         default:
588                 error = CUSE_ERR_INVALID;
589                 break;
590         }
591
592         DPRINTF("cuse: Command error = %d for %s\n",
593             error, cuse_cmd_str(info.command));
594
595         CUSE_LOCK();
596         TAILQ_REMOVE(&h_cuse_entered, &enter, entry);
597         CUSE_UNLOCK();
598
599         /* we ignore any sync command failures */
600         ioctl(f_cuse, CUSE_IOCTL_SYNC_COMMAND, &error);
601
602         return (0);
603 }
604
605 static struct cuse_dev_entered *
606 cuse_dev_get_entered(void)
607 {
608         struct cuse_dev_entered *pe;
609         pthread_t curr = pthread_self();
610
611         CUSE_LOCK();
612         TAILQ_FOREACH(pe, &h_cuse_entered, entry) {
613                 if (pe->thread == curr)
614                         break;
615         }
616         CUSE_UNLOCK();
617         return (pe);
618 }
619
620 void
621 cuse_dev_set_per_file_handle(struct cuse_dev *cdev, void *handle)
622 {
623         struct cuse_dev_entered *pe;
624
625         pe = cuse_dev_get_entered();
626         if (pe == NULL || pe->cdev != cdev)
627                 return;
628
629         pe->per_file_handle = handle;
630         ioctl(f_cuse, CUSE_IOCTL_SET_PFH, &handle);
631 }
632
633 void   *
634 cuse_dev_get_per_file_handle(struct cuse_dev *cdev)
635 {
636         struct cuse_dev_entered *pe;
637
638         pe = cuse_dev_get_entered();
639         if (pe == NULL || pe->cdev != cdev)
640                 return (NULL);
641
642         return (pe->per_file_handle);
643 }
644
645 void
646 cuse_set_local(int val)
647 {
648         struct cuse_dev_entered *pe;
649
650         pe = cuse_dev_get_entered();
651         if (pe == NULL)
652                 return;
653
654         pe->is_local = val;
655 }
656
657 #ifdef HAVE_DEBUG
658 static const char *
659 cuse_cmd_str(int cmd)
660 {
661         static const char *str[CUSE_CMD_MAX] = {
662                 [CUSE_CMD_NONE] = "none",
663                 [CUSE_CMD_OPEN] = "open",
664                 [CUSE_CMD_CLOSE] = "close",
665                 [CUSE_CMD_READ] = "read",
666                 [CUSE_CMD_WRITE] = "write",
667                 [CUSE_CMD_IOCTL] = "ioctl",
668                 [CUSE_CMD_POLL] = "poll",
669                 [CUSE_CMD_SIGNAL] = "signal",
670                 [CUSE_CMD_SYNC] = "sync",
671         };
672
673         if ((cmd >= 0) && (cmd < CUSE_CMD_MAX) &&
674             (str[cmd] != NULL))
675                 return (str[cmd]);
676         else
677                 return ("unknown");
678 }
679
680 #endif
681
682 int
683 cuse_get_local(void)
684 {
685         struct cuse_dev_entered *pe;
686
687         pe = cuse_dev_get_entered();
688         if (pe == NULL)
689                 return (0);
690
691         return (pe->is_local);
692 }
693
694 int
695 cuse_copy_out(const void *src, void *user_dst, int len)
696 {
697         struct cuse_data_chunk info;
698         struct cuse_dev_entered *pe;
699         int error;
700
701         if ((f_cuse < 0) || (len < 0))
702                 return (CUSE_ERR_INVALID);
703
704         pe = cuse_dev_get_entered();
705         if (pe == NULL)
706                 return (CUSE_ERR_INVALID);
707
708         DPRINTF("cuse: copy_out(%p,%p,%d), cmd = %d = %s\n",
709             src, user_dst, len, pe->cmd, cuse_cmd_str(pe->cmd));
710
711         if (pe->is_local) {
712                 memcpy(user_dst, src, len);
713         } else {
714                 info.local_ptr = (uintptr_t)src;
715                 info.peer_ptr = (uintptr_t)user_dst;
716                 info.length = len;
717
718                 error = ioctl(f_cuse, CUSE_IOCTL_WRITE_DATA, &info);
719                 if (error) {
720                         DPRINTF("cuse: copy_out() error = %d\n", errno);
721                         return (CUSE_ERR_FAULT);
722                 }
723         }
724         return (0);
725 }
726
727 int
728 cuse_copy_in(const void *user_src, void *dst, int len)
729 {
730         struct cuse_data_chunk info;
731         struct cuse_dev_entered *pe;
732         int error;
733
734         if ((f_cuse < 0) || (len < 0))
735                 return (CUSE_ERR_INVALID);
736
737         pe = cuse_dev_get_entered();
738         if (pe == NULL)
739                 return (CUSE_ERR_INVALID);
740
741         DPRINTF("cuse: copy_in(%p,%p,%d), cmd = %d = %s\n",
742             user_src, dst, len, pe->cmd, cuse_cmd_str(pe->cmd));
743
744         if (pe->is_local) {
745                 memcpy(dst, user_src, len);
746         } else {
747                 info.local_ptr = (uintptr_t)dst;
748                 info.peer_ptr = (uintptr_t)user_src;
749                 info.length = len;
750
751                 error = ioctl(f_cuse, CUSE_IOCTL_READ_DATA, &info);
752                 if (error) {
753                         DPRINTF("cuse: copy_in() error = %d\n", errno);
754                         return (CUSE_ERR_FAULT);
755                 }
756         }
757         return (0);
758 }
759
760 struct cuse_dev *
761 cuse_dev_get_current(int *pcmd)
762 {
763         struct cuse_dev_entered *pe;
764
765         pe = cuse_dev_get_entered();
766         if (pe == NULL) {
767                 if (pcmd != NULL)
768                         *pcmd = 0;
769                 return (NULL);
770         }
771         if (pcmd != NULL)
772                 *pcmd = pe->cmd;
773         return (pe->cdev);
774 }
775
776 int
777 cuse_got_peer_signal(void)
778 {
779         struct cuse_dev_entered *pe;
780
781         pe = cuse_dev_get_entered();
782         if (pe == NULL)
783                 return (CUSE_ERR_INVALID);
784
785         if (pe->got_signal)
786                 return (0);
787
788         return (CUSE_ERR_OTHER);
789 }
790
791 void
792 cuse_poll_wakeup(void)
793 {
794         int error = 0;
795
796         if (f_cuse < 0)
797                 return;
798
799         ioctl(f_cuse, CUSE_IOCTL_SELWAKEUP, &error);
800 }