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