Exemple #1
0
void
puffs_parkdone_asyncbioread(struct puffs_mount *pmp,
	struct puffs_req *preq, void *arg)
{
	struct puffs_vnmsg_read *read_msg = (void *)preq;
	struct buf *bp = arg;
	size_t moved;

	DPRINTF(("%s\n", __func__));

	bp->b_error = checkerr(pmp, preq->preq_rv, __func__);
	if (bp->b_error == 0) {
		if (read_msg->pvnr_resid > bp->b_bcount) {
			puffs_senderr(pmp, PUFFS_ERR_READ, E2BIG,
			    "resid grew", preq->preq_cookie);
			bp->b_error = E2BIG;
		} else {
			moved = bp->b_bcount - read_msg->pvnr_resid;
			bp->b_resid = read_msg->pvnr_resid;

			memcpy(bp->b_data, read_msg->pvnr_data, moved);
		}
	}

	biodone(bp);
}
Exemple #2
0
void
puffs_parkdone_asyncbiowrite(struct puffs_mount *pmp,
	struct puffs_req *preq, void *arg)
{
	struct puffs_vnmsg_write *write_msg = (void *)preq;
	struct buf *bp = arg;

	DPRINTF(("%s\n", __func__));

	bp->b_error = checkerr(pmp, preq->preq_rv, __func__);
	if (bp->b_error == 0) {
		if (write_msg->pvnr_resid > bp->b_bcount) {
			puffs_senderr(pmp, PUFFS_ERR_WRITE, E2BIG,
			    "resid grew", preq->preq_cookie);
			bp->b_error = E2BIG;
		} else {
			bp->b_resid = write_msg->pvnr_resid;
		}
	}

	biodone(bp);
}
Exemple #3
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;
}
Exemple #4
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;
}
Exemple #5
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;
}
Exemple #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;
}
Exemple #7
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;
}
Exemple #8
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;
}