예제 #1
0
static int
puffs_vnop_advlock(struct vop_advlock_args *ap)
{
    PUFFS_MSG_VARS(vn, advlock);
    struct vnode *vp = ap->a_vp;
    struct puffs_node *pn = VPTOPP(vp);
    struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
    int error;

    if (!EXISTSOP(pmp, ADVLOCK))
        return lf_advlock(ap, &pn->pn_lockf, vp->v_filesize);

    PUFFS_MSG_ALLOC(vn, advlock);
    (void)memcpy(&advlock_msg->pvnr_fl, ap->a_fl,
                 sizeof(advlock_msg->pvnr_fl));
    advlock_msg->pvnr_id = ap->a_id;
    advlock_msg->pvnr_op = ap->a_op;
    advlock_msg->pvnr_flags = ap->a_flags;
    puffs_msg_setinfo(park_advlock, PUFFSOP_VN,
                      PUFFS_VN_ADVLOCK, VPTOPNC(vp));
    PUFFS_MSG_ENQUEUEWAIT2(pmp, park_advlock, vp->v_data, NULL, error);
    error = checkerr(pmp, error, __func__);
    PUFFS_MSG_RELEASE(advlock);

    return error;
}
예제 #2
0
static int
puffs_vnop_open(struct vop_open_args *ap)
{
    PUFFS_MSG_VARS(vn, open);
    struct vnode *vp = ap->a_vp;
    struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
    int mode = ap->a_mode;
    int error;

    DPRINTF(("puffs_open: vp %p, mode 0x%x\n", vp, mode));

    if (vp->v_type == VREG && mode & FWRITE && !EXISTSOP(pmp, WRITE))
        ERROUT(EROFS);

    if (!EXISTSOP(pmp, OPEN))
        ERROUT(0);

    PUFFS_MSG_ALLOC(vn, open);
    open_msg->pvnr_mode = mode;
    puffs_credcvt(&open_msg->pvnr_cred, ap->a_cred);
    puffs_msg_setinfo(park_open, PUFFSOP_VN,
                      PUFFS_VN_OPEN, VPTOPNC(vp));

    PUFFS_MSG_ENQUEUEWAIT2(pmp, park_open, vp->v_data, NULL, error);
    error = checkerr(pmp, error, __func__);

out:
    DPRINTF(("puffs_open: returning %d\n", error));
    PUFFS_MSG_RELEASE(open);
    if (error)
        return error;
    return vop_stdopen(ap);
}
예제 #3
0
static int
puffs_vnop_print(struct vop_print_args *ap)
{
    PUFFS_MSG_VARS(vn, print);
    struct vnode *vp = ap->a_vp;
    struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
    struct puffs_node *pn = VPTOPP(vp);
    int error;

    /* kernel portion */
    kprintf("tag VT_PUFFS, vnode %p, puffs node: %p,\n"
            "\tuserspace cookie: %p", vp, pn, pn->pn_cookie);
    if (vp->v_type == VFIFO)
        fifo_printinfo(vp);
    kprintf("\n");

    /* userspace portion */
    if (EXISTSOP(pmp, PRINT)) {
        PUFFS_MSG_ALLOC(vn, print);
        puffs_msg_setinfo(park_print, PUFFSOP_VN,
                          PUFFS_VN_PRINT, VPTOPNC(vp));
        PUFFS_MSG_ENQUEUEWAIT2(pmp, park_print, vp->v_data,
                               NULL, error);
        PUFFS_MSG_RELEASE(print);
    }

    return 0;
}
예제 #4
0
/*
 * XXX: can't use callremove now because can't catch setbacks with
 * it due to lack of a pnode argument.
 */
static int
puffs_vnop_remove(struct vop_nremove_args *ap)
{
    PUFFS_MSG_VARS(vn, remove);
    struct vnode *dvp = ap->a_dvp;
    struct vnode *vp;
    struct puffs_node *dpn = VPTOPP(dvp);
    struct puffs_node *pn;
    struct nchandle *nch = ap->a_nch;
    struct namecache *ncp = nch->ncp;
    struct ucred *cred = ap->a_cred;
    struct mount *mp = dvp->v_mount;
    struct puffs_mount *pmp = MPTOPUFFSMP(mp);
    int error;

    if (!EXISTSOP(pmp, REMOVE))
        return EOPNOTSUPP;

    error = vget(dvp, LK_EXCLUSIVE);
    if (error != 0) {
        DPRINTF(("puffs_vnop_remove: EAGAIN on parent vnode %p %s\n",
                 dvp, ncp->nc_name));
        return EAGAIN;
    }

    error = cache_vget(nch, cred, LK_EXCLUSIVE, &vp);
    if (error != 0) {
        DPRINTF(("puffs_vnop_remove: cache_vget error: %p %s\n",
                 dvp, ncp->nc_name));
        return EAGAIN;
    }
    if (vp->v_type == VDIR) {
        error = EISDIR;
        goto out;
    }

    pn = VPTOPP(vp);
    PUFFS_MSG_ALLOC(vn, remove);
    remove_msg->pvnr_cookie_targ = VPTOPNC(vp);
    puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred,
                 ncp, cred);
    puffs_msg_setinfo(park_remove, PUFFSOP_VN,
                      PUFFS_VN_REMOVE, VPTOPNC(dvp));

    puffs_msg_enqueue(pmp, park_remove);
    error = puffs_msg_wait2(pmp, park_remove, dpn, pn);

    PUFFS_MSG_RELEASE(remove);

    error = checkerr(pmp, error, __func__);

