xref: /qemu/hw/vfio/cpr-legacy.c (revision c29a65ed68535288551d2bf70ae32f3df371a57d)
154857b08SSteve Sistare /*
254857b08SSteve Sistare  * Copyright (c) 2021-2025 Oracle and/or its affiliates.
354857b08SSteve Sistare  *
454857b08SSteve Sistare  * SPDX-License-Identifier: GPL-2.0-or-later
554857b08SSteve Sistare  */
654857b08SSteve Sistare 
754857b08SSteve Sistare #include <sys/ioctl.h>
854857b08SSteve Sistare #include <linux/vfio.h>
954857b08SSteve Sistare #include "qemu/osdep.h"
1054857b08SSteve Sistare #include "hw/vfio/vfio-container.h"
11*c29a65edSSteve Sistare #include "hw/vfio/vfio-device.h"
1254857b08SSteve Sistare #include "migration/blocker.h"
1354857b08SSteve Sistare #include "migration/cpr.h"
1454857b08SSteve Sistare #include "migration/migration.h"
1554857b08SSteve Sistare #include "migration/vmstate.h"
1654857b08SSteve Sistare #include "qapi/error.h"
1754857b08SSteve Sistare 
1854857b08SSteve Sistare static bool vfio_cpr_supported(VFIOContainer *container, Error **errp)
1954857b08SSteve Sistare {
2054857b08SSteve Sistare     if (!ioctl(container->fd, VFIO_CHECK_EXTENSION, VFIO_UPDATE_VADDR)) {
2154857b08SSteve Sistare         error_setg(errp, "VFIO container does not support VFIO_UPDATE_VADDR");
2254857b08SSteve Sistare         return false;
2354857b08SSteve Sistare 
2454857b08SSteve Sistare     } else if (!ioctl(container->fd, VFIO_CHECK_EXTENSION, VFIO_UNMAP_ALL)) {
2554857b08SSteve Sistare         error_setg(errp, "VFIO container does not support VFIO_UNMAP_ALL");
2654857b08SSteve Sistare         return false;
2754857b08SSteve Sistare 
2854857b08SSteve Sistare     } else {
2954857b08SSteve Sistare         return true;
3054857b08SSteve Sistare     }
3154857b08SSteve Sistare }
3254857b08SSteve Sistare 
3354857b08SSteve Sistare static const VMStateDescription vfio_container_vmstate = {
3454857b08SSteve Sistare     .name = "vfio-container",
3554857b08SSteve Sistare     .version_id = 0,
3654857b08SSteve Sistare     .minimum_version_id = 0,
3754857b08SSteve Sistare     .needed = cpr_incoming_needed,
3854857b08SSteve Sistare     .fields = (VMStateField[]) {
3954857b08SSteve Sistare         VMSTATE_END_OF_LIST()
4054857b08SSteve Sistare     }
4154857b08SSteve Sistare };
4254857b08SSteve Sistare 
4354857b08SSteve Sistare bool vfio_legacy_cpr_register_container(VFIOContainer *container, Error **errp)
4454857b08SSteve Sistare {
4554857b08SSteve Sistare     VFIOContainerBase *bcontainer = &container->bcontainer;
4654857b08SSteve Sistare     Error **cpr_blocker = &container->cpr.blocker;
4754857b08SSteve Sistare 
4854857b08SSteve Sistare     migration_add_notifier_mode(&bcontainer->cpr_reboot_notifier,
4954857b08SSteve Sistare                                 vfio_cpr_reboot_notifier,
5054857b08SSteve Sistare                                 MIG_MODE_CPR_REBOOT);
5154857b08SSteve Sistare 
5254857b08SSteve Sistare     if (!vfio_cpr_supported(container, cpr_blocker)) {
5354857b08SSteve Sistare         return migrate_add_blocker_modes(cpr_blocker, errp,
5454857b08SSteve Sistare                                          MIG_MODE_CPR_TRANSFER, -1) == 0;
5554857b08SSteve Sistare     }
5654857b08SSteve Sistare 
5754857b08SSteve Sistare     vmstate_register(NULL, -1, &vfio_container_vmstate, container);
5854857b08SSteve Sistare 
5954857b08SSteve Sistare     return true;
6054857b08SSteve Sistare }
6154857b08SSteve Sistare 
6254857b08SSteve Sistare void vfio_legacy_cpr_unregister_container(VFIOContainer *container)
6354857b08SSteve Sistare {
6454857b08SSteve Sistare     VFIOContainerBase *bcontainer = &container->bcontainer;
6554857b08SSteve Sistare 
6654857b08SSteve Sistare     migration_remove_notifier(&bcontainer->cpr_reboot_notifier);
6754857b08SSteve Sistare     migrate_del_blocker(&container->cpr.blocker);
6854857b08SSteve Sistare     vmstate_unregister(NULL, &vfio_container_vmstate, container);
6954857b08SSteve Sistare }
70*c29a65edSSteve Sistare 
71*c29a65edSSteve Sistare int vfio_cpr_group_get_device_fd(int d, const char *name)
72*c29a65edSSteve Sistare {
73*c29a65edSSteve Sistare     const int id = 0;
74*c29a65edSSteve Sistare     int fd = cpr_find_fd(name, id);
75*c29a65edSSteve Sistare 
76*c29a65edSSteve Sistare     if (fd < 0) {
77*c29a65edSSteve Sistare         fd = ioctl(d, VFIO_GROUP_GET_DEVICE_FD, name);
78*c29a65edSSteve Sistare         if (fd >= 0) {
79*c29a65edSSteve Sistare             cpr_save_fd(name, id, fd);
80*c29a65edSSteve Sistare         }
81*c29a65edSSteve Sistare     }
82*c29a65edSSteve Sistare     return fd;
83*c29a65edSSteve Sistare }
84*c29a65edSSteve Sistare 
85*c29a65edSSteve Sistare static bool same_device(int fd1, int fd2)
86*c29a65edSSteve Sistare {
87*c29a65edSSteve Sistare     struct stat st1, st2;
88*c29a65edSSteve Sistare 
89*c29a65edSSteve Sistare     return !fstat(fd1, &st1) && !fstat(fd2, &st2) && st1.st_dev == st2.st_dev;
90*c29a65edSSteve Sistare }
91*c29a65edSSteve Sistare 
92*c29a65edSSteve Sistare bool vfio_cpr_container_match(VFIOContainer *container, VFIOGroup *group,
93*c29a65edSSteve Sistare                               int fd)
94*c29a65edSSteve Sistare {
95*c29a65edSSteve Sistare     if (container->fd == fd) {
96*c29a65edSSteve Sistare         return true;
97*c29a65edSSteve Sistare     }
98*c29a65edSSteve Sistare     if (!same_device(container->fd, fd)) {
99*c29a65edSSteve Sistare         return false;
100*c29a65edSSteve Sistare     }
101*c29a65edSSteve Sistare     /*
102*c29a65edSSteve Sistare      * Same device, different fd.  This occurs when the container fd is
103*c29a65edSSteve Sistare      * cpr_save'd multiple times, once for each groupid, so SCM_RIGHTS
104*c29a65edSSteve Sistare      * produces duplicates.  De-dup it.
105*c29a65edSSteve Sistare      */
106*c29a65edSSteve Sistare     cpr_delete_fd("vfio_container_for_group", group->groupid);
107*c29a65edSSteve Sistare     close(fd);
108*c29a65edSSteve Sistare     cpr_save_fd("vfio_container_for_group", group->groupid, container->fd);
109*c29a65edSSteve Sistare     return true;
110*c29a65edSSteve Sistare }
111