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