out:
    vput(dvp);
    vn_unlock(vp);
    if (error == 0)
        cache_unlink(nch);
    vrele(vp);
    return error;
}
예제 #5
0
static int
puffs_vnop_mknod(struct vop_nmknod_args *ap)
{
    PUFFS_MSG_VARS(vn, mknod);
    struct vnode *dvp = ap->a_dvp;
    struct vattr *vap = ap->a_vap;
    struct puffs_node *dpn = VPTOPP(dvp);
    struct nchandle *nch = ap->a_nch;
    struct namecache *ncp = nch->ncp;
    struct ucred *cred = ap->a_cred;
    struct mount *mp = dvp->v_mount;
    struct puffs_mount *pmp = MPTOPUFFSMP(mp);
    int error;

    if (!EXISTSOP(pmp, MKNOD))
        return EOPNOTSUPP;

    DPRINTF(("puffs_mknod: dvp %p, name: %s\n",
             dvp, ncp->nc_name));

    if (vap->va_type != VFIFO)
        return EINVAL;

    if ((error = vget(dvp, LK_EXCLUSIVE)) != 0) {
        DPRINTF(("puffs_vnop_mknod: EAGAIN on ncp %p %s\n",
                 ncp, ncp->nc_name));
        return EAGAIN;
    }

    PUFFS_MSG_ALLOC(vn, mknod);
    puffs_makecn(&mknod_msg->pvnr_cn, &mknod_msg->pvnr_cn_cred,
                 ncp, cred);
    mknod_msg->pvnr_va = *ap->a_vap;
    puffs_msg_setinfo(park_mknod, PUFFSOP_VN,
                      PUFFS_VN_MKNOD, VPTOPNC(dvp));

    PUFFS_MSG_ENQUEUEWAIT2(pmp, park_mknod, dvp->v_data, NULL, error);

    error = checkerr(pmp, error, __func__);
    if (error)
        goto out;

    error = puffs_newnode(mp, dvp, ap->a_vpp,
                          mknod_msg->pvnr_newnode, vap->va_type);
    if (error)
        puffs_abortbutton(pmp, PUFFS_ABORT_MKNOD, dpn->pn_cookie,
                          mknod_msg->pvnr_newnode, ncp, cred);

out:
    vput(dvp);
    if (!error) {
        cache_setunresolved(nch);
        cache_setvp(nch, *ap->a_vpp);
    }
    PUFFS_MSG_RELEASE(mknod);
    return error;
}
예제 #6
0
static int
puffs_vnop_link(struct vop_nlink_args *ap)
{
    PUFFS_MSG_VARS(vn, link);
    struct vnode *dvp = ap->a_dvp;
    struct vnode *vp = ap->a_vp;
    struct puffs_node *dpn = VPTOPP(dvp);
    struct puffs_node *pn = VPTOPP(vp);
    struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
    struct nchandle *nch = ap->a_nch;
    struct namecache *ncp = nch->ncp;
    struct ucred *cred = ap->a_cred;
    int error;

    if (!EXISTSOP(pmp, LINK))
        return EOPNOTSUPP;

    if (vp->v_mount != dvp->v_mount)
        return EXDEV;

    if ((error = vget(dvp, LK_EXCLUSIVE)) != 0) {
        DPRINTF(("puffs_vnop_link: EAGAIN on ncp %p %s\n",
                 ncp, ncp->nc_name));
        return EAGAIN;
    }

    PUFFS_MSG_ALLOC(vn, link);
    link_msg->pvnr_cookie_targ = VPTOPNC(vp);
    puffs_makecn(&link_msg->pvnr_cn, &link_msg->pvnr_cn_cred,
                 ncp, cred);
    puffs_msg_setinfo(park_link, PUFFSOP_VN,
                      PUFFS_VN_LINK, VPTOPNC(dvp));

    puffs_msg_enqueue(pmp, park_link);
    error = puffs_msg_wait2(pmp, park_link, dpn, pn);

    PUFFS_MSG_RELEASE(link);

    error = checkerr(pmp, error, __func__);

    /*
     * XXX: stay in touch with the cache.  I don't like this, but
     * don't have a better solution either.  See also puffs_rename().
     */
    if (error == 0) {
        puffs_updatenode(pn, PUFFS_UPDATECTIME);
    }

    vput(dvp);
    if (error == 0) {
        cache_setunresolved(nch);
        cache_setvp(nch, vp);
    }
    return error;
}
예제 #7
0
static int
puffs_vnop_symlink(struct vop_nsymlink_args *ap)
{
    PUFFS_MSG_VARS(vn, symlink);
    struct vnode *dvp = ap->a_dvp;
    struct puffs_node *dpn = VPTOPP(dvp);
    struct mount *mp = dvp->v_mount;
    struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
    struct nchandle *nch = ap->a_nch;
    struct namecache *ncp = nch->ncp;
    struct ucred *cred = ap->a_cred;
    int error;

    if (!EXISTSOP(pmp, SYMLINK))
        return EOPNOTSUPP;

    if ((error = vget(dvp, LK_EXCLUSIVE)) != 0) {
        DPRINTF(("puffs_vnop_symlink: EAGAIN on ncp %p %s\n",
                 ncp, ncp->nc_name));
        return EAGAIN;
    }

    *ap->a_vpp = NULL;

    PUFFS_MSG_ALLOC(vn, symlink);
    puffs_makecn(&symlink_msg->pvnr_cn, &symlink_msg->pvnr_cn_cred,
                 ncp, cred);
    symlink_msg->pvnr_va = *ap->a_vap;
    (void)strlcpy(symlink_msg->pvnr_link, ap->a_target,
                  sizeof(symlink_msg->pvnr_link));
    puffs_msg_setinfo(park_symlink, PUFFSOP_VN,
                      PUFFS_VN_SYMLINK, VPTOPNC(dvp));

    PUFFS_MSG_ENQUEUEWAIT2(pmp, park_symlink, dvp->v_data, NULL, error);

    error = checkerr(pmp, error, __func__);
    if (error)
        goto out;

    error = puffs_newnode(mp, dvp, ap->a_vpp,
                          symlink_msg->pvnr_newnode, VLNK);
    if (error)
        puffs_abortbutton(pmp, PUFFS_ABORT_SYMLINK, dpn->pn_cookie,
                          symlink_msg->pvnr_newnode, ncp, cred);

out:
    vput(dvp);
    PUFFS_MSG_RELEASE(symlink);
    if (!error) {
        cache_setunresolved(nch);
        cache_setvp(nch, *ap->a_vpp);
    }
    return error;
}
예제 #8
0
static int
puffs_vnop_getattr(struct vop_getattr_args *ap)
{
    PUFFS_MSG_VARS(vn, getattr);
    struct vnode *vp = ap->a_vp;
    struct mount *mp = vp->v_mount;
    struct puffs_mount *pmp = MPTOPUFFSMP(mp);
    struct vattr *vap, *rvap;
    struct puffs_node *pn = VPTOPP(vp);
    int error = 0;

    if (vp->v_type == VBLK || vp->v_type == VCHR)
        return ENOTSUP;

    vap = ap->a_vap;

    PUFFS_MSG_ALLOC(vn, getattr);
    vattr_null(&getattr_msg->pvnr_va);
    puffs_credcvt(&getattr_msg->pvnr_cred, curproc->p_ucred);
    puffs_msg_setinfo(park_getattr, PUFFSOP_VN,
                      PUFFS_VN_GETATTR, VPTOPNC(vp));

    PUFFS_MSG_ENQUEUEWAIT2(pmp, park_getattr, vp->v_data, NULL, error);
    error = checkerr(pmp, error, __func__);
    if (error)
        goto out;

    rvap = &getattr_msg->pvnr_va;

    (void) memcpy(vap, rvap, sizeof(struct vattr));
    vap->va_fsid = mp->mnt_stat.f_fsid.val[0];

    if (pn->pn_stat & PNODE_METACACHE_ATIME)
        vap->va_atime = pn->pn_mc_atime;
    if (pn->pn_stat & PNODE_METACACHE_CTIME)
        vap->va_ctime = pn->pn_mc_ctime;
    if (pn->pn_stat & PNODE_METACACHE_MTIME)
        vap->va_mtime = pn->pn_mc_mtime;
    if (pn->pn_stat & PNODE_METACACHE_SIZE) {
        vap->va_size = pn->pn_mc_size;
    } else {
        if (rvap->va_size != VNOVAL
                && vp->v_type != VBLK && vp->v_type != VCHR) {
            pn->pn_serversize = rvap->va_size;
            if (vp->v_type == VREG)
                puffs_meta_setsize(vp, rvap->va_size, 0);
        }
    }

out:
    PUFFS_MSG_RELEASE(getattr);
    return error;
}
예제 #9
0
static void
callreclaim(struct puffs_mount *pmp, puffs_cookie_t ck)
{
    PUFFS_MSG_VARS(vn, reclaim);

    if (!EXISTSOP(pmp, RECLAIM))
        return;

    PUFFS_MSG_ALLOC(vn, reclaim);
    puffs_msg_setfaf(park_reclaim);
    puffs_msg_setinfo(park_reclaim, PUFFSOP_VN, PUFFS_VN_RECLAIM, ck);

    puffs_msg_enqueue(pmp, park_reclaim);
    PUFFS_MSG_RELEASE(reclaim);
}
예제 #10
0
static void
callinactive(struct puffs_mount *pmp, puffs_cookie_t ck, int iaflag)
{
    int error;
    PUFFS_MSG_VARS(vn, inactive);

    if (doinact(pmp, iaflag)) {
        PUFFS_MSG_ALLOC(vn, inactive);
        puffs_msg_setinfo(park_inactive, PUFFSOP_VN,
                          PUFFS_VN_INACTIVE, ck);

        PUFFS_MSG_ENQUEUEWAIT(pmp, park_inactive, error);
        PUFFS_MSG_RELEASE(inactive);
    }
}
예제 #11
0
파일: puffs_subr.c 프로젝트: Hooman3/minix
void
puffs_senderr(struct puffs_mount *pmp, int type, int error,
	const char *str, puffs_cookie_t ck)
{
	struct puffs_msgpark *park;
	struct puffs_error *perr;

	puffs_msgmem_alloc(sizeof(struct puffs_error), &park, (void *)&perr, 1);
	puffs_msg_setfaf(park);
	puffs_msg_setinfo(park, PUFFSOP_ERROR, type, ck);

	perr->perr_error = error;
	strlcpy(perr->perr_str, str, sizeof(perr->perr_str));

	puffs_msg_enqueue(pmp, park);
	puffs_msgmem_release(park);
}
예제 #12
0
static int
callremove(struct puffs_mount *pmp, puffs_cookie_t dck, puffs_cookie_t ck,
           struct namecache *ncp, struct ucred *cred)
{
    PUFFS_MSG_VARS(vn, remove);
    int error;

