From baf8f8bdbf1fd7ed2206dbd5aec9fac1c1e2ef3e Mon Sep 17 00:00:00 2001 From: Jian Jun Chen Date: Wed, 12 Dec 2018 14:14:53 +0800 Subject: [PATCH] dm: virtio-input: apply new mevent API to avoid race issue Teardown callback is provided when mevent_add is called and it is used to free the virtio-input resources. Tracked-On: #1877 Signed-off-by: Jian Jun Chen Acked-by: Yin Fengwei --- devicemodel/hw/pci/virtio/virtio_input.c | 106 ++++++++++++----------- 1 file changed, 55 insertions(+), 51 deletions(-) diff --git a/devicemodel/hw/pci/virtio/virtio_input.c b/devicemodel/hw/pci/virtio/virtio_input.c index 9a4e4fd04..15b0d6b81 100644 --- a/devicemodel/hw/pci/virtio/virtio_input.c +++ b/devicemodel/hw/pci/virtio/virtio_input.c @@ -543,12 +543,32 @@ virtio_input_get_config(struct virtio_input *vi, uint8_t select, return found; } +static void +virtio_input_teardown(void *param) +{ + struct virtio_input *vi; + + vi = (struct virtio_input *)param; + if (vi) { + pthread_mutex_destroy(&vi->mtx); + if (vi->event_queue) + free(vi->event_queue); + if (vi->fd > 0) + close(vi->fd); + if (vi->evdev) + free(vi->evdev); + if (vi->serial) + free(vi->serial); + free(vi); + vi = NULL; + } +} + static int virtio_input_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts) { struct virtio_input *vi; pthread_mutexattr_t attr; - bool mutex_initialized = false; char *opt; int flags, ver; int rc; @@ -570,27 +590,27 @@ virtio_input_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts) opt = strsep(&opts, ","); if (!opt) { WPRINTF(("%s: evdev path is NULL\n", __func__)); - goto fail; + goto opt_fail; } vi->evdev = strdup(opt); if (!vi->evdev) { WPRINTF(("%s: strdup failed\n", __func__)); - goto fail; + goto opt_fail; } if (opts) { vi->serial = strdup(opts); if (!vi->serial) { WPRINTF(("%s: strdup serial failed\n", __func__)); - goto fail; + goto serial_fail; } } vi->fd = open(vi->evdev, O_RDWR); if (vi->fd < 0) { WPRINTF(("open %s failed %d\n", vi->evdev, errno)); - goto fail; + goto open_fail; } flags = fcntl(vi->fd, F_GETFL); fcntl(vi->fd, F_SETFL, flags | O_NONBLOCK); @@ -598,13 +618,13 @@ virtio_input_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts) rc = ioctl(vi->fd, EVIOCGVERSION, &ver); /* is it a evdev device? */ if (rc < 0) { WPRINTF(("%s: get version failed\n", vi->evdev)); - goto fail; + goto evdev_fail; } rc = ioctl(vi->fd, EVIOCGRAB, 1); /* exclusive access */ if (rc < 0) { WPRINTF(("%s: grab device failed %d\n", vi->evdev, errno)); - goto fail; + goto evdev_fail; } /* init mutex attribute properly to avoid deadlock */ @@ -619,7 +639,6 @@ virtio_input_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts) if (rc) DPRINTF(("vtinput: pthread_mutex_init failed with " "error %d!\n", rc)); - mutex_initialized = (rc == 0) ? true : false; vi->event_qsize = VIRTIO_INPUT_PACKET_SIZE; vi->event_qindex = 0; @@ -627,13 +646,14 @@ virtio_input_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts) sizeof(struct virtio_input_event_elem)); if (!vi->event_queue) { WPRINTF(("vtinput: could not alloc event queue buf\n")); - goto fail; + goto evqueue_fail; } - vi->mevp = mevent_add(vi->fd, EVF_READ, virtio_input_read_event, vi, NULL, NULL); + vi->mevp = mevent_add(vi->fd, EVF_READ, virtio_input_read_event, vi, + virtio_input_teardown, vi); if (vi->mevp == NULL) { WPRINTF(("vtinput: could not register event\n")); - goto fail; + goto mevent_fail; } virtio_linkup(&vi->base, &virtio_input_ops, vi, dev, vi->queues, BACKEND_VBSU); @@ -665,32 +685,29 @@ virtio_input_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts) return rc; fail: - if (vi) { - if (mutex_initialized) - pthread_mutex_destroy(&vi->mtx); - if (vi->event_queue) { - free(vi->event_queue); - vi->event_queue = NULL; - } - if (vi->mevp) { - mevent_delete(vi->mevp); - vi->mevp = NULL; - } - if (vi->fd > 0) { - close(vi->fd); - vi->fd = -1; - } - if (vi->serial) { - free(vi->serial); - vi->serial = NULL; - } - if (vi->evdev) { - free(vi->evdev); - vi->evdev = NULL; - } - free(vi); - vi = NULL; + /* all resources will be freed in the teardown callback */ + mevent_delete(vi->mevp); + return -1; + +mevent_fail: + free(vi->event_queue); + vi->event_queue = NULL; +evqueue_fail: + pthread_mutex_destroy(&vi->mtx); +evdev_fail: + close(vi->fd); + vi->fd = -1; +open_fail: + if (vi->serial) { + free(vi->serial); + vi->serial = NULL; } +serial_fail: + free(vi->evdev); + vi->evdev = NULL; +opt_fail: + free(vi); + vi = NULL; return -1; } @@ -700,21 +717,8 @@ virtio_input_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts) struct virtio_input *vi; vi = (struct virtio_input *)dev->arg; - if (vi) { - pthread_mutex_destroy(&vi->mtx); - if (vi->event_queue) - free(vi->event_queue); - if (vi->mevp) - mevent_delete(vi->mevp); - if (vi->fd > 0) - close(vi->fd); - if (vi->evdev) - free(vi->evdev); - if (vi->serial) - free(vi->serial); - free(vi); - vi = NULL; - } + if (vi && vi->mevp) + mevent_delete(vi->mevp); } struct pci_vdev_ops pci_ops_virtio_input = {