Пример #1
0
/*
    struct vnop_fsync_args {
	struct vnodeop_desc *a_desc;
	struct vnode * a_vp;
	struct ucred * a_cred;
	int  a_waitfor;
	struct thread * a_td;
    };
*/
static int
fuse_vnop_fsync(struct vop_fsync_args *ap)
{
	struct vnode *vp = ap->a_vp;
	struct thread *td = ap->a_td;

	struct fuse_filehandle *fufh;
	struct fuse_vnode_data *fvdat = VTOFUD(vp);

	int type, err = 0;

	fuse_trace_printf_vnop();

	if (fuse_isdeadfs(vp)) {
		return 0;
	}
	if ((err = vop_stdfsync(ap)))
		return err;

	if (!fsess_isimpl(vnode_mount(vp),
	    (vnode_vtype(vp) == VDIR ? FUSE_FSYNCDIR : FUSE_FSYNC))) {
		goto out;
	}
	for (type = 0; type < FUFH_MAXTYPE; type++) {
		fufh = &(fvdat->fufh[type]);
		if (FUFH_IS_VALID(fufh)) {
			fuse_internal_fsync(vp, td, NULL, fufh);
		}
	}

out:
	return 0;
}
Пример #2
0
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;
}
Пример #3
0
int
fuse_filehandle_valid(struct vnode *vp, fufh_type_t fufh_type)
{
    struct fuse_vnode_data *fvdat = VTOFUD(vp);
    struct fuse_filehandle *fufh;

    fufh = &(fvdat->fufh[fufh_type]);
    return FUFH_IS_VALID(fufh);
}
Пример #4
0
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;
}
Пример #5
0
static int
fuse_sync_callback(vnode_t vp, void *cargs)
{
    int type;
    struct fuse_sync_cargs *args;
    struct fuse_vnode_data *fvdat;
    struct fuse_filehandle *fufh;
    struct fuse_data       *data;
    mount_t mp;

    if (!vnode_hasdirtyblks(vp)) {
        return VNODE_RETURNED;
    }

    mp = vnode_mount(vp);

    if (fuse_isdeadfs_mp(mp)) {
        return VNODE_RETURNED_DONE;
    }

    data = fuse_get_mpdata(mp);

    if (!fuse_implemented(data, (vnode_isdir(vp)) ?
        FSESS_NOIMPLBIT(FSYNCDIR) : FSESS_NOIMPLBIT(FSYNC))) {
        return VNODE_RETURNED;
    }

    args = (struct fuse_sync_cargs *)cargs;
    fvdat = VTOFUD(vp);

#if M_OSXFUSE_ENABLE_BIG_LOCK
    fuse_biglock_unlock(data->biglock);
#endif
    cluster_push(vp, 0);
#if M_OSXFUSE_ENABLE_BIG_LOCK
    fuse_biglock_lock(data->biglock);
#endif

    for (type = 0; type < FUFH_MAXTYPE; type++) {
        fufh = &(fvdat->fufh[type]);
        if (FUFH_IS_VALID(fufh)) {
            (void)fuse_internal_fsync_fh(vp, args->context, fufh,
                                         FUSE_OP_FOREGROUNDED);
        }
    }

    /*
     * In general:
     *
     * - can use vnode_isinuse() if the need be
     * - vnode and UBC are in lock-step
     * - note that umount will call ubc_sync_range()
     */

    return VNODE_RETURNED;
}
Пример #6
0
void
fuse_filehandle_init(struct vnode *vp,
    fufh_type_t fufh_type,
    struct fuse_filehandle **fufhp,
    uint64_t fh_id)
{
	struct fuse_vnode_data *fvdat = VTOFUD(vp);
	struct fuse_filehandle *fufh;

	FS_DEBUG("id=%jd type=%d\n", (intmax_t)fh_id, fufh_type);
	fufh = &(fvdat->fufh[fufh_type]);
	MPASS(!FUFH_IS_VALID(fufh));
	fufh->fh_id = fh_id;
	fufh->fh_type = fufh_type;
	if (!FUFH_IS_VALID(fufh)) {
		panic("FUSE: init: invalid filehandle id (type=%d)", fufh_type);
	}
	if (fufhp != NULL)
		*fufhp = fufh;

	atomic_add_acq_int(&fuse_fh_count, 1);
}
Пример #7
0
int
fuse_filehandle_getrw(struct vnode *vp, fufh_type_t fufh_type,
    struct fuse_filehandle **fufhp)
{
    struct fuse_vnode_data *fvdat = VTOFUD(vp);
    struct fuse_filehandle *fufh;

