diff --git a/hw/vfio/helpers.c b/hw/vfio/helpers.c index f68f8165d0..00d42d3b98 100644 --- a/hw/vfio/helpers.c +++ b/hw/vfio/helpers.c @@ -116,6 +116,88 @@ bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info, * we'll re-use it should another vfio device be attached before then. */ int vfio_kvm_device_fd = -1; + +/* + * Confidential virtual machines: + * During reset of confidential vms, the kvm vm file descriptor changes. + * In this case, the old vfio kvm file descriptor is + * closed and a new descriptor is created against the new kvm vm file + * descriptor. + */ + +typedef struct VFIODeviceFd { + int fd; + QLIST_ENTRY(VFIODeviceFd) node; +} VFIODeviceFd; + +static QLIST_HEAD(, VFIODeviceFd) vfio_device_fds = + QLIST_HEAD_INITIALIZER(vfio_device_fds); + +static void vfio_device_fd_list_add(int fd) +{ + VFIODeviceFd *file_fd; + file_fd = g_malloc0(sizeof(*file_fd)); + file_fd->fd = fd; + QLIST_INSERT_HEAD(&vfio_device_fds, file_fd, node); +} + +static void vfio_device_fd_list_remove(int fd) +{ + VFIODeviceFd *file_fd, *next; + + QLIST_FOREACH_SAFE(file_fd, &vfio_device_fds, node, next) { + if (file_fd->fd == fd) { + QLIST_REMOVE(file_fd, node); + g_free(file_fd); + break; + } + } +} + +static int vfio_device_fd_rebind(NotifierWithReturn *notifier, void *data, + Error **errp) +{ + VFIODeviceFd *file_fd; + struct kvm_device_attr attr = { + .group = KVM_DEV_VFIO_FILE, + .attr = KVM_DEV_VFIO_FILE_ADD, + }; + struct kvm_create_device cd = { + .type = KVM_DEV_TYPE_VFIO, + }; + + /* we are not interested in pre vmfd change notification */ + if (((VmfdChangeNotifier *)data)->pre) { + return 0; + } + + if (kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)) { + error_setg_errno(errp, errno, "Failed to create KVM VFIO device"); + return -errno; + } + + if (vfio_kvm_device_fd != -1) { + close(vfio_kvm_device_fd); + } + + vfio_kvm_device_fd = cd.fd; + + QLIST_FOREACH(file_fd, &vfio_device_fds, node) { + attr.addr = (uint64_t)(unsigned long)&file_fd->fd; + if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) { + error_setg_errno(errp, errno, + "Failed to add fd %d to KVM VFIO device", + file_fd->fd); + return -errno; + } + } + return 0; +} + +static struct NotifierWithReturn vfio_vmfd_change_notifier = { + .notify = vfio_device_fd_rebind, +}; + #endif void vfio_kvm_device_close(void) @@ -153,6 +235,11 @@ int vfio_kvm_device_add_fd(int fd, Error **errp) } vfio_kvm_device_fd = cd.fd; + /* + * If the vm file descriptor changes, add a notifier so that we can + * re-create the vfio_kvm_device_fd. + */ + kvm_vmfd_add_change_notifier(&vfio_vmfd_change_notifier); } if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) { @@ -160,6 +247,8 @@ int vfio_kvm_device_add_fd(int fd, Error **errp) fd); return -errno; } + + vfio_device_fd_list_add(fd); #endif return 0; } @@ -183,6 +272,8 @@ int vfio_kvm_device_del_fd(int fd, Error **errp) "Failed to remove fd %d from KVM VFIO device", fd); return -errno; } + + vfio_device_fd_list_remove(fd); #endif return 0; }