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; uint32_t i;
struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id); struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id);
struct acrn_vm_pci_dev_config *dev_config = NULL; struct acrn_vm_pci_dev_config *dev_config = NULL;
struct pci_vdev *vdev = NULL;
int32_t ret = -EINVAL; int32_t ret = -EINVAL;
for (i = 0U; i < vm_config->pci_dev_num; i++) { 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_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];
dev_config->vbar_base[IVSHMEM_SHM_BAR] |= ((uint64_t) dev->io_addr[IVSHMEM_SHM_BAR + 1U]) << 32U; 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); spinlock_release(&vm->vpci.lock);
if (vdev != NULL) {
ret = 0; 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);
} }
break; 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; return ret;
} }
int32_t destroy_ivshmem_vdev(struct pci_vdev *vdev) int32_t destroy_ivshmem_vdev(struct pci_vdev *vdev)
{ {
uint32_t i; uint32_t i;
struct acrn_vpci *vpci = vdev->vpci;
for (i = 0U; i < vdev->nr_bars; i++) { for (i = 0U; i < vdev->nr_bars; i++) {
vpci_update_one_vbar(vdev, i, 0U, NULL, ivshmem_vbar_unmap); 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; 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) int32_t create_vmcs9900_vdev(struct acrn_vm *vm, struct acrn_vdev *dev)
{ {
uint16_t i; uint16_t i;
struct pci_vdev *vdev;
struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id); struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id);
struct acrn_vm_pci_dev_config *dev_config = NULL; struct acrn_vm_pci_dev_config *dev_config = NULL;
int32_t ret = -EINVAL; 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->vbdf.value = (uint16_t) dev->slot;
dev_config->vbar_base[0] = (uint64_t) dev->io_addr[0]; dev_config->vbar_base[0] = (uint64_t) dev->io_addr[0];
dev_config->vbar_base[1] = (uint64_t) dev->io_addr[1]; dev_config->vbar_base[1] = (uint64_t) dev->io_addr[1];
(void) vpci_init_vdev(&vm->vpci, dev_config, NULL); spinlock_obtain(&vm->vpci.lock);
vdev = vpci_init_vdev(&vm->vpci, dev_config, NULL);
spinlock_release(&vm->vpci.lock);
if (vdev != NULL) {
ret = 0; ret = 0;
}
break; break;
} }
} }
if (ret != 0) { 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; 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) int32_t destroy_vmcs9900_vdev(struct pci_vdev *vdev)
{ {
uint32_t i; uint32_t i;
struct acrn_vpci *vpci = vdev->vpci;
for (i = 0U; i < vdev->nr_bars; i++) { for (i = 0U; i < vdev->nr_bars; i++) {
vpci_update_one_vbar(vdev, i, 0U, NULL, unmap_vmcs9900_vbar); 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); deinit_pci_vuart(vdev);
spinlock_obtain(&vpci->lock);
vpci_deinit_vdev(vdev);
spinlock_release(&vpci->lock);
return 0; 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->vrp_max_payload = vrp_config->max_payload;
dev_config->vdev_ops = &vrp_ops; dev_config->vdev_ops = &vrp_ops;
spinlock_obtain(&vm->vpci.lock);
vdev = vpci_init_vdev(&vm->vpci, dev_config, NULL); vdev = vpci_init_vdev(&vm->vpci, dev_config, NULL);
spinlock_release(&vm->vpci.lock);
if (vdev == NULL) { if (vdev == NULL) {
pr_err("%s: failed to create virtual root port\n", __func__); pr_err("%s: failed to create virtual root port\n", __func__);
ret = -EFAULT; ret = -EFAULT;
@ -156,8 +158,14 @@ int32_t create_vrp(struct acrn_vm *vm, struct acrn_vdev *dev)
return ret; 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; 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_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); 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); 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) static inline bool is_pci_io_bar(struct pci_vbar *vbar)
{ {