__private_extern__ void fuse_internal_vnode_disappear(vnode_t vp, vfs_context_t context, int how) { int err = 0; fuse_vncache_purge(vp); if (how != REVOKE_NONE) { err = fuse_internal_revoke(vp, REVOKEALL, context, how); if (err) { IOLog("MacFUSE: disappearing act: revoke failed (%d)\n", err); } err = vnode_recycle(vp); if (err) { IOLog("MacFUSE: disappearing act: recycle failed (%d)\n", err); } } }
__private_extern__ void fuse_internal_vnode_disappear(vnode_t vp, vfs_context_t context, int how) { int err = 0; fuse_vncache_purge(vp); if (how != REVOKE_NONE) { err = fuse_internal_revoke(vp, REVOKEALL, context, how); if (err) { IOLog("MacFUSE: disappearing act: revoke failed (%d)\n", err); } #if __LP64__ /* Checking whether the vnode is in the process of being recycled * to avoid the 'vnode reclaim in progress' kernel panic. * * Obviously this is a quick fix done without much understanding of * the code flow of a recycle operation, but it seems that we * shouldn't call this again if a recycle operation was the reason * that we got here. */ if(!vnode_isrecycled(vp)) { #endif err = vnode_recycle(vp); if (err) { IOLog("MacFUSE: disappearing act: recycle failed (%d)\n", err); } #if __LP64__ } else { IOLog("MacFUSE: Avoided 'vnode reclaim in progress' kernel " "panic. What now?\n"); } #endif } }
int fuse_notify_inval_entry(struct fuse_data *data, struct fuse_iov *iov) { int err = 0; struct fuse_notify_inval_entry_out fnieo; char name[FUSE_MAXNAMLEN + 1]; void *next; HNodeRef dhp; vnode_t dvp; vnode_t vp; struct componentname cn; next = fuse_abi_out(fuse_notify_inval_entry_out, DTOABI(data), iov->base, &fnieo); if (fnieo.namelen > iov->len - ((char *)next - (char *)iov->base)) { return EINVAL; } if (fnieo.namelen > FUSE_MAXNAMLEN) { return ENAMETOOLONG; } memcpy(name, next, fnieo.namelen); name[fnieo.namelen] = '\0'; err = (int)HNodeLookupRealQuickIfExists(data->fdev, (ino_t)fnieo.parent, 0 /* fork index */, &dhp, &dvp); if (err) { return err; } assert(dvp != NULL); /* * We have to look up the vnode for the specified name in the vnode cache, * to purge it from the cache. * * Note: Without flag MAKEENTRY cache_lookup does not return the vnode. */ memset(&cn, 0, sizeof(cn)); cn.cn_nameiop = LOOKUP; cn.cn_flags = MAKEENTRY; cn.cn_namelen = fnieo.namelen; cn.cn_nameptr = name; fuse_nodelock_lock(VTOFUD(dvp), FUSEFS_EXCLUSIVE_LOCK); err = fuse_vncache_lookup(dvp, &vp, &cn); switch (err) { case -1: /* positive match */ err = 0; fuse_vncache_purge(vp); vnode_put(vp); case 0: /* no match in cache */ break; case ENOENT: /* negative match */ default: goto out; } fuse_invalidate_attr(dvp); FUSE_KNOTE(dvp, NOTE_ATTRIB); out: fuse_nodelock_unlock(VTOFUD(dvp)); vnode_put(dvp); return err; }
/* ioctl */ __private_extern__ int fuse_internal_ioctl_avfi(vnode_t vp, __unused vfs_context_t context, struct fuse_avfi_ioctl *avfi) { int ret = 0; uint32_t hint = 0; if (!avfi) { return EINVAL; } if (avfi->cmd & FUSE_AVFI_MARKGONE) { /* * TBD */ return EINVAL; } /* The result of this /does/ alter our return value. */ if (avfi->cmd & FUSE_AVFI_UBC) { int ubc_flags = avfi->ubc_flags & (UBC_PUSHDIRTY | UBC_PUSHALL | UBC_INVALIDATE | UBC_SYNC); if (ubc_msync(vp, (off_t)0, ubc_getsize(vp), (off_t*)0, ubc_flags) == 0) { /* failed */ ret = EINVAL; /* don't really have a good error to return */ } } if (avfi->cmd & FUSE_AVFI_UBC_SETSIZE) { if (VTOFUD(vp)->filesize != avfi->size) { hint |= NOTE_WRITE; if (avfi->size > VTOFUD(vp)->filesize) { hint |= NOTE_EXTEND; } VTOFUD(vp)->filesize = avfi->size; ubc_setsize(vp, avfi->size); } (void)fuse_invalidate_attr(vp); } /* The result of this doesn't alter our return value. */ if (avfi->cmd & FUSE_AVFI_PURGEATTRCACHE) { hint |= NOTE_ATTRIB; (void)fuse_invalidate_attr(vp); } /* The result of this doesn't alter our return value. */ if (avfi->cmd & FUSE_AVFI_PURGEVNCACHE) { (void)fuse_vncache_purge(vp); } if (avfi->cmd & FUSE_AVFI_KNOTE) { hint |= avfi->note; } if (hint) { FUSE_KNOTE(vp, hint); } return ret; }
/* * 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; }