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