    PUFFS_MSG_ALLOC(vn, remove);
    remove_msg->pvnr_cookie_targ = ck;
    puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred,
                 ncp, cred);
    puffs_msg_setinfo(park_remove, PUFFSOP_VN, PUFFS_VN_REMOVE, dck);

    PUFFS_MSG_ENQUEUEWAIT(pmp, park_remove, error);
    PUFFS_MSG_RELEASE(remove);

    return checkerr(pmp, error, __func__);
}
예제 #13
0
static int
puffs_vnop_fsync(struct vop_fsync_args *ap)
{
    PUFFS_MSG_VARS(vn, fsync);
    struct vnode *vp = ap->a_vp;
    int waitfor = ap->a_waitfor;
    struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
    struct puffs_node *pn = VPTOPP(vp);
    int error, dofaf;

    error = flushvncache(vp, waitfor);
    if (error)
        return error;

    /*
     * HELLO!  We exit already here if the user server does not
     * support fsync OR if we should call fsync for a node which
     * has references neither in the kernel or the fs server.
     * Otherwise we continue to issue fsync() forward.
     */
    if (!EXISTSOP(pmp, FSYNC) || (pn->pn_stat & PNODE_DYING))
        return 0;

    dofaf = (waitfor & MNT_WAIT) == 0 || (waitfor & MNT_LAZY) != 0;

    PUFFS_MSG_ALLOC(vn, fsync);
    if (dofaf)
        puffs_msg_setfaf(park_fsync);

    fsync_msg->pvnr_flags = ap->a_flags;
    puffs_msg_setinfo(park_fsync, PUFFSOP_VN,
                      PUFFS_VN_FSYNC, VPTOPNC(vp));

    PUFFS_MSG_ENQUEUEWAIT2(pmp, park_fsync, vp->v_data, NULL, error);
    PUFFS_MSG_RELEASE(fsync);

    error = checkerr(pmp, error, __func__);

    return error;
}
예제 #14
0
static int
puffs_vnop_close(struct vop_close_args *ap)
{
    PUFFS_MSG_VARS(vn, close);
    struct vnode *vp = ap->a_vp;
    struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);

    vn_lock(vp, LK_UPGRADE | LK_RETRY);

    if (!EXISTSOP(pmp, CLOSE))
        return vop_stdclose(ap);

    PUFFS_MSG_ALLOC(vn, close);
    puffs_msg_setfaf(park_close);
    close_msg->pvnr_fflag = ap->a_fflag;
    puffs_msg_setinfo(park_close, PUFFSOP_VN,
                      PUFFS_VN_CLOSE, VPTOPNC(vp));

    puffs_msg_enqueue(pmp, park_close);
    PUFFS_MSG_RELEASE(close);
    return vop_stdclose(ap);
}
예제 #15
0
static int
puffs_vnop_readlink(struct vop_readlink_args *ap)
{
    PUFFS_MSG_VARS(vn, readlink);
    struct vnode *vp = ap->a_vp;
    struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
    size_t linklen;
    int error;

    if (!EXISTSOP(pmp, READLINK))
        return EOPNOTSUPP;

    PUFFS_MSG_ALLOC(vn, readlink);
    puffs_credcvt(&readlink_msg->pvnr_cred, ap->a_cred);
    linklen = sizeof(readlink_msg->pvnr_link);
    readlink_msg->pvnr_linklen = linklen;
    puffs_msg_setinfo(park_readlink, PUFFSOP_VN,
                      PUFFS_VN_READLINK, VPTOPNC(vp));

    PUFFS_MSG_ENQUEUEWAIT2(pmp, park_readlink, vp->v_data, NULL, error);
    error = checkerr(pmp, error, __func__);
    if (error)
        goto out;

    /* bad bad user file server */
    if (readlink_msg->pvnr_linklen > linklen) {
        puffs_senderr(pmp, PUFFS_ERR_READLINK, E2BIG,
                      "linklen too big", VPTOPNC(ap->a_vp));
        error = EPROTO;
        goto out;
    }

    error = uiomove(readlink_msg->pvnr_link, readlink_msg->pvnr_linklen,
                    ap->a_uio);
out:
    PUFFS_MSG_RELEASE(readlink);
    return error;
}
예제 #16
0
static int
puffs_vnop_access(struct vop_access_args *ap)
{
    PUFFS_MSG_VARS(vn, access);
    struct vnode *vp = ap->a_vp;
    struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
    int mode = ap->a_mode;
    int error;

    if (mode & VWRITE) {
        switch (vp->v_type) {
        case VDIR:
        case VLNK:
        case VREG:
            if ((vp->v_mount->mnt_flag & MNT_RDONLY)
                    || !EXISTSOP(pmp, WRITE))
                return EROFS;
            break;
        default:
            break;
        }
    }

    if (!EXISTSOP(pmp, ACCESS))
        return 0;

    PUFFS_MSG_ALLOC(vn, access);
    access_msg->pvnr_mode = ap->a_mode;
    puffs_credcvt(&access_msg->pvnr_cred, ap->a_cred);
    puffs_msg_setinfo(park_access, PUFFSOP_VN,
                      PUFFS_VN_ACCESS, VPTOPNC(vp));

    PUFFS_MSG_ENQUEUEWAIT2(pmp, park_access, vp->v_data, NULL, error);
    error = checkerr(pmp, error, __func__);
    PUFFS_MSG_RELEASE(access);

    return error;
}
예제 #17
0
static int
puffs_vnop_pathconf(struct vop_pathconf_args *ap)
{
    PUFFS_MSG_VARS(vn, pathconf);
    struct vnode *vp = ap->a_vp;
    struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
    int error;

    if (!EXISTSOP(pmp, PATHCONF))
        return EOPNOTSUPP;

    PUFFS_MSG_ALLOC(vn, pathconf);
    pathconf_msg->pvnr_name = ap->a_name;
    puffs_msg_setinfo(park_pathconf, PUFFSOP_VN,
                      PUFFS_VN_PATHCONF, VPTOPNC(vp));
    PUFFS_MSG_ENQUEUEWAIT2(pmp, park_pathconf, vp->v_data, NULL, error);
    error = checkerr(pmp, error, __func__);
    if (!error)
        *ap->a_retval = pathconf_msg->pvnr_retval;
    PUFFS_MSG_RELEASE(pathconf);

    return error;
}
예제 #18
0
/* XXX: callinactive can't setback */
static int
puffs_vnop_inactive(struct vop_inactive_args *ap)
{
    PUFFS_MSG_VARS(vn, inactive);
    struct vnode *vp = ap->a_vp;
    struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
    struct puffs_node *pnode = VPTOPP(vp);

    flushvncache(vp, MNT_NOWAIT);

    if (doinact(pmp, pnode->pn_stat & PNODE_DOINACT)) {
        /*
         * do not wait for reply from userspace, otherwise it may
         * deadlock.
         */

        PUFFS_MSG_ALLOC(vn, inactive);
        puffs_msg_setfaf(park_inactive);
        puffs_msg_setinfo(park_inactive, PUFFSOP_VN,
                          PUFFS_VN_INACTIVE, VPTOPNC(vp));

        puffs_msg_enqueue(pmp, park_inactive);
        PUFFS_MSG_RELEASE(inactive);
    }
    pnode->pn_stat &= ~PNODE_DOINACT;

    /*
     * file server thinks it's gone?  then don't be afraid care,
     * node's life was already all it would ever be
     */
    if (pnode->pn_stat & PNODE_NOREFS) {
        pnode->pn_stat |= PNODE_DYING;
        vrecycle(vp);
    }

    return 0;
}
예제 #19
0
/*
 * Begin vnode operations.
 *
 * A word from the keymaster about locks: generally we don't want
 * to use the vnode locks at all: it creates an ugly dependency between
 * the userlandia file server and the kernel.  But we'll play along with
 * the kernel vnode locks for now.  However, even currently we attempt
 * to release locks as early as possible.  This is possible for some
 * operations which a) don't need a locked vnode after the userspace op
 * and b) return with the vnode unlocked.  Theoretically we could
 * unlock-do op-lock for others and order the graph in userspace, but I
 * don't want to think of the consequences for the time being.
 */
