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