xref: /qemu/hw/vfio/cpr-legacy.c (revision c29a65ed68535288551d2bf70ae32f3df371a57d)
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