static int
puffs_vnop_lookup(struct vop_nresolve_args *ap)
{
    PUFFS_MSG_VARS(vn, lookup);
    struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_dvp->v_mount);
    struct nchandle *nch = ap->a_nch;
    struct namecache *ncp = nch->ncp;
    struct ucred *cred = ap->a_cred;
    struct vnode *vp = NULL, *dvp = ap->a_dvp;
    struct puffs_node *dpn;
    int error;

    DPRINTF(("puffs_lookup: \"%s\", parent vnode %p\n",
             ncp->nc_name, dvp));

    PUFFS_MSG_ALLOC(vn, lookup);
    puffs_makecn(&lookup_msg->pvnr_cn, &lookup_msg->pvnr_cn_cred,
                 ncp, cred);

    puffs_msg_setinfo(park_lookup, PUFFSOP_VN,
                      PUFFS_VN_LOOKUP, VPTOPNC(dvp));
    PUFFS_MSG_ENQUEUEWAIT2(pmp, park_lookup, dvp->v_data, NULL, error);
    DPRINTF(("puffs_lookup: return of the userspace, part %d\n", error));
    if (error) {
        error = checkerr(pmp, error, __func__);
        if (error == ENOENT)
            cache_setvp(nch, NULL);
        goto out;
    }

    /*
     * Check that we don't get our parent node back, that would cause
     * a pretty obvious deadlock.
     */
    dpn = VPTOPP(dvp);
    if (lookup_msg->pvnr_newnode == dpn->pn_cookie) {
        puffs_senderr(pmp, PUFFS_ERR_LOOKUP, EINVAL,
                      "lookup produced parent cookie", lookup_msg->pvnr_newnode);
        error = EPROTO;
        goto out;
    }

    error = puffs_cookie2vnode(pmp, lookup_msg->pvnr_newnode, 1, &vp);
    if (error == PUFFS_NOSUCHCOOKIE) {
        error = puffs_getvnode(dvp->v_mount,
                               lookup_msg->pvnr_newnode, lookup_msg->pvnr_vtype,
                               lookup_msg->pvnr_size, &vp);
        if (error) {
            puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
                              lookup_msg->pvnr_newnode, ncp, cred);
            goto out;
        }
    } else if (error) {
        puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
                          lookup_msg->pvnr_newnode, ncp, cred);
        goto out;
    }

