#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: puffs_rumpglue.c,v 1.16 2016/01/26 23:12:17 pooka Exp $");
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/file.h>
#include <sys/filedesc.h>
#include <sys/kthread.h>
#include <sys/mount.h>
#include <dev/putter/putter.h>
#include <dev/putter/putter_sys.h>
#include <rump-sys/vfs.h>
#include <rump/rump.h>
#include <rump/rumpuser.h>
void putterattach(void);
dev_type_open(puttercdopen);
struct ptargs {
int comfd;
int fpfd;
struct filedesc *fdp;
};
#define BUFSIZE (64*1024)
extern int hz;
static void
readthread(void *arg)
{
struct ptargs *pap = arg;
struct file *fp;
register_t rv;
char *buf;
off_t off;
int error, inited;
buf = kmem_alloc(BUFSIZE, KM_SLEEP);
inited = 0;
retry:
kpause(NULL, 0, hz/4, NULL);
for (;;) {
size_t n;
off = 0;
fp = fd_getfile(pap->fpfd);
if (fp == NULL)
error = EINVAL;
else
error = dofileread(pap->fpfd, fp, buf, BUFSIZE,
&off, 0, &rv);
if (error) {
if (error == ENOENT && inited == 0)
goto retry;
if (error == ENXIO)
break;
panic("fileread failed: %d", error);
}
inited = 1;
while (rv) {
struct rumpuser_iovec iov;
iov.iov_base = buf;
iov.iov_len = rv;
error = rumpuser_iovwrite(pap->comfd, &iov, 1,
RUMPUSER_IOV_NOSEEK, &n);
if (error)
panic("fileread failed: %d", error);
if (n == 0)
panic("fileread failed: closed");
rv -= n;
}
}
kthread_exit(0);
}
static void
writethread(void *arg)
{
struct ptargs *pap = arg;
struct file *fp;
struct putter_hdr *phdr;
register_t rv;
char *buf;
off_t off;
size_t toread;
int error;
buf = kmem_alloc(BUFSIZE, KM_SLEEP);
phdr = (struct putter_hdr *)buf;
for (;;) {
size_t n;
off = 0;
toread = sizeof(struct putter_hdr);
do {
struct rumpuser_iovec iov;
iov.iov_base = buf+off;
iov.iov_len = toread;
error = rumpuser_iovread(pap->comfd, &iov, 1,
RUMPUSER_IOV_NOSEEK, &n);
if (error)
panic("rumpuser_read %zd %d", n, error);
if (n == 0)
goto out;
off += n;
if (off >= sizeof(struct putter_hdr))
toread = phdr->pth_framelen - off;
else
toread = off - sizeof(struct putter_hdr);
} while (toread);
off = 0;
rv = 0;
fp = fd_getfile(pap->fpfd);
if (fp == NULL)
error = EINVAL;
else
error = dofilewrite(pap->fpfd, fp, buf,
phdr->pth_framelen, &off, 0, &rv);
if (error == ENXIO)
goto out;
KASSERT(rv == phdr->pth_framelen);
}
out:
kthread_exit(0);
}
int
rump_syspuffs_glueinit(int fd, int *newfd)
{
struct ptargs *pap;
int rv;
if ((rv = rump_init()) != 0)
return rv;
putterattach();
rv = puttercdopen(makedev(178, 0), 0, 0, curlwp);
if (rv && rv != EMOVEFD)
return rv;
pap = kmem_alloc(sizeof(struct ptargs), KM_SLEEP);
pap->comfd = fd;
pap->fpfd = curlwp->l_dupfd;
pap->fdp = curlwp->l_proc->p_fd;
rv = kthread_create(PRI_NONE, 0, NULL, readthread, pap, NULL,
"rputter");
if (rv)
return rv;
rv = kthread_create(PRI_NONE, 0, NULL, writethread, pap, NULL,
"wputter");
if (rv)
return rv;
*newfd = curlwp->l_dupfd;
return 0;
}