mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-04 21:29:43 +00:00
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:
parent
baf8f8bdbf
commit
4f36244fef
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user