Exemple #1
0
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);
}
Exemple #2
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 #3
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 #4
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;
}