out:
    if (!error && vp != NULL) {
        vn_unlock(vp);
        cache_setvp(nch, vp);
        vrele(vp);
    }
    DPRINTF(("puffs_lookup: returning %d\n", error));
    PUFFS_MSG_RELEASE(lookup);
    return error;
}
예제 #20
0
int
puffs_directread(struct vnode *vp, struct uio *uio, int ioflag,
    struct ucred *cred)
{
	PUFFS_MSG_VARS(vn, read);
	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
	size_t tomove, argsize;
	int error;

	KKASSERT(vp->v_type == VREG);

	if (uio->uio_offset < 0)
		return EINVAL;
	if (uio->uio_resid == 0)
		return 0;

	read_msg = NULL;
	error = 0;

	/* std sanity */
	if (uio->uio_resid == 0)
		return 0;
	if (uio->uio_offset < 0)
		return EINVAL;

	/*
	 * in case it's not a regular file or we're operating
	 * uncached, do read in the old-fashioned style,
	 * i.e. explicit read operations
	 */

	tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
	argsize = sizeof(struct puffs_vnmsg_read);
	puffs_msgmem_alloc(argsize + tomove, &park_read,
	    (void *)&read_msg, 1);

	error = 0;
	while (uio->uio_resid > 0) {
		tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
		memset(read_msg, 0, argsize); /* XXX: touser KASSERT */
		RWARGS(read_msg, ioflag, tomove,
		    uio->uio_offset, cred);
		puffs_msg_setinfo(park_read, PUFFSOP_VN,
		    PUFFS_VN_READ, VPTOPNC(vp));
		puffs_msg_setdelta(park_read, tomove);

		PUFFS_MSG_ENQUEUEWAIT2(pmp, park_read, vp->v_data,
		    NULL, error);
		error = checkerr(pmp, error, __func__);
		if (error)
			break;

		if (read_msg->pvnr_resid > tomove) {
			puffs_senderr(pmp, PUFFS_ERR_READ,
			    E2BIG, "resid grew", VPTOPNC(vp));
			error = EPROTO;
			break;
		}

		error = uiomove(read_msg->pvnr_data,
		    tomove - read_msg->pvnr_resid, uio);

		/*
		 * in case the file is out of juice, resid from
		 * userspace is != 0.  and the error-case is
		 * quite obvious
		 */
		if (error || read_msg->pvnr_resid)
			break;
	}

