virtio: fix vq init error handling
We didn't handle vq alloc or init failure, because queues are initialized all at once on device init and if one vq fails, all of them are to be destroyed. This behavior is really unintuitive, and with the latest changes we have a possible segfault scenario. (We could spdk_dma_free() a buffer that failed to allocate). It is now required that the queue allocation function cleans up after itself. Change-Id: I6cd1d30c710eb9266288905ab982db363f972a1d Signed-off-by: Dariusz Stojaczyk <dariuszx.stojaczyk@intel.com> Reviewed-on: https://review.gerrithub.io/419001 Tested-by: SPDK Automated Test System <sys_sgsw@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
parent
e8762a41db
commit
65165d795d
@ -165,6 +165,8 @@ virtio_init_queue(struct virtio_dev *dev, uint16_t vtpci_queue_idx)
|
|||||||
|
|
||||||
if (virtio_dev_backend_ops(dev)->setup_queue(dev, vq) < 0) {
|
if (virtio_dev_backend_ops(dev)->setup_queue(dev, vq) < 0) {
|
||||||
SPDK_ERRLOG("setup_queue failed\n");
|
SPDK_ERRLOG("setup_queue failed\n");
|
||||||
|
spdk_dma_free(vq);
|
||||||
|
dev->vqs[vtpci_queue_idx] = NULL;
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,6 +281,7 @@ modern_setup_queue(struct virtio_dev *dev, struct virtqueue *vq)
|
|||||||
vq->vq_ring_virt_mem = queue_mem;
|
vq->vq_ring_virt_mem = queue_mem;
|
||||||
|
|
||||||
if (!check_vq_phys_addr_ok(vq)) {
|
if (!check_vq_phys_addr_ok(vq)) {
|
||||||
|
spdk_dma_free(queue_mem);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,14 +366,6 @@ virtio_user_setup_queue(struct virtio_dev *vdev, struct virtqueue *vq)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
queue_mem = spdk_dma_zmalloc(vq->vq_ring_size, VIRTIO_PCI_VRING_ALIGN, NULL);
|
|
||||||
if (queue_mem == NULL) {
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
vq->vq_ring_mem = SPDK_VTOPHYS_ERROR;
|
|
||||||
vq->vq_ring_virt_mem = queue_mem;
|
|
||||||
|
|
||||||
/* May use invalid flag, but some backend uses kickfd and
|
/* May use invalid flag, but some backend uses kickfd and
|
||||||
* callfd as criteria to judge if dev is alive. so finally we
|
* callfd as criteria to judge if dev is alive. so finally we
|
||||||
* use real event_fd.
|
* use real event_fd.
|
||||||
@ -391,6 +383,16 @@ virtio_user_setup_queue(struct virtio_dev *vdev, struct virtqueue *vq)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
queue_mem = spdk_dma_zmalloc(vq->vq_ring_size, VIRTIO_PCI_VRING_ALIGN, NULL);
|
||||||
|
if (queue_mem == NULL) {
|
||||||
|
close(kickfd);
|
||||||
|
close(callfd);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
vq->vq_ring_mem = SPDK_VTOPHYS_ERROR;
|
||||||
|
vq->vq_ring_virt_mem = queue_mem;
|
||||||
|
|
||||||
state.index = vq->vq_queue_index;
|
state.index = vq->vq_queue_index;
|
||||||
state.num = 0;
|
state.num = 0;
|
||||||
|
|
||||||
@ -398,6 +400,7 @@ virtio_user_setup_queue(struct virtio_dev *vdev, struct virtqueue *vq)
|
|||||||
dev->ops->send_request(dev, VHOST_USER_SET_VRING_ENABLE, &state) < 0) {
|
dev->ops->send_request(dev, VHOST_USER_SET_VRING_ENABLE, &state) < 0) {
|
||||||
SPDK_ERRLOG("failed to send VHOST_USER_SET_VRING_ENABLE: %s\n",
|
SPDK_ERRLOG("failed to send VHOST_USER_SET_VRING_ENABLE: %s\n",
|
||||||
spdk_strerror(errno));
|
spdk_strerror(errno));
|
||||||
|
spdk_dma_free(queue_mem);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user