int fuse_notify_inval_inode(struct fuse_data *data, struct fuse_iov *iov) { int err = 0; struct fuse_notify_inval_inode_out fniio; HNodeRef hp; vnode_t vp; fuse_abi_out(fuse_notify_inval_inode_out, DTOABI(data), iov->base, &fniio); err = (int)HNodeLookupRealQuickIfExists(data->fdev, (ino_t)fniio.ino, 0 /* fork index */, &hp, &vp); if (err) { return err; } assert(vp != NULL); fuse_nodelock_lock(VTOFUD(vp), FUSEFS_EXCLUSIVE_LOCK); fuse_invalidate_attr(vp); if (fniio.off >= 0) { off_t end_off; if (fniio.len > 0) { end_off = (off_t) min(fniio.off + fniio.len, ubc_getsize(vp)); } else { end_off = ubc_getsize(vp); } ubc_msync(vp, (off_t)fniio.off, end_off, NULL, UBC_PUSHDIRTY | UBC_PUSHALL | UBC_INVALIDATE | UBC_SYNC); } FUSE_KNOTE(vp, NOTE_ATTRIB); fuse_nodelock_unlock(VTOFUD(vp)); vnode_put(vp); return err; }
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; }
static errno_t fuse_vfsop_getattr(mount_t mp, struct vfs_attr *attr, vfs_context_t context) { int err = 0; bool deading = false, faking = false; struct fuse_dispatcher fdi; struct fuse_statfs_out fsfo; struct fuse_data *data; fuse_trace_printf_vfsop(); data = fuse_get_mpdata(mp); if (!data) { panic("OSXFUSE: no private data for mount point?"); } if (!(data->dataflags & FSESS_INITED)) { /* * coreservices process requests ATTR_VOL_CAPABILITIES on the mount * point right before returning from syscall mount. We need to fake * the output because the FUSE server might not be ready to respond yet. */ faking = true; goto dostatfs; } fdisp_init(&fdi, 0); fdisp_make(&fdi, FUSE_STATFS, mp, FUSE_ROOT_ID, context); err = fdisp_wait_answ(&fdi); if (err) { /* * If we cannot communicate with the daemon (most likely because * it's dead), we still want to portray that we are a bonafide * file system so that we can be gracefully unmounted. */ if (err == ENOTCONN) { deading = faking = true; goto dostatfs; } return err; } dostatfs: if (faking) { bzero(&fsfo, sizeof(fsfo)); } else { fuse_abi_out(fuse_statfs_out, DTOABI(data), fdi.answ, &fsfo); } if (fsfo.st.bsize == 0) { fsfo.st.bsize = FUSE_DEFAULT_IOSIZE; } if (fsfo.st.frsize == 0) { fsfo.st.frsize = FUSE_DEFAULT_BLOCKSIZE; } /* optimal transfer block size; will go into f_iosize in the kernel */ fsfo.st.bsize = fuse_round_size(fsfo.st.bsize, FUSE_MIN_IOSIZE, FUSE_MAX_IOSIZE); /* file system fragment size; will go into f_bsize in the kernel */ fsfo.st.frsize = fuse_round_size(fsfo.st.frsize, FUSE_MIN_BLOCKSIZE, FUSE_MAX_BLOCKSIZE); /* We must have: f_iosize >= f_bsize (fsfo.st.bsize >= fsfo.st_frsize) */ if (fsfo.st.bsize < fsfo.st.frsize) { fsfo.st.bsize = fsfo.st.frsize; } /* * TBD: Possibility: * * For actual I/O to OSXFUSE's "virtual" storage device, we use * data->blocksize and data->iosize. These are really meant to be * constant across the lifetime of a single mount. If necessary, we * can experiment by updating the mount point's stat with the frsize * and bsize values we come across here. */ /* * FUSE server will (might) give us this: * * __u64 blocks; // total data blocks in the file system * __u64 bfree; // free blocks in the file system * __u64 bavail; // free blocks available to non-superuser * __u64 files; // total file nodes in the file system * __u64 ffree; // free file nodes in the file system * __u32 bsize; // preferred/optimal file system block size * __u32 namelen; // maximum length of filenames * __u32 frsize; // fundamental file system block size * * On Mac OS X, we will map this data to struct vfs_attr as follows: * * Mac OS X FUSE * -------- ---- * uint64_t f_supported <- // handled here * uint64_t f_active <- // handled here * uint64_t f_objcount <- - * uint64_t f_filecount <- files * uint64_t f_dircount <- - * uint32_t f_bsize <- frsize * size_t f_iosize <- bsize * uint64_t f_blocks <- blocks * uint64_t f_bfree <- bfree * uint64_t f_bavail <- bavail * uint64_t f_bused <- blocks - bfree * uint64_t f_files <- files * uint64_t f_ffree <- ffree * fsid_t f_fsid <- // handled elsewhere * uid_t f_owner <- // handled elsewhere * ... capabilities <- // handled here * ... attributes <- // handled here * f_create_time <- - * f_modify_time <- - * f_access_time <- - * f_backup_time <- - * uint32_t f_fssubtype <- // daemon provides * char *f_vol_name <- // handled here * uint16_t f_signature <- // handled here * uint16_t f_carbon_fsid <- // handled here */ VFSATTR_RETURN(attr, f_filecount, fsfo.st.files); VFSATTR_RETURN(attr, f_bsize, fsfo.st.frsize); VFSATTR_RETURN(attr, f_iosize, fsfo.st.bsize); VFSATTR_RETURN(attr, f_blocks, fsfo.st.blocks); VFSATTR_RETURN(attr, f_bfree, fsfo.st.bfree); VFSATTR_RETURN(attr, f_bavail, fsfo.st.bavail); VFSATTR_RETURN(attr, f_bused, (fsfo.st.blocks - fsfo.st.bfree)); VFSATTR_RETURN(attr, f_files, fsfo.st.files); VFSATTR_RETURN(attr, f_ffree, fsfo.st.ffree); /* f_fsid and f_owner handled elsewhere. */ /* Handle capabilities and attributes. */ if (VFSATTR_IS_ACTIVE(attr, f_capabilities) || VFSATTR_IS_ACTIVE(attr, f_attributes)) { handle_capabilities_and_attributes(mp, attr); } VFSATTR_RETURN(attr, f_create_time, kZeroTime); VFSATTR_RETURN(attr, f_modify_time, kZeroTime); VFSATTR_RETURN(attr, f_access_time, kZeroTime); VFSATTR_RETURN(attr, f_backup_time, kZeroTime); if (deading) { VFSATTR_RETURN(attr, f_fssubtype, (uint32_t)FUSE_FSSUBTYPE_INVALID); } else { VFSATTR_RETURN(attr, f_fssubtype, data->fssubtype); } /* Daemon needs to pass this. */ if (VFSATTR_IS_ACTIVE(attr, f_vol_name)) { if (data->volname[0] != 0) { strncpy(attr->f_vol_name, data->volname, MAXPATHLEN); attr->f_vol_name[MAXPATHLEN - 1] = 0; VFSATTR_SET_SUPPORTED(attr, f_vol_name); } } VFSATTR_RETURN(attr, f_signature, OSSwapBigToHostInt16(FUSEFS_SIGNATURE)); VFSATTR_RETURN(attr, f_carbon_fsid, 0); if (!faking) { fuse_ticket_release(fdi.tick); } return 0; }