    fufh = &(fvdat->fufh[fufh_type]);
    if (!FUFH_IS_VALID(fufh)) {
        fufh_type = FUFH_RDWR;
    }
    return fuse_filehandle_get(vp, fufh_type, fufhp);
}
Пример #8
0
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;
}
Пример #9
0
static int
fuse_sync_callback(vnode_t vp, void *cargs)
{
    int type;
    struct fuse_sync_cargs *args;
    struct fuse_vnode_data *fvdat;
    struct fuse_dispatcher  fdi;
    struct fuse_filehandle *fufh;
    struct fuse_data       *data;
    mount_t mp;

    if (!vnode_hasdirtyblks(vp)) {
        return VNODE_RETURNED;
    }

    mp = vnode_mount(vp);

    if (fuse_isdeadfs(vp)) {
        return VNODE_RETURNED_DONE;
    }

    data = fuse_get_mpdata(mp);

    if (!fuse_implemented(data, (vnode_isdir(vp)) ?
        FSESS_NOIMPLBIT(FSYNCDIR) : FSESS_NOIMPLBIT(FSYNC))) {
        return VNODE_RETURNED;
    }

    args = (struct fuse_sync_cargs *)cargs;
    fvdat = VTOFUD(vp);

    cluster_push(vp, 0);

    fuse_dispatcher_init(&fdi, 0);
    for (type = 0; type < FUFH_MAXTYPE; type++) {
        fufh = &(fvdat->fufh[type]);
        if (FUFH_IS_VALID(fufh)) {
            (void)fuse_internal_fsync(vp, args->context, fufh, &fdi);
        }
    }

    /*
     * In general:
     *
     * - can use vnode_isinuse() if the need be
     * - vnode and UBC are in lock-step
     * - note that umount will call ubc_sync_range()
     */

    return VNODE_RETURNED;
}
Пример #10
0
int
fuse_filehandle_get(struct vnode *vp, fufh_type_t fufh_type,
    struct fuse_filehandle **fufhp)
{
    struct fuse_vnode_data *fvdat = VTOFUD(vp);
    struct fuse_filehandle *fufh;

