Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
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;
}