1 /* $OpenBSD: fuse_vnops.c,v 1.72 2024/10/31 13:55:21 claudio 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/dirent.h> 21 #include <sys/fcntl.h> 22 #include <sys/file.h> 23 #include <sys/lockf.h> 24 #include <sys/malloc.h> 25 #include <sys/mount.h> 26 #include <sys/namei.h> 27 #include <sys/pool.h> 28 #include <sys/proc.h> 29 #include <sys/specdev.h> 30 #include <sys/stat.h> 31 #include <sys/statvfs.h> 32 #include <sys/vnode.h> 33 #include <sys/lock.h> 34 #include <sys/fusebuf.h> 35 36 #include "fusefs_node.h" 37 #include "fusefs.h" 38 39 /* Prototypes for fusefs vnode ops */ 40 int fusefs_kqfilter(void *); 41 int fusefs_lookup(void *); 42 int fusefs_open(void *); 43 int fusefs_close(void *); 44 int fusefs_access(void *); 45 int fusefs_getattr(void *); 46 int fusefs_setattr(void *); 47 int fusefs_ioctl(void *); 48 int fusefs_link(void *); 49 int fusefs_symlink(void *); 50 int fusefs_readdir(void *); 51 int fusefs_readlink(void *); 52 int fusefs_inactive(void *); 53 int fusefs_reclaim(void *); 54 int fusefs_print(void *); 55 int fusefs_create(void *); 56 int fusefs_mknod(void *); 57 int fusefs_read(void *); 58 int fusefs_write(void *); 59 int fusefs_remove(void *); 60 int fusefs_rename(void *); 61 int fusefs_mkdir(void *); 62 int fusefs_rmdir(void *); 63 int fusefs_strategy(void *); 64 int fusefs_lock(void *); 65 int fusefs_unlock(void *); 66 int fusefs_islocked(void *); 67 int fusefs_advlock(void *); 68 int fusefs_fsync(void *); 69 70 /* Prototypes for fusefs kqfilter */ 71 int filt_fusefsread(struct knote *, long); 72 int filt_fusefswrite(struct knote *, long); 73 int filt_fusefsvnode(struct knote *, long); 74 void filt_fusefsdetach(struct knote *); 75 76 const struct vops fusefs_vops = { 77 .vop_lookup = fusefs_lookup, 78 .vop_create = fusefs_create, 79 .vop_mknod = fusefs_mknod, 80 .vop_open = fusefs_open, 81 .vop_close = fusefs_close, 82 .vop_access = fusefs_access, 83 .vop_getattr = fusefs_getattr, 84 .vop_setattr = fusefs_setattr, 85 .vop_read = fusefs_read, 86 .vop_write = fusefs_write, 87 .vop_ioctl = fusefs_ioctl, 88 .vop_kqfilter = fusefs_kqfilter, 89 .vop_revoke = NULL, 90 .vop_fsync = fusefs_fsync, 91 .vop_remove = fusefs_remove, 92 .vop_link = fusefs_link, 93 .vop_rename = fusefs_rename, 94 .vop_mkdir = fusefs_mkdir, 95 .vop_rmdir = fusefs_rmdir, 96 .vop_symlink = fusefs_symlink, 97 .vop_readdir = fusefs_readdir, 98 .vop_readlink = fusefs_readlink, 99 .vop_abortop = vop_generic_abortop, 100 .vop_inactive = fusefs_inactive, 101 .vop_reclaim = fusefs_reclaim, 102 .vop_lock = fusefs_lock, 103 .vop_unlock = fusefs_unlock, 104 .vop_bmap = vop_generic_bmap, 105 .vop_strategy = fusefs_strategy, 106 .vop_print = fusefs_print, 107 .vop_islocked = fusefs_islocked, 108 .vop_pathconf = spec_pathconf, 109 .vop_advlock = fusefs_advlock, 110 .vop_bwrite = NULL, 111 }; 112 113 const struct filterops fusefsread_filtops = { 114 .f_flags = FILTEROP_ISFD, 115 .f_attach = NULL, 116 .f_detach = filt_fusefsdetach, 117 .f_event = filt_fusefsread, 118 }; 119 120 const struct filterops fusefswrite_filtops = { 121 .f_flags = FILTEROP_ISFD, 122 .f_attach = NULL, 123 .f_detach = filt_fusefsdetach, 124 .f_event = filt_fusefswrite, 125 }; 126 127 const struct filterops fusefsvnode_filtops = { 128 .f_flags = FILTEROP_ISFD, 129 .f_attach = NULL, 130 .f_detach = filt_fusefsdetach, 131 .f_event = filt_fusefsvnode, 132 }; 133 134 int 135 fusefs_kqfilter(void *v) 136 { 137 struct vop_kqfilter_args *ap = v; 138 struct vnode *vp = ap->a_vp; 139 struct knote *kn = ap->a_kn; 140 141 switch (kn->kn_filter) { 142 case EVFILT_READ: 143 kn->kn_fop = &fusefsread_filtops; 144 break; 145 case EVFILT_WRITE: 146 kn->kn_fop = &fusefswrite_filtops; 147 break; 148 case EVFILT_VNODE: 149 kn->kn_fop = &fusefsvnode_filtops; 150 break; 151 default: 152 return (EINVAL); 153 } 154 155 kn->kn_hook = (caddr_t)vp; 156 157 klist_insert_locked(&vp->v_klist, kn); 158 159 return (0); 160 } 161 162 void 163 filt_fusefsdetach(struct knote *kn) 164 { 165 struct vnode *vp = (struct vnode *)kn->kn_hook; 166 167 klist_remove_locked(&vp->v_klist, kn); 168 } 169 170 int 171 filt_fusefsread(struct knote *kn, long hint) 172 { 173 struct vnode *vp = (struct vnode *)kn->kn_hook; 174 struct fusefs_node *ip = VTOI(vp); 175 176 /* 177 * filesystem is gone, so set the EOF flag and schedule 178 * the knote for deletion 179 */ 180 if (hint == NOTE_REVOKE) { 181 kn->kn_flags |= (EV_EOF | EV_ONESHOT); 182 return (1); 183 } 184 185 kn->kn_data = ip->filesize - foffset(kn->kn_fp); 186 if (kn->kn_data == 0 && kn->kn_sfflags & NOTE_EOF) { 187 kn->kn_fflags |= NOTE_EOF; 188 return (1); 189 } 190 191 if (kn->kn_flags & (__EV_POLL | __EV_SELECT)) 192 return (1); 193 194 return (kn->kn_data != 0); 195 } 196 197 int 198 filt_fusefswrite(struct knote *kn, long hint) 199 { 200 /* 201 * filesystem is gone, so set the EOF flag and schedule 202 * the knote for deletion 203 */ 204 if (hint == NOTE_REVOKE) { 205 kn->kn_flags |= (EV_EOF | EV_ONESHOT); 206 return (1); 207 } 208 209 kn->kn_data = 0; 210 return (1); 211 } 212 213 int 214 filt_fusefsvnode(struct knote *kn, long int hint) 215 { 216 if (kn->kn_sfflags & hint) 217 kn->kn_fflags |= hint; 218 if (hint == NOTE_REVOKE) { 219 kn->kn_flags |= EV_EOF; 220 return (1); 221 } 222 return (kn->kn_fflags != 0); 223 } 224 225 /* 226 * FUSE file systems can maintain a file handle for each VFS file descriptor 227 * that is opened. The OpenBSD VFS does not make file descriptors visible to 228 * us so we fake it by mapping open flags to file handles. 229 * There is no way for FUSE to know which file descriptor is being used 230 * by an application for a file operation. We only maintain 3 descriptors, 231 * one each for O_RDONLY, O_WRONLY and O_RDWR. When reading and writing, the 232 * first open descriptor is used and this may well not be the one that was set 233 * by FUSE open and may have even been opened by another application. 234 */ 235 int 236 fusefs_open(void *v) 237 { 238 struct vop_open_args *ap; 239 struct fusefs_node *ip; 240 struct fusefs_mnt *fmp; 241 struct vnode *vp; 242 enum fufh_type fufh_type = FUFH_RDONLY; 243 int flags; 244 int error; 245 int isdir; 246 247 ap = v; 248 vp = ap->a_vp; 249 ip = VTOI(vp); 250 fmp = (struct fusefs_mnt *)ip->i_ump; 251 252 if (!fmp->sess_init) 253 return (ENXIO); 254 255 isdir = 0; 256 if (vp->v_type == VDIR) 257 isdir = 1; 258 else { 259 if ((ap->a_mode & FREAD) && (ap->a_mode & FWRITE)) 260 fufh_type = FUFH_RDWR; 261 else if (ap->a_mode & (FWRITE)) 262 fufh_type = FUFH_WRONLY; 263 264 /* 265 * Due to possible attribute caching, there is no 266 * reliable way to determine if the file was modified 267 * externally (e.g. network file system) so clear the 268 * UVM cache to ensure that it is not stale. The file 269 * can still become stale later on read but this will 270 * satisfy most situations. 271 */ 272 uvm_vnp_uncache(vp); 273 } 274 275 /* already open i think all is ok */ 276 if (ip->fufh[fufh_type].fh_type != FUFH_INVALID) 277 return (0); 278 279 /* 280 * The file has already been created and/or truncated so FUSE dictates 281 * that no creation and truncation flags are passed to open. 282 */ 283 flags = OFLAGS(ap->a_mode) & ~(O_CREAT|O_EXCL|O_TRUNC); 284 error = fusefs_file_open(fmp, ip, fufh_type, flags, isdir, ap->a_p); 285 286 return (error); 287 } 288 289 int 290 fusefs_close(void *v) 291 { 292 struct vop_close_args *ap; 293 struct fusefs_node *ip; 294 struct fusefs_mnt *fmp; 295 struct fusebuf *fbuf; 296 enum fufh_type fufh_type = FUFH_RDONLY; 297 int error = 0; 298 299 ap = v; 300 ip = VTOI(ap->a_vp); 301 fmp = (struct fusefs_mnt *)ip->i_ump; 302 303 if (!fmp->sess_init) 304 return (0); 305 306 /* 307 * The file or directory may have been opened more than once so there 308 * is no reliable way to determine when to ask the FUSE daemon to 309 * release its file descriptor. For files, ask the daemon to flush any 310 * buffers to disk now. All open file descriptors will be released on 311 * VOP_INACTIVE(9). 312 */ 313 314 if (ap->a_vp->v_type == VDIR) 315 return (0); 316 317 /* Implementing flush is optional so don't error. */ 318 if (fmp->undef_op & UNDEF_FLUSH) 319 return (0); 320 321 /* Only flush writeable file descriptors. */ 322 if ((ap->a_fflag & FREAD) && (ap->a_fflag & FWRITE)) 323 fufh_type = FUFH_RDWR; 324 else if (ap->a_fflag & (FWRITE)) 325 fufh_type = FUFH_WRONLY; 326 else 327 return (0); 328 329 if (ip->fufh[fufh_type].fh_type == FUFH_INVALID) 330 return (EBADF); 331 332 fbuf = fb_setup(0, ip->i_number, FBT_FLUSH, ap->a_p); 333 fbuf->fb_io_fd = ip->fufh[fufh_type].fh_id; 334 error = fb_queue(fmp->dev, fbuf); 335 fb_delete(fbuf); 336 if (error == ENOSYS) { 337 fmp->undef_op |= UNDEF_FLUSH; 338 339 /* Implementing flush is optional so don't error. */ 340 return (0); 341 } 342 343 return (error); 344 } 345 346 int 347 fusefs_access(void *v) 348 { 349 struct vop_access_args *ap; 350 struct fusefs_node *ip; 351 struct fusefs_mnt *fmp; 352 struct ucred *cred; 353 struct vattr vattr; 354 struct proc *p; 355 int error = 0; 356 357 ap = v; 358 p = ap->a_p; 359 cred = p->p_ucred; 360 ip = VTOI(ap->a_vp); 361 fmp = (struct fusefs_mnt *)ip->i_ump; 362 363 /* 364 * Only user that mounted the file system can access it unless 365 * allow_other mount option was specified. 366 */ 367 if (!fmp->allow_other && cred->cr_uid != fmp->mp->mnt_stat.f_owner) 368 return (EACCES); 369 370 if (!fmp->sess_init) 371 return (ENXIO); 372 373 /* 374 * Disallow write attempts on filesystems mounted read-only; 375 * unless the file is a socket, fifo, or a block or character 376 * device resident on the filesystem. 377 */ 378 if ((ap->a_mode & VWRITE) && (fmp->mp->mnt_flag & MNT_RDONLY)) { 379 switch (ap->a_vp->v_type) { 380 case VREG: 381 case VDIR: 382 case VLNK: 383 return (EROFS); 384 default: 385 break; 386 } 387 } 388 389 if ((error = VOP_GETATTR(ap->a_vp, &vattr, cred, p)) != 0) 390 return (error); 391 392 return (vaccess(ap->a_vp->v_type, vattr.va_mode & ALLPERMS, 393 vattr.va_uid, vattr.va_gid, ap->a_mode, 394 ap->a_cred)); 395 } 396 397 int 398 fusefs_getattr(void *v) 399 { 400 struct vop_getattr_args *ap = v; 401 struct vnode *vp = ap->a_vp; 402 struct fusefs_mnt *fmp; 403 struct vattr *vap = ap->a_vap; 404 struct proc *p = ap->a_p; 405 struct ucred *cred = p->p_ucred; 406 struct fusefs_node *ip; 407 struct fusebuf *fbuf; 408 struct stat *st; 409 int error = 0; 410 411 ip = VTOI(vp); 412 fmp = (struct fusefs_mnt *)ip->i_ump; 413 414 /* 415 * Only user that mounted the file system can access it unless 416 * allow_other mount option was specified. Return dummy values 417 * for the root inode in this situation. 418 */ 419 if (!fmp->allow_other && cred->cr_uid != fmp->mp->mnt_stat.f_owner) { 420 memset(vap, 0, sizeof(*vap)); 421 vap->va_type = VNON; 422 if (vp->v_mount->mnt_flag & MNT_RDONLY) 423 vap->va_mode = S_IRUSR | S_IXUSR; 424 else 425 vap->va_mode = S_IRWXU; 426 vap->va_nlink = 1; 427 vap->va_uid = fmp->mp->mnt_stat.f_owner; 428 vap->va_gid = fmp->mp->mnt_stat.f_owner; 429 vap->va_fsid = fmp->mp->mnt_stat.f_fsid.val[0]; 430 vap->va_fileid = ip->i_number; 431 vap->va_size = S_BLKSIZE; 432 vap->va_blocksize = S_BLKSIZE; 433 vap->va_atime.tv_sec = fmp->mp->mnt_stat.f_ctime; 434 vap->va_mtime.tv_sec = fmp->mp->mnt_stat.f_ctime; 435 vap->va_ctime.tv_sec = fmp->mp->mnt_stat.f_ctime; 436 vap->va_rdev = fmp->dev; 437 vap->va_bytes = S_BLKSIZE; 438 return (0); 439 } 440 441 if (!fmp->sess_init) 442 return (ENXIO); 443 444 fbuf = fb_setup(0, ip->i_number, FBT_GETATTR, p); 445 446 error = fb_queue(fmp->dev, fbuf); 447 if (error) { 448 fb_delete(fbuf); 449 return (error); 450 } 451 452 st = &fbuf->fb_attr; 453 454 memset(vap, 0, sizeof(*vap)); 455 vap->va_type = IFTOVT(st->st_mode); 456 vap->va_mode = st->st_mode & ~S_IFMT; 457 vap->va_nlink = st->st_nlink; 458 vap->va_uid = st->st_uid; 459 vap->va_gid = st->st_gid; 460 vap->va_fsid = fmp->mp->mnt_stat.f_fsid.val[0]; 461 vap->va_fileid = st->st_ino; 462 vap->va_size = st->st_size; 463 vap->va_blocksize = st->st_blksize; 464 vap->va_atime = st->st_atim; 465 vap->va_mtime = st->st_mtim; 466 vap->va_ctime = st->st_ctim; 467 vap->va_rdev = st->st_rdev; 468 vap->va_bytes = st->st_blocks * S_BLKSIZE; 469 470 fb_delete(fbuf); 471 return (error); 472 } 473 474 int 475 fusefs_setattr(void *v) 476 { 477 struct vop_setattr_args *ap = v; 478 struct vattr *vap = ap->a_vap; 479 struct vnode *vp = ap->a_vp; 480 struct fusefs_node *ip = VTOI(vp); 481 struct ucred *cred = ap->a_cred; 482 struct proc *p = ap->a_p; 483 struct fusefs_mnt *fmp; 484 struct fusebuf *fbuf; 485 struct fb_io *io; 486 int error = 0; 487 488 fmp = (struct fusefs_mnt *)ip->i_ump; 489 /* 490 * Check for unsettable attributes. 491 */ 492 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 493 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 494 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 495 ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) 496 return (EINVAL); 497 498 if (!fmp->sess_init) 499 return (ENXIO); 500 501 if (fmp->undef_op & UNDEF_SETATTR) 502 return (ENOSYS); 503 504 fbuf = fb_setup(sizeof(*io), ip->i_number, FBT_SETATTR, p); 505 io = fbtod(fbuf, struct fb_io *); 506 io->fi_flags = 0; 507 508 if (vap->va_uid != (uid_t)VNOVAL) { 509 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 510 error = EROFS; 511 goto out; 512 } 513 fbuf->fb_attr.st_uid = vap->va_uid; 514 io->fi_flags |= FUSE_FATTR_UID; 515 } 516 517 if (vap->va_gid != (gid_t)VNOVAL) { 518 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 519 error = EROFS; 520 goto out; 521 } 522 fbuf->fb_attr.st_gid = vap->va_gid; 523 io->fi_flags |= FUSE_FATTR_GID; 524 } 525 526 if (vap->va_size != VNOVAL) { 527 /* 528 * Disallow write attempts on read-only file systems; 529 * unless the file is a socket, fifo, or a block or 530 * character device resident on the file system. 531 */ 532 switch (vp->v_type) { 533 case VDIR: 534 error = EISDIR; 535 goto out; 536 case VLNK: 537 case VREG: 538 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 539 error = EROFS; 540 goto out; 541 } 542 break; 543 default: 544 break; 545 } 546 547 fbuf->fb_attr.st_size = vap->va_size; 548 io->fi_flags |= FUSE_FATTR_SIZE; 549 } 550 551 if (vap->va_atime.tv_nsec != VNOVAL) { 552 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 553 error = EROFS; 554 goto out; 555 } 556 fbuf->fb_attr.st_atim = vap->va_atime; 557 io->fi_flags |= FUSE_FATTR_ATIME; 558 } 559 560 if (vap->va_mtime.tv_nsec != VNOVAL) { 561 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 562 error = EROFS; 563 goto out; 564 } 565 fbuf->fb_attr.st_mtim = vap->va_mtime; 566 io->fi_flags |= FUSE_FATTR_MTIME; 567 } 568 /* XXX should set a flag if (vap->va_vaflags & VA_UTIMES_CHANGE) */ 569 570 if (vap->va_mode != (mode_t)VNOVAL) { 571 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 572 error = EROFS; 573 goto out; 574 } 575 576 /* 577 * chmod returns EFTYPE if the effective user ID is not the 578 * super-user, the mode includes the sticky bit (S_ISVTX), and 579 * path does not refer to a directory 580 */ 581 if (cred->cr_uid != 0 && vp->v_type != VDIR && 582 (vap->va_mode & S_ISTXT)) { 583 error = EFTYPE; 584 goto out; 585 } 586 587 fbuf->fb_attr.st_mode = vap->va_mode & ALLPERMS; 588 io->fi_flags |= FUSE_FATTR_MODE; 589 } 590 591 if (!io->fi_flags) { 592 goto out; 593 } 594 595 error = fb_queue(fmp->dev, fbuf); 596 if (error) { 597 if (error == ENOSYS) 598 fmp->undef_op |= UNDEF_SETATTR; 599 goto out; 600 } 601 602 /* truncate was successful, let uvm know */ 603 if (vap->va_size != VNOVAL && vap->va_size != ip->filesize) { 604 ip->filesize = vap->va_size; 605 uvm_vnp_setsize(vp, vap->va_size); 606 } 607 608 VN_KNOTE(ap->a_vp, NOTE_ATTRIB); 609 610 out: 611 fb_delete(fbuf); 612 return (error); 613 } 614 615 int 616 fusefs_ioctl(void *v) 617 { 618 return (ENOTTY); 619 } 620 621 int 622 fusefs_link(void *v) 623 { 624 struct vop_link_args *ap = v; 625 struct vnode *dvp = ap->a_dvp; 626 struct vnode *vp = ap->a_vp; 627 struct componentname *cnp = ap->a_cnp; 628 struct proc *p = cnp->cn_proc; 629 struct fusefs_mnt *fmp; 630 struct fusefs_node *ip; 631 struct fusefs_node *dip; 632 struct fusebuf *fbuf; 633 int error = 0; 634 635 ip = VTOI(vp); 636 dip = VTOI(dvp); 637 fmp = (struct fusefs_mnt *)ip->i_ump; 638 639 if (!fmp->sess_init) { 640 VOP_ABORTOP(dvp, cnp); 641 error = ENXIO; 642 goto out2; 643 } 644 if (fmp->undef_op & UNDEF_LINK) { 645 VOP_ABORTOP(dvp, cnp); 646 error = ENOSYS; 647 goto out2; 648 } 649 if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE))) { 650 VOP_ABORTOP(dvp, cnp); 651 goto out2; 652 } 653 654 fbuf = fb_setup(cnp->cn_namelen + 1, dip->i_number, 655 FBT_LINK, p); 656 657 fbuf->fb_io_ino = ip->i_number; 658 memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen); 659 fbuf->fb_dat[cnp->cn_namelen] = '\0'; 660 661 error = fb_queue(fmp->dev, fbuf); 662 663 if (error) { 664 if (error == ENOSYS) 665 fmp->undef_op |= UNDEF_LINK; 666 667 fb_delete(fbuf); 668 goto out1; 669 } 670 671 fb_delete(fbuf); 672 VN_KNOTE(vp, NOTE_LINK); 673 VN_KNOTE(dvp, NOTE_WRITE); 674 675 out1: 676 pool_put(&namei_pool, cnp->cn_pnbuf); 677 if (dvp != vp) 678 VOP_UNLOCK(vp); 679 out2: 680 vput(dvp); 681 return (error); 682 } 683 684 int 685 fusefs_symlink(void *v) 686 { 687 struct vop_symlink_args *ap = v; 688 struct vnode **vpp = ap->a_vpp; 689 struct componentname *cnp = ap->a_cnp; 690 struct vnode *dvp = ap->a_dvp; 691 struct proc *p = cnp->cn_proc; 692 char *target = ap->a_target; 693 struct fusefs_node *dp; 694 struct fusefs_mnt *fmp; 695 struct fusebuf *fbuf; 696 struct vnode *tdp; 697 int error = 0; 698 int len; 699 700 dp = VTOI(dvp); 701 fmp = (struct fusefs_mnt *)dp->i_ump; 702 703 if (!fmp->sess_init) { 704 error = ENXIO; 705 goto bad; 706 } 707 708 if (fmp->undef_op & UNDEF_SYMLINK) { 709 error = ENOSYS; 710 goto bad; 711 } 712 713 len = strlen(target) + 1; 714 715 fbuf = fb_setup(len + cnp->cn_namelen + 1, dp->i_number, 716 FBT_SYMLINK, p); 717 718 memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen); 719 fbuf->fb_dat[cnp->cn_namelen] = '\0'; 720 memcpy(&fbuf->fb_dat[cnp->cn_namelen + 1], target, len); 721 722 error = fb_queue(fmp->dev, fbuf); 723 if (error) { 724 if (error == ENOSYS) 725 fmp->undef_op |= UNDEF_SYMLINK; 726 727 fb_delete(fbuf); 728 goto bad; 729 } 730 731 if ((error = VFS_VGET(fmp->mp, fbuf->fb_ino, &tdp))) { 732 fb_delete(fbuf); 733 goto bad; 734 } 735 736 tdp->v_type = VLNK; 737 VN_KNOTE(ap->a_dvp, NOTE_WRITE); 738 739 *vpp = tdp; 740 fb_delete(fbuf); 741 vput(tdp); 742 bad: 743 pool_put(&namei_pool, cnp->cn_pnbuf); 744 vput(dvp); 745 return (error); 746 } 747 748 int 749 fusefs_readdir(void *v) 750 { 751 struct vop_readdir_args *ap = v; 752 struct fusefs_node *ip; 753 struct fusefs_mnt *fmp; 754 struct fusebuf *fbuf; 755 struct dirent *dp; 756 char *edp; 757 struct vnode *vp; 758 struct proc *p; 759 struct uio *uio; 760 int error = 0, eofflag = 0, diropen = 0; 761 762 vp = ap->a_vp; 763 uio = ap->a_uio; 764 p = uio->uio_procp; 765 766 ip = VTOI(vp); 767 fmp = (struct fusefs_mnt *)ip->i_ump; 768 769 if (!fmp->sess_init) 770 return (ENXIO); 771 772 if (uio->uio_resid < sizeof(struct dirent)) 773 return (EINVAL); 774 775 if (ip->fufh[FUFH_RDONLY].fh_type == FUFH_INVALID) { 776 error = fusefs_file_open(fmp, ip, FUFH_RDONLY, O_RDONLY, 1, p); 777 if (error) 778 return (error); 779 780 diropen = 1; 781 } 782 783 while (uio->uio_resid > 0) { 784 fbuf = fb_setup(0, ip->i_number, FBT_READDIR, p); 785 786 fbuf->fb_io_fd = ip->fufh[FUFH_RDONLY].fh_id; 787 fbuf->fb_io_off = uio->uio_offset; 788 fbuf->fb_io_len = MIN(uio->uio_resid, fmp->max_read); 789 790 error = fb_queue(fmp->dev, fbuf); 791 792 if (error) { 793 /* 794 * dirent was larger than residual space left in 795 * buffer. 796 */ 797 if (error == ENOBUFS) 798 error = 0; 799 800 fb_delete(fbuf); 801 break; 802 } 803 804 /* ack end of readdir */ 805 if (fbuf->fb_len == 0) { 806 eofflag = 1; 807 fb_delete(fbuf); 808 break; 809 } 810 811 /* validate the returned dirents */ 812 dp = (struct dirent *)fbuf->fb_dat; 813 edp = fbuf->fb_dat + fbuf->fb_len; 814 while ((char *)dp < edp) { 815 if ((char *)dp + offsetof(struct dirent, d_name) >= edp 816 || dp->d_reclen <= offsetof(struct dirent, d_name) 817 || (char *)dp + dp->d_reclen > edp) { 818 error = EINVAL; 819 break; 820 } 821 if (dp->d_namlen + offsetof(struct dirent, d_name) >= 822 dp->d_reclen) { 823 error = EINVAL; 824 break; 825 } 826 memset(dp->d_name + dp->d_namlen, 0, dp->d_reclen - 827 dp->d_namlen - offsetof(struct dirent, d_name)); 828 829 if (memchr(dp->d_name, '/', dp->d_namlen) != NULL) { 830 error = EINVAL; 831 break; 832 } 833 dp = (struct dirent *)((char *)dp + dp->d_reclen); 834 } 835 if (error) { 836 fb_delete(fbuf); 837 break; 838 } 839 840 if ((error = uiomove(fbuf->fb_dat, fbuf->fb_len, uio))) { 841 fb_delete(fbuf); 842 break; 843 } 844 845 fb_delete(fbuf); 846 } 847 848 if (!error && ap->a_eofflag != NULL) 849 *ap->a_eofflag = eofflag; 850 851 if (diropen) 852 fusefs_file_close(fmp, ip, FUFH_RDONLY, O_RDONLY, 1, p); 853 854 return (error); 855 } 856 857 int 858 fusefs_inactive(void *v) 859 { 860 struct vop_inactive_args *ap = v; 861 struct vnode *vp = ap->a_vp; 862 struct proc *p = ap->a_p; 863 struct fusefs_node *ip = VTOI(vp); 864 struct fusefs_filehandle *fufh = NULL; 865 struct fusefs_mnt *fmp; 866 int type, flags; 867 868 fmp = (struct fusefs_mnt *)ip->i_ump; 869 870 /* Close all open file handles. */ 871 for (type = 0; type < FUFH_MAXTYPE; type++) { 872 fufh = &(ip->fufh[type]); 873 if (fufh->fh_type != FUFH_INVALID) { 874 875 /* 876 * FUSE file systems expect the same flags to be sent 877 * on release that were sent on open. We don't have a 878 * record of them so make a best guess. 879 */ 880 switch (type) { 881 case FUFH_RDONLY: 882 flags = O_RDONLY; 883 break; 884 case FUFH_WRONLY: 885 flags = O_WRONLY; 886 break; 887 default: 888 flags = O_RDWR; 889 } 890 891 fusefs_file_close(fmp, ip, fufh->fh_type, flags, 892 (vp->v_type == VDIR), p); 893 } 894 } 895 896 VOP_UNLOCK(vp); 897 898 /* Don't return error to prevent kernel panic in vclean(9). */ 899 return (0); 900 } 901 902 int 903 fusefs_readlink(void *v) 904 { 905 struct vop_readlink_args *ap = v; 906 struct vnode *vp = ap->a_vp; 907 struct fusefs_node *ip; 908 struct fusefs_mnt *fmp; 909 struct fusebuf *fbuf; 910 struct uio *uio; 911 struct proc *p; 912 int error = 0; 913 914 ip = VTOI(vp); 915 fmp = (struct fusefs_mnt *)ip->i_ump; 916 uio = ap->a_uio; 917 p = uio->uio_procp; 918 919 if (!fmp->sess_init) 920 return (ENXIO); 921 922 if (fmp->undef_op & UNDEF_READLINK) 923 return (ENOSYS); 924 925 fbuf = fb_setup(0, ip->i_number, FBT_READLINK, p); 926 927 error = fb_queue(fmp->dev, fbuf); 928 929 if (error) { 930 if (error == ENOSYS) 931 fmp->undef_op |= UNDEF_READLINK; 932 933 fb_delete(fbuf); 934 return (error); 935 } 936 937 error = uiomove(fbuf->fb_dat, fbuf->fb_len, uio); 938 fb_delete(fbuf); 939 940 return (error); 941 } 942 943 int 944 fusefs_reclaim(void *v) 945 { 946 struct vop_reclaim_args *ap = v; 947 struct vnode *vp = ap->a_vp; 948 struct proc *p = ap->a_p; 949 struct fusefs_node *ip = VTOI(vp); 950 struct fusefs_filehandle *fufh = NULL; 951 struct fusefs_mnt *fmp; 952 struct fusebuf *fbuf; 953 int type, error = 0; 954 955 fmp = (struct fusefs_mnt *)ip->i_ump; 956 957 /* Close opened files. */ 958 for (type = 0; type < FUFH_MAXTYPE; type++) { 959 fufh = &(ip->fufh[type]); 960 if (fufh->fh_type != FUFH_INVALID) { 961 printf("fusefs: vnode being reclaimed is valid\n"); 962 fusefs_file_close(fmp, ip, fufh->fh_type, type, 963 (vp->v_type == VDIR), ap->a_p); 964 } 965 } 966 967 /* 968 * If the fuse connection is opened ask libfuse to free the vnodes. 969 */ 970 if (fmp->sess_init && ip->i_number != FUSE_ROOTINO) { 971 fbuf = fb_setup(0, ip->i_number, FBT_RECLAIM, p); 972 error = fb_queue(fmp->dev, fbuf); 973 if (error) 974 printf("fusefs: vnode reclaim failed: %d\n", error); 975 fb_delete(fbuf); 976 } 977 978 /* 979 * Remove the inode from its hash chain. 980 */ 981 fuse_ihashrem(ip); 982 983 free(ip, M_FUSEFS, sizeof(*ip)); 984 vp->v_data = NULL; 985 986 /* Must return success otherwise kernel panic in vclean(9). */ 987 return (0); 988 } 989 990 int 991 fusefs_print(void *v) 992 { 993 #if defined(DEBUG) || defined(DIAGNOSTIC) || defined(VFSLCKDEBUG) 994 struct vop_print_args *ap = v; 995 struct vnode *vp = ap->a_vp; 996 struct fusefs_node *ip = VTOI(vp); 997 998 /* Complete the information given by vprint(). */ 999 printf("tag VT_FUSE, hash id %llu ", ip->i_number); 1000 printf("\n"); 1001 #endif 1002 return (0); 1003 } 1004 1005 int 1006 fusefs_create(void *v) 1007 { 1008 struct vop_create_args *ap = v; 1009 struct componentname *cnp = ap->a_cnp; 1010 struct vnode **vpp = ap->a_vpp; 1011 struct vnode *dvp = ap->a_dvp; 1012 struct vattr *vap = ap->a_vap; 1013 struct proc *p = cnp->cn_proc; 1014 struct vnode *tdp = NULL; 1015 struct fusefs_mnt *fmp; 1016 struct fusefs_node *ip; 1017 struct fusebuf *fbuf; 1018 int error = 0; 1019 mode_t mode; 1020 1021 ip = VTOI(dvp); 1022 fmp = (struct fusefs_mnt *)ip->i_ump; 1023 mode = MAKEIMODE(vap->va_type, vap->va_mode); 1024 1025 if (!fmp->sess_init) { 1026 VOP_ABORTOP(dvp, cnp); 1027 return (ENXIO); 1028 } 1029 1030 if (fmp->undef_op & UNDEF_MKNOD) { 1031 VOP_ABORTOP(dvp, cnp); 1032 return (ENOSYS); 1033 } 1034 1035 fbuf = fb_setup(cnp->cn_namelen + 1, ip->i_number, 1036 FBT_MKNOD, p); 1037 1038 fbuf->fb_io_mode = mode; 1039 1040 memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen); 1041 fbuf->fb_dat[cnp->cn_namelen] = '\0'; 1042 1043 error = fb_queue(fmp->dev, fbuf); 1044 if (error) { 1045 if (error == ENOSYS) 1046 fmp->undef_op |= UNDEF_MKNOD; 1047 1048 goto out; 1049 } 1050 1051 if ((error = VFS_VGET(fmp->mp, fbuf->fb_ino, &tdp))) 1052 goto out; 1053 1054 tdp->v_type = IFTOVT(fbuf->fb_io_mode); 1055 1056 *vpp = tdp; 1057 VN_KNOTE(ap->a_dvp, NOTE_WRITE); 1058 out: 1059 fb_delete(fbuf); 1060 pool_put(&namei_pool, cnp->cn_pnbuf); 1061 return (error); 1062 } 1063 1064 int 1065 fusefs_mknod(void *v) 1066 { 1067 struct vop_mknod_args *ap = v; 1068 struct componentname *cnp = ap->a_cnp; 1069 struct vnode **vpp = ap->a_vpp; 1070 struct vnode *dvp = ap->a_dvp; 1071 struct vattr *vap = ap->a_vap; 1072 struct proc *p = cnp->cn_proc; 1073 struct vnode *tdp = NULL; 1074 struct fusefs_mnt *fmp; 1075 struct fusefs_node *ip; 1076 struct fusebuf *fbuf; 1077 int error = 0; 1078 1079 ip = VTOI(dvp); 1080 fmp = (struct fusefs_mnt *)ip->i_ump; 1081 1082 if (!fmp->sess_init) { 1083 VOP_ABORTOP(dvp, cnp); 1084 return (ENXIO); 1085 } 1086 1087 if (fmp->undef_op & UNDEF_MKNOD) { 1088 VOP_ABORTOP(dvp, cnp); 1089 return (ENOSYS); 1090 } 1091 1092 fbuf = fb_setup(cnp->cn_namelen + 1, ip->i_number, 1093 FBT_MKNOD, p); 1094 1095 fbuf->fb_io_mode = MAKEIMODE(vap->va_type, vap->va_mode); 1096 if (vap->va_rdev != VNOVAL) 1097 fbuf->fb_io_rdev = vap->va_rdev; 1098 1099 memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen); 1100 fbuf->fb_dat[cnp->cn_namelen] = '\0'; 1101 1102 error = fb_queue(fmp->dev, fbuf); 1103 if (error) { 1104 if (error == ENOSYS) 1105 fmp->undef_op |= UNDEF_MKNOD; 1106 1107 goto out; 1108 } 1109 1110 if ((error = VFS_VGET(fmp->mp, fbuf->fb_ino, &tdp))) 1111 goto out; 1112 1113 tdp->v_type = IFTOVT(fbuf->fb_io_mode); 1114 1115 *vpp = tdp; 1116 VN_KNOTE(ap->a_dvp, NOTE_WRITE); 1117 1118 /* Remove inode so that it will be reloaded by VFS_VGET and 1119 * checked to see if it is an alias of an existing entry in 1120 * the inode cache. 1121 */ 1122 vput(*vpp); 1123 (*vpp)->v_type = VNON; 1124 vgone(*vpp); 1125 *vpp = NULL; 1126 out: 1127 fb_delete(fbuf); 1128 pool_put(&namei_pool, cnp->cn_pnbuf); 1129 return (error); 1130 } 1131 1132 int 1133 fusefs_read(void *v) 1134 { 1135 struct vop_read_args *ap = v; 1136 struct vnode *vp = ap->a_vp; 1137 struct uio *uio = ap->a_uio; 1138 struct proc *p = uio->uio_procp; 1139 struct fusefs_node *ip; 1140 struct fusefs_mnt *fmp; 1141 struct fusebuf *fbuf = NULL; 1142 size_t size; 1143 int error=0; 1144 1145 ip = VTOI(vp); 1146 fmp = (struct fusefs_mnt *)ip->i_ump; 1147 1148 if (!fmp->sess_init) 1149 return (ENXIO); 1150 if (uio->uio_resid == 0) 1151 return (error); 1152 if (uio->uio_offset < 0) 1153 return (EINVAL); 1154 1155 while (uio->uio_resid > 0) { 1156 fbuf = fb_setup(0, ip->i_number, FBT_READ, p); 1157 1158 size = MIN(uio->uio_resid, fmp->max_read); 1159 fbuf->fb_io_fd = fusefs_fd_get(ip, FUFH_RDONLY); 1160 fbuf->fb_io_off = uio->uio_offset; 1161 fbuf->fb_io_len = size; 1162 1163 error = fb_queue(fmp->dev, fbuf); 1164 1165 if (error) 1166 break; 1167 1168 error = uiomove(fbuf->fb_dat, ulmin(size, fbuf->fb_len), uio); 1169 if (error) 1170 break; 1171 1172 if (fbuf->fb_len < size) 1173 break; 1174 1175 fb_delete(fbuf); 1176 fbuf = NULL; 1177 } 1178 1179 fb_delete(fbuf); 1180 return (error); 1181 } 1182 1183 int 1184 fusefs_write(void *v) 1185 { 1186 struct vop_write_args *ap = v; 1187 struct vnode *vp = ap->a_vp; 1188 struct uio *uio = ap->a_uio; 1189 struct proc *p = uio->uio_procp; 1190 struct ucred *cred = p->p_ucred; 1191 struct vattr vattr; 1192 int ioflag = ap->a_ioflag; 1193 struct fusefs_node *ip; 1194 struct fusefs_mnt *fmp; 1195 struct fusebuf *fbuf = NULL; 1196 size_t len, diff; 1197 int error=0; 1198 1199 ip = VTOI(vp); 1200 fmp = (struct fusefs_mnt *)ip->i_ump; 1201 1202 if (!fmp->sess_init) 1203 return (ENXIO); 1204 if (uio->uio_resid == 0) 1205 return (error); 1206 1207 if (ioflag & IO_APPEND) { 1208 if ((error = VOP_GETATTR(vp, &vattr, cred, p)) != 0) 1209 return (error); 1210 1211 uio->uio_offset = vattr.va_size; 1212 } 1213 1214 while (uio->uio_resid > 0) { 1215 len = MIN(uio->uio_resid, fmp->max_read); 1216 fbuf = fb_setup(len, ip->i_number, FBT_WRITE, p); 1217 1218 fbuf->fb_io_fd = fusefs_fd_get(ip, FUFH_WRONLY); 1219 fbuf->fb_io_off = uio->uio_offset; 1220 fbuf->fb_io_len = len; 1221 1222 if ((error = uiomove(fbuf->fb_dat, len, uio))) { 1223 printf("fusefs: uio error %i\n", error); 1224 break; 1225 } 1226 1227 error = fb_queue(fmp->dev, fbuf); 1228 1229 if (error) 1230 break; 1231 1232 diff = len - fbuf->fb_io_len; 1233 if (fbuf->fb_io_len > len) { 1234 error = EINVAL; 1235 break; 1236 } 1237 1238 uio->uio_resid += diff; 1239 uio->uio_offset -= diff; 1240 1241 if (uio->uio_offset > ip->filesize) { 1242 ip->filesize = uio->uio_offset; 1243 uvm_vnp_setsize(vp, uio->uio_offset); 1244 } 1245 uvm_vnp_uncache(vp); 1246 1247 fb_delete(fbuf); 1248 fbuf = NULL; 1249 } 1250 1251 fb_delete(fbuf); 1252 return (error); 1253 } 1254 1255 int 1256 fusefs_rename(void *v) 1257 { 1258 struct vop_rename_args *ap = v; 1259 struct vnode *tvp = ap->a_tvp; 1260 struct vnode *tdvp = ap->a_tdvp; 1261 struct vnode *fvp = ap->a_fvp; 1262 struct vnode *fdvp = ap->a_fdvp; 1263 struct componentname *tcnp = ap->a_tcnp; 1264 struct componentname *fcnp = ap->a_fcnp; 1265 struct proc *p = fcnp->cn_proc; 1266 struct fusefs_node *ip, *dp; 1267 struct fusefs_mnt *fmp; 1268 struct fusebuf *fbuf; 1269 int error = 0; 1270 1271 #ifdef DIAGNOSTIC 1272 if ((tcnp->cn_flags & HASBUF) == 0 || 1273 (fcnp->cn_flags & HASBUF) == 0) 1274 panic("fusefs_rename: no name"); 1275 #endif 1276 /* 1277 * Check for cross-device rename. 1278 */ 1279 if ((fvp->v_mount != tdvp->v_mount) || 1280 (tvp && (fvp->v_mount != tvp->v_mount))) { 1281 error = EXDEV; 1282 abortit: 1283 VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */ 1284 if (tdvp == tvp) 1285 vrele(tdvp); 1286 else 1287 vput(tdvp); 1288 if (tvp) 1289 vput(tvp); 1290 VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */ 1291 vrele(fdvp); 1292 vrele(fvp); 1293 return (error); 1294 } 1295 1296 /* 1297 * If source and dest are the same, do nothing. 1298 */ 1299 if (tvp == fvp) { 1300 error = 0; 1301 goto abortit; 1302 } 1303 1304 if ((error = vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY)) != 0) 1305 goto abortit; 1306 dp = VTOI(fdvp); 1307 ip = VTOI(fvp); 1308 fmp = (struct fusefs_mnt *)ip->i_ump; 1309 1310 /* 1311 * Be sure we are not renaming ".", "..", or an alias of ".". This 1312 * leads to a crippled directory tree. It's pretty tough to do a 1313 * "ls" or "pwd" with the "." directory entry missing, and "cd .." 1314 * doesn't work if the ".." entry is missing. 1315 */ 1316 if (fvp->v_type == VDIR) { 1317 /* 1318 * Avoid ".", "..", and aliases of "." for obvious reasons. 1319 */ 1320 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') || 1321 dp == ip || 1322 (fcnp->cn_flags & ISDOTDOT) || 1323 (tcnp->cn_flags & ISDOTDOT)) { 1324 VOP_UNLOCK(fvp); 1325 error = EINVAL; 1326 goto abortit; 1327 } 1328 } 1329 VN_KNOTE(fdvp, NOTE_WRITE); /* XXX right place? */ 1330 1331 if (!fmp->sess_init) { 1332 error = ENXIO; 1333 VOP_UNLOCK(fvp); 1334 goto abortit; 1335 } 1336 1337 if (fmp->undef_op & UNDEF_RENAME) { 1338 error = ENOSYS; 1339 VOP_UNLOCK(fvp); 1340 goto abortit; 1341 } 1342 1343 fbuf = fb_setup(fcnp->cn_namelen + tcnp->cn_namelen + 2, 1344 dp->i_number, FBT_RENAME, p); 1345 1346 memcpy(fbuf->fb_dat, fcnp->cn_nameptr, fcnp->cn_namelen); 1347 fbuf->fb_dat[fcnp->cn_namelen] = '\0'; 1348 memcpy(fbuf->fb_dat + fcnp->cn_namelen + 1, tcnp->cn_nameptr, 1349 tcnp->cn_namelen); 1350 fbuf->fb_dat[fcnp->cn_namelen + tcnp->cn_namelen + 1] = '\0'; 1351 fbuf->fb_io_ino = VTOI(tdvp)->i_number; 1352 1353 error = fb_queue(fmp->dev, fbuf); 1354 1355 if (error) { 1356 if (error == ENOSYS) { 1357 fmp->undef_op |= UNDEF_RENAME; 1358 } 1359 1360 fb_delete(fbuf); 1361 VOP_UNLOCK(fvp); 1362 goto abortit; 1363 } 1364 1365 fb_delete(fbuf); 1366 VN_KNOTE(fvp, NOTE_RENAME); 1367 1368 VOP_UNLOCK(fvp); 1369 if (tdvp == tvp) 1370 vrele(tdvp); 1371 else 1372 vput(tdvp); 1373 if (tvp) 1374 vput(tvp); 1375 vrele(fdvp); 1376 vrele(fvp); 1377 1378 return (error); 1379 } 1380 1381 int 1382 fusefs_mkdir(void *v) 1383 { 1384 struct vop_mkdir_args *ap = v; 1385 struct vnode *dvp = ap->a_dvp; 1386 struct vnode **vpp = ap->a_vpp; 1387 struct componentname *cnp = ap->a_cnp; 1388 struct vattr *vap = ap->a_vap; 1389 struct proc *p = cnp->cn_proc; 1390 struct vnode *tdp = NULL; 1391 struct fusefs_node *ip; 1392 struct fusefs_mnt *fmp; 1393 struct fusebuf *fbuf; 1394 int error = 0; 1395 1396 ip = VTOI(dvp); 1397 fmp = (struct fusefs_mnt *)ip->i_ump; 1398 1399 1400 if (!fmp->sess_init) { 1401 error = ENXIO; 1402 goto out; 1403 } 1404 1405 if (fmp->undef_op & UNDEF_MKDIR) { 1406 error = ENOSYS; 1407 goto out; 1408 } 1409 1410 fbuf = fb_setup(cnp->cn_namelen + 1, ip->i_number, 1411 FBT_MKDIR, p); 1412 1413 fbuf->fb_io_mode = MAKEIMODE(vap->va_type, vap->va_mode); 1414 memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen); 1415 fbuf->fb_dat[cnp->cn_namelen] = '\0'; 1416 1417 error = fb_queue(fmp->dev, fbuf); 1418 if (error) { 1419 if (error == ENOSYS) 1420 fmp->undef_op |= UNDEF_MKDIR; 1421 1422 fb_delete(fbuf); 1423 goto out; 1424 } 1425 1426 if ((error = VFS_VGET(fmp->mp, fbuf->fb_ino, &tdp))) { 1427 fb_delete(fbuf); 1428 goto out; 1429 } 1430 1431 tdp->v_type = IFTOVT(fbuf->fb_io_mode); 1432 1433 *vpp = tdp; 1434 VN_KNOTE(ap->a_dvp, NOTE_WRITE | NOTE_LINK); 1435 fb_delete(fbuf); 1436 out: 1437 pool_put(&namei_pool, cnp->cn_pnbuf); 1438 vput(dvp); 1439 return (error); 1440 } 1441 1442 int 1443 fusefs_rmdir(void *v) 1444 { 1445 struct vop_rmdir_args *ap = v; 1446 struct vnode *vp = ap->a_vp; 1447 struct vnode *dvp = ap->a_dvp; 1448 struct componentname *cnp = ap->a_cnp; 1449 struct proc *p = cnp->cn_proc; 1450 struct fusefs_node *ip, *dp; 1451 struct fusefs_mnt *fmp; 1452 struct fusebuf *fbuf; 1453 int error; 1454 1455 ip = VTOI(vp); 1456 dp = VTOI(dvp); 1457 fmp = (struct fusefs_mnt *)ip->i_ump; 1458 1459 if (!fmp->sess_init) { 1460 error = ENXIO; 1461 goto out; 1462 } 1463 1464 if (fmp->undef_op & UNDEF_RMDIR) { 1465 error = ENOSYS; 1466 goto out; 1467 } 1468 1469 VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK); 1470 1471 fbuf = fb_setup(cnp->cn_namelen + 1, dp->i_number, 1472 FBT_RMDIR, p); 1473 memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen); 1474 fbuf->fb_dat[cnp->cn_namelen] = '\0'; 1475 1476 error = fb_queue(fmp->dev, fbuf); 1477 1478 if (error) { 1479 if (error == ENOSYS) 1480 fmp->undef_op |= UNDEF_RMDIR; 1481 if (error != ENOTEMPTY) 1482 VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK); 1483 1484 fb_delete(fbuf); 1485 goto out; 1486 } 1487 1488 vput(dvp); 1489 dvp = NULL; 1490 1491 fb_delete(fbuf); 1492 out: 1493 if (dvp) 1494 vput(dvp); 1495 VN_KNOTE(vp, NOTE_DELETE); 1496 pool_put(&namei_pool, cnp->cn_pnbuf); 1497 vput(vp); 1498 return (error); 1499 } 1500 1501 int 1502 fusefs_remove(void *v) 1503 { 1504 struct vop_remove_args *ap = v; 1505 struct vnode *vp = ap->a_vp; 1506 struct vnode *dvp = ap->a_dvp; 1507 struct componentname *cnp = ap->a_cnp; 1508 struct proc *p = cnp->cn_proc; 1509 struct fusefs_node *ip; 1510 struct fusefs_node *dp; 1511 struct fusefs_mnt *fmp; 1512 struct fusebuf *fbuf; 1513 int error = 0; 1514 1515 ip = VTOI(vp); 1516 dp = VTOI(dvp); 1517 fmp = (struct fusefs_mnt *)ip->i_ump; 1518 1519 if (!fmp->sess_init) { 1520 error = ENXIO; 1521 goto out; 1522 } 1523 1524 if (fmp->undef_op & UNDEF_REMOVE) { 1525 error = ENOSYS; 1526 goto out; 1527 } 1528 1529 fbuf = fb_setup(cnp->cn_namelen + 1, dp->i_number, 1530 FBT_UNLINK, p); 1531 memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen); 1532 fbuf->fb_dat[cnp->cn_namelen] = '\0'; 1533 1534 error = fb_queue(fmp->dev, fbuf); 1535 if (error) { 1536 if (error == ENOSYS) 1537 fmp->undef_op |= UNDEF_REMOVE; 1538 1539 fb_delete(fbuf); 1540 goto out; 1541 } 1542 1543 VN_KNOTE(vp, NOTE_DELETE); 1544 VN_KNOTE(dvp, NOTE_WRITE); 1545 fb_delete(fbuf); 1546 out: 1547 pool_put(&namei_pool, cnp->cn_pnbuf); 1548 return (error); 1549 } 1550 1551 int 1552 fusefs_strategy(void *v) 1553 { 1554 return (0); 1555 } 1556 1557 int 1558 fusefs_lock(void *v) 1559 { 1560 struct vop_lock_args *ap = v; 1561 struct vnode *vp = ap->a_vp; 1562 1563 return rrw_enter(&VTOI(vp)->i_lock, ap->a_flags & LK_RWFLAGS); 1564 } 1565 1566 int 1567 fusefs_unlock(void *v) 1568 { 1569 struct vop_unlock_args *ap = v; 1570 struct vnode *vp = ap->a_vp; 1571 1572 rrw_exit(&VTOI(vp)->i_lock); 1573 return 0; 1574 } 1575 1576 int 1577 fusefs_islocked(void *v) 1578 { 1579 struct vop_islocked_args *ap = v; 1580 1581 return rrw_status(&VTOI(ap->a_vp)->i_lock); 1582 } 1583 1584 int 1585 fusefs_advlock(void *v) 1586 { 1587 struct vop_advlock_args *ap = v; 1588 struct fusefs_node *ip = VTOI(ap->a_vp); 1589 1590 return (lf_advlock(&ip->i_lockf, ip->filesize, ap->a_id, 1591 ap->a_op, ap->a_fl, ap->a_flags)); 1592 } 1593 1594 int 1595 fusefs_fsync(void *v) 1596 { 1597 struct vop_fsync_args *ap = v; 1598 struct vnode *vp = ap->a_vp; 1599 struct proc *p = ap->a_p; 1600 struct fusefs_node *ip; 1601 struct fusefs_mnt *fmp; 1602 struct fusefs_filehandle *fufh; 1603 struct fusebuf *fbuf; 1604 int type, error = 0; 1605 1606 /* 1607 * Can't write to directory file handles so no need to fsync. 1608 * FUSE has fsyncdir but it doesn't make sense on OpenBSD. 1609 */ 1610 if (vp->v_type == VDIR) 1611 return (0); 1612 1613 ip = VTOI(vp); 1614 fmp = (struct fusefs_mnt *)ip->i_ump; 1615 1616 if (!fmp->sess_init) 1617 return (ENXIO); 1618 1619 /* Implementing fsync is optional so don't error. */ 1620 if (fmp->undef_op & UNDEF_FSYNC) 1621 return (0); 1622 1623 /* Sync all writeable file descriptors. */ 1624 for (type = 0; type < FUFH_MAXTYPE; type++) { 1625 fufh = &(ip->fufh[type]); 1626 if (fufh->fh_type == FUFH_WRONLY || 1627 fufh->fh_type == FUFH_RDWR) { 1628 1629 fbuf = fb_setup(0, ip->i_number, FBT_FSYNC, p); 1630 fbuf->fb_io_fd = fufh->fh_id; 1631 1632 /* Always behave as if ap->a_waitfor = MNT_WAIT. */ 1633 error = fb_queue(fmp->dev, fbuf); 1634 fb_delete(fbuf); 1635 if (error) 1636 break; 1637 } 1638 } 1639 1640 if (error == ENOSYS) { 1641 fmp->undef_op |= UNDEF_FSYNC; 1642 1643 /* Implementing fsync is optional so don't error. */ 1644 return (0); 1645 } 1646 1647 return (error); 1648 } 1649