1 /* 2 * Copyright (c) 2021-2025 Oracle and/or its affiliates. 3 * 4 * SPDX-License-Identifier: GPL-2.0-or-later 5 */ 6 7 #include <sys/ioctl.h> 8 #include <linux/vfio.h> 9 #include "qemu/osdep.h" 10 #include "hw/vfio/vfio-container.h" 11 #include "hw/vfio/vfio-device.h" 12 #include "migration/blocker.h" 13 #include "migration/cpr.h" 14 #include "migration/migration.h" 15 #include "migration/vmstate.h" 16 #include "qapi/error.h" 17 18 static bool vfio_dma_unmap_vaddr_all(VFIOContainer *container, Error **errp) 19 { 20 struct vfio_iommu_type1_dma_unmap unmap = { 21 .argsz = sizeof(unmap), 22 .flags = VFIO_DMA_UNMAP_FLAG_VADDR | VFIO_DMA_UNMAP_FLAG_ALL, 23 .iova = 0, 24 .size = 0, 25 }; 26 if (ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, &unmap)) { 27 error_setg_errno(errp, errno, "vfio_dma_unmap_vaddr_all"); 28 return false; 29 } 30 return true; 31 } 32 33 34 static bool vfio_cpr_supported(VFIOContainer *container, Error **errp) 35 { 36 if (!ioctl(container->fd, VFIO_CHECK_EXTENSION, VFIO_UPDATE_VADDR)) { 37 error_setg(errp, "VFIO container does not support VFIO_UPDATE_VADDR"); 38 return false; 39 40 } else if (!ioctl(container->fd, VFIO_CHECK_EXTENSION, VFIO_UNMAP_ALL)) { 41 error_setg(errp, "VFIO container does not support VFIO_UNMAP_ALL"); 42 return false; 43 44 } else { 45 return true; 46 } 47 } 48 49 static int vfio_container_pre_save(void *opaque) 50 { 51 VFIOContainer *container = opaque; 52 Error *local_err = NULL; 53 54 if (!vfio_dma_unmap_vaddr_all(container, &local_err)) { 55 error_report_err(local_err); 56 return -1; 57 } 58 return 0; 59 } 60 61 static const VMStateDescription vfio_container_vmstate = { 62 .name = "vfio-container", 63 .version_id = 0, 64 .minimum_version_id = 0, 65 .pre_save = vfio_container_pre_save, 66 .needed = cpr_incoming_needed, 67 .fields = (VMStateField[]) { 68 VMSTATE_END_OF_LIST() 69 } 70 }; 71 72 bool vfio_legacy_cpr_register_container(VFIOContainer *container, Error **errp) 73 { 74 VFIOContainerBase *bcontainer = &container->bcontainer; 75 Error **cpr_blocker = &container->cpr.blocker; 76 77 migration_add_notifier_mode(&bcontainer->cpr_reboot_notifier, 78 vfio_cpr_reboot_notifier, 79 MIG_MODE_CPR_REBOOT); 80 81 if (!vfio_cpr_supported(container, cpr_blocker)) { 82 return migrate_add_blocker_modes(cpr_blocker, errp, 83 MIG_MODE_CPR_TRANSFER, -1) == 0; 84 } 85 86 vmstate_register(NULL, -1, &vfio_container_vmstate, container); 87 88 return true; 89 } 90 91 void vfio_legacy_cpr_unregister_container(VFIOContainer *container) 92 { 93 VFIOContainerBase *bcontainer = &container->bcontainer; 94 95 migration_remove_notifier(&bcontainer->cpr_reboot_notifier); 96 migrate_del_blocker(&container->cpr.blocker); 97 vmstate_unregister(NULL, &vfio_container_vmstate, container); 98 } 99 100 int vfio_cpr_group_get_device_fd(int d, const char *name) 101 { 102 const int id = 0; 103 int fd = cpr_find_fd(name, id); 104 105 if (fd < 0) { 106 fd = ioctl(d, VFIO_GROUP_GET_DEVICE_FD, name); 107 if (fd >= 0) { 108 cpr_save_fd(name, id, fd); 109 } 110 } 111 return fd; 112 } 113 114 static bool same_device(int fd1, int fd2) 115 { 116 struct stat st1, st2; 117 118 return !fstat(fd1, &st1) && !fstat(fd2, &st2) && st1.st_dev == st2.st_dev; 119 } 120 121 bool vfio_cpr_container_match(VFIOContainer *container, VFIOGroup *group, 122 int fd) 123 { 124 if (container->fd == fd) { 125 return true; 126 } 127 if (!same_device(container->fd, fd)) { 128 return false; 129 } 130 /* 131 * Same device, different fd. This occurs when the container fd is 132 * cpr_save'd multiple times, once for each groupid, so SCM_RIGHTS 133 * produces duplicates. De-dup it. 134 */ 135 cpr_delete_fd("vfio_container_for_group", group->groupid); 136 close(fd); 137 cpr_save_fd("vfio_container_for_group", group->groupid, container->fd); 138 return true; 139 } 140