dm: virtio-console: apply new mevent API to avoid race issue

Teardown callback is provided when mevent_add is called. A ref_count
is added to virtio_console data structure. Teardown callback needs to
free the resources of the backend and when the ref_count of the
virtio_console is zero the whole virtio-console is freed.

Tracked-On: #1877
Signed-off-by: Jian Jun Chen <jian.jun.chen@intel.com>
Acked-by: Yin Fengwei <fengwei.yin@intel.com>
This commit is contained in:
Jian Jun Chen 2018-12-12 14:20:46 +08:00 committed by wenlingz
parent baf8f8bdbf
commit 4f36244fef

View File

@ -124,6 +124,7 @@ struct virtio_console {
struct virtio_console_port control_port;
struct virtio_console_port ports[VIRTIO_CONSOLE_MAXPORTS];
struct virtio_console_config *config;
int ref_count;
};
struct virtio_console_config {
@ -153,6 +154,7 @@ static void virtio_console_control_send(struct virtio_console *,
struct virtio_console_control *, const void *, size_t);
static void virtio_console_announce_port(struct virtio_console_port *);
static void virtio_console_open_port(struct virtio_console_port *, bool);
static void virtio_console_teardown_backend(void *);
static struct virtio_ops virtio_console_ops = {
"vtcon", /* our name */
@ -413,17 +415,10 @@ virtio_console_reset_backend(struct virtio_console_backend *be)
if (!be)
return;
if (be->evp)
mevent_disable(be->evp);
if (be->fd != STDIN_FILENO)
mevent_delete_close(be->evp);
else
mevent_delete(be->evp);
if (be->be_type == VIRTIO_CONSOLE_BE_PTY && be->pts_fd > 0) {
close(be->pts_fd);
be->pts_fd = -1;
}
be->evp = NULL;
close(be->fd);
be->fd = -1;
be->open = false;
}
@ -679,12 +674,14 @@ virtio_console_add_backend(struct virtio_console *console,
if (virtio_console_backend_can_read(be_type)) {
if (isatty(fd)) {
be->evp = mevent_add(fd, EVF_READ,
virtio_console_backend_read, be, NULL, NULL);
virtio_console_backend_read, be,
virtio_console_teardown_backend, be);
if (be->evp == NULL) {
WPRINTF(("vtcon: mevent_add failed\n"));
error = -1;
goto out;
}
console->ref_count++;
}
}
@ -694,8 +691,6 @@ virtio_console_add_backend(struct virtio_console *console,
out:
if (error != 0) {
if (be) {
if (be->evp)
mevent_delete(be->evp);
if (be->port) {
be->port->enabled = false;
be->port->arg = NULL;
@ -732,18 +727,71 @@ virtio_console_close_backend(struct virtio_console_backend *be)
break;
}
be->fd = -1;
be->open = false;
if (be->be_type != VIRTIO_CONSOLE_BE_STDIO && be->fd > 0) {
close(be->fd);
be->fd = -1;
}
memset(be->port, 0, sizeof(*be->port));
free(be);
}
static void
virtio_console_destroy(struct virtio_console *console)
{
if (console) {
if (console->config)
free(console->config);
free(console);
console = NULL;
}
}
static void
virtio_console_teardown_backend(void *param)
{
struct virtio_console *console = NULL;
struct virtio_console_backend *be;
be = (struct virtio_console_backend *)param;
if (!be)
return;
if (be->port)
console = be->port->console;
virtio_console_close_backend(be);
if (console) {
console->ref_count--;
/* free virtio_console if this is the last backend */
if (console->ref_count == 0)
virtio_console_destroy(console);
}
}
static int
virtio_console_close_all(struct virtio_console *console)
{
int i;
int i, rc = 0;
struct virtio_console_port *port;
struct virtio_console_backend *be;
/*
* we should close ports without mevent first.
* port->enabled is reset to false when a backend is closed.
*/
for (i = 0; i < console->nports; i++) {
port = &console->ports[i];
if (!port->enabled)
continue;
be = (struct virtio_console_backend *)port->arg;
if (be && !be->evp)
virtio_console_close_backend(be);
}
for (i = 0; i < console->nports; i++) {
port = &console->ports[i];
@ -751,18 +799,14 @@ virtio_console_close_all(struct virtio_console *console)
continue;
be = (struct virtio_console_backend *)port->arg;
if (be) {
if (be->evp) {
if (be->fd != STDIN_FILENO)
mevent_delete_close(be->evp);
else
mevent_delete(be->evp);
}
virtio_console_close_backend(be);
free(be);
if (be && be->evp) {
/* resources will be freed in the teardown callback */
mevent_delete(be->evp);
rc = 1;
}
}
return rc;
}
static enum virtio_console_be_type
@ -914,13 +958,18 @@ static void
virtio_console_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
{
struct virtio_console *console;
int rc;
console = (struct virtio_console *)dev->arg;
if (console) {
virtio_console_close_all(console);
if (console->config)
free(console->config);
free(console);
rc = virtio_console_close_all(console);
/*
* if all the ports are without mevent attached,
* no teardown will be called, we should destroy
* console here explicitly.
*/
if (!rc)
virtio_console_destroy(console);
}
}