Re: [PATCH V5 30/38] migration: vfio cpr state hook

2025-07-02 Thread Steven Sistare

On 7/2/2025 9:39 AM, Duan, Zhenzhong wrote:

-Original Message-
From: Steven Sistare 
Subject: Re: [PATCH V5 30/38] migration: vfio cpr state hook

On 6/24/2025 7:24 AM, Duan, Zhenzhong wrote:

-Original Message-
From: Steve Sistare 
Subject: [PATCH V5 30/38] migration: vfio cpr state hook

Define a list of vfio devices in CPR state, in a subsection so that
older QEMU can be live updated to this version.  However, new QEMU
will not be live updateable to old QEMU.  This is acceptable because
CPR is not yet commonly used, and updates to older versions are unusual.


I'm not familiar with migration, may I ask how subsection help blocking

migration

from new to old QEMU?


Migrating new to old will fail with an error message saying the subsection is
not recognized.


You mean old qemu supporting legacy container live update, migrate to new qemu 
supporting iommufd live update?


No, more basic.

Even with no vfio devices in the VM, qemu 10.1 will send an empty
vmstate_cpr_vfio_devices subsection, which qemu 10.0 does not recognize.
Thus live update from qemu 10.1 to qemu 10.0 will fail.
Live update from qemu 10.0 to qemu 10.1 will work.

- Steve


The contents of each device object will be defined by the vfio subsystem
in a subsequent patch.

Signed-off-by: Steve Sistare 
---
include/hw/vfio/vfio-cpr.h |  1 +
include/migration/cpr.h| 12 
hw/vfio/cpr-iommufd.c  |  2 ++
hw/vfio/iommufd-stubs.c| 18 ++
migration/cpr.c| 14 +-
hw/vfio/meson.build|  1 +
6 files changed, 39 insertions(+), 9 deletions(-)
create mode 100644 hw/vfio/iommufd-stubs.c

diff --git a/include/hw/vfio/vfio-cpr.h b/include/hw/vfio/vfio-cpr.h
index b9b77ae..619af07 100644
--- a/include/hw/vfio/vfio-cpr.h
+++ b/include/hw/vfio/vfio-cpr.h
@@ -74,5 +74,6 @@ void vfio_cpr_delete_vector_fd(struct

VFIOPCIDevice *vdev,

const char *name,
 int nr);

extern const VMStateDescription vfio_cpr_pci_vmstate;
+extern const VMStateDescription vmstate_cpr_vfio_devices;

#endif /* HW_VFIO_VFIO_CPR_H */
diff --git a/include/migration/cpr.h b/include/migration/cpr.h
index 7fd8065..8fd8bfe 100644
--- a/include/migration/cpr.h
+++ b/include/migration/cpr.h
@@ -9,11 +9,23 @@
#define MIGRATION_CPR_H

#include "qapi/qapi-types-migration.h"
+#include "qemu/queue.h"

#define MIG_MODE_NONE   -1

#define QEMU_CPR_FILE_MAGIC 0x51435052
#define QEMU_CPR_FILE_VERSION   0x0001
+#define CPR_STATE "CprState"
+
+typedef QLIST_HEAD(CprFdList, CprFd) CprFdList;
+typedef QLIST_HEAD(CprVFIODeviceList, CprVFIODevice)

CprVFIODeviceList;

+
+typedef struct CprState {
+CprFdList fds;
+CprVFIODeviceList vfio_devices;
+} CprState;
+
+extern CprState cpr_state;

void cpr_save_fd(const char *name, int id, int fd);
void cpr_delete_fd(const char *name, int id);
diff --git a/hw/vfio/cpr-iommufd.c b/hw/vfio/cpr-iommufd.c
index 60bd7e8..3e78265 100644
--- a/hw/vfio/cpr-iommufd.c
+++ b/hw/vfio/cpr-iommufd.c
@@ -14,6 +14,8 @@
#include "system/iommufd.h"
#include "vfio-iommufd.h"

