virtio/blk: Reset virtqueue
Move pthread creation to init_vq, and kill the thread in exit_vq.
Initialize the virtqueue states at runtime.
All in-flight I/O is canceled with the virtqueue pthreads, except for AIO
threads, but after reading the code I'm not sure if AIO has ever worked
anyway.
Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
Signed-off-by: Julien Thierry <julien.thierry@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
diff --git a/virtio/blk.c b/virtio/blk.c
index 6a6b3b7..a57df2e 100644
--- a/virtio/blk.c
+++ b/virtio/blk.c
@@ -178,25 +178,6 @@
{
}
-static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 page_size, u32 align,
- u32 pfn)
-{
- struct blk_dev *bdev = dev;
- struct virt_queue *queue;
- void *p;
-
- compat__remove_message(compat_id);
-
- queue = &bdev->vqs[vq];
- queue->pfn = pfn;
- p = virtio_get_vq(kvm, queue->pfn, page_size);
-
- vring_init(&queue->vring, VIRTIO_BLK_QUEUE_SIZE, p, align);
- virtio_init_device_vq(&bdev->vdev, queue);
-
- return 0;
-}
-
static void *virtio_blk_thread(void *dev)
{
struct blk_dev *bdev = dev;
@@ -216,6 +197,56 @@
return NULL;
}
+static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 page_size, u32 align,
+ u32 pfn)
+{
+ unsigned int i;
+ struct blk_dev *bdev = dev;
+ struct virt_queue *queue;
+ void *p;
+
+ compat__remove_message(compat_id);
+
+ queue = &bdev->vqs[vq];
+ queue->pfn = pfn;
+ p = virtio_get_vq(kvm, queue->pfn, page_size);
+
+ vring_init(&queue->vring, VIRTIO_BLK_QUEUE_SIZE, p, align);
+ virtio_init_device_vq(&bdev->vdev, queue);
+
+ if (vq != 0)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(bdev->reqs); i++) {
+ bdev->reqs[i] = (struct blk_dev_req) {
+ .bdev = bdev,
+ .kvm = kvm,
+ };
+ }
+
+ mutex_init(&bdev->mutex);
+ bdev->io_efd = eventfd(0, 0);
+ if (bdev->io_efd < 0)
+ return -errno;
+
+ if (pthread_create(&bdev->io_thread, NULL, virtio_blk_thread, bdev))
+ return -errno;
+
+ return 0;
+}
+
+static void exit_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+ struct blk_dev *bdev = dev;
+
+ if (vq != 0)
+ return;
+
+ close(bdev->io_efd);
+ pthread_cancel(bdev->io_thread);
+ pthread_join(bdev->io_thread, NULL);
+}
+
static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
{
struct blk_dev *bdev = dev;
@@ -259,6 +290,7 @@
.set_guest_features = set_guest_features,
.get_vq_count = get_vq_count,
.init_vq = init_vq,
+ .exit_vq = exit_vq,
.notify_status = notify_status,
.notify_vq = notify_vq,
.get_vq = get_vq,
@@ -269,7 +301,6 @@
static int virtio_blk__init_one(struct kvm *kvm, struct disk_image *disk)
{
struct blk_dev *bdev;
- unsigned int i;
if (!disk)
return -EINVAL;
@@ -279,13 +310,11 @@
return -ENOMEM;
*bdev = (struct blk_dev) {
- .mutex = MUTEX_INITIALIZER,
.disk = disk,
.blk_config = (struct virtio_blk_config) {
.capacity = disk->size / SECTOR_SIZE,
.seg_max = DISK_SEG_MAX,
},
- .io_efd = eventfd(0, 0),
.kvm = kvm,
};
@@ -295,14 +324,8 @@
list_add_tail(&bdev->list, &bdevs);
- for (i = 0; i < ARRAY_SIZE(bdev->reqs); i++) {
- bdev->reqs[i].bdev = bdev;
- bdev->reqs[i].kvm = kvm;
- }
-
disk_image__set_callback(bdev->disk, virtio_blk_complete);
- pthread_create(&bdev->io_thread, NULL, virtio_blk_thread, bdev);
if (compat_id == -1)
compat_id = virtio_compat_add_message("virtio-blk", "CONFIG_VIRTIO_BLK");