1 /* $OpenBSD: fuse_device.c,v 1.40 2023/12/16 22:17:08 mvs 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/event.h> 23 #include <sys/malloc.h> 24 #include <sys/mount.h> 25 #include <sys/rwlock.h> 26 #include <sys/stat.h> 27 #include <sys/statvfs.h> 28 #include <sys/vnode.h> 29 #include <sys/fusebuf.h> 30 31 #include "fusefs_node.h" 32 #include "fusefs.h" 33 34 #ifdef FUSE_DEBUG 35 #define DPRINTF(fmt, arg...) printf("%s: " fmt, "fuse", ##arg) 36 #else 37 #define DPRINTF(fmt, arg...) 38 #endif 39 40 /* 41 * Locks used to protect struct members and global data 42 * l fd_lock 43 */ 44 45 SIMPLEQ_HEAD(fusebuf_head, fusebuf); 46 47 struct fuse_d { 48 struct rwlock fd_lock; 49 struct fusefs_mnt *fd_fmp; 50 int fd_unit; 51 52 /*fusebufs queues*/ 53 struct fusebuf_head fd_fbufs_in; /* [l] */ 54 struct fusebuf_head fd_fbufs_wait; 55 56 /* kq fields */ 57 struct klist fd_rklist; /* [l] */ 58 LIST_ENTRY(fuse_d) fd_list; 59 }; 60 61 int stat_fbufs_in = 0; 62 int stat_fbufs_wait = 0; 63 int stat_opened_fusedev = 0; 64 65 LIST_HEAD(, fuse_d) fuse_d_list; 66 struct fuse_d *fuse_lookup(int); 67 68 void fuseattach(int); 69 int fuseopen(dev_t, int, int, struct proc *); 70 int fuseclose(dev_t, int, int, struct proc *); 71 int fuseioctl(dev_t, u_long, caddr_t, int, struct proc *); 72 int fuseread(dev_t, struct uio *, int); 73 int fusewrite(dev_t, struct uio *, int); 74 int fusekqfilter(dev_t dev, struct knote *kn); 75 int filt_fuse_read(struct knote *, long); 76 void filt_fuse_rdetach(struct knote *); 77 int filt_fuse_modify(struct kevent *, struct knote *); 78 int filt_fuse_process(struct knote *, struct kevent *); 79 80 static const struct filterops fuse_rd_filtops = { 81 .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE, 82 .f_attach = NULL, 83 .f_detach = filt_fuse_rdetach, 84 .f_event = filt_fuse_read, 85 .f_modify = filt_fuse_modify, 86 .f_process = filt_fuse_process, 87 }; 88 89 #ifdef FUSE_DEBUG 90 static void 91 fuse_dump_buff(char *buff, int len) 92 { 93 char text[17]; 94 int i; 95 96 if (len < 0) { 97 printf("invalid len: %d", len); 98 return; 99 } 100 if (buff == NULL) { 101 printf("invalid buff"); 102 return; 103 } 104 105 memset(text, 0, 17); 106 for (i = 0; i < len; i++) { 107 if (i != 0 && (i % 16) == 0) { 108 printf(": %s\n", text); 109 memset(text, 0, 17); 110 } 111 112 printf("%.2x ", buff[i] & 0xff); 113 114 if (buff[i] > ' ' && buff[i] < '~') 115 text[i%16] = buff[i] & 0xff; 116 else 117 text[i%16] = '.'; 118 } 119 120 if ((i % 16) != 0) 121 while ((i % 16) != 0) { 122 printf(" "); 123 i++; 124 } 125 126 printf(": %s\n", text); 127 } 128 #endif 129 130 struct fuse_d * 131 fuse_lookup(int unit) 132 { 133 struct fuse_d *fd; 134 135 LIST_FOREACH(fd, &fuse_d_list, fd_list) 136 if (fd->fd_unit == unit) 137 return (fd); 138 return (NULL); 139 } 140 141 /* 142 * Cleanup all msgs from sc_fbufs_in and sc_fbufs_wait. 143 */ 144 void 145 fuse_device_cleanup(dev_t dev) 146 { 147 struct fuse_d *fd; 148 struct fusebuf *f, *ftmp, *lprev; 149 150 fd = fuse_lookup(minor(dev)); 151 if (fd == NULL) 152 return; 153 154 /* clear FIFO IN */ 155 lprev = NULL; 156 rw_enter_write(&fd->fd_lock); 157 SIMPLEQ_FOREACH_SAFE(f, &fd->fd_fbufs_in, fb_next, ftmp) { 158 DPRINTF("cleanup unprocessed msg in sc_fbufs_in\n"); 159 if (lprev == NULL) 160 SIMPLEQ_REMOVE_HEAD(&fd->fd_fbufs_in, fb_next); 161 else 162 SIMPLEQ_REMOVE_AFTER(&fd->fd_fbufs_in, lprev, 163 fb_next); 164 165 stat_fbufs_in--; 166 f->fb_err = ENXIO; 167 wakeup(f); 168 lprev = f; 169 } 170 rw_exit_write(&fd->fd_lock); 171 172 /* clear FIFO WAIT*/ 173 lprev = NULL; 174 SIMPLEQ_FOREACH_SAFE(f, &fd->fd_fbufs_wait, fb_next, ftmp) { 175 DPRINTF("umount unprocessed msg in sc_fbufs_wait\n"); 176 if (lprev == NULL) 177 SIMPLEQ_REMOVE_HEAD(&fd->fd_fbufs_wait, fb_next); 178 else 179 SIMPLEQ_REMOVE_AFTER(&fd->fd_fbufs_wait, lprev, 180 fb_next); 181 182 stat_fbufs_wait--; 183 f->fb_err = ENXIO; 184 wakeup(f); 185 lprev = f; 186 } 187 } 188 189 void 190 fuse_device_queue_fbuf(dev_t dev, struct fusebuf *fbuf) 191 { 192 struct fuse_d *fd; 193 194 fd = fuse_lookup(minor(dev)); 195 if (fd == NULL) 196 return; 197 198 rw_enter_write(&fd->fd_lock); 199 SIMPLEQ_INSERT_TAIL(&fd->fd_fbufs_in, fbuf, fb_next); 200 knote_locked(&fd->fd_rklist, 0); 201 rw_exit_write(&fd->fd_lock); 202 stat_fbufs_in++; 203 } 204 205 void 206 fuse_device_set_fmp(struct fusefs_mnt *fmp, int set) 207 { 208 struct fuse_d *fd; 209 210 fd = fuse_lookup(minor(fmp->dev)); 211 if (fd == NULL) 212 return; 213 214 fd->fd_fmp = set ? fmp : NULL; 215 } 216 217 void 218 fuseattach(int num) 219 { 220 LIST_INIT(&fuse_d_list); 221 } 222 223 int 224 fuseopen(dev_t dev, int flags, int fmt, struct proc * p) 225 { 226 struct fuse_d *fd; 227 int unit = minor(dev); 228 229 if (flags & O_EXCL) 230 return (EBUSY); /* No exclusive opens */ 231 232 if ((fd = fuse_lookup(unit)) != NULL) 233 return (EBUSY); 234 235 fd = malloc(sizeof(*fd), M_DEVBUF, M_WAITOK | M_ZERO); 236 fd->fd_unit = unit; 237 SIMPLEQ_INIT(&fd->fd_fbufs_in); 238 SIMPLEQ_INIT(&fd->fd_fbufs_wait); 239 rw_init(&fd->fd_lock, "fusedlk"); 240 klist_init_rwlock(&fd->fd_rklist, &fd->fd_lock); 241 242 LIST_INSERT_HEAD(&fuse_d_list, fd, fd_list); 243 244 stat_opened_fusedev++; 245 return (0); 246 } 247 248 int 249 fuseclose(dev_t dev, int flags, int fmt, struct proc *p) 250 { 251 struct fuse_d *fd; 252 int error; 253 254 fd = fuse_lookup(minor(dev)); 255 if (fd == NULL) 256 return (EINVAL); 257 258 if (fd->fd_fmp) { 259 printf("fuse: device close without umount\n"); 260 fd->fd_fmp->sess_init = 0; 261 fuse_device_cleanup(dev); 262 if ((vfs_busy(fd->fd_fmp->mp, VB_WRITE | VB_NOWAIT)) != 0) 263 goto end; 264 error = dounmount(fd->fd_fmp->mp, MNT_FORCE, p); 265 if (error) 266 printf("fuse: unmount failed with error %d\n", error); 267 fd->fd_fmp = NULL; 268 } 269 270 end: 271 LIST_REMOVE(fd, fd_list); 272 free(fd, M_DEVBUF, sizeof(*fd)); 273 stat_opened_fusedev--; 274 return (0); 275 } 276 277 /* 278 * FIOCGETFBDAT Get fusebuf data from kernel to user 279 * FIOCSETFBDAT Set fusebuf data from user to kernel 280 */ 281 int 282 fuseioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) 283 { 284 struct fb_ioctl_xch *ioexch; 285 struct fusebuf *lastfbuf; 286 struct fusebuf *fbuf; 287 struct fuse_d *fd; 288 int error = 0; 289 290 fd = fuse_lookup(minor(dev)); 291 if (fd == NULL) 292 return (ENXIO); 293 294 switch (cmd) { 295 case FIOCGETFBDAT: 296 ioexch = (struct fb_ioctl_xch *)addr; 297 298 /* Looking for uuid in fd_fbufs_in */ 299 rw_enter_write(&fd->fd_lock); 300 SIMPLEQ_FOREACH(fbuf, &fd->fd_fbufs_in, fb_next) { 301 if (fbuf->fb_uuid == ioexch->fbxch_uuid) 302 break; 303 304 lastfbuf = fbuf; 305 } 306 if (fbuf == NULL) { 307 rw_exit_write(&fd->fd_lock); 308 printf("fuse: Cannot find fusebuf\n"); 309 return (EINVAL); 310 } 311 312 /* Remove the fbuf from fd_fbufs_in */ 313 if (fbuf == SIMPLEQ_FIRST(&fd->fd_fbufs_in)) 314 SIMPLEQ_REMOVE_HEAD(&fd->fd_fbufs_in, fb_next); 315 else 316 SIMPLEQ_REMOVE_AFTER(&fd->fd_fbufs_in, lastfbuf, 317 fb_next); 318 rw_exit_write(&fd->fd_lock); 319 320 stat_fbufs_in--; 321 322 /* Do not handle fbufs with bad len */ 323 if (fbuf->fb_len != ioexch->fbxch_len) { 324 printf("fuse: Bad fusebuf len\n"); 325 return (EINVAL); 326 } 327 328 /* Update the userland fbuf */ 329 error = copyout(fbuf->fb_dat, ioexch->fbxch_data, 330 ioexch->fbxch_len); 331 if (error) { 332 printf("fuse: cannot copyout\n"); 333 return (error); 334 } 335 336 #ifdef FUSE_DEBUG 337 fuse_dump_buff(fbuf->fb_dat, fbuf->fb_len); 338 #endif 339 340 /* Adding fbuf in fd_fbufs_wait */ 341 free(fbuf->fb_dat, M_FUSEFS, fbuf->fb_len); 342 fbuf->fb_dat = NULL; 343 SIMPLEQ_INSERT_TAIL(&fd->fd_fbufs_wait, fbuf, fb_next); 344 stat_fbufs_wait++; 345 break; 346 347 case FIOCSETFBDAT: 348 DPRINTF("SET BUFFER\n"); 349 ioexch = (struct fb_ioctl_xch *)addr; 350 351 /* looking for uuid in fd_fbufs_wait */ 352 SIMPLEQ_FOREACH(fbuf, &fd->fd_fbufs_wait, fb_next) { 353 if (fbuf->fb_uuid == ioexch->fbxch_uuid) 354 break; 355 356 lastfbuf = fbuf; 357 } 358 if (fbuf == NULL) { 359 printf("fuse: Cannot find fusebuf\n"); 360 return (EINVAL); 361 } 362 363 /* Do not handle fbufs with bad len */ 364 if (fbuf->fb_len != ioexch->fbxch_len) { 365 printf("fuse: Bad fusebuf size\n"); 366 return (EINVAL); 367 } 368 369 /* fetching data from userland */ 370 fbuf->fb_dat = malloc(ioexch->fbxch_len, M_FUSEFS, 371 M_WAITOK | M_ZERO); 372 error = copyin(ioexch->fbxch_data, fbuf->fb_dat, 373 ioexch->fbxch_len); 374 if (error) { 375 printf("fuse: Cannot copyin\n"); 376 free(fbuf->fb_dat, M_FUSEFS, fbuf->fb_len); 377 fbuf->fb_dat = NULL; 378 return (error); 379 } 380 381 #ifdef FUSE_DEBUG 382 fuse_dump_buff(fbuf->fb_dat, fbuf->fb_len); 383 #endif 384 385 /* Remove fbuf from fd_fbufs_wait */ 386 if (fbuf == SIMPLEQ_FIRST(&fd->fd_fbufs_wait)) 387 SIMPLEQ_REMOVE_HEAD(&fd->fd_fbufs_wait, fb_next); 388 else 389 SIMPLEQ_REMOVE_AFTER(&fd->fd_fbufs_wait, lastfbuf, 390 fb_next); 391 stat_fbufs_wait--; 392 wakeup(fbuf); 393 break; 394 default: 395 error = EINVAL; 396 } 397 398 return (error); 399 } 400 401 int 402 fuseread(dev_t dev, struct uio *uio, int ioflag) 403 { 404 struct fuse_d *fd; 405 struct fusebuf *fbuf; 406 struct fb_hdr hdr; 407 void *tmpaddr; 408 int error = 0; 409 410 /* We get the whole fusebuf or nothing */ 411 if (uio->uio_resid != FUSEBUFSIZE) 412 return (EINVAL); 413 414 fd = fuse_lookup(minor(dev)); 415 if (fd == NULL) 416 return (ENXIO); 417 418 rw_enter_write(&fd->fd_lock); 419 420 if (SIMPLEQ_EMPTY(&fd->fd_fbufs_in)) { 421 if (ioflag & O_NONBLOCK) 422 error = EAGAIN; 423 goto end; 424 } 425 fbuf = SIMPLEQ_FIRST(&fd->fd_fbufs_in); 426 427 /* Do not send kernel pointers */ 428 memcpy(&hdr.fh_next, &fbuf->fb_next, sizeof(fbuf->fb_next)); 429 memset(&fbuf->fb_next, 0, 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 rw_exit_write(&fd->fd_lock); 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 data 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 fusekqfilter(dev_t dev, struct knote *kn) 536 { 537 struct fuse_d *fd; 538 struct klist *klist; 539 540 fd = fuse_lookup(minor(dev)); 541 if (fd == NULL) 542 return (EINVAL); 543 544 switch (kn->kn_filter) { 545 case EVFILT_READ: 546 klist = &fd->fd_rklist; 547 kn->kn_fop = &fuse_rd_filtops; 548 break; 549 case EVFILT_WRITE: 550 return (seltrue_kqfilter(dev, kn)); 551 default: 552 return (EINVAL); 553 } 554 555 kn->kn_hook = fd; 556 557 klist_insert(klist, kn); 558 559 return (0); 560 } 561 562 void 563 filt_fuse_rdetach(struct knote *kn) 564 { 565 struct fuse_d *fd = kn->kn_hook; 566 struct klist *klist = &fd->fd_rklist; 567 568 klist_remove(klist, kn); 569 } 570 571 int 572 filt_fuse_read(struct knote *kn, long hint) 573 { 574 struct fuse_d *fd = kn->kn_hook; 575 int event = 0; 576 577 rw_assert_wrlock(&fd->fd_lock); 578 579 if (!SIMPLEQ_EMPTY(&fd->fd_fbufs_in)) 580 event = 1; 581 582 return (event); 583 } 584 585 int 586 filt_fuse_modify(struct kevent *kev, struct knote *kn) 587 { 588 struct fuse_d *fd = kn->kn_hook; 589 int active; 590 591 rw_enter_write(&fd->fd_lock); 592 active = knote_modify(kev, kn); 593 rw_exit_write(&fd->fd_lock); 594 595 return (active); 596 } 597 598 int 599 filt_fuse_process(struct knote *kn, struct kevent *kev) 600 { 601 struct fuse_d *fd = kn->kn_hook; 602 int active; 603 604 rw_enter_write(&fd->fd_lock); 605 active = knote_process(kn, kev); 606 rw_exit_write(&fd->fd_lock); 607 608 return (active); 609 } 610