On Tue, Jan 27, 2026 at 10:47 AM Ani Sinha <[email protected]> wrote:
>
> Normally the vfio pseudo device file descriptor lives for the life of the VM.
> However, when the kvm VM file descriptor changes, a new file descriptor
> for the pseudo device needs to be generated against the new kvm VM descriptor.
> Other existing vfio descriptors needs to be reattached to the new pseudo 
> device
> descriptor. This change performs the above steps.

I have not been able to test this change. Can someone suggest a way to
add a functional test and/or test this manually?
Otherwise I am going to add a comment in the next spin up that this
change is not tested.

>
> Signed-off-by: Ani Sinha <[email protected]>
> ---
>  hw/vfio/helpers.c | 86 +++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 83 insertions(+), 3 deletions(-)
>
> diff --git a/hw/vfio/helpers.c b/hw/vfio/helpers.c
> index f68f8165d0..d467875b4b 100644
> --- a/hw/vfio/helpers.c
> +++ b/hw/vfio/helpers.c
> @@ -110,12 +110,71 @@ bool vfio_get_info_dma_avail(struct 
> vfio_iommu_type1_info *info,
>  #ifdef CONFIG_KVM
>  /*
>   * We have a single VFIO pseudo device per KVM VM.  Once created it lives
> - * for the life of the VM.  Closing the file descriptor only drops our
> - * reference to it and the device's reference to kvm.  Therefore once
> - * initialized, this file descriptor is only released on QEMU exit and
> + * for the life of the VM except when the vm file descriptor changes for
> + * confidential virtual machines. In that case, the old file descriptor is
> + * closed and a new file descriptor is recreated.  Closing the file 
> descriptor
> + * only drops our reference to it and the device's reference to kvm.
> + * Therefore once initialized, this file descriptor is normally only released
> + * on QEMU exit (except for confidential VMs as stated above) and
>   * we'll re-use it should another vfio device be attached before then.
>   */
>  int vfio_kvm_device_fd = -1;
> +
> +typedef struct KVMVfioFileFd {
> +    int fd;
> +    QLIST_ENTRY(KVMVfioFileFd) node;
> +} KVMVfioFileFd;
> +
> +static QLIST_HEAD(, KVMVfioFileFd) kvm_vfio_file_fds =
> +    QLIST_HEAD_INITIALIZER(kvm_vfio_file_fds);
> +
> +static int kvm_vfio_filefd_rebind(NotifierWithReturn *notifier, void *data,
> +                                  Error **errp);
> +static struct NotifierWithReturn kvm_vfio_vmfd_change_notifier = {
> +    .notify = kvm_vfio_filefd_rebind,
> +};
> +
> +static int kvm_vfio_filefd_rebind(NotifierWithReturn *notifier, void *data,
> +                                  Error **errp)
> +{
> +    KVMVfioFileFd *file_fd;
> +    int ret = 0;
> +    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) {
> +        close(vfio_kvm_device_fd);
> +    }
> +
> +    vfio_kvm_device_fd = cd.fd;
> +
> +    QLIST_FOREACH(file_fd, &kvm_vfio_file_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);
> +            ret = -errno;
> +        }
> +    }
> +    return ret;
> +}
> +
>  #endif
>
>  void vfio_kvm_device_close(void)
> @@ -137,6 +196,7 @@ int vfio_kvm_device_add_fd(int fd, Error **errp)
>          .attr = KVM_DEV_VFIO_FILE_ADD,
>          .addr = (uint64_t)(unsigned long)&fd,
>      };
> +    KVMVfioFileFd *file_fd;
>
>      if (!kvm_enabled()) {
>          return 0;
> @@ -153,6 +213,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(&kvm_vfio_vmfd_change_notifier);
>      }
>
>      if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
> @@ -160,6 +225,11 @@ int vfio_kvm_device_add_fd(int fd, Error **errp)
>                           fd);
>          return -errno;
>      }
> +
> +    file_fd = g_malloc0(sizeof(*file_fd));
> +    file_fd->fd = fd;
> +    QLIST_INSERT_HEAD(&kvm_vfio_file_fds, file_fd, node);
> +
>  #endif
>      return 0;
>  }
> @@ -172,6 +242,7 @@ int vfio_kvm_device_del_fd(int fd, Error **errp)
>          .attr = KVM_DEV_VFIO_FILE_DEL,
>          .addr = (uint64_t)(unsigned long)&fd,
>      };
> +    KVMVfioFileFd *file_fd;
>
>      if (vfio_kvm_device_fd < 0) {
>          error_setg(errp, "KVM VFIO device isn't created yet");
> @@ -183,6 +254,15 @@ int vfio_kvm_device_del_fd(int fd, Error **errp)
>                           "Failed to remove fd %d from KVM VFIO device", fd);
>          return -errno;
>      }
> +
> +    QLIST_FOREACH(file_fd, &kvm_vfio_file_fds, node) {
> +        if (file_fd->fd == fd) {
> +            QLIST_REMOVE(file_fd, node);
> +            g_free(file_fd);
> +            break;
> +        }
> +    }
> +
>  #endif
>      return 0;
>  }
> --
> 2.42.0
>


Reply via email to