hv: dm: refine create/destroy functions

The create function of hv-emulated device must check the return value
of vpci_init_vdev() as it returns NULL pointer on failure, and that
function should be called atomically.

Also, the destory function should deinit the vpci devices created to
prevent resource leak.

Tracked-On: #8590
Signed-off-by: Jiaqing Zhao <jiaqing.zhao@linux.intel.com>
Reviewed-by: Junjie Mao <junjie.mao@intel.com>
This commit is contained in:
Jiaqing Zhao 2024-05-31 07:22:53 +00:00 committed by acrnsi-robot
parent 626e2f1d17
commit 91e0612e88
4 changed files with 39 additions and 10 deletions

View File

@ -384,6 +384,7 @@ int32_t create_ivshmem_vdev(struct acrn_vm *vm, struct acrn_vdev *dev)
uint32_t i;
struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id);
struct acrn_vm_pci_dev_config *dev_config = NULL;
struct pci_vdev *vdev = NULL;
int32_t ret = -EINVAL;
for (i = 0U; i < vm_config->pci_dev_num; i++) {
@ -397,27 +398,36 @@ int32_t create_ivshmem_vdev(struct acrn_vm *vm, struct acrn_vdev *dev)
dev_config->vbar_base[IVSHMEM_MSIX_BAR] = (uint64_t) dev->io_addr[IVSHMEM_MSIX_BAR];
dev_config->vbar_base[IVSHMEM_SHM_BAR] = (uint64_t) dev->io_addr[IVSHMEM_SHM_BAR];
dev_config->vbar_base[IVSHMEM_SHM_BAR] |= ((uint64_t) dev->io_addr[IVSHMEM_SHM_BAR + 1U]) << 32U;
(void) vpci_init_vdev(&vm->vpci, dev_config, NULL);
vdev = vpci_init_vdev(&vm->vpci, dev_config, NULL);
spinlock_release(&vm->vpci.lock);
ret = 0;
} else {
pr_warn("%s, failed to create ivshmem device %x:%x.%x\n", __func__,
dev->slot >> 8U, (dev->slot >> 3U) & 0x1fU, dev->slot & 0x7U);
}
if (vdev != NULL) {
ret = 0;
}
}
break;
}
}
if (ret != 0) {
pr_warn("%s, failed to create ivshmem device %x:%x.%x\n", __func__,
dev->slot >> 8U, (dev->slot >> 3U) & 0x1fU, dev->slot & 0x7U);
}
return ret;
}
int32_t destroy_ivshmem_vdev(struct pci_vdev *vdev)
{
uint32_t i;
struct acrn_vpci *vpci = vdev->vpci;
for (i = 0U; i < vdev->nr_bars; i++) {
vpci_update_one_vbar(vdev, i, 0U, NULL, ivshmem_vbar_unmap);
}
spinlock_obtain(&vpci->lock);
vpci_deinit_vdev(vdev);
spinlock_release(&vpci->lock);
return 0;
}

View File

@ -166,6 +166,7 @@ const struct pci_vdev_ops vmcs9900_ops = {
int32_t create_vmcs9900_vdev(struct acrn_vm *vm, struct acrn_vdev *dev)
{
uint16_t i;
struct pci_vdev *vdev;
struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id);
struct acrn_vm_pci_dev_config *dev_config = NULL;
int32_t ret = -EINVAL;
@ -177,14 +178,18 @@ int32_t create_vmcs9900_vdev(struct acrn_vm *vm, struct acrn_vdev *dev)
dev_config->vbdf.value = (uint16_t) dev->slot;
dev_config->vbar_base[0] = (uint64_t) dev->io_addr[0];
dev_config->vbar_base[1] = (uint64_t) dev->io_addr[1];
(void) vpci_init_vdev(&vm->vpci, dev_config, NULL);
ret = 0;
spinlock_obtain(&vm->vpci.lock);
vdev = vpci_init_vdev(&vm->vpci, dev_config, NULL);
spinlock_release(&vm->vpci.lock);
if (vdev != NULL) {
ret = 0;
}
break;
}
}
if (ret != 0) {
pr_err("Unsupport: create VM%d vuart_idx=%d", vm->vm_id, vuart_idx);
pr_err("Failed: create VM%d vuart_idx=%d", vm->vm_id, vuart_idx);
}
return ret;
@ -193,6 +198,7 @@ int32_t create_vmcs9900_vdev(struct acrn_vm *vm, struct acrn_vdev *dev)
int32_t destroy_vmcs9900_vdev(struct pci_vdev *vdev)
{
uint32_t i;
struct acrn_vpci *vpci = vdev->vpci;
for (i = 0U; i < vdev->nr_bars; i++) {
vpci_update_one_vbar(vdev, i, 0U, NULL, unmap_vmcs9900_vbar);
@ -200,5 +206,9 @@ int32_t destroy_vmcs9900_vdev(struct pci_vdev *vdev)
deinit_pci_vuart(vdev);
spinlock_obtain(&vpci->lock);
vpci_deinit_vdev(vdev);
spinlock_release(&vpci->lock);
return 0;
}

View File

@ -140,7 +140,9 @@ int32_t create_vrp(struct acrn_vm *vm, struct acrn_vdev *dev)
dev_config->vrp_max_payload = vrp_config->max_payload;
dev_config->vdev_ops = &vrp_ops;
spinlock_obtain(&vm->vpci.lock);
vdev = vpci_init_vdev(&vm->vpci, dev_config, NULL);
spinlock_release(&vm->vpci.lock);
if (vdev == NULL) {
pr_err("%s: failed to create virtual root port\n", __func__);
ret = -EFAULT;
@ -156,8 +158,14 @@ int32_t create_vrp(struct acrn_vm *vm, struct acrn_vdev *dev)
return ret;
}
int32_t destroy_vrp(__unused struct pci_vdev *vdev)
int32_t destroy_vrp(struct pci_vdev *vdev)
{
struct acrn_vpci *vpci = vdev->vpci;
spinlock_obtain(&vpci->lock);
vpci_deinit_vdev(vdev);
spinlock_release(&vpci->lock);
return 0;
}

View File

@ -194,6 +194,7 @@ struct acrn_pcidev;
int32_t vpci_assign_pcidev(struct acrn_vm *tgt_vm, struct acrn_pcidev *pcidev);
int32_t vpci_deassign_pcidev(struct acrn_vm *tgt_vm, struct acrn_pcidev *pcidev);
struct pci_vdev *vpci_init_vdev(struct acrn_vpci *vpci, struct acrn_vm_pci_dev_config *dev_config, struct pci_vdev *parent_pf_vdev);
void vpci_deinit_vdev(struct pci_vdev *vdev);
static inline bool is_pci_io_bar(struct pci_vbar *vbar)
{