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); }
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; }
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; }
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; }