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