Add support for non-blocking I/O. Also fixes problems the providers
and popen() caused with concurrent access. This should match the original portalfs in functionality now.
This commit is contained in:
parent
0bc323f5cd
commit
e395775675
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: puffs_portal.c,v 1.1 2007/07/02 18:35:14 pooka Exp $ */
|
||||
/* $NetBSD: puffs_portal.c,v 1.2 2007/07/08 10:43:03 pooka Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
|
||||
@ -27,6 +27,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
@ -51,9 +52,10 @@ static void usage(void);
|
||||
PUFFSOP_PROTOS(portal);
|
||||
|
||||
#define PORTAL_ROOT NULL
|
||||
#define METADATASIZE (sizeof(int) + sizeof(size_t))
|
||||
|
||||
qelem q;
|
||||
int readcfg;
|
||||
int readcfg, sigchild;
|
||||
const char *cfg;
|
||||
|
||||
static void
|
||||
@ -71,6 +73,13 @@ sighup(int sig)
|
||||
readcfg = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
sigcry(int sig)
|
||||
{
|
||||
|
||||
sigchild = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
portal_loopfn(struct puffs_usermount *pu)
|
||||
{
|
||||
@ -78,6 +87,273 @@ portal_loopfn(struct puffs_usermount *pu)
|
||||
if (readcfg)
|
||||
conf_read(&q, cfg);
|
||||
readcfg = 0;
|
||||
|
||||
if (sigchild) {
|
||||
sigchild = 0;
|
||||
while (waitpid(-1, NULL, WNOHANG) != -1)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
#define PUFBUF_FD 1
|
||||
#define PUFBUF_DATA 2
|
||||
|
||||
#define CMSIZE (sizeof(struct cmsghdr) + sizeof(int))
|
||||
|
||||
/* receive file descriptor produced by our child process */
|
||||
static int
|
||||
readfd(struct puffs_framebuf *pufbuf, int fd, int *done)
|
||||
{
|
||||
struct cmsghdr *cmp;
|
||||
struct msghdr msg;
|
||||
struct iovec iov;
|
||||
ssize_t n;
|
||||
int error, rv;
|
||||
|
||||
rv = 0;
|
||||
cmp = emalloc(CMSG_LEN(sizeof(int)));
|
||||
|
||||
iov.iov_base = &error;
|
||||
iov.iov_len = sizeof(int);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_control = cmp;
|
||||
msg.msg_controllen = CMSG_LEN(sizeof(int));
|
||||
|
||||
n = recvmsg(fd, &msg, 0);
|
||||
if (n == -1) {
|
||||
rv = errno;
|
||||
goto out;
|
||||
}
|
||||
if (n == 0) {
|
||||
rv = ECONNRESET;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* the data for the server */
|
||||
puffs_framebuf_putdata_atoff(pufbuf, 0, &error, sizeof(int));
|
||||
puffs_framebuf_putdata_atoff(pufbuf, sizeof(int),
|
||||
CMSG_DATA(cmp), sizeof(int));
|
||||
*done = 1;
|
||||
|
||||
out:
|
||||
free(cmp);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* receive data from provider */
|
||||
static int
|
||||
readdata(struct puffs_framebuf *pufbuf, int fd, int *done)
|
||||
{
|
||||
char buf[1024];
|
||||
size_t max;
|
||||
ssize_t n;
|
||||
int moved = 0;
|
||||
|
||||
/* we're always done */
|
||||
*done = 1;
|
||||
|
||||
/* don't override metadata */
|
||||
if (puffs_framebuf_telloff(pufbuf) == 0)
|
||||
puffs_framebuf_seekset(pufbuf, METADATASIZE);
|
||||
puffs_framebuf_getdata_atoff(pufbuf, sizeof(int), &max, sizeof(size_t));
|
||||
|
||||
do {
|
||||
n = read(fd, buf, MIN(sizeof(buf), max));
|
||||
if (n == 0) {
|
||||
if (moved)
|
||||
return 0;
|
||||
else
|
||||
return -1; /* caught by read */
|
||||
}
|
||||
if (n < 0) {
|
||||
if (errno != EAGAIN)
|
||||
return errno;
|
||||
break;
|
||||
}
|
||||
|
||||
puffs_framebuf_putdata(pufbuf, buf, n);
|
||||
moved = 1;
|
||||
max -= n;
|
||||
} while (n == sizeof(buf) || max == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
portal_frame_rf(struct puffs_usermount *pu, struct puffs_framebuf *pufbuf,
|
||||
int fd, int *done)
|
||||
{
|
||||
int type;
|
||||
|
||||
if (puffs_framebuf_getdata_atoff(pufbuf, 0, &type, sizeof(int)) == -1)
|
||||
return EINVAL;
|
||||
|
||||
if (type == PUFBUF_FD)
|
||||
return readfd(pufbuf, fd, done);
|
||||
else if (type == PUFBUF_DATA)
|
||||
return readdata(pufbuf, fd, done);
|
||||
else
|
||||
abort();
|
||||
}
|
||||
|
||||
static int
|
||||
portal_frame_wf(struct puffs_usermount *pu, struct puffs_framebuf *pufbuf,
|
||||
int fd, int *done)
|
||||
{
|
||||
void *win;
|
||||
size_t pbsize, pboff, winlen;
|
||||
ssize_t n;
|
||||
int moved, error;
|
||||
|
||||
pboff = puffs_framebuf_telloff(pufbuf);
|
||||
pbsize = puffs_framebuf_tellsize(pufbuf);
|
||||
error = 0;
|
||||
|
||||
do {
|
||||
assert(pbsize > pboff);
|
||||
winlen = pbsize - pboff;
|
||||
if (puffs_framebuf_getwindow(pufbuf, pboff, &win, &winlen)==-1)
|
||||
return errno;
|
||||
n = write(fd, win, winlen);
|
||||
if (n == 0) {
|
||||
if (moved)
|
||||
return 0;
|
||||
else {
|
||||
error = -1; /* caught by node_write */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n < 0) {
|
||||
if (errno != EAGAIN) {
|
||||
error = errno;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
pboff += n;
|
||||
puffs_framebuf_seekset(pufbuf, pboff);
|
||||
moved = 1;
|
||||
} while (pboff != pbsize);
|
||||
|
||||
*done = 1;
|
||||
puffs_framebuf_putdata_atoff(pufbuf, 0, &pboff, sizeof(size_t));
|
||||
return error;
|
||||
}
|
||||
|
||||
static void
|
||||
portal_frame_notify(struct puffs_usermount *pu, int fd, int what)
|
||||
{
|
||||
|
||||
/* nada */
|
||||
}
|
||||
|
||||
/* transfer file descriptor to master file server */
|
||||
static int
|
||||
sendfd(int s, int fd, int error)
|
||||
{
|
||||
struct cmsghdr *cmp;
|
||||
struct msghdr msg;
|
||||
struct iovec iov;
|
||||
ssize_t n;
|
||||
int rv;
|
||||
|
||||
rv = 0;
|
||||
cmp = emalloc(CMSG_LEN(sizeof(int)));
|
||||
|
||||
iov.iov_base = &error;
|
||||
iov.iov_len = sizeof(int);
|
||||
|
||||
cmp->cmsg_level = SOL_SOCKET;
|
||||
cmp->cmsg_type = SCM_RIGHTS;
|
||||
cmp->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_control = cmp;
|
||||
msg.msg_controllen = CMSG_LEN(sizeof(int));
|
||||
*(int *)CMSG_DATA(cmp) = fd;
|
||||
|
||||
n = sendmsg(s, &msg, 0);
|
||||
if (n == -1)
|
||||
rv = errno;
|
||||
else if (n < sizeof(int))
|
||||
rv = EPROTO;
|
||||
|
||||
free(cmp);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Produce I/O file descriptor by forking (like original portald).
|
||||
*
|
||||
* child: run provider and transfer produced fd to parent
|
||||
* parent: yield until child produces fd. receive it and store it.
|
||||
*/
|
||||
static int
|
||||
provide(struct puffs_cc *pcc, struct portal_node *portn,
|
||||
struct portal_cred *portc, char **v)
|
||||
{
|
||||
struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
|
||||
struct puffs_framebuf *pufbuf;
|
||||
int s[2];
|
||||
int fd, error;
|
||||
int data;
|
||||
|
||||
pufbuf = puffs_framebuf_make();
|
||||
if (pufbuf == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
data = PUFBUF_FD;
|
||||
if (puffs_framebuf_putdata(pufbuf, &data, sizeof(int)) == -1)
|
||||
return errno;
|
||||
|
||||
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, s) == -1) {
|
||||
puffs_framebuf_destroy(pufbuf);
|
||||
return errno;
|
||||
}
|
||||
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
return errno;
|
||||
case 0:
|
||||
error = activate_argv(portc, portn->path, v, &fd);
|
||||
sendfd(s[1], fd, error);
|
||||
exit(0);
|
||||
default:
|
||||
puffs_framev_addfd(pu, s[0], PUFFS_FBIO_READ);
|
||||
puffs_framev_enqueue_directreceive(pcc, s[0], pufbuf, 0);
|
||||
puffs_framev_removefd(pu, s[0], 0);
|
||||
close(s[0]);
|
||||
close(s[1]);
|
||||
if (puffs_framebuf_tellsize(pufbuf) != 2*sizeof(int)) {
|
||||
puffs_framebuf_destroy(pufbuf);
|
||||
return EIO;
|
||||
}
|
||||
|
||||
puffs_framebuf_getdata_atoff(pufbuf, 0, &error, sizeof(int));
|
||||
puffs_framebuf_getdata_atoff(pufbuf, sizeof(int),
|
||||
&fd, sizeof(int));
|
||||
puffs_framebuf_destroy(pufbuf);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
data = 1;
|
||||
if (ioctl(fd, FIONBIO, &data) == -1)
|
||||
return errno;
|
||||
|
||||
if (puffs_framev_addfd(pu, fd, PUFFS_FBIO_WRITE) == -1)
|
||||
return errno;
|
||||
|
||||
portn->fd = fd;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
@ -140,6 +416,9 @@ main(int argc, char *argv[])
|
||||
|
||||
if (signal(SIGHUP, sighup) == SIG_ERR)
|
||||
warn("cannot set sighup handler");
|
||||
if (signal(SIGCHLD, sigcry) == SIG_ERR)
|
||||
err(1, "cannot set sigchild handler");
|
||||
|
||||
readcfg = 0;
|
||||
cfg = argv[0];
|
||||
if (*cfg != '/')
|
||||
@ -149,6 +428,8 @@ main(int argc, char *argv[])
|
||||
err(1, "cannot read cfg \"%s\"", cfg);
|
||||
|
||||
puffs_ml_setloopfn(pu, portal_loopfn);
|
||||
puffs_framev_init(pu, portal_frame_rf, portal_frame_wf,
|
||||
NULL, portal_frame_notify);
|
||||
if (puffs_mount(pu, argv[1], mntflags, PORTAL_ROOT) == -1)
|
||||
err(1, "mount");
|
||||
if (puffs_mainloop(pu, lflags) == -1)
|
||||
@ -259,7 +540,6 @@ portal_node_open(struct puffs_cc *pcc, void *opc, int mode,
|
||||
struct portal_node *portn = opc;
|
||||
struct portal_cred portc;
|
||||
char **v;
|
||||
int fd;
|
||||
|
||||
if (opc == PORTAL_ROOT)
|
||||
return 0;
|
||||
@ -269,29 +549,63 @@ portal_node_open(struct puffs_cc *pcc, void *opc, int mode,
|
||||
return ENOENT;
|
||||
|
||||
credtr(&portc, pcr, mode);
|
||||
if (activate_argv(&portc, portn->path, v, &fd) != 0)
|
||||
return ENOENT;
|
||||
|
||||
portn->fd = fd;
|
||||
|
||||
return 0;
|
||||
return provide(pcc, portn, &portc, v);
|
||||
}
|
||||
|
||||
int
|
||||
portal_node_read(struct puffs_cc *pcc, void *opc, uint8_t *buf, off_t offset,
|
||||
size_t *resid, const struct puffs_cred *pcr, int ioflag)
|
||||
{
|
||||
struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
|
||||
struct portal_node *portn = opc;
|
||||
ssize_t n;
|
||||
struct puffs_framebuf *pufbuf;
|
||||
size_t xfersize, winsize, boff;
|
||||
void *win;
|
||||
int rv, error;
|
||||
int data;
|
||||
|
||||
assert(opc != PORTAL_ROOT);
|
||||
error = 0;
|
||||
|
||||
n = read(portn->fd, buf, *resid);
|
||||
if (n == -1)
|
||||
return errno;
|
||||
/* if we can't (re-)enable it, treat it as EOF */
|
||||
rv = puffs_framev_enablefd(pu, portn->fd, PUFFS_FBIO_READ);
|
||||
if (rv == -1)
|
||||
return 0;
|
||||
|
||||
*resid -= n;
|
||||
return 0;
|
||||
pufbuf = puffs_framebuf_make();
|
||||
data = PUFBUF_DATA;
|
||||
puffs_framebuf_putdata(pufbuf, &data, sizeof(int));
|
||||
puffs_framebuf_putdata(pufbuf, resid, sizeof(size_t));
|
||||
|
||||
rv = puffs_framev_enqueue_directreceive(pcc, portn->fd, pufbuf, 0);
|
||||
if (rv == -1) {
|
||||
error = errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
xfersize = puffs_framebuf_tellsize(pufbuf) - METADATASIZE;
|
||||
*resid -= xfersize;
|
||||
boff = 0;
|
||||
do {
|
||||
winsize = xfersize;
|
||||
rv = puffs_framebuf_getwindow(pufbuf, METADATASIZE,
|
||||
&win, &winsize);
|
||||
assert(rv == 0);
|
||||
assert(winsize > 0);
|
||||
|
||||
memcpy(buf + boff, win, winsize);
|
||||
xfersize -= winsize;
|
||||
boff += winsize;
|
||||
} while (xfersize);
|
||||
|
||||
out:
|
||||
puffs_framev_disablefd(pu, portn->fd, PUFFS_FBIO_READ);
|
||||
puffs_framebuf_destroy(pufbuf);
|
||||
|
||||
/* a trickery, from readdata() */
|
||||
if (error == -1)
|
||||
return 0;
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
@ -299,15 +613,30 @@ portal_node_write(struct puffs_cc *pcc, void *opc, uint8_t *buf, off_t offset,
|
||||
size_t *resid, const struct puffs_cred *pcr, int ioflag)
|
||||
{
|
||||
struct portal_node *portn = opc;
|
||||
ssize_t n;
|
||||
struct puffs_framebuf *pufbuf;
|
||||
size_t written;
|
||||
int error, rv;
|
||||
|
||||
assert(opc != PORTAL_ROOT);
|
||||
|
||||
n = write(portn->fd, buf, *resid);
|
||||
if (n == -1)
|
||||
return errno;
|
||||
pufbuf = puffs_framebuf_make();
|
||||
puffs_framebuf_putdata(pufbuf, buf, *resid);
|
||||
|
||||
*resid -= n;
|
||||
error = 0;
|
||||
if (puffs_framev_enqueue_directsend(pcc, portn->fd, pufbuf, 0) == -1) {
|
||||
error = errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rv = puffs_framebuf_getdata_atoff(pufbuf, 0, &written, sizeof(size_t));
|
||||
assert(rv == 0);
|
||||
assert(written <= *resid);
|
||||
*resid -= written;
|
||||
|
||||
out:
|
||||
puffs_framebuf_destroy(pufbuf);
|
||||
if (error == -1)
|
||||
error = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -316,6 +645,9 @@ portal_node_inactive(struct puffs_cc *pcc, void *opc,
|
||||
const struct puffs_cid *pcid)
|
||||
{
|
||||
|
||||
if (opc == PORTAL_ROOT)
|
||||
return 0;
|
||||
|
||||
puffs_setback(pcc, PUFFS_SETBACK_NOREF_N1);
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user