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