	puffs_msgmem_release(park_read);

	return error;
}
예제 #21
0
int
puffs_directwrite(struct vnode *vp, struct uio *uio, int ioflag,
    struct ucred *cred)
{
	PUFFS_MSG_VARS(vn, write);
	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
	size_t tomove, argsize;
	int error, uflags;

	KKASSERT(vp->v_type == VREG);

	if (uio->uio_offset < 0)
		return EINVAL;
	if (uio->uio_resid == 0)
		return 0;

	error = uflags = 0;
	write_msg = NULL;

	/* tomove is non-increasing */
	tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
	argsize = sizeof(struct puffs_vnmsg_write) + tomove;
	puffs_msgmem_alloc(argsize, &park_write, (void *)&write_msg,1);

	while (uio->uio_resid > 0) {
		/* move data to buffer */
		tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
		memset(write_msg, 0, argsize); /* XXX: touser KASSERT */
		RWARGS(write_msg, ioflag, tomove,
		    uio->uio_offset, cred);
		error = uiomove(write_msg->pvnr_data, tomove, uio);
		if (error)
			break;

		/* move buffer to userspace */
		puffs_msg_setinfo(park_write, PUFFSOP_VN,
		    PUFFS_VN_WRITE, VPTOPNC(vp));
		PUFFS_MSG_ENQUEUEWAIT2(pmp, park_write, vp->v_data,
		    NULL, error);
		error = checkerr(pmp, error, __func__);
		if (error)
			break;

		if (write_msg->pvnr_resid > tomove) {
			puffs_senderr(pmp, PUFFS_ERR_WRITE,
			    E2BIG, "resid grew", VPTOPNC(vp));
			error = EPROTO;
			break;
		}

		if (PUFFS_USE_PAGECACHE(pmp))
			KKASSERT(vp->v_filesize >= uio->uio_offset);

		/* didn't move everything?  bad userspace.  bail */
		if (write_msg->pvnr_resid != 0) {
			error = EIO;
			break;
		}
	}
	puffs_msgmem_release(park_write);

	return error;
}
예제 #22
0
static int
puffs_vnop_rename(struct vop_nrename_args *ap)
{
    PUFFS_MSG_VARS(vn, rename);
    struct nchandle *fnch = ap->a_fnch;
    struct nchandle *tnch = ap->a_tnch;
    struct vnode *fdvp = ap->a_fdvp;
    struct vnode *fvp = fnch->ncp->nc_vp;
    struct vnode *tdvp = ap->a_tdvp;
    struct vnode *tvp = tnch->ncp->nc_vp;
    struct ucred *cred = ap->a_cred;
    struct puffs_mount *pmp = MPTOPUFFSMP(fdvp->v_mount);
    int error;

    if (!EXISTSOP(pmp, RENAME))
        return EOPNOTSUPP;

    error = vget(tdvp, LK_EXCLUSIVE);
    if (error != 0) {
        DPRINTF(("puffs_vnop_rename: EAGAIN on tdvp vnode %p %s\n",
                 tdvp, tnch->ncp->nc_name));
        return EAGAIN;
    }
    if (tvp != NULL) {
        error = vget(tvp, LK_EXCLUSIVE);
        if (error != 0) {
            DPRINTF(("puffs_vnop_rename: EAGAIN on tvp vnode %p %s\n",
                     tvp, tnch->ncp->nc_name));
            vput(tdvp);
            return EAGAIN;
        }
    }

    if ((fvp->v_mount != tdvp->v_mount) ||
            (tvp && (fvp->v_mount != tvp->v_mount))) {
        error = EXDEV;
        goto out;
    }

    if (tvp) {
        if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
            error = ENOTDIR;
            goto out;
        } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
            error = EISDIR;
            goto out;
        }
    }

    PUFFS_MSG_ALLOC(vn, rename);
    rename_msg->pvnr_cookie_src = VPTOPNC(fvp);
    rename_msg->pvnr_cookie_targdir = VPTOPNC(tdvp);
    if (tvp)
        rename_msg->pvnr_cookie_targ = VPTOPNC(tvp);
    else
        rename_msg->pvnr_cookie_targ = NULL;
    puffs_makecn(&rename_msg->pvnr_cn_src, &rename_msg->pvnr_cn_src_cred,
                 fnch->ncp, cred);
    puffs_makecn(&rename_msg->pvnr_cn_targ, &rename_msg->pvnr_cn_targ_cred,
                 tnch->ncp, cred);
    puffs_msg_setinfo(park_rename, PUFFSOP_VN,
                      PUFFS_VN_RENAME, VPTOPNC(fdvp));

    PUFFS_MSG_ENQUEUEWAIT2(pmp, park_rename, fdvp->v_data, NULL, error);
    PUFFS_MSG_RELEASE(rename);
    error = checkerr(pmp, error, __func__);

    if (error == 0)
        puffs_updatenode(VPTOPP(fvp), PUFFS_UPDATECTIME);

