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