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_cpr_supported(VFIOContainer *container, Error **errp) 19 { 20 if (!ioctl(container->fd, VFIO_CHECK_EXTENSION, VFIO_UPDATE_VADDR)) { 21 error_setg(errp, "VFIO container does not support VFIO_UPDATE_VADDR"); 22 return false; 23 24 } else if (!ioctl(container->fd, VFIO_CHECK_EXTENSION, VFIO_UNMAP_ALL)) { 25 error_setg(errp, "VFIO container does not support VFIO_UNMAP_ALL"); 26 return false; 27 28 } else { 29 return true; 30 } 31 } 32 33 static const VMStateDescription vfio_container_vmstate = { 34 .name = "vfio-container", 35 .version_id = 0, 36 .minimum_version_id = 0, 37 .needed = cpr_incoming_needed, 38 .fields = (VMStateField[]) { 39 VMSTATE_END_OF_LIST() 40 } 41 }; 42 43 bool vfio_legacy_cpr_register_container(VFIOContainer *container, Error **errp) 44 { 45 VFIOContainerBase *bcontainer = &container->bcontainer; 46 Error **cpr_blocker = &container->cpr.blocker; 47 48 migration_add_notifier_mode(&bcontainer->cpr_reboot_notifier, 49 vfio_cpr_reboot_notifier, 50 MIG_MODE_CPR_REBOOT); 51 52 if (!vfio_cpr_supported(container, cpr_blocker)) { 53 return migrate_add_blocker_modes(cpr_blocker, errp, 54 MIG_MODE_CPR_TRANSFER, -1) == 0; 55 } 56 57 vmstate_register(NULL, -1, &vfio_container_vmstate, container); 58 59 return true; 60 } 61 62 void vfio_legacy_cpr_unregister_container(VFIOContainer *container) 63 { 64 VFIOContainerBase *bcontainer = &container->bcontainer; 65 66 migration_remove_notifier(&bcontainer->cpr_reboot_notifier); 67 migrate_del_blocker(&container->cpr.blocker); 68 vmstate_unregister(NULL, &vfio_container_vmstate, container); 69 } 70 71 int vfio_cpr_group_get_device_fd(int d, const char *name) 72 { 73 const int id = 0; 74 int fd = cpr_find_fd(name, id); 75 76 if (fd < 0) { 77 fd = ioctl(d, VFIO_GROUP_GET_DEVICE_FD, name); 78 if (fd >= 0) { 79 cpr_save_fd(name, id, fd); 80 } 81 } 82 return fd; 83 } 84 85 static bool same_device(int fd1, int fd2) 86 { 87 struct stat st1, st2; 88 89 return !fstat(fd1, &st1) && !fstat(fd2, &st2) && st1.st_dev == st2.st_dev; 90 } 91 92 bool vfio_cpr_container_match(VFIOContainer *container, VFIOGroup *group, 93 int fd) 94 { 95 if (container->fd == fd) { 96 return true; 97 } 98 if (!same_device(container->fd, fd)) { 99 return false; 100 } 101 /* 102 * Same device, different fd. This occurs when the container fd is 103 * cpr_save'd multiple times, once for each groupid, so SCM_RIGHTS 104 * produces duplicates. De-dup it. 105 */ 106 cpr_delete_fd("vfio_container_for_group", group->groupid); 107 close(fd); 108 cpr_save_fd("vfio_container_for_group", group->groupid, container->fd); 109 return true; 110 } 111