out:
    if (tvp != NULL)
        vn_unlock(tvp);
    if (tdvp != tvp)
        vn_unlock(tdvp);
    if (error == 0)
        cache_rename(fnch, tnch);
    if (tvp != NULL)
        vrele(tvp);
    vrele(tdvp);

    return error;
}
예제 #23
0
static int
puffs_vnop_lookupdotdot(struct vop_nlookupdotdot_args *ap)
{
    PUFFS_MSG_VARS(vn, lookupdotdot);
    struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_dvp->v_mount);
    struct ucred *cred = ap->a_cred;
    struct vnode *vp, *dvp = ap->a_dvp;
    struct puffs_node *dpn;
    int error;

    *ap->a_vpp = NULL;

    DPRINTF(("puffs_lookupdotdot: vnode %p\n", dvp));

    PUFFS_MSG_ALLOC(vn, lookupdotdot);
    puffs_credcvt(&lookupdotdot_msg->pvnr_cred, cred);

    puffs_msg_setinfo(park_lookupdotdot, PUFFSOP_VN,
                      PUFFS_VN_LOOKUPDOTDOT, VPTOPNC(dvp));
    PUFFS_MSG_ENQUEUEWAIT2(pmp, park_lookupdotdot, dvp->v_data, NULL,
                           error);
    DPRINTF(("puffs_lookupdotdot: return of the userspace, part %d\n",
             error));
    if (error) {
        error = checkerr(pmp, error, __func__);
        goto out;
    }

    /*
     * Check that we don't get our node back, that would cause
     * a pretty obvious deadlock.
     */
    dpn = VPTOPP(dvp);
    if (lookupdotdot_msg->pvnr_newnode == dpn->pn_cookie) {
        puffs_senderr(pmp, PUFFS_ERR_LOOKUP, EINVAL,
                      "lookupdotdot produced the same cookie",
                      lookupdotdot_msg->pvnr_newnode);
        error = EPROTO;
        goto out;
    }

    error = puffs_cookie2vnode(pmp, lookupdotdot_msg->pvnr_newnode,
                               1, &vp);
    if (error == PUFFS_NOSUCHCOOKIE) {
        error = puffs_getvnode(dvp->v_mount,
                               lookupdotdot_msg->pvnr_newnode, VDIR, 0, &vp);
        if (error) {
            puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
                              lookupdotdot_msg->pvnr_newnode, NULL, cred);
            goto out;
        }
    } else if (error) {
        puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
                          lookupdotdot_msg->pvnr_newnode, NULL, cred);
        goto out;
    }

    *ap->a_vpp = vp;
    vn_unlock(vp);

