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