Пример #1
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);
}
Пример #2
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;
}
Пример #3
0
void
puffs_makecn(struct puffs_kcn *pkcn, struct puffs_kcred *pkcr,
	const struct componentname *cn, int full)
{

	pkcn->pkcn_nameiop = cn->cn_nameiop;
	pkcn->pkcn_flags = cn->cn_flags;

	if (full) {
		(void)strcpy(pkcn->pkcn_name, cn->cn_nameptr);
	} else {
		(void)memcpy(pkcn->pkcn_name, cn->cn_nameptr, cn->cn_namelen);
		pkcn->pkcn_name[cn->cn_namelen] = '\0';
	}
	pkcn->pkcn_namelen = cn->cn_namelen;
	pkcn->pkcn_consume = 0;

	puffs_credcvt(pkcr, cn->cn_cred);
}
Пример #4
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;
}
Пример #5
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;
}
Пример #6
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;
}
Пример #7
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;
}
Пример #8
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;
}