+const VMStateDescription vmstate_cpr_vfio_devices;  /* TBD in a later

patch */

+
static bool vfio_cpr_supported(IOMMUFDBackend *be, Error **errp)
{
  if (!iommufd_change_process_capable(be)) {
diff --git a/hw/vfio/iommufd-stubs.c b/hw/vfio/iommufd-stubs.c
new file mode 100644
index 000..0be5276
--- /dev/null
+++ b/hw/vfio/iommufd-stubs.c
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2025 Oracle and/or its affiliates.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "migration/cpr.h"
+#include "migration/vmstate.h"
+
+const VMStateDescription vmstate_cpr_vfio_devices = {
+.name = CPR_STATE "/vfio devices",
+.version_id = 1,
+.minimum_version_id = 1,


Is there difference if version_id=minimum_version_id=0?


No.  Some developers add a new VMStateDescription starting at 0,
and some starting at 1.


OK.

Thanks
Zhenzhong





RE: [PATCH V5 30/38] migration: vfio cpr state hook

2025-07-02 Thread Duan, Zhenzhong



>-Original Message-
>From: Steven Sistare 
>Subject: Re: [PATCH V5 30/38] migration: vfio cpr state hook
>
>On 6/24/2025 7:24 AM, Duan, Zhenzhong wrote:
>>> -Original Message-
>>> From: Steve Sistare 
>>> Subject: [PATCH V5 30/38] migration: vfio cpr state hook
>>>
>>> Define a list of vfio devices in CPR state, in a subsection so that
>>> older QEMU can be live updated to this version.  However, new QEMU
>>> will not be live updateable to old QEMU.  This is acceptable because
>>> CPR is not yet commonly used, and updates to older versions are unusual.
>>
>> I'm not familiar with migration, may I ask how subsection help blocking
>migration
>> from new to old QEMU?
>
>Migrating new to old will fail with an error message saying the subsection is
>not recognized.

You mean old qemu supporting legacy container live update, migrate to new qemu 
supporting iommufd live update?

>
>>> The contents of each device object will be defined by the vfio subsystem
>>> in a subsequent patch.
>>>
>>> Signed-off-by: Steve Sistare 
>>> ---
>>> include/hw/vfio/vfio-cpr.h |  1 +
>>> include/migration/cpr.h| 12 
>>> hw/vfio/cpr-iommufd.c  |  2 ++
>>> hw/vfio/iommufd-stubs.c| 18 ++
>>> migration/cpr.c| 14 +-
>>> hw/vfio/meson.build|  1 +
>>> 6 files changed, 39 insertions(+), 9 deletions(-)
>>> create mode 100644 hw/vfio/iommufd-stubs.c
>>>
>>> diff --git a/include/hw/vfio/vfio-cpr.h b/include/hw/vfio/vfio-cpr.h
>>> index b9b77ae..619af07 100644
>>> --- a/include/hw/vfio/vfio-cpr.h
>>> +++ b/include/hw/vfio/vfio-cpr.h
>>> @@ -74,5 +74,6 @@ void vfio_cpr_delete_vector_fd(struct
>VFIOPCIDevice *vdev,
>>> const char *name,
>>> int nr);
>>>
>>> extern const VMStateDescription vfio_cpr_pci_vmstate;
>>> +extern const VMStateDescription vmstate_cpr_vfio_devices;
>>>
>>> #endif /* HW_VFIO_VFIO_CPR_H */
>>> diff --git a/include/migration/cpr.h b/include/migration/cpr.h
>>> index 7fd8065..8fd8bfe 100644
>>> --- a/include/migration/cpr.h
>>> +++ b/include/migration/cpr.h
>>> @@ -9,11 +9,23 @@
>>> #define MIGRATION_CPR_H
>>>
>>> #include "qapi/qapi-types-migration.h"
>>> +#include "qemu/queue.h"
>>>
>>> #define MIG_MODE_NONE   -1
>>>
>>> #define QEMU_CPR_FILE_MAGIC 0x51435052
>>> #define QEMU_CPR_FILE_VERSION   0x0001
>>> +#define CPR_STATE "CprState"
>>> +
>>> +typedef QLIST_HEAD(CprFdList, CprFd) CprFdList;
>>> +typedef QLIST_HEAD(CprVFIODeviceList, CprVFIODevice)
>CprVFIODeviceList;
>>> +
>>> +typedef struct CprState {
>>> +CprFdList fds;
>>> +CprVFIODeviceList vfio_devices;
>>> +} CprState;
>>> +
>>> +extern CprState cpr_state;
>>>
>>> void cpr_save_fd(const char *name, int id, int fd);
>>> void cpr_delete_fd(const char *name, int id);
>>> diff --git a/hw/vfio/cpr-iommufd.c b/hw/vfio/cpr-iommufd.c
>>> index 60bd7e8..3e78265 100644
>>> --- a/hw/vfio/cpr-iommufd.c
>>> +++ b/hw/vfio/cpr-iommufd.c
>>> @@ -14,6 +14,8 @@
>>> #include "system/iommufd.h"
>>> #include "vfio-iommufd.h"
>>>
>>> +const VMStateDescription vmstate_cpr_vfio_devices;  /* TBD in a later
>patch */
>>> +
>>> static bool vfio_cpr_supported(IOMMUFDBackend *be, Error **errp)
>>> {
>>>  if (!iommufd_change_process_capable(be)) {
>>> diff --git a/hw/vfio/iommufd-stubs.c b/hw/vfio/iommufd-stubs.c
>>> new file mode 100644
>>> index 000..0be5276
>>> --- /dev/null
>>> +++ b/hw/vfio/iommufd-stubs.c
>>> @@ -0,0 +1,18 @@
>>> +/*
>>> + * Copyright (c) 2025 Oracle and/or its affiliates.
>>> + *
>>> + * SPDX-License-Identifier: GPL-2.0-or-later
>>> + */
>>> +
>>> +#include "qemu/osdep.h"
>>> +#include "migration/cpr.h"
>>> +#include "migration/vmstate.h"
>>> +
>>> +const VMStateDescription vmstate_cpr_vfio_devices = {
>>> +.name = CPR_STATE "/vfio devices",
>>> +.version_id = 1,
>>> +.minimum_version_id = 1,
>>
>> Is there difference if version_id=minimum_version_id=0?
>
>No.  Some developers add a new VMStateDescription starting at 0,
>and some starting at 1.

OK.

Thanks
Zhenzhong



Re: [PATCH V5 30/38] migration: vfio cpr state hook

2025-07-01 Thread Steven Sistare

On 6/24/2025 7:24 AM, Duan, Zhenzhong wrote:

-Original Message-
From: Steve Sistare 
Subject: [PATCH V5 30/38] migration: vfio cpr state hook

Define a list of vfio devices in CPR state, in a subsection so that
older QEMU can be live updated to this version.  However, new QEMU
will not be live updateable to old QEMU.  This is acceptable because
CPR is not yet commonly used, and updates to older versions are unusual.


I'm not familiar with migration, may I ask how subsection help blocking 
migration
from new to old QEMU?


Migrating new to old will fail with an error message saying the subsection is
not recognized.


The contents of each device object will be defined by the vfio subsystem
in a subsequent patch.

Signed-off-by: Steve Sistare 
---
include/hw/vfio/vfio-cpr.h |  1 +
include/migration/cpr.h| 12 
hw/vfio/cpr-iommufd.c  |  2 ++
hw/vfio/iommufd-stubs.c| 18 ++
migration/cpr.c| 14 +-
hw/vfio/meson.build|  1 +
6 files changed, 39 insertions(+), 9 deletions(-)
create mode 100644 hw/vfio/iommufd-stubs.c

diff --git a/include/hw/vfio/vfio-cpr.h b/include/hw/vfio/vfio-cpr.h
index b9b77ae..619af07 100644
--- a/include/hw/vfio/vfio-cpr.h
+++ b/include/hw/vfio/vfio-cpr.h
@@ -74,5 +74,6 @@ void vfio_cpr_delete_vector_fd(struct VFIOPCIDevice *vdev,
const char *name,
int nr);

extern const VMStateDescription vfio_cpr_pci_vmstate;
+extern const VMStateDescription vmstate_cpr_vfio_devices;

#endif /* HW_VFIO_VFIO_CPR_H */
diff --git a/include/migration/cpr.h b/include/migration/cpr.h
index 7fd8065..8fd8bfe 100644
--- a/include/migration/cpr.h
+++ b/include/migration/cpr.h
@@ -9,11 +9,23 @@
#define MIGRATION_CPR_H

#include "qapi/qapi-types-migration.h"
+#include "qemu/queue.h"

#define MIG_MODE_NONE   -1

#define QEMU_CPR_FILE_MAGIC 0x51435052
#define QEMU_CPR_FILE_VERSION   0x0001
+#define CPR_STATE "CprState"
+
+typedef QLIST_HEAD(CprFdList, CprFd) CprFdList;
+typedef QLIST_HEAD(CprVFIODeviceList, CprVFIODevice) CprVFIODeviceList;
+
+typedef struct CprState {
+CprFdList fds;
+CprVFIODeviceList vfio_devices;
+} CprState;
+
+extern CprState cpr_state;

void cpr_save_fd(const char *name, int id, int fd);
void cpr_delete_fd(const char *name, int id);
diff --git a/hw/vfio/cpr-iommufd.c b/hw/vfio/cpr-iommufd.c
index 60bd7e8..3e78265 100644
--- a/hw/vfio/cpr-iommufd.c
+++ b/hw/vfio/cpr-iommufd.c
@@ -14,6 +14,8 @@
#include "system/iommufd.h"
#include "vfio-iommufd.h"

+const VMStateDescription vmstate_cpr_vfio_devices;  /* TBD in a later patch */
+
static bool vfio_cpr_supported(IOMMUFDBackend *be, Error **errp)
{
 if (!iommufd_change_process_capable(be)) {
diff --git a/hw/vfio/iommufd-stubs.c b/hw/vfio/iommufd-stubs.c
new file mode 100644
index 000..0be5276
--- /dev/null
+++ b/hw/vfio/iommufd-stubs.c
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2025 Oracle and/or its affiliates.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "migration/cpr.h"
+#include "migration/vmstate.h"
+
+const VMStateDescription vmstate_cpr_vfio_devices = {
+.name = CPR_STATE "/vfio devices",
+.version_id = 1,
+.minimum_version_id = 1,


Is there difference if version_id=minimum_version_id=0?


No.  Some developers add a new VMStateDescription starting at 0,
and some starting at 1.

- Steve


Thanks
Zhenzhong


+.fields = (const VMStateField[]){
+VMSTATE_END_OF_LIST()
+}
+};
diff --git a/migration/cpr.c b/migration/cpr.c
index 4574608..47898ab 100644
--- a/migration/cpr.c
+++ b/migration/cpr.c
@@ -22,13 +22,7 @@

/*
/
/* cpr state container for all information to be saved. */

-typedef QLIST_HEAD(CprFdList, CprFd) CprFdList;
-
-typedef struct CprState {
-CprFdList fds;
-} CprState;
-
-static CprState cpr_state;
+CprState cpr_state;


/*
***/

@@ -129,8 +123,6 @@ int cpr_open_fd(const char *path, int flags, const char
*name, int id,
}


/*
/
-#define CPR_STATE "CprState"
-
static const VMStateDescription vmstate_cpr_state = {
 .name = CPR_STATE,
 .version_id = 1,
@@ -138,6 +130,10 @@ static const VMStateDescription vmstate_cpr_state = {
 .fields = (VMStateField[]) {
 VMSTATE_QLIST_V(fds, CprState, 1, vmstate_cpr_fd, CprFd, next),
 VMSTATE_END_OF_LIST()
+},
+.subsections = (const VMStateDescription * const []) {
+&vmstate_cpr_vfio_devices,
+NULL
 }
};

/*
/
diff --git a/hw/vfio/meson.build b/hw/vfio/meson.build
index 56373e3..b9420cf 100644
--- a/hw/vfio/meson.build
+++ b/hw/vfio/meson

RE: [PATCH V5 30/38] migration: vfio cpr state hook

2025-06-24 Thread Duan, Zhenzhong



>-Original Message-
>From: Steve Sistare 
>Subject: [PATCH V5 30/38] migration: vfio cpr state hook
>
>Define a list of vfio devices in CPR state, in a subsection so that
>older QEMU can be live updated to this version.  However, new QEMU
>will not be live updateable to old QEMU.  This is acceptable because
>CPR is not yet commonly used, and updates to older versions are unusual.

I'm not familiar with migration, may I ask how subsection help blocking 
migration
from new to old QEMU?

>
>The contents of each device object will be defined by the vfio subsystem
>in a subsequent patch.
>
>Signed-off-by: Steve Sistare 
>---
> include/hw/vfio/vfio-cpr.h |  1 +
> include/migration/cpr.h| 12 
> hw/vfio/cpr-iommufd.c  |  2 ++
> hw/vfio/iommufd-stubs.c| 18 ++
> migration/cpr.c| 14 +-
> hw/vfio/meson.build|  1 +
> 6 files changed, 39 insertions(+), 9 deletions(-)
> create mode 100644 hw/vfio/iommufd-stubs.c
>
>diff --git a/include/hw/vfio/vfio-cpr.h b/include/hw/vfio/vfio-cpr.h
>index b9b77ae..619af07 100644
>--- a/include/hw/vfio/vfio-cpr.h
>+++ b/include/hw/vfio/vfio-cpr.h
>@@ -74,5 +74,6 @@ void vfio_cpr_delete_vector_fd(struct VFIOPCIDevice *vdev,
>const char *name,
>int nr);
>
> extern const VMStateDescription vfio_cpr_pci_vmstate;
>+extern const VMStateDescription vmstate_cpr_vfio_devices;
>
> #endif /* HW_VFIO_VFIO_CPR_H */
>diff --git a/include/migration/cpr.h b/include/migration/cpr.h
>index 7fd8065..8fd8bfe 100644
>--- a/include/migration/cpr.h
>+++ b/include/migration/cpr.h
>@@ -9,11 +9,23 @@
> #define MIGRATION_CPR_H
>
> #include "qapi/qapi-types-migration.h"
>+#include "qemu/queue.h"
>
> #define MIG_MODE_NONE   -1
>
> #define QEMU_CPR_FILE_MAGIC 0x51435052
> #define QEMU_CPR_FILE_VERSION   0x0001
>+#define CPR_STATE "CprState"
>+
>+typedef QLIST_HEAD(CprFdList, CprFd) CprFdList;
>+typedef QLIST_HEAD(CprVFIODeviceList, CprVFIODevice) CprVFIODeviceList;
>+
>+typedef struct CprState {
>+CprFdList fds;
>+CprVFIODeviceList vfio_devices;
>+} CprState;
>+
>+extern CprState cpr_state;
>
> void cpr_save_fd(const char *name, int id, int fd);
> void cpr_delete_fd(const char *name, int id);
>diff --git a/hw/vfio/cpr-iommufd.c b/hw/vfio/cpr-iommufd.c
>index 60bd7e8..3e78265 100644
>--- a/hw/vfio/cpr-iommufd.c
>+++ b/hw/vfio/cpr-iommufd.c
>@@ -14,6 +14,8 @@
> #include "system/iommufd.h"
> #include "vfio-iommufd.h"
>
>+const VMStateDescription vmstate_cpr_vfio_devices;  /* TBD in a later patch */
>+
> static bool vfio_cpr_supported(IOMMUFDBackend *be, Error **errp)
> {
> if (!iommufd_change_process_capable(be)) {
>diff --git a/hw/vfio/iommufd-stubs.c b/hw/vfio/iommufd-stubs.c
>new file mode 100644
>index 000..0be5276
>--- /dev/null
>+++ b/hw/vfio/iommufd-stubs.c
>@@ -0,0 +1,18 @@
>+/*
>+ * Copyright (c) 2025 Oracle and/or its affiliates.
>+ *
>+ * SPDX-License-Identifier: GPL-2.0-or-later
>+ */
>+
>+#include "qemu/osdep.h"
>+#include "migration/cpr.h"
>+#include "migration/vmstate.h"
>+
>+const VMStateDescription vmstate_cpr_vfio_devices = {
>+.name = CPR_STATE "/vfio devices",
>+.version_id = 1,
>+.minimum_version_id = 1,

Is there difference if version_id=minimum_version_id=0?

Thanks
Zhenzhong

>+.fields = (const VMStateField[]){
>+VMSTATE_END_OF_LIST()
>+}
>+};
>diff --git a/migration/cpr.c b/migration/cpr.c
>index 4574608..47898ab 100644
>--- a/migration/cpr.c
>+++ b/migration/cpr.c
>@@ -22,13 +22,7 @@
>
>/*
>/
> /* cpr state container for all information to be saved. */
>
>-typedef QLIST_HEAD(CprFdList, CprFd) CprFdList;
>-
>-typedef struct CprState {
>-CprFdList fds;
>-} CprState;
>-
>-static CprState cpr_state;
>+CprState cpr_state;
>
>
>/*
>***/
>
>@@ -129,8 +123,6 @@ int cpr_open_fd(const char *path, int flags, const char
>*name, int id,
> }
>
>
>/*
>/
>-#define CPR_STATE "CprState"
>-
> static const VMStateDescription vmstate_cpr_state = {
> .name = CPR_STATE,
> .version_id = 1,
>@@ -138,6 +130,10 @@ static const VMStateDescription vmstate_cpr_state = {
> .fields = (VMStateField[]) {
> VMSTATE_QLIST_V(fds, CprState, 1, vmstate_cpr_fd, CprFd, next),
> VMSTATE_END_OF_LIST()
>+ 

[PATCH V5 30/38] migration: vfio cpr state hook

2025-06-10 Thread Steve Sistare
Define a list of vfio devices in CPR state, in a subsection so that
older QEMU can be live updated to this version.  However, new QEMU
will not be live updateable to old QEMU.  This is acceptable because
CPR is not yet commonly used, and updates to older versions are unusual.

The contents of each device object will be defined by the vfio subsystem
in a subsequent patch.

Signed-off-by: Steve Sistare 
---
 include/hw/vfio/vfio-cpr.h |  1 +
 include/migration/cpr.h| 12 
 hw/vfio/cpr-iommufd.c  |  2 ++
 hw/vfio/iommufd-stubs.c| 18 ++
 migration/cpr.c| 14 +-
 hw/vfio/meson.build|  1 +
 6 files changed, 39 insertions(+), 9 deletions(-)
 create mode 100644 hw/vfio/iommufd-stubs.c

diff --git a/include/hw/vfio/vfio-cpr.h b/include/hw/vfio/vfio-cpr.h
index b9b77ae..619af07 100644
--- a/include/hw/vfio/vfio-cpr.h
+++ b/include/hw/vfio/vfio-cpr.h
@@ -74,5 +74,6 @@ void vfio_cpr_delete_vector_fd(struct VFIOPCIDevice *vdev, 
const char *name,
int nr);
 
 extern const VMStateDescription vfio_cpr_pci_vmstate;
+extern const VMStateDescription vmstate_cpr_vfio_devices;
 
 #endif /* HW_VFIO_VFIO_CPR_H */
diff --git a/include/migration/cpr.h b/include/migration/cpr.h
index 7fd8065..8fd8bfe 100644
--- a/include/migration/cpr.h
+++ b/include/migration/cpr.h
@@ -9,11 +9,23 @@
 #define MIGRATION_CPR_H
 
 #include "qapi/qapi-types-migration.h"
+#include "qemu/queue.h"
 
 #define MIG_MODE_NONE   -1
 
 #define QEMU_CPR_FILE_MAGIC 0x51435052
 #define QEMU_CPR_FILE_VERSION   0x0001
+#define CPR_STATE "CprState"
+
+typedef QLIST_HEAD(CprFdList, CprFd) CprFdList;
+typedef QLIST_HEAD(CprVFIODeviceList, CprVFIODevice) CprVFIODeviceList;
+
+typedef struct CprState {
+CprFdList fds;
+CprVFIODeviceList vfio_devices;
+} CprState;
+
+extern CprState cpr_state;
 
 void cpr_save_fd(const char *name, int id, int fd);
 void cpr_delete_fd(const char *name, int id);
diff --git a/hw/vfio/cpr-iommufd.c b/hw/vfio/cpr-iommufd.c
index 60bd7e8..3e78265 100644
--- a/hw/vfio/cpr-iommufd.c
+++ b/hw/vfio/cpr-iommufd.c
@@ -14,6 +14,8 @@
 #include "system/iommufd.h"
 #include "vfio-iommufd.h"
 
+const VMStateDescription vmstate_cpr_vfio_devices;  /* TBD in a later patch */
+
 static bool vfio_cpr_supported(IOMMUFDBackend *be, Error **errp)
 {
 if (!iommufd_change_process_capable(be)) {
diff --git a/hw/vfio/iommufd-stubs.c b/hw/vfio/iommufd-stubs.c
new file mode 100644
index 000..0be5276
--- /dev/null
+++ b/hw/vfio/iommufd-stubs.c
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2025 Oracle and/or its affiliates.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "migration/cpr.h"
+#include "migration/vmstate.h"
+
+const VMStateDescription vmstate_cpr_vfio_devices = {
+.name = CPR_STATE "/vfio devices",
+.version_id = 1,
+.minimum_version_id = 1,
+.fields = (const VMStateField[]){
+VMSTATE_END_OF_LIST()
+}
+};
diff --git a/migration/cpr.c b/migration/cpr.c
index 4574608..47898ab 100644
--- a/migration/cpr.c
+++ b/migration/cpr.c
@@ -22,13 +22,7 @@
 /*/
 /* cpr state container for all information to be saved. */
 
-typedef QLIST_HEAD(CprFdList, CprFd) CprFdList;
-
-typedef struct CprState {
-CprFdList fds;
-} CprState;
-
-static CprState cpr_state;
+CprState cpr_state;
 
 //
 
@@ -129,8 +123,6 @@ int cpr_open_fd(const char *path, int flags, const char 
*name, int id,
 }
 
 /*/
-#define CPR_STATE "CprState"
-
 static const VMStateDescription vmstate_cpr_state = {
 .name = CPR_STATE,
 .version_id = 1,
@@ -138,6 +130,10 @@ static const VMStateDescription vmstate_cpr_state = {
 .fields = (VMStateField[]) {
 VMSTATE_QLIST_V(fds, CprState, 1, vmstate_cpr_fd, CprFd, next),
 VMSTATE_END_OF_LIST()
+},
+.subsections = (const VMStateDescription * const []) {
+&vmstate_cpr_vfio_devices,
+NULL
 }
 };
 /*/
diff --git a/hw/vfio/meson.build b/hw/vfio/meson.build
index 56373e3..b9420cf 100644
--- a/hw/vfio/meson.build
+++ b/hw/vfio/meson.build
@@ -33,6 +33,7 @@ system_ss.add(when: ['CONFIG_VFIO', 'CONFIG_IOMMUFD'], 
if_true: files(
   'iommufd.c',
   'cpr-iommufd.c',
 ))
+system_ss.add(when: 'CONFIG_IOMMUFD', if_false: files('iommufd-stubs.c'))
 system_ss.add(when: 'CONFIG_VFIO_PCI', if_true: files(
   'display.c',
 ))
-- 
1.8.3.1