hw/vfio: generate new file fd for pseudo device and rebind existing descriptors
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. Tested-by: Cédric Le Goater <clg@redhat.com> Reviewed-by: Cédric Le Goater <clg@redhat.com> Signed-off-by: Ani Sinha <anisinha@redhat.com> Link: https://lore.kernel.org/r/20260227072445.406907-1-anisinha@redhat.com Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Ani Sinha committed
Feb 27, 2026 at 12:54 UTC
668c8abd8f9c83061180b5488d1129f61456a65a
1 file changed
+91
hw/vfio/helpers.c
+91
@@ -116,6 +116,88 @@ bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info,
116
* we'll re-use it should another vfio device be attached before then.
117
*/
118
int vfio_kvm_device_fd = -1;
119
+
120
+/*
121
+ * Confidential virtual machines:
122
+ * During reset of confidential vms, the kvm vm file descriptor changes.
123
+ * In this case, the old vfio kvm file descriptor is
124
+ * closed and a new descriptor is created against the new kvm vm file
125
+ * descriptor.
126
+ */
127
+
128
+typedef struct VFIODeviceFd {
129
+ int fd;
130
+ QLIST_ENTRY(VFIODeviceFd) node;
131
+} VFIODeviceFd;
132
+
133
+static QLIST_HEAD(, VFIODeviceFd) vfio_device_fds =
134
+ QLIST_HEAD_INITIALIZER(vfio_device_fds);
135
+
136
+static void vfio_device_fd_list_add(int fd)
137
+{
138
+ VFIODeviceFd *file_fd;
139
+ file_fd = g_malloc0(sizeof(*file_fd));
140
+ file_fd->fd = fd;
141
+ QLIST_INSERT_HEAD(&vfio_device_fds, file_fd, node);
142
+}
143
+
144
+static void vfio_device_fd_list_remove(int fd)
145
+{
146
+ VFIODeviceFd *file_fd, *next;
147
+
148
+ QLIST_FOREACH_SAFE(file_fd, &vfio_device_fds, node, next) {
149
+ if (file_fd->fd == fd) {
150
+ QLIST_REMOVE(file_fd, node);
151
+ g_free(file_fd);
152
+ break;
153
+ }
154
+ }
155
+}
156
+
157
+static int vfio_device_fd_rebind(NotifierWithReturn *notifier, void *data,
158
+ Error **errp)
159
+{
160
+ VFIODeviceFd *file_fd;
161
+ struct kvm_device_attr attr = {
162
+ .group = KVM_DEV_VFIO_FILE,
163
+ .attr = KVM_DEV_VFIO_FILE_ADD,
164
+ };
165
+ struct kvm_create_device cd = {
166
+ .type = KVM_DEV_TYPE_VFIO,
167
+ };
168
+
169
+ /* we are not interested in pre vmfd change notification */
170
+ if (((VmfdChangeNotifier *)data)->pre) {
171
+ return 0;
172
+ }
173
+
174
+ if (kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)) {
175
+ error_setg_errno(errp, errno, "Failed to create KVM VFIO device");
176
+ return -errno;
177
+ }
178
+
179
+ if (vfio_kvm_device_fd != -1) {
180
+ close(vfio_kvm_device_fd);
181
+ }
182
+
183
+ vfio_kvm_device_fd = cd.fd;
184
+
185
+ QLIST_FOREACH(file_fd, &vfio_device_fds, node) {
186
+ attr.addr = (uint64_t)(unsigned long)&file_fd->fd;
187
+ if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
188
+ error_setg_errno(errp, errno,
189
+ "Failed to add fd %d to KVM VFIO device",
190
+ file_fd->fd);
191
+ return -errno;
192
+ }
193
+ }
194
+ return 0;
195
+}
196
+
197
+static struct NotifierWithReturn vfio_vmfd_change_notifier = {
198
+ .notify = vfio_device_fd_rebind,
199
+};
200
+
201
#endif
202
203
void vfio_kvm_device_close(void)
@@ -153,6 +235,11 @@ int vfio_kvm_device_add_fd(int fd, Error **errp)
235
}
236
237
vfio_kvm_device_fd = cd.fd;
238
+ /*
239
+ * If the vm file descriptor changes, add a notifier so that we can
240
+ * re-create the vfio_kvm_device_fd.
241
+ */
242
+ kvm_vmfd_add_change_notifier(&vfio_vmfd_change_notifier);
243
}
244
245
if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
@@ -160,6 +247,8 @@ int vfio_kvm_device_add_fd(int fd, Error **errp)
247
fd);
248
return -errno;
249
}
250
+
251
+ vfio_device_fd_list_add(fd);
252
#endif
253
return 0;
254
}
@@ -183,6 +272,8 @@ int vfio_kvm_device_del_fd(int fd, Error **errp)
272
"Failed to remove fd %d from KVM VFIO device", fd);
273
return -errno;
274
}
275
+
276
+ vfio_device_fd_list_remove(fd);
277
#endif
278
return 0;
279
}