Line data Source code
1 : /* $OpenBSD: fuse_device.c,v 1.29 2018/06/27 13:58:22 helg Exp $ */
2 : /*
3 : * Copyright (c) 2012-2013 Sylvestre Gallon <ccna.syl@gmail.com>
4 : *
5 : * Permission to use, copy, modify, and distribute this software for any
6 : * purpose with or without fee is hereby granted, provided that the above
7 : * copyright notice and this permission notice appear in all copies.
8 : *
9 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 : */
17 :
18 : #include <sys/param.h>
19 : #include <sys/systm.h>
20 : #include <sys/fcntl.h>
21 : #include <sys/ioctl.h>
22 : #include <sys/malloc.h>
23 : #include <sys/mount.h>
24 : #include <sys/poll.h>
25 : #include <sys/stat.h>
26 : #include <sys/statvfs.h>
27 : #include <sys/vnode.h>
28 : #include <sys/fusebuf.h>
29 :
30 : #include "fusefs_node.h"
31 : #include "fusefs.h"
32 :
33 : #ifdef FUSE_DEBUG
34 : #define DPRINTF(fmt, arg...) printf("%s: " fmt, "fuse", ##arg)
35 : #else
36 : #define DPRINTF(fmt, arg...)
37 : #endif
38 :
39 : SIMPLEQ_HEAD(fusebuf_head, fusebuf);
40 :
41 : struct fuse_d {
42 : struct fusefs_mnt *fd_fmp;
43 : int fd_unit;
44 :
45 : /*fusebufs queues*/
46 : struct fusebuf_head fd_fbufs_in;
47 : struct fusebuf_head fd_fbufs_wait;
48 :
49 : /* kq fields */
50 : struct selinfo fd_rsel;
51 : LIST_ENTRY(fuse_d) fd_list;
52 : };
53 :
54 : int stat_fbufs_in = 0;
55 : int stat_fbufs_wait = 0;
56 : int stat_opened_fusedev = 0;
57 :
58 : LIST_HEAD(, fuse_d) fuse_d_list;
59 : struct fuse_d *fuse_lookup(int);
60 :
61 : void fuseattach(int);
62 : int fuseopen(dev_t, int, int, struct proc *);
63 : int fuseclose(dev_t, int, int, struct proc *);
64 : int fuseioctl(dev_t, u_long, caddr_t, int, struct proc *);
65 : int fuseread(dev_t, struct uio *, int);
66 : int fusewrite(dev_t, struct uio *, int);
67 : int fusepoll(dev_t, int, struct proc *);
68 : int fusekqfilter(dev_t dev, struct knote *kn);
69 : int filt_fuse_read(struct knote *, long);
70 : void filt_fuse_rdetach(struct knote *);
71 :
72 : const static struct filterops fuse_rd_filtops = {
73 : 1,
74 : NULL,
75 : filt_fuse_rdetach,
76 : filt_fuse_read
77 : };
78 :
79 : const static struct filterops fuse_seltrue_filtops = {
80 : 1,
81 : NULL,
82 : filt_fuse_rdetach,
83 : filt_seltrue
84 : };
85 :
86 : #ifdef FUSE_DEBUG
87 : static void
88 : fuse_dump_buff(char *buff, int len)
89 : {
90 : char text[17];
91 : int i;
92 :
93 : if (len < 0) {
94 : printf("invalid len: %d", len);
95 : return;
96 : }
97 : if (buff == NULL) {
98 : printf("invalid buff");
99 : return;
100 : }
101 :
102 : memset(text, 0, 17);
103 : for (i = 0; i < len; i++) {
104 : if (i != 0 && (i % 16) == 0) {
105 : printf(": %s\n", text);
106 : memset(text, 0, 17);
107 : }
108 :
109 : printf("%.2x ", buff[i] & 0xff);
110 :
111 : if (buff[i] > ' ' && buff[i] < '~')
112 : text[i%16] = buff[i] & 0xff;
113 : else
114 : text[i%16] = '.';
115 : }
116 :
117 : if ((i % 16) != 0)
118 : while ((i % 16) != 0) {
119 : printf(" ");
120 : i++;
121 : }
122 :
123 : printf(": %s\n", text);
124 : }
125 : #endif
126 :
127 : struct fuse_d *
128 0 : fuse_lookup(int unit)
129 : {
130 : struct fuse_d *fd;
131 :
132 0 : LIST_FOREACH(fd, &fuse_d_list, fd_list)
133 0 : if (fd->fd_unit == unit)
134 0 : return (fd);
135 0 : return (NULL);
136 0 : }
137 :
138 : /*
139 : * Cleanup all msgs from sc_fbufs_in and sc_fbufs_wait.
140 : */
141 : void
142 0 : fuse_device_cleanup(dev_t dev)
143 : {
144 : struct fuse_d *fd;
145 : struct fusebuf *f, *ftmp, *lprev;
146 :
147 0 : fd = fuse_lookup(minor(dev));
148 0 : if (fd == NULL)
149 0 : return;
150 :
151 : /* clear FIFO IN */
152 : lprev = NULL;
153 0 : SIMPLEQ_FOREACH_SAFE(f, &fd->fd_fbufs_in, fb_next, ftmp) {
154 : DPRINTF("cleanup unprocessed msg in sc_fbufs_in\n");
155 0 : if (lprev == NULL)
156 0 : SIMPLEQ_REMOVE_HEAD(&fd->fd_fbufs_in, fb_next);
157 : else
158 0 : SIMPLEQ_REMOVE_AFTER(&fd->fd_fbufs_in, lprev,
159 : fb_next);
160 :
161 0 : stat_fbufs_in--;
162 0 : f->fb_err = ENXIO;
163 0 : wakeup(f);
164 : lprev = f;
165 : }
166 :
167 : /* clear FIFO WAIT*/
168 : lprev = NULL;
169 0 : SIMPLEQ_FOREACH_SAFE(f, &fd->fd_fbufs_wait, fb_next, ftmp) {
170 : DPRINTF("umount unprocessed msg in sc_fbufs_wait\n");
171 0 : if (lprev == NULL)
172 0 : SIMPLEQ_REMOVE_HEAD(&fd->fd_fbufs_wait, fb_next);
173 : else
174 0 : SIMPLEQ_REMOVE_AFTER(&fd->fd_fbufs_wait, lprev,
175 : fb_next);
176 :
177 0 : stat_fbufs_wait--;
178 0 : f->fb_err = ENXIO;
179 0 : wakeup(f);
180 : lprev = f;
181 : }
182 0 : }
183 :
184 : void
185 0 : fuse_device_queue_fbuf(dev_t dev, struct fusebuf *fbuf)
186 : {
187 : struct fuse_d *fd;
188 :
189 0 : fd = fuse_lookup(minor(dev));
190 0 : if (fd == NULL)
191 0 : return;
192 :
193 0 : SIMPLEQ_INSERT_TAIL(&fd->fd_fbufs_in, fbuf, fb_next);
194 0 : stat_fbufs_in++;
195 0 : selwakeup(&fd->fd_rsel);
196 0 : }
197 :
198 : void
199 0 : fuse_device_set_fmp(struct fusefs_mnt *fmp, int set)
200 : {
201 : struct fuse_d *fd;
202 :
203 0 : fd = fuse_lookup(minor(fmp->dev));
204 0 : if (fd == NULL)
205 0 : return;
206 :
207 0 : fd->fd_fmp = set ? fmp : NULL;
208 0 : }
209 :
210 : void
211 0 : fuseattach(int num)
212 : {
213 0 : LIST_INIT(&fuse_d_list);
214 0 : }
215 :
216 : int
217 0 : fuseopen(dev_t dev, int flags, int fmt, struct proc * p)
218 : {
219 : struct fuse_d *fd;
220 0 : int unit = minor(dev);
221 :
222 0 : if (flags & O_EXCL)
223 0 : return (EBUSY); /* No exclusive opens */
224 :
225 0 : if ((fd = fuse_lookup(unit)) != NULL)
226 0 : return (EBUSY);
227 :
228 0 : fd = malloc(sizeof(*fd), M_DEVBUF, M_WAITOK | M_ZERO);
229 0 : fd->fd_unit = unit;
230 0 : SIMPLEQ_INIT(&fd->fd_fbufs_in);
231 0 : SIMPLEQ_INIT(&fd->fd_fbufs_wait);
232 0 : LIST_INSERT_HEAD(&fuse_d_list, fd, fd_list);
233 :
234 0 : stat_opened_fusedev++;
235 0 : return (0);
236 0 : }
237 :
238 : int
239 0 : fuseclose(dev_t dev, int flags, int fmt, struct proc *p)
240 : {
241 : struct fuse_d *fd;
242 : int error;
243 :
244 0 : fd = fuse_lookup(minor(dev));
245 0 : if (fd == NULL)
246 0 : return (EINVAL);
247 :
248 0 : if (fd->fd_fmp) {
249 0 : printf("fuse: device close without umount\n");
250 0 : fd->fd_fmp->sess_init = 0;
251 0 : fuse_device_cleanup(dev);
252 0 : if ((vfs_busy(fd->fd_fmp->mp, VB_WRITE | VB_NOWAIT)) != 0)
253 : goto end;
254 0 : error = dounmount(fd->fd_fmp->mp, MNT_FORCE, p);
255 0 : if (error)
256 0 : printf("fuse: unmount failed with error %d\n", error);
257 0 : fd->fd_fmp = NULL;
258 0 : }
259 :
260 : end:
261 0 : LIST_REMOVE(fd, fd_list);
262 0 : free(fd, M_DEVBUF, sizeof(*fd));
263 0 : stat_opened_fusedev--;
264 0 : return (0);
265 0 : }
266 :
267 : /*
268 : * FIOCGETFBDAT Get fusebuf datas from kernel to user
269 : * FIOCSETFBDAT Set fusebuf datas from user to kernel
270 : */
271 : int
272 0 : fuseioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
273 : {
274 : struct fb_ioctl_xch *ioexch;
275 : struct fusebuf *lastfbuf;
276 : struct fusebuf *fbuf;
277 : struct fuse_d *fd;
278 : int error = 0;
279 :
280 0 : fd = fuse_lookup(minor(dev));
281 0 : if (fd == NULL)
282 0 : return (ENXIO);
283 :
284 0 : switch (cmd) {
285 : case FIOCGETFBDAT:
286 0 : ioexch = (struct fb_ioctl_xch *)addr;
287 :
288 : /* Looking for uuid in fd_fbufs_in */
289 0 : SIMPLEQ_FOREACH(fbuf, &fd->fd_fbufs_in, fb_next) {
290 0 : if (fbuf->fb_uuid == ioexch->fbxch_uuid)
291 : break;
292 :
293 : lastfbuf = fbuf;
294 : }
295 0 : if (fbuf == NULL) {
296 0 : printf("fuse: Cannot find fusebuf\n");
297 0 : return (EINVAL);
298 : }
299 :
300 : /* Remove the fbuf from fd_fbufs_in */
301 0 : if (fbuf == SIMPLEQ_FIRST(&fd->fd_fbufs_in))
302 0 : SIMPLEQ_REMOVE_HEAD(&fd->fd_fbufs_in, fb_next);
303 : else
304 0 : SIMPLEQ_REMOVE_AFTER(&fd->fd_fbufs_in, lastfbuf,
305 : fb_next);
306 0 : stat_fbufs_in--;
307 :
308 : /* Do not handle fbufs with bad len */
309 0 : if (fbuf->fb_len != ioexch->fbxch_len) {
310 0 : printf("fuse: Bad fusebuf len\n");
311 0 : return (EINVAL);
312 : }
313 :
314 : /* Update the userland fbuf */
315 0 : error = copyout(fbuf->fb_dat, ioexch->fbxch_data,
316 : ioexch->fbxch_len);
317 0 : if (error) {
318 0 : printf("fuse: cannot copyout\n");
319 0 : return (error);
320 : }
321 :
322 : #ifdef FUSE_DEBUG
323 : fuse_dump_buff(fbuf->fb_dat, fbuf->fb_len);
324 : #endif
325 :
326 : /* Adding fbuf in fd_fbufs_wait */
327 0 : free(fbuf->fb_dat, M_FUSEFS, fbuf->fb_len);
328 0 : fbuf->fb_dat = NULL;
329 0 : SIMPLEQ_INSERT_TAIL(&fd->fd_fbufs_wait, fbuf, fb_next);
330 0 : stat_fbufs_wait++;
331 0 : break;
332 :
333 : case FIOCSETFBDAT:
334 : DPRINTF("SET BUFFER\n");
335 0 : ioexch = (struct fb_ioctl_xch *)addr;
336 :
337 : /* looking for uuid in fd_fbufs_wait */
338 0 : SIMPLEQ_FOREACH(fbuf, &fd->fd_fbufs_wait, fb_next) {
339 0 : if (fbuf->fb_uuid == ioexch->fbxch_uuid)
340 : break;
341 :
342 : lastfbuf = fbuf;
343 : }
344 0 : if (fbuf == NULL) {
345 0 : printf("fuse: Cannot find fusebuf\n");
346 0 : return (EINVAL);
347 : }
348 :
349 : /* Do not handle fbufs with bad len */
350 0 : if (fbuf->fb_len != ioexch->fbxch_len) {
351 0 : printf("fuse: Bad fusebuf size\n");
352 0 : return (EINVAL);
353 : }
354 :
355 : /* fetching data from userland */
356 0 : fbuf->fb_dat = malloc(ioexch->fbxch_len, M_FUSEFS,
357 : M_WAITOK | M_ZERO);
358 0 : error = copyin(ioexch->fbxch_data, fbuf->fb_dat,
359 0 : ioexch->fbxch_len);
360 0 : if (error) {
361 0 : printf("fuse: Cannot copyin\n");
362 0 : free(fbuf->fb_dat, M_FUSEFS, fbuf->fb_len);
363 0 : fbuf->fb_dat = NULL;
364 0 : return (error);
365 : }
366 :
367 : #ifdef FUSE_DEBUG
368 : fuse_dump_buff(fbuf->fb_dat, fbuf->fb_len);
369 : #endif
370 :
371 : /* Remove fbuf from fd_fbufs_wait */
372 0 : if (fbuf == SIMPLEQ_FIRST(&fd->fd_fbufs_wait))
373 0 : SIMPLEQ_REMOVE_HEAD(&fd->fd_fbufs_wait, fb_next);
374 : else
375 0 : SIMPLEQ_REMOVE_AFTER(&fd->fd_fbufs_wait, lastfbuf,
376 : fb_next);
377 0 : stat_fbufs_wait--;
378 0 : wakeup(fbuf);
379 0 : break;
380 : default:
381 : error = EINVAL;
382 0 : }
383 :
384 0 : return (error);
385 0 : }
386 :
387 : int
388 0 : fuseread(dev_t dev, struct uio *uio, int ioflag)
389 : {
390 : struct fuse_d *fd;
391 : struct fusebuf *fbuf;
392 0 : struct fb_hdr hdr;
393 : void *tmpaddr;
394 : int error = 0;
395 :
396 0 : fd = fuse_lookup(minor(dev));
397 0 : if (fd == NULL)
398 0 : return (ENXIO);
399 :
400 0 : if (SIMPLEQ_EMPTY(&fd->fd_fbufs_in)) {
401 0 : if (ioflag & O_NONBLOCK)
402 0 : return (EAGAIN);
403 :
404 : goto end;
405 : }
406 : fbuf = SIMPLEQ_FIRST(&fd->fd_fbufs_in);
407 :
408 : /* We get the whole fusebuf or nothing */
409 0 : if (uio->uio_resid != FUSEBUFSIZE)
410 0 : return (EINVAL);
411 :
412 : /* Do not send kernel pointers */
413 0 : memcpy(&hdr.fh_next, &fbuf->fb_next, sizeof(fbuf->fb_next));
414 0 : memset(&fbuf->fb_next, 0, sizeof(fbuf->fb_next));
415 0 : tmpaddr = fbuf->fb_dat;
416 0 : fbuf->fb_dat = NULL;
417 0 : error = uiomove(fbuf, FUSEBUFSIZE, uio);
418 0 : if (error)
419 : goto end;
420 :
421 : #ifdef FUSE_DEBUG
422 : fuse_dump_buff((char *)fbuf, FUSEBUFSIZE);
423 : #endif
424 : /* Restore kernel pointers */
425 0 : memcpy(&fbuf->fb_next, &hdr.fh_next, sizeof(fbuf->fb_next));
426 0 : fbuf->fb_dat = tmpaddr;
427 :
428 : /* Remove the fbuf if it does not contains data */
429 0 : if (fbuf->fb_len == 0) {
430 0 : SIMPLEQ_REMOVE_HEAD(&fd->fd_fbufs_in, fb_next);
431 0 : stat_fbufs_in--;
432 0 : SIMPLEQ_INSERT_TAIL(&fd->fd_fbufs_wait, fbuf, fb_next);
433 0 : stat_fbufs_wait++;
434 0 : }
435 :
436 : end:
437 0 : return (error);
438 0 : }
439 :
440 : int
441 0 : fusewrite(dev_t dev, struct uio *uio, int ioflag)
442 : {
443 : struct fusebuf *lastfbuf;
444 : struct fuse_d *fd;
445 : struct fusebuf *fbuf;
446 0 : struct fb_hdr hdr;
447 : int error = 0;
448 :
449 0 : fd = fuse_lookup(minor(dev));
450 0 : if (fd == NULL)
451 0 : return (ENXIO);
452 :
453 : /* We get the whole fusebuf or nothing */
454 0 : if (uio->uio_resid != FUSEBUFSIZE)
455 0 : return (EINVAL);
456 :
457 0 : if ((error = uiomove(&hdr, sizeof(hdr), uio)) != 0)
458 0 : return (error);
459 :
460 : /* looking for uuid in fd_fbufs_wait */
461 0 : SIMPLEQ_FOREACH(fbuf, &fd->fd_fbufs_wait, fb_next) {
462 0 : if (fbuf->fb_uuid == hdr.fh_uuid)
463 : break;
464 :
465 : lastfbuf = fbuf;
466 : }
467 0 : if (fbuf == NULL)
468 0 : return (EINVAL);
469 :
470 : /* Update fb_hdr */
471 0 : fbuf->fb_len = hdr.fh_len;
472 0 : fbuf->fb_err = hdr.fh_err;
473 0 : fbuf->fb_ino = hdr.fh_ino;
474 :
475 : /* Check for corrupted fbufs */
476 0 : if ((fbuf->fb_len && fbuf->fb_err) ||
477 0 : SIMPLEQ_EMPTY(&fd->fd_fbufs_wait)) {
478 0 : printf("fuse: dropping corrupted fusebuf\n");
479 : error = EINVAL;
480 0 : goto end;
481 : }
482 :
483 : /* Get the missing datas from the fbuf */
484 0 : error = uiomove(&fbuf->FD, uio->uio_resid, uio);
485 0 : if (error)
486 0 : return error;
487 0 : fbuf->fb_dat = NULL;
488 : #ifdef FUSE_DEBUG
489 : fuse_dump_buff((char *)fbuf, FUSEBUFSIZE);
490 : #endif
491 :
492 0 : switch (fbuf->fb_type) {
493 : case FBT_INIT:
494 0 : fd->fd_fmp->sess_init = 1;
495 0 : break ;
496 : case FBT_DESTROY:
497 0 : fd->fd_fmp = NULL;
498 0 : break ;
499 : }
500 : end:
501 : /* Remove the fbuf if it does not contains data */
502 0 : if (fbuf->fb_len == 0) {
503 0 : if (fbuf == SIMPLEQ_FIRST(&fd->fd_fbufs_wait))
504 0 : SIMPLEQ_REMOVE_HEAD(&fd->fd_fbufs_wait, fb_next);
505 : else
506 0 : SIMPLEQ_REMOVE_AFTER(&fd->fd_fbufs_wait, lastfbuf,
507 : fb_next);
508 0 : stat_fbufs_wait--;
509 0 : if (fbuf->fb_type == FBT_INIT)
510 0 : fb_delete(fbuf);
511 : else
512 0 : wakeup(fbuf);
513 : }
514 :
515 0 : return (error);
516 0 : }
517 :
518 : int
519 0 : fusepoll(dev_t dev, int events, struct proc *p)
520 : {
521 : struct fuse_d *fd;
522 : int revents = 0;
523 :
524 0 : fd = fuse_lookup(minor(dev));
525 0 : if (fd == NULL)
526 0 : return (EINVAL);
527 :
528 0 : if (events & (POLLIN | POLLRDNORM))
529 0 : if (!SIMPLEQ_EMPTY(&fd->fd_fbufs_in))
530 0 : revents |= events & (POLLIN | POLLRDNORM);
531 :
532 0 : if (events & (POLLOUT | POLLWRNORM))
533 0 : revents |= events & (POLLOUT | POLLWRNORM);
534 :
535 0 : if (revents == 0)
536 0 : if (events & (POLLIN | POLLRDNORM))
537 0 : selrecord(p, &fd->fd_rsel);
538 :
539 0 : return (revents);
540 0 : }
541 :
542 : int
543 0 : fusekqfilter(dev_t dev, struct knote *kn)
544 : {
545 : struct fuse_d *fd;
546 : struct klist *klist;
547 :
548 0 : fd = fuse_lookup(minor(dev));
549 0 : if (fd == NULL)
550 0 : return (EINVAL);
551 :
552 0 : switch (kn->kn_filter) {
553 : case EVFILT_READ:
554 0 : klist = &fd->fd_rsel.si_note;
555 0 : kn->kn_fop = &fuse_rd_filtops;
556 0 : break;
557 : case EVFILT_WRITE:
558 0 : klist = &fd->fd_rsel.si_note;
559 0 : kn->kn_fop = &fuse_seltrue_filtops;
560 0 : break;
561 : default:
562 0 : return (EINVAL);
563 : }
564 :
565 0 : kn->kn_hook = fd;
566 :
567 0 : SLIST_INSERT_HEAD(klist, kn, kn_selnext);
568 :
569 0 : return (0);
570 0 : }
571 :
572 : void
573 0 : filt_fuse_rdetach(struct knote *kn)
574 : {
575 0 : struct fuse_d *fd = kn->kn_hook;
576 0 : struct klist *klist = &fd->fd_rsel.si_note;
577 :
578 0 : SLIST_REMOVE(klist, kn, knote, kn_selnext);
579 0 : }
580 :
581 : int
582 0 : filt_fuse_read(struct knote *kn, long hint)
583 : {
584 0 : struct fuse_d *fd = kn->kn_hook;
585 : int event = 0;
586 :
587 0 : if (!SIMPLEQ_EMPTY(&fd->fd_fbufs_in))
588 : event = 1;
589 :
590 0 : return (event);
591 : }
|