    fufh = &(fvdat->fufh[fufh_type]);
    if (!FUFH_IS_VALID(fufh))
	return EBADF;
    if (fufhp != NULL)
        *fufhp = fufh;
    return 0;
}
Пример #11
0
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;
}
Пример #12
0
/*
    struct vnop_reclaim_args {
	struct vnode *a_vp;
	struct thread *a_td;
    };
*/
static int
fuse_vnop_reclaim(struct vop_reclaim_args *ap)
{
	struct vnode *vp = ap->a_vp;
	struct thread *td = ap->a_td;

	struct fuse_vnode_data *fvdat = VTOFUD(vp);
	struct fuse_filehandle *fufh = NULL;

	int type;

	if (!fvdat) {
		panic("FUSE: no vnode data during recycling");
	}
	FS_DEBUG("inode=%ju\n", (uintmax_t)VTOI(vp));

	for (type = 0; type < FUFH_MAXTYPE; type++) {
		fufh = &(fvdat->fufh[type]);
		if (FUFH_IS_VALID(fufh)) {
			printf("FUSE: vnode being reclaimed but fufh (type=%d) is valid",
			    type);
			fuse_filehandle_close(vp, type, td, NULL);
		}
	}

	if ((!fuse_isdeadfs(vp)) && (fvdat->nlookup)) {
		fuse_internal_forget_send(vnode_mount(vp), td, NULL, VTOI(vp),
		    fvdat->nlookup);
	}
	fuse_vnode_setparent(vp, NULL);
	cache_purge(vp);
	vfs_hash_remove(vp);
	vnode_destroy_vobject(vp);
	fuse_vnode_destroy(vp);

	return 0;
}
Пример #13
0
/*
    struct vnop_inactive_args {
	struct vnode *a_vp;
	struct thread *a_td;
    };
*/
static int
fuse_vnop_inactive(struct vop_inactive_args *ap)
{
	struct vnode *vp = ap->a_vp;
	struct thread *td = ap->a_td;

	struct fuse_vnode_data *fvdat = VTOFUD(vp);
	struct fuse_filehandle *fufh = NULL;

	int type, need_flush = 1;

	FS_DEBUG("inode=%ju\n", (uintmax_t)VTOI(vp));

	for (type = 0; type < FUFH_MAXTYPE; type++) {
		fufh = &(fvdat->fufh[type]);
		if (FUFH_IS_VALID(fufh)) {
			if (need_flush && vp->v_type == VREG) {
				if ((VTOFUD(vp)->flag & FN_SIZECHANGE) != 0) {
					fuse_vnode_savesize(vp, NULL);
				}
				if (fuse_data_cache_invalidate ||
				    (fvdat->flag & FN_REVOKED) != 0)
					fuse_io_invalbuf(vp, td);
				else
					fuse_io_flushbuf(vp, MNT_WAIT, td);
				need_flush = 0;
			}
			fuse_filehandle_close(vp, type, td, NULL);
		}
	}

	if ((fvdat->flag & FN_REVOKED) != 0 && fuse_reclaim_revoked) {
		vrecycle(vp);
	}
	return 0;
}
Пример #14
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;
}
Пример #15
0
/* setattr sidekicks */
__private_extern__
int
fuse_internal_attr_vat2fsai(mount_t                 mp,
                            vnode_t                 vp,
                            struct vnode_attr      *vap,
                            struct fuse_setattr_in *fsai,
                            uint64_t               *newsize)
{
    /*
     * XXX: Locking
     *
     * We need to worry about the file size changing in setattr(). If the call
     * is indeed altering the size, then:
     *
     * lock_exclusive(truncatelock)
     *   lock(nodelock)
     *     set the new size
     *   unlock(nodelock)
     *   adjust ubc
     *   lock(nodelock)
     *     do cleanup
     *   unlock(nodelock)
     * unlock(truncatelock)
     * ...
     */

    int sizechanged = 0;
    uid_t nuid;
    gid_t ngid;

    fsai->valid = 0;

    if (newsize) {
        *newsize = 0;
    }

    nuid = VATTR_IS_ACTIVE(vap, va_uid) ? vap->va_uid : (uid_t)VNOVAL;
    if (nuid != (uid_t)VNOVAL) {
        fsai->uid = nuid;
        fsai->valid |= FATTR_UID;
    }
    VATTR_SET_SUPPORTED(vap, va_uid);

    ngid = VATTR_IS_ACTIVE(vap, va_gid) ? vap->va_gid : (gid_t)VNOVAL;
    if (ngid != (gid_t)VNOVAL) {
        fsai->gid = ngid;
        fsai->valid |= FATTR_GID;
    }
    VATTR_SET_SUPPORTED(vap, va_gid);

    if (VATTR_IS_ACTIVE(vap, va_data_size)) {

        // Truncate to a new value.
        fsai->size = vap->va_data_size;
        sizechanged = 1;
	if (newsize) {
            *newsize = vap->va_data_size;
        }
        fsai->valid |= FATTR_SIZE;      

        if (vp) {
            struct fuse_filehandle *fufh = NULL;
            fufh_type_t fufh_type = FUFH_WRONLY;
            struct fuse_vnode_data *fvdat = VTOFUD(vp);

            fufh = &(fvdat->fufh[fufh_type]);

            if (!FUFH_IS_VALID(fufh)) {
                fufh_type = FUFH_RDWR;
                fufh = &(fvdat->fufh[fufh_type]);
                if (!FUFH_IS_VALID(fufh)) {
                    fufh = NULL;
                }
            }

            if (fufh) {
                fsai->fh = fufh->fh_id;
                fsai->valid |= FATTR_FH;
            }
        }
    }
    VATTR_SET_SUPPORTED(vap, va_data_size);

    /*
     * Possible timestamps:
     *
     * Mac OS X                                          Linux  FUSE API
     *  
     * va_access_time    last access time                atime  atime
     * va_backup_time    last backup time                -      -
     * va_change_time    last metadata change time       ctime* -
     * va_create_time    creation time                   -      -
     * va_modify_time    last data modification time     mtime  mtime
     *
     */

    if (VATTR_IS_ACTIVE(vap, va_access_time)) {
        fsai->atime = vap->va_access_time.tv_sec;
        /* XXX: truncation */
        fsai->atimensec = (uint32_t)vap->va_access_time.tv_nsec;
        fsai->valid |=  FATTR_ATIME;
    }
    VATTR_SET_SUPPORTED(vap, va_access_time);

    if (VATTR_IS_ACTIVE(vap, va_modify_time)) {
        fsai->mtime = vap->va_modify_time.tv_sec;
        /* XXX: truncation */
        fsai->mtimensec = (uint32_t)vap->va_modify_time.tv_nsec;
        fsai->valid |=  FATTR_MTIME;
    }
    VATTR_SET_SUPPORTED(vap, va_modify_time);

    if (VATTR_IS_ACTIVE(vap, va_backup_time) && fuse_isxtimes_mp(mp)) {
        fsai->bkuptime = vap->va_backup_time.tv_sec;
        /* XXX: truncation */
        fsai->bkuptimensec = (uint32_t)vap->va_backup_time.tv_nsec;
        fsai->valid |= FATTR_BKUPTIME;
        VATTR_SET_SUPPORTED(vap, va_backup_time);
    }

    if (VATTR_IS_ACTIVE(vap, va_change_time)) {
        if (fuse_isxtimes_mp(mp)) {
            fsai->chgtime = vap->va_change_time.tv_sec;
            /* XXX: truncation */
            fsai->chgtimensec = (uint32_t)vap->va_change_time.tv_nsec;
            fsai->valid |=  FATTR_CHGTIME;
            VATTR_SET_SUPPORTED(vap, va_change_time);
        }
    }

    if (VATTR_IS_ACTIVE(vap, va_create_time) && fuse_isxtimes_mp(mp)) {
        fsai->crtime = vap->va_create_time.tv_sec;
        /* XXX: truncation */
        fsai->crtimensec = (uint32_t)vap->va_create_time.tv_nsec;
        fsai->valid |= FATTR_CRTIME;
        VATTR_SET_SUPPORTED(vap, va_create_time);
    }

    if (VATTR_IS_ACTIVE(vap, va_mode)) {
        fsai->mode = vap->va_mode & ALLPERMS;
        fsai->valid |= FATTR_MODE;
    }
    VATTR_SET_SUPPORTED(vap, va_mode);

    if (VATTR_IS_ACTIVE(vap, va_flags)) {
        fsai->flags = vap->va_flags;
        fsai->valid |= FATTR_FLAGS;
    }
    VATTR_SET_SUPPORTED(vap, va_flags);

    /*
     * We /are/ OK with va_acl, va_guuid, and va_uuuid passing through here.
     */

    return sizechanged;
}
Пример #16
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;
}
Пример #17
0
__private_extern__
int
fuse_internal_strategy(vnode_t vp, buf_t bp)
{
    size_t biosize;
    size_t chunksize;
    size_t respsize;

    int mapped = FALSE;
    int mode;
    int op;
    int vtype = vnode_vtype(vp);

    int err = 0;

    caddr_t bufdat;
    off_t   left;
    off_t   offset;
    int32_t bflags = buf_flags(bp);

    fufh_type_t             fufh_type;
    struct fuse_dispatcher  fdi;
    struct fuse_data       *data;
    struct fuse_vnode_data *fvdat = VTOFUD(vp);
    struct fuse_filehandle *fufh = NULL;
    mount_t mp = vnode_mount(vp);

    data = fuse_get_mpdata(mp);

    biosize = data->blocksize;

    if (!(vtype == VREG || vtype == VDIR)) {
        return ENOTSUP;
    }
 
    if (bflags & B_READ) {
        mode = FREAD;
        fufh_type = FUFH_RDONLY; /* FUFH_RDWR will also do */
    } else {
        mode = FWRITE;
        fufh_type = FUFH_WRONLY; /* FUFH_RDWR will also do */
    }

    if (fvdat->flag & FN_CREATING) {
        fuse_lck_mtx_lock(fvdat->createlock);
        if (fvdat->flag & FN_CREATING) {
            (void)fuse_msleep(fvdat->creator, fvdat->createlock,
                              PDROP | PINOD | PCATCH, "fuse_internal_strategy",
                              NULL);
        } else {
            fuse_lck_mtx_unlock(fvdat->createlock);
        }
    }

    fufh = &(fvdat->fufh[fufh_type]);

    if (!FUFH_IS_VALID(fufh)) {
        fufh_type = FUFH_RDWR;
        fufh = &(fvdat->fufh[fufh_type]);
        if (!FUFH_IS_VALID(fufh)) {
            fufh = NULL;
        } else {
            /* We've successfully fallen back to FUFH_RDWR. */
        }
    }

    if (!fufh) {

        if (mode == FREAD) {
            fufh_type = FUFH_RDONLY;
        } else {
            fufh_type = FUFH_RDWR;
        }

        /*
         * Lets NOT do the filehandle preflight check here.
         */

        err = fuse_filehandle_get(vp, NULL, fufh_type, 0 /* mode */);

        if (!err) {
            fufh = &(fvdat->fufh[fufh_type]);
            FUFH_AUX_INC(fufh);
            /* We've created a NEW fufh of type fufh_type. open_count is 1. */
        }

    } else { /* good fufh */

        FUSE_OSAddAtomic(1, (SInt32 *)&fuse_fh_reuse_count);

        /* We're using an existing fufh of type fufh_type. */
    }

    if (err) {

         /* A more typical error case. */
         if ((err == ENOTCONN) || fuse_isdeadfs(vp)) {
             buf_seterror(bp, EIO);
             buf_biodone(bp);
             return EIO;
         }

         IOLog("MacFUSE: strategy failed to get fh "
               "(vtype=%d, fufh_type=%d, err=%d)\n", vtype, fufh_type, err);

         if (!vfs_issynchronous(mp)) {
             IOLog("MacFUSE: asynchronous write failed!\n");
         }

         buf_seterror(bp, EIO);
         buf_biodone(bp);
         return EIO;
    }

    if (!fufh) {
        panic("MacFUSE: tried everything but still no fufh");
        /* NOTREACHED */
    }

#define B_INVAL 0x00040000 /* Does not contain valid info. */
#define B_ERROR 0x00080000 /* I/O error occurred. */

    if (bflags & B_INVAL) {
        IOLog("MacFUSE: buffer does not contain valid information\n");
    } 

    if (bflags & B_ERROR) {
        IOLog("MacFUSE: an I/O error has occured\n");
    }

    if (buf_count(bp) == 0) {
        return 0;
    }

    fdisp_init(&fdi, 0);

    if (mode == FREAD) {

        struct fuse_read_in *fri;

        buf_setresid(bp, buf_count(bp));
        offset = (off_t)((off_t)buf_blkno(bp) * biosize);

        if (offset >= fvdat->filesize) {
            /* Trying to read at/after EOF? */           
            if (offset != fvdat->filesize) {
                /* Trying to read after EOF? */
                buf_seterror(bp, EINVAL);
            }
            buf_biodone(bp);
            return 0;
        }

        /* Note that we just made sure that offset < fvdat->filesize. */
        if ((offset + buf_count(bp)) > fvdat->filesize) {
            /* Trimming read */
            buf_setcount(bp, (uint32_t)(fvdat->filesize - offset));
        }

        if (buf_map(bp, &bufdat)) {
            IOLog("MacFUSE: failed to map buffer in strategy\n");
            return EFAULT;
        } else {
            mapped = TRUE;
        }

        while (buf_resid(bp) > 0) {

            chunksize = min((size_t)buf_resid(bp), data->iosize);

            fdi.iosize = sizeof(*fri);

            op = FUSE_READ;
            if (vtype == VDIR) {
                op = FUSE_READDIR;
            }
            fdisp_make_vp(&fdi, op, vp, (vfs_context_t)0);
        
            fri = fdi.indata;
            fri->fh = fufh->fh_id;

            /*
             * Historical note:
             *
             * fri->offset = ((off_t)(buf_blkno(bp))) * biosize;
             *
             * This wasn't being incremented!?
             */

            fri->offset = offset;
            fri->size = (typeof(fri->size))chunksize;
            fdi.tick->tk_aw_type = FT_A_BUF;
            fdi.tick->tk_aw_bufdata = bufdat;
        
            if ((err = fdisp_wait_answ(&fdi))) {
                /* There was a problem with reading. */
                goto out;
            }

            respsize = fdi.tick->tk_aw_bufsize;

            if (respsize < 0) { /* Cannot really happen... */
                err = EIO;
                goto out;
            }

            buf_setresid(bp, (uint32_t)(buf_resid(bp) - respsize));
            bufdat += respsize;
            offset += respsize;

            /* Did we hit EOF before being done? */
            if ((respsize == 0) && (buf_resid(bp) > 0)) {
                 /*
                  * Historical note:
                  * If we don't get enough data, just fill the rest with zeros.
                  * In NFS context, this would mean a hole in the file.
                  */

                 /* Zero-pad the incomplete buffer. */
                 bzero(bufdat, buf_resid(bp));
                 buf_setresid(bp, 0);
                 break;
            }
        } /* while (buf_resid(bp) > 0) */
    } else {
        /* write */
        struct fuse_write_in  *fwi;
        struct fuse_write_out *fwo;
        int merr = 0;
        off_t diff;

        if (buf_map(bp, &bufdat)) {
            IOLog("MacFUSE: failed to map buffer in strategy\n");
            return EFAULT;
        } else {
            mapped = TRUE;
        }

        /* Write begin */

        buf_setresid(bp, buf_count(bp));
        offset = (off_t)((off_t)buf_blkno(bp) * biosize);

        /* XXX: TBD -- Check here for extension (writing past end) */

        left = buf_count(bp);

        while (left) {

            fdi.iosize = sizeof(*fwi);
            op = FUSE_WRITE;

            fdisp_make_vp(&fdi, op, vp, (vfs_context_t)0);
            chunksize = min((size_t)left, data->iosize);

            fwi = fdi.indata;
            fwi->fh = fufh->fh_id;
            fwi->offset = offset;
            fwi->size = (typeof(fwi->size))chunksize;

            fdi.tick->tk_ms_type = FT_M_BUF;
            fdi.tick->tk_ms_bufdata = bufdat;
            fdi.tick->tk_ms_bufsize = chunksize;

            /* About to write <chunksize> at <offset> */

            if ((err = fdisp_wait_answ(&fdi))) {
                merr = 1;
                break;
            }
    
            fwo = fdi.answ;
            diff = chunksize - fwo->size;
            if (diff < 0) {
                err = EINVAL;
                break;
            }
    
            left -= fwo->size;
            bufdat += fwo->size;
            offset += fwo->size;
            buf_setresid(bp, buf_resid(bp) - fwo->size);
        }

        if (merr) {
            goto out;
        }
    }

    if (fdi.tick) {
        fuse_ticket_drop(fdi.tick);
    } else {
        /* No ticket upon leaving */
    }

out:

    if (err) {
        buf_seterror(bp, err);
    }

    if (mapped == TRUE) {
        buf_unmap(bp);
    }

    buf_biodone(bp);

    return err;
}