int fuse_filehandle_open(struct vnode *vp, fufh_type_t fufh_type, struct fuse_filehandle **fufhp, struct thread *td, struct ucred *cred) { struct fuse_dispatcher fdi; struct fuse_open_in *foi; struct fuse_open_out *foo; int err = 0; int isdir = 0; int oflags = 0; int op = FUSE_OPEN; fuse_trace_printf("fuse_filehandle_open(vp=%p, fufh_type=%d)\n", vp, fufh_type); if (fuse_filehandle_valid(vp, fufh_type)) { panic("FUSE: filehandle_open called despite valid fufh (type=%d)", fufh_type); /* NOTREACHED */ } /* * Note that this means we are effectively FILTERING OUT open() flags. */ oflags = fuse_filehandle_xlate_to_oflags(fufh_type); if (vnode_isdir(vp)) { isdir = 1; op = FUSE_OPENDIR; if (fufh_type != FUFH_RDONLY) { printf("FUSE:non-rdonly fh requested for a directory?\n"); fufh_type = FUFH_RDONLY; } } fdisp_init(&fdi, sizeof(*foi)); fdisp_make_vp(&fdi, op, vp, td, cred); foi = fdi.indata; foi->flags = oflags; if ((err = fdisp_wait_answ(&fdi))) { debug_printf("OUCH ... daemon didn't give fh (err = %d)\n", err); if (err == ENOENT) { fuse_internal_vnode_disappear(vp); } goto out; } foo = fdi.answ; fuse_filehandle_init(vp, fufh_type, fufhp, foo->fh); fuse_vnode_open(vp, foo->open_flags, td); out: fdisp_destroy(&fdi); return err; }
int fuse_filehandle_put(vnode_t vp, vfs_context_t context, fufh_type_t fufh_type, fuse_op_waitfor_t waitfor) { struct fuse_data *data; struct fuse_dispatcher fdi; struct fuse_abi_data fri; struct fuse_vnode_data *fvdat = VTOFUD(vp); struct fuse_filehandle *fufh = NULL; int err = 0; int op = FUSE_RELEASE; fuse_trace_printf("fuse_filehandle_put(vp=%p, fufh_type=%d)\n", vp, fufh_type); fufh = &(fvdat->fufh[fufh_type]); if (FUFH_IS_VALID(fufh)) { panic("osxfuse: filehandle_put called on a valid fufh (type=%d)", fufh_type); /* NOTREACHED */ } if (fuse_isdeadfs(vp)) { goto out; } data = fuse_get_mpdata(vnode_mount(vp)); if (vnode_isdir(vp)) { op = FUSE_RELEASEDIR; } fdisp_init_abi(&fdi, fuse_release_in, data); fdisp_make_vp(&fdi, op, vp, context); fuse_abi_data_init(&fri, DATOI(data), fdi.indata); fuse_release_in_set_fh(&fri, fufh->fh_id); fuse_release_in_set_flags(&fri, fufh->open_flags); if (waitfor == FUSE_OP_FOREGROUNDED) { err = fdisp_wait_answ(&fdi); if (err) { goto out; } } else { fuse_insert_message(fdi.tick); } fuse_ticket_release(fdi.tick); out: FUSE_OSAddAtomic(-1, (SInt32 *)&fuse_fh_current); fuse_invalidate_attr(vp); return err; }
int fuse_filehandle_put(vnode_t vp, vfs_context_t context, fufh_type_t fufh_type) { struct fuse_dispatcher fdi; struct fuse_release_in *fri; struct fuse_vnode_data *fvdat = VTOFUD(vp); struct fuse_filehandle *fufh = NULL; int err = 0; int isdir = 0; int op = FUSE_RELEASE; const bool wait_for_completion = true; fuse_trace_printf("fuse_filehandle_put(vp=%p, fufh_type=%d)\n", vp, fufh_type); fufh = &(fvdat->fufh[fufh_type]); if (FUFH_IS_VALID(fufh)) { panic("fuse4x: filehandle_put called on a valid fufh (type=%d)", fufh_type); /* NOTREACHED */ } if (fuse_isdeadfs(vp)) { goto out; } if (vnode_isdir(vp)) { op = FUSE_RELEASEDIR; isdir = 1; } fdisp_init(&fdi, sizeof(*fri)); fdisp_make_vp(&fdi, op, vp, context); fri = fdi.indata; fri->fh = fufh->fh_id; fri->flags = fufh->open_flags; if (wait_for_completion) { if ((err = fdisp_wait_answ(&fdi))) { goto out; } else { fuse_ticket_drop(fdi.tick); } } else { fuse_insert_callback(fdi.tick, NULL); fuse_insert_message(fdi.tick); } out: OSAddAtomic(-1, (SInt32 *)&fuse_fh_current); fuse_invalidate_attr(vp); return err; }
int fuse_filehandle_close(struct vnode *vp, fufh_type_t fufh_type, struct thread *td, struct ucred *cred) { struct fuse_dispatcher fdi; struct fuse_release_in *fri; struct fuse_vnode_data *fvdat = VTOFUD(vp); struct fuse_filehandle *fufh = NULL; int err = 0; int isdir = 0; int op = FUSE_RELEASE; fuse_trace_printf("fuse_filehandle_put(vp=%p, fufh_type=%d)\n", vp, fufh_type); fufh = &(fvdat->fufh[fufh_type]); if (!FUFH_IS_VALID(fufh)) { panic("FUSE: filehandle_put called on invalid fufh (type=%d)", fufh_type); /* NOTREACHED */ } if (fuse_isdeadfs(vp)) { goto out; } if (vnode_isdir(vp)) { op = FUSE_RELEASEDIR; isdir = 1; } fdisp_init(&fdi, sizeof(*fri)); fdisp_make_vp(&fdi, op, vp, td, cred); fri = fdi.indata; fri->fh = fufh->fh_id; fri->flags = fuse_filehandle_xlate_to_oflags(fufh_type); err = fdisp_wait_answ(&fdi); fdisp_destroy(&fdi); out: atomic_subtract_acq_int(&fuse_fh_count, 1); fufh->fh_id = (uint64_t)-1; fufh->fh_type = FUFH_INVALID; fuse_invalidate_attr(vp); return err; }
int fuse_filehandle_put(vnode_t vp, vfs_context_t context, fufh_type_t fufh_type) { struct fuse_dispatcher fdi; struct fuse_release_in *fri; struct fuse_vnode_data *fvdat = VTOFUD(vp); struct fuse_filehandle *fufh = NULL; fuse_trace_printf("fuse_filehandle_put(vp=%p, fufh_type=%d)\n", vp, fufh_type); fufh = &(fvdat->fufh[fufh_type]); if (FUFH_IS_VALID(fufh)) { panic("fuse4x: filehandle_put called on a valid fufh (type=%d)", fufh_type); /* NOTREACHED */ } if (fuse_isdeadfs(vp)) { goto out; } int op = vnode_isdir(vp) ? FUSE_RELEASEDIR : FUSE_RELEASE; fuse_dispatcher_init(&fdi, sizeof(*fri)); fuse_dispatcher_make_vp(&fdi, op, vp, context); fri = fdi.indata; fri->fh = fufh->fh_id; fri->flags = fufh->open_flags; int err = fuse_dispatcher_wait_answer(&fdi); if (!err) { fuse_ticket_drop(fdi.ticket); } out: OSDecrementAtomic((SInt32 *)&fuse_fh_current); fuse_invalidate_attr(vp); return err; }
static errno_t fuse_vfsop_unmount(mount_t mp, int mntflags, vfs_context_t context) { int err = 0; int flags = 0; fuse_device_t fdev; struct fuse_data *data; struct fuse_dispatcher fdi; vnode_t fuse_rootvp = NULLVP; fuse_trace_printf_vfsop(); if (mntflags & MNT_FORCE) { flags |= FORCECLOSE; } data = fuse_get_mpdata(mp); if (!data) { panic("fuse4x: no mount private data in vfs_unmount"); } #if M_FUSE4X_ENABLE_BIGLOCK fuse_biglock_lock(data->biglock); #endif fdev = data->fdev; if (fdata_dead_get(data)) { /* * If the file system daemon is dead, it's pointless to try to do * any unmount-time operations that go out to user space. Therefore, * we pretend that this is a force unmount. However, this isn't of much * use. That's because if any non-root vnode is in use, the vflush() * that the kernel does before calling our VFS_UNMOUNT will fail * if the original unmount wasn't forcible already. That earlier * vflush is called with SKIPROOT though, so it wouldn't bail out * on the root vnode being in use. * * If we want, we could set FORCECLOSE here so that a non-forced * unmount will be "upgraded" to a forced unmount if the root vnode * is busy (you are cd'd to the mount point, for example). It's not * quite pure to do that though. * * flags |= FORCECLOSE; * log("fuse4x: forcing unmount on a dead file system\n"); */ } else if (!(data->dataflags & FSESS_INITED)) { flags |= FORCECLOSE; log("fuse4x: forcing unmount on not-yet-alive file system\n"); fdata_set_dead(data); } fuse_rootvp = data->rootvp; fuse_trace_printf("%s: Calling vflush(mp, fuse_rootvp, flags=0x%X);\n", __FUNCTION__, flags); #if M_FUSE4X_ENABLE_BIGLOCK fuse_biglock_unlock(data->biglock); #endif err = vflush(mp, fuse_rootvp, flags); #if M_FUSE4X_ENABLE_BIGLOCK fuse_biglock_lock(data->biglock); #endif fuse_trace_printf("%s: Done.\n", __FUNCTION__); if (err) { #if M_FUSE4X_ENABLE_BIGLOCK fuse_biglock_unlock(data->biglock); #endif return err; } if (vnode_isinuse(fuse_rootvp, 1) && !(flags & FORCECLOSE)) { #if M_FUSE4X_ENABLE_BIGLOCK fuse_biglock_unlock(data->biglock); #endif return EBUSY; } if (fdata_dead_get(data)) { goto alreadydead; } fdisp_init(&fdi, 0 /* no data to send along */); fdisp_make(&fdi, FUSE_DESTROY, mp, FUSE_ROOT_ID, context); fuse_trace_printf("%s: Waiting for reply from FUSE_DESTROY.\n", __FUNCTION__); err = fdisp_wait_answ(&fdi); fuse_trace_printf("%s: Reply received.\n", __FUNCTION__); if (!err) { fuse_ticket_drop(fdi.tick); } /* * Note that dounmount() signals a VQ_UNMOUNT VFS event. */ fdata_set_dead(data); alreadydead: fuse_trace_printf("%s: Calling vnode_rele(fuse_rootp);\n", __FUNCTION__); #if M_FUSE4X_ENABLE_BIGLOCK fuse_biglock_unlock(data->biglock); #endif vnode_rele(fuse_rootvp); /* We got this reference in fuse_vfsop_mount(). */ #if M_FUSE4X_ENABLE_BIGLOCK fuse_biglock_lock(data->biglock); #endif fuse_trace_printf("%s: Done.\n", __FUNCTION__); data->rootvp = NULLVP; fuse_trace_printf("%s: Calling vflush(mp, NULLVP, FORCECLOSE);\n", __FUNCTION__); #if M_FUSE4X_ENABLE_BIGLOCK fuse_biglock_unlock(data->biglock); #endif (void)vflush(mp, NULLVP, FORCECLOSE); #if M_FUSE4X_ENABLE_BIGLOCK fuse_biglock_lock(data->biglock); #endif fuse_trace_printf("%s: Done.\n", __FUNCTION__); fuse_lck_mtx_lock(fdev->mtx); vfs_setfsprivate(mp, NULL); data->dataflags &= ~FSESS_MOUNTED; OSAddAtomic(-1, (SInt32 *)&fuse_mount_count); #if M_FUSE4X_ENABLE_BIGLOCK fuse_biglock_unlock(data->biglock); #endif if (!(data->dataflags & FSESS_OPENED)) { /* fdev->data was left for us to clean up */ fuse_device_close_final(fdev); /* fdev->data is gone now */ } fuse_lck_mtx_unlock(fdev->mtx); return 0; }
/* * Because of the vagaries of how a filehandle can be used, we try not to * be too smart in here (we try to be smart elsewhere). It is required that * you come in here only if you really do not have the said filehandle--else * we panic. */ int fuse_filehandle_get(vnode_t vp, vfs_context_t context, fufh_type_t fufh_type, int mode) { struct fuse_dispatcher fdi; struct fuse_abi_data foi; struct fuse_abi_data foo; struct fuse_filehandle *fufh; struct fuse_vnode_data *fvdat = VTOFUD(vp); struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp)); int err = 0; int oflags = 0; int op = FUSE_OPEN; fuse_trace_printf("fuse_filehandle_get(vp=%p, fufh_type=%d, mode=%x)\n", vp, fufh_type, mode); fufh = &(fvdat->fufh[fufh_type]); if (FUFH_IS_VALID(fufh)) { panic("osxfuse: filehandle_get called despite valid fufh (type=%d)", fufh_type); /* NOTREACHED */ } /* * Note that this means we are effectively FILTERING OUT open() flags. */ (void)mode; oflags = fuse_filehandle_xlate_to_oflags(fufh_type); if (vnode_isdir(vp)) { op = FUSE_OPENDIR; if (fufh_type != FUFH_RDONLY) { IOLog("osxfuse: non-rdonly fufh requested for directory\n"); fufh_type = FUFH_RDONLY; } } if (vnode_islnk(vp) && (mode & O_SYMLINK)) { oflags |= O_SYMLINK; } if ((mode & O_TRUNC) && (data->dataflags & FSESS_ATOMIC_O_TRUNC)) { oflags |= O_TRUNC; } fdisp_init_abi(&fdi, fuse_open_in, data); fdisp_make_vp(&fdi, op, vp, context); fuse_abi_data_init(&foi, DATOI(data), fdi.indata); fuse_open_in_set_flags(&foi, oflags); FUSE_OSAddAtomic(1, (SInt32 *)&fuse_fh_upcall_count); err = fdisp_wait_answ(&fdi); if (err) { #if M_OSXFUSE_ENABLE_UNSUPPORTED const char *vname = vnode_getname(vp); #endif /* M_OSXFUSE_ENABLE_UNSUPPORTED */ if (err == ENOENT) { /* * See comment in fuse_vnop_reclaim(). */ cache_purge(vp); } #if M_OSXFUSE_ENABLE_UNSUPPORTED IOLog("osxfuse: filehandle_get: failed for %s " "(type=%d, err=%d, caller=%p)\n", (vname) ? vname : "?", fufh_type, err, __builtin_return_address(0)); if (vname) { vnode_putname(vname); } #endif /* M_OSXFUSE_ENABLE_UNSUPPORTED */ if (err == ENOENT) { #if M_OSXFUSE_ENABLE_BIG_LOCK fuse_biglock_unlock(data->biglock); #endif fuse_internal_vnode_disappear(vp, context, REVOKE_SOFT); #if M_OSXFUSE_ENABLE_BIG_LOCK fuse_biglock_lock(data->biglock); #endif } return err; } FUSE_OSAddAtomic(1, (SInt32 *)&fuse_fh_current); fuse_abi_data_init(&foo, DATOI(data), fdi.answ); fufh->fh_id = fuse_open_out_get_fh(&foo); fufh->open_count = 1; fufh->open_flags = oflags; fufh->fuse_open_flags = fuse_open_out_get_open_flags(&foo); fufh->aux_count = 0; fuse_ticket_release(fdi.tick); return 0; }
/* * Because of the vagaries of how a filehandle can be used, we try not to * be too smart in here (we try to be smart elsewhere). It is required that * you come in here only if you really do not have the said filehandle--else * we panic. * * This function should be called with fufh_mtx mutex locked. */ int fuse_filehandle_get(vnode_t vp, vfs_context_t context, fufh_type_t fufh_type, int mode) { struct fuse_dispatcher fdi; struct fuse_open_in *foi; struct fuse_open_out *foo; struct fuse_filehandle *fufh; struct fuse_vnode_data *fvdat = VTOFUD(vp); int err = 0; int oflags = 0; int op = FUSE_OPEN; fuse_trace_printf("fuse_filehandle_get(vp=%p, fufh_type=%d, mode=%x)\n", vp, fufh_type, mode); fufh = &(fvdat->fufh[fufh_type]); if (FUFH_IS_VALID(fufh)) { panic("fuse4x: filehandle_get called despite valid fufh (type=%d)", fufh_type); /* NOTREACHED */ } /* * Note that this means we are effectively FILTERING OUT open() flags. */ oflags = fuse_filehandle_xlate_to_oflags(fufh_type); if (vnode_isdir(vp)) { op = FUSE_OPENDIR; if (fufh_type != FUFH_RDONLY) { log("fuse4x: non-rdonly fufh requested for directory\n"); fufh_type = FUFH_RDONLY; } } fuse_dispatcher_init(&fdi, sizeof(*foi)); fuse_dispatcher_make_vp(&fdi, op, vp, context); if (vnode_islnk(vp) && (mode & O_SYMLINK)) { oflags |= O_SYMLINK; } foi = fdi.indata; foi->flags = oflags; OSIncrementAtomic((SInt32 *)&fuse_fh_upcall_count); if ((err = fuse_dispatcher_wait_answer(&fdi))) { const char *vname = vnode_getname(vp); if (err == ENOENT) { /* * See comment in fuse_vnop_reclaim(). */ cache_purge(vp); } log("fuse4x: filehandle_get: failed for %s " "(type=%d, err=%d, caller=%p)\n", (vname) ? vname : "?", fufh_type, err, __builtin_return_address(0)); if (vname) { vnode_putname(vname); } if (err == ENOENT) { fuse_vncache_purge(vp); } return err; } OSIncrementAtomic((SInt32 *)&fuse_fh_current); foo = fdi.answer; fufh->fh_id = foo->fh; fufh->open_count = 1; fufh->open_flags = oflags; fufh->fuse_open_flags = foo->open_flags; fuse_ticket_drop(fdi.ticket); return 0; }