out:
    DPRINTF(("puffs_lookupdotdot: returning %d %p\n", error, *ap->a_vpp));
    PUFFS_MSG_RELEASE(lookupdotdot);
    return error;
}
예제 #24
0
static int
puffs_vnop_readdir(struct vop_readdir_args *ap)
{
    PUFFS_MSG_VARS(vn, readdir);
    struct vnode *vp = ap->a_vp;
    struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
    size_t argsize, tomove, cookiemem, cookiesmax;
    struct uio *uio = ap->a_uio;
    size_t howmuch, resid;
    int error;

    if (!EXISTSOP(pmp, READDIR))
        return EOPNOTSUPP;

    /*
     * ok, so we need: resid + cookiemem = maxreq
     * => resid + cookiesize * (resid/minsize) = maxreq
     * => resid + cookiesize/minsize * resid = maxreq
     * => (cookiesize/minsize + 1) * resid = maxreq
     * => resid = maxreq / (cookiesize/minsize + 1)
     *
     * Since cookiesize <= minsize and we're not very big on floats,
     * we approximate that to be 1.  Therefore:
     *
     * resid = maxreq / 2;
     *
     * Well, at least we didn't have to use differential equations
     * or the Gram-Schmidt process.
     *
     * (yes, I'm very afraid of this)
     */
    KKASSERT(CSIZE <= _DIRENT_RECLEN(1));

    if (ap->a_cookies) {
        KKASSERT(ap->a_ncookies != NULL);
        if (pmp->pmp_args.pa_fhsize == 0)
            return EOPNOTSUPP;
        resid = PUFFS_TOMOVE(uio->uio_resid, pmp) / 2;
        cookiesmax = resid/_DIRENT_RECLEN(1);
        cookiemem = ALIGN(cookiesmax*CSIZE); /* play safe */
    } else {
        resid = PUFFS_TOMOVE(uio->uio_resid, pmp);
        cookiesmax = 0;
        cookiemem = 0;
    }

    argsize = sizeof(struct puffs_vnmsg_readdir);
    tomove = resid + cookiemem;
    puffs_msgmem_alloc(argsize + tomove, &park_readdir,
                       (void *)&readdir_msg, 1);

    puffs_credcvt(&readdir_msg->pvnr_cred, ap->a_cred);
    readdir_msg->pvnr_offset = uio->uio_offset;
    readdir_msg->pvnr_resid = resid;
    readdir_msg->pvnr_ncookies = cookiesmax;
    readdir_msg->pvnr_eofflag = 0;
    readdir_msg->pvnr_dentoff = cookiemem;
    puffs_msg_setinfo(park_readdir, PUFFSOP_VN,
                      PUFFS_VN_READDIR, VPTOPNC(vp));
    puffs_msg_setdelta(park_readdir, tomove);

    PUFFS_MSG_ENQUEUEWAIT2(pmp, park_readdir, vp->v_data, NULL, error);
    error = checkerr(pmp, error, __func__);
    if (error)
        goto out;

    /* userspace is cheating? */
    if (readdir_msg->pvnr_resid > resid) {
        puffs_senderr(pmp, PUFFS_ERR_READDIR, E2BIG,
                      "resid grew", VPTOPNC(vp));
        ERROUT(EPROTO);
    }
    if (readdir_msg->pvnr_ncookies > cookiesmax) {
        puffs_senderr(pmp, PUFFS_ERR_READDIR, E2BIG,
                      "too many cookies", VPTOPNC(vp));
        ERROUT(EPROTO);
    }

    /* check eof */
    if (readdir_msg->pvnr_eofflag)
        *ap->a_eofflag = 1;

    /* bouncy-wouncy with the directory data */
    howmuch = resid - readdir_msg->pvnr_resid;

    /* force eof if no data was returned (getcwd() needs this) */
    if (howmuch == 0) {
        *ap->a_eofflag = 1;
        goto out;
    }

    error = uiomove(readdir_msg->pvnr_data + cookiemem, howmuch, uio);
    if (error)
        goto out;

    /* provide cookies to caller if so desired */
    if (ap->a_cookies) {
        *ap->a_cookies = kmalloc(readdir_msg->pvnr_ncookies*CSIZE,
                                 M_TEMP, M_WAITOK);
        *ap->a_ncookies = readdir_msg->pvnr_ncookies;
        memcpy(*ap->a_cookies, readdir_msg->pvnr_data,
               *ap->a_ncookies*CSIZE);
    }

    /* next readdir starts here */
    uio->uio_offset = readdir_msg->pvnr_offset;

out:
    puffs_msgmem_release(park_readdir);
    return error;
}
예제 #25
0
static int
dosetattr(struct vnode *vp, struct vattr *vap, struct ucred *cred, int flags)
{
    PUFFS_MSG_VARS(vn, setattr);
    struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
    struct puffs_node *pn = VPTOPP(vp);
    int error = 0;

    if ((vp->v_mount->mnt_flag & MNT_RDONLY) &&
            (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL
             || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL
             || vap->va_mode != (mode_t)VNOVAL))
        return EROFS;

    if ((vp->v_mount->mnt_flag & MNT_RDONLY)
            && vp->v_type == VREG && vap->va_size != VNOVAL)
        return EROFS;

    /*
     * Flush metacache first.  If we are called with some explicit
     * parameters, treat them as information overriding metacache
     * information.
     */
    if (pn->pn_stat & PNODE_METACACHE_MASK) {
        if ((pn->pn_stat & PNODE_METACACHE_ATIME)
                && vap->va_atime.tv_sec == VNOVAL)
            vap->va_atime = pn->pn_mc_atime;
        if ((pn->pn_stat & PNODE_METACACHE_CTIME)
                && vap->va_ctime.tv_sec == VNOVAL)
            vap->va_ctime = pn->pn_mc_ctime;
        if ((pn->pn_stat & PNODE_METACACHE_MTIME)
                && vap->va_mtime.tv_sec == VNOVAL)
            vap->va_mtime = pn->pn_mc_mtime;
        if ((pn->pn_stat & PNODE_METACACHE_SIZE)
                && vap->va_size == VNOVAL)
            vap->va_size = pn->pn_mc_size;

        pn->pn_stat &= ~PNODE_METACACHE_MASK;
    }

    PUFFS_MSG_ALLOC(vn, setattr);
    (void)memcpy(&setattr_msg->pvnr_va, vap, sizeof(struct vattr));
    puffs_credcvt(&setattr_msg->pvnr_cred, cred);
    puffs_msg_setinfo(park_setattr, PUFFSOP_VN,
                      PUFFS_VN_SETATTR, VPTOPNC(vp));
    if (flags & SETATTR_ASYNC)
        puffs_msg_setfaf(park_setattr);

    puffs_msg_enqueue(pmp, park_setattr);
    if ((flags & SETATTR_ASYNC) == 0)
        error = puffs_msg_wait2(pmp, park_setattr, vp->v_data, NULL);
    PUFFS_MSG_RELEASE(setattr);
    if ((flags & SETATTR_ASYNC) == 0) {
        error = checkerr(pmp, error, __func__);
        if (error)
            return error;
    } else {
        error = 0;
    }

    if (vap->va_size != VNOVAL) {
        pn->pn_serversize = vap->va_size;
        if (flags & SETATTR_CHSIZE)
            puffs_meta_setsize(vp, vap->va_size, 0);
    }

    return 0;
}