To preserve CPR state across exec, create a QEMUFile based on a memfd, and
keep the memfd open across exec. Save the value of the memfd in an
environment variable so post-exec QEMU can find it.
These new functions are called in a subsequent patch.
Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
---
include/migration/cpr.h | 5 +++
migration/cpr-exec.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++
migration/meson.build | 1 +
3 files changed, 100 insertions(+)
create mode 100644 migration/cpr-exec.c
diff --git a/include/migration/cpr.h b/include/migration/cpr.h
index 2b074d7..b84389f 100644
--- a/include/migration/cpr.h
+++ b/include/migration/cpr.h
@@ -53,4 +53,9 @@ int cpr_get_fd_param(const char *name, const char *fdname, int index,
QEMUFile *cpr_transfer_output(MigrationChannel *channel, Error **errp);
QEMUFile *cpr_transfer_input(MigrationChannel *channel, Error **errp);
+QEMUFile *cpr_exec_output(Error **errp);
+QEMUFile *cpr_exec_input(Error **errp);
+void cpr_exec_persist_state(QEMUFile *f);
+bool cpr_exec_has_state(void);
+void cpr_exec_unpersist_state(void);
#endif
diff --git a/migration/cpr-exec.c b/migration/cpr-exec.c
new file mode 100644
index 0000000..2c32e9c
--- /dev/null
+++ b/migration/cpr-exec.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2021-2025 Oracle and/or its affiliates.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/cutils.h"
+#include "qemu/memfd.h"
+#include "qapi/error.h"
+#include "io/channel-file.h"
+#include "io/channel-socket.h"
+#include "migration/cpr.h"
+#include "migration/qemu-file.h"
+#include "migration/misc.h"
+#include "migration/vmstate.h"
+#include "system/runstate.h"
+
+#define CPR_EXEC_STATE_NAME "QEMU_CPR_EXEC_STATE"
+
+static QEMUFile *qemu_file_new_fd_input(int fd, const char *name)
+{
+ g_autoptr(QIOChannelFile) fioc = qio_channel_file_new_fd(fd);
+ QIOChannel *ioc = QIO_CHANNEL(fioc);
+ qio_channel_set_name(ioc, name);
+ return qemu_file_new_input(ioc);
+}
+
+static QEMUFile *qemu_file_new_fd_output(int fd, const char *name)
+{
+ g_autoptr(QIOChannelFile) fioc = qio_channel_file_new_fd(fd);
+ QIOChannel *ioc = QIO_CHANNEL(fioc);
+ qio_channel_set_name(ioc, name);
+ return qemu_file_new_output(ioc);
+}
+
+void cpr_exec_persist_state(QEMUFile *f)
+{
+ QIOChannelFile *fioc = QIO_CHANNEL_FILE(qemu_file_get_ioc(f));
+ int mfd = dup(fioc->fd);
+ char val[16];
+
+ /* Remember mfd in environment for post-exec load */
+ qemu_clear_cloexec(mfd);
+ snprintf(val, sizeof(val), "%d", mfd);
+ g_setenv(CPR_EXEC_STATE_NAME, val, 1);
+}
+
+static int cpr_exec_find_state(void)
+{
+ const char *val = g_getenv(CPR_EXEC_STATE_NAME);
+ int mfd;
+
+ assert(val);
+ g_unsetenv(CPR_EXEC_STATE_NAME);
+ assert(!qemu_strtoi(val, NULL, 10, &mfd));
+ return mfd;
+}
+
+bool cpr_exec_has_state(void)
+{
+ return g_getenv(CPR_EXEC_STATE_NAME) != NULL;
+}
+
+void cpr_exec_unpersist_state(void)
+{
+ int mfd;
+ const char *val = g_getenv(CPR_EXEC_STATE_NAME);
+
+ g_unsetenv(CPR_EXEC_STATE_NAME);
+ assert(val);
+ assert(!qemu_strtoi(val, NULL, 10, &mfd));
+ close(mfd);
+}
+
+QEMUFile *cpr_exec_output(Error **errp)
+{
+ int mfd = memfd_create(CPR_EXEC_STATE_NAME, 0);
+
+ if (mfd < 0) {
+ error_setg_errno(errp, errno, "memfd_create failed");
+ return NULL;
+ }
+
+ return qemu_file_new_fd_output(mfd, CPR_EXEC_STATE_NAME);
+}
+
+QEMUFile *cpr_exec_input(Error **errp)
+{
+ int mfd = cpr_exec_find_state();
+
+ lseek(mfd, 0, SEEK_SET);
+ return qemu_file_new_fd_input(mfd, CPR_EXEC_STATE_NAME);
+}
diff --git a/migration/meson.build b/migration/meson.build
index 0f71544..16909d5 100644
--- a/migration/meson.build
+++ b/migration/meson.build
@@ -16,6 +16,7 @@ system_ss.add(files(
'channel-block.c',
'cpr.c',
'cpr-transfer.c',
+ 'cpr-exec.c',
'cpu-throttle.c',
'dirtyrate.c',
'exec.c',
--
1.8.3.1
On 9/22/25 15:49, Steve Sistare wrote: > To preserve CPR state across exec, create a QEMUFile based on a memfd, and > keep the memfd open across exec. Save the value of the memfd in an > environment variable so post-exec QEMU can find it. Couldn't we preserve some memory to hand off to QEMU ? Like firmwares An environment variable is a limited method. Thanks, C. That's a short term hack right ? it's not even documented. I am sure you something else in mind. > These new functions are called in a subsequent patch. > > Signed-off-by: Steve Sistare <steven.sistare@oracle.com> > --- > include/migration/cpr.h | 5 +++ > migration/cpr-exec.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++ > migration/meson.build | 1 + > 3 files changed, 100 insertions(+) > create mode 100644 migration/cpr-exec.c > > diff --git a/include/migration/cpr.h b/include/migration/cpr.h > index 2b074d7..b84389f 100644 > --- a/include/migration/cpr.h > +++ b/include/migration/cpr.h > @@ -53,4 +53,9 @@ int cpr_get_fd_param(const char *name, const char *fdname, int index, > QEMUFile *cpr_transfer_output(MigrationChannel *channel, Error **errp); > QEMUFile *cpr_transfer_input(MigrationChannel *channel, Error **errp); > > +QEMUFile *cpr_exec_output(Error **errp); > +QEMUFile *cpr_exec_input(Error **errp); > +void cpr_exec_persist_state(QEMUFile *f); > +bool cpr_exec_has_state(void); > +void cpr_exec_unpersist_state(void); > #endif > diff --git a/migration/cpr-exec.c b/migration/cpr-exec.c > new file mode 100644 > index 0000000..2c32e9c > --- /dev/null > +++ b/migration/cpr-exec.c > @@ -0,0 +1,94 @@ > +/* > + * Copyright (c) 2021-2025 Oracle and/or its affiliates. > + * > + * SPDX-License-Identifier: GPL-2.0-or-later > + */ > + > +#include "qemu/osdep.h" > +#include "qemu/cutils.h" > +#include "qemu/memfd.h" > +#include "qapi/error.h" > +#include "io/channel-file.h" > +#include "io/channel-socket.h" > +#include "migration/cpr.h" > +#include "migration/qemu-file.h" > +#include "migration/misc.h" > +#include "migration/vmstate.h" > +#include "system/runstate.h" > + > +#define CPR_EXEC_STATE_NAME "QEMU_CPR_EXEC_STATE" > + > +static QEMUFile *qemu_file_new_fd_input(int fd, const char *name) > +{ > + g_autoptr(QIOChannelFile) fioc = qio_channel_file_new_fd(fd); > + QIOChannel *ioc = QIO_CHANNEL(fioc); > + qio_channel_set_name(ioc, name); > + return qemu_file_new_input(ioc); > +} > + > +static QEMUFile *qemu_file_new_fd_output(int fd, const char *name) > +{ > + g_autoptr(QIOChannelFile) fioc = qio_channel_file_new_fd(fd); > + QIOChannel *ioc = QIO_CHANNEL(fioc); > + qio_channel_set_name(ioc, name); > + return qemu_file_new_output(ioc); > +} > + > +void cpr_exec_persist_state(QEMUFile *f) > +{ > + QIOChannelFile *fioc = QIO_CHANNEL_FILE(qemu_file_get_ioc(f)); > + int mfd = dup(fioc->fd); > + char val[16]; > + > + /* Remember mfd in environment for post-exec load */ > + qemu_clear_cloexec(mfd); > + snprintf(val, sizeof(val), "%d", mfd); > + g_setenv(CPR_EXEC_STATE_NAME, val, 1); > +} > + > +static int cpr_exec_find_state(void) > +{ > + const char *val = g_getenv(CPR_EXEC_STATE_NAME); > + int mfd; > + > + assert(val); > + g_unsetenv(CPR_EXEC_STATE_NAME); > + assert(!qemu_strtoi(val, NULL, 10, &mfd)); > + return mfd; > +} > + > +bool cpr_exec_has_state(void) > +{ > + return g_getenv(CPR_EXEC_STATE_NAME) != NULL; > +} > + > +void cpr_exec_unpersist_state(void) > +{ > + int mfd; > + const char *val = g_getenv(CPR_EXEC_STATE_NAME); > + > + g_unsetenv(CPR_EXEC_STATE_NAME); > + assert(val); > + assert(!qemu_strtoi(val, NULL, 10, &mfd)); > + close(mfd); > +} > + > +QEMUFile *cpr_exec_output(Error **errp) > +{ > + int mfd = memfd_create(CPR_EXEC_STATE_NAME, 0); The build should be adjusted for Linux only. Thanks, C. > + > + if (mfd < 0) { > + error_setg_errno(errp, errno, "memfd_create failed"); > + return NULL; > + } > + > + return qemu_file_new_fd_output(mfd, CPR_EXEC_STATE_NAME); > +} > + > +QEMUFile *cpr_exec_input(Error **errp) > +{ > + int mfd = cpr_exec_find_state(); > + > + lseek(mfd, 0, SEEK_SET); > + return qemu_file_new_fd_input(mfd, CPR_EXEC_STATE_NAME); > +} > diff --git a/migration/meson.build b/migration/meson.build > index 0f71544..16909d5 100644 > --- a/migration/meson.build > +++ b/migration/meson.build > @@ -16,6 +16,7 @@ system_ss.add(files( > 'channel-block.c', > 'cpr.c', > 'cpr-transfer.c', > + 'cpr-exec.c', > 'cpu-throttle.c', > 'dirtyrate.c', > 'exec.c',
On 9/22/2025 12:00 PM, Cédric Le Goater wrote: > On 9/22/25 15:49, Steve Sistare wrote: >> To preserve CPR state across exec, create a QEMUFile based on a memfd, and >> keep the memfd open across exec. Save the value of the memfd in an >> environment variable so post-exec QEMU can find it. > > Couldn't we preserve some memory to hand off to QEMU ? Like firmwares > An environment variable is a limited method. There is no upside in making this more complicated. We only need to pass one tidbit of information -- the file descriptor number of the memfd that contains all other information. > Thanks, > > C. > > That's a short term hack right ? it's not even documented. It is an implementation detail, known only to the matched saving and loading functions inside qemu. No one else needs to know, so no documentation. - Steve >I am sure > you something else in mind. > >> These new functions are called in a subsequent patch. >> >> Signed-off-by: Steve Sistare <steven.sistare@oracle.com> >> --- >> include/migration/cpr.h | 5 +++ >> migration/cpr-exec.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++ >> migration/meson.build | 1 + >> 3 files changed, 100 insertions(+) >> create mode 100644 migration/cpr-exec.c >> >> diff --git a/include/migration/cpr.h b/include/migration/cpr.h >> index 2b074d7..b84389f 100644 >> --- a/include/migration/cpr.h >> +++ b/include/migration/cpr.h >> @@ -53,4 +53,9 @@ int cpr_get_fd_param(const char *name, const char *fdname, int index, >> QEMUFile *cpr_transfer_output(MigrationChannel *channel, Error **errp); >> QEMUFile *cpr_transfer_input(MigrationChannel *channel, Error **errp); >> +QEMUFile *cpr_exec_output(Error **errp); >> +QEMUFile *cpr_exec_input(Error **errp); >> +void cpr_exec_persist_state(QEMUFile *f); >> +bool cpr_exec_has_state(void); >> +void cpr_exec_unpersist_state(void); >> #endif >> diff --git a/migration/cpr-exec.c b/migration/cpr-exec.c >> new file mode 100644 >> index 0000000..2c32e9c >> --- /dev/null >> +++ b/migration/cpr-exec.c >> @@ -0,0 +1,94 @@ >> +/* >> + * Copyright (c) 2021-2025 Oracle and/or its affiliates. >> + * >> + * SPDX-License-Identifier: GPL-2.0-or-later >> + */ >> + >> +#include "qemu/osdep.h" >> +#include "qemu/cutils.h" >> +#include "qemu/memfd.h" >> +#include "qapi/error.h" >> +#include "io/channel-file.h" >> +#include "io/channel-socket.h" >> +#include "migration/cpr.h" >> +#include "migration/qemu-file.h" >> +#include "migration/misc.h" >> +#include "migration/vmstate.h" >> +#include "system/runstate.h" >> + >> +#define CPR_EXEC_STATE_NAME "QEMU_CPR_EXEC_STATE" >> + >> +static QEMUFile *qemu_file_new_fd_input(int fd, const char *name) >> +{ >> + g_autoptr(QIOChannelFile) fioc = qio_channel_file_new_fd(fd); >> + QIOChannel *ioc = QIO_CHANNEL(fioc); >> + qio_channel_set_name(ioc, name); >> + return qemu_file_new_input(ioc); >> +} >> + >> +static QEMUFile *qemu_file_new_fd_output(int fd, const char *name) >> +{ >> + g_autoptr(QIOChannelFile) fioc = qio_channel_file_new_fd(fd); >> + QIOChannel *ioc = QIO_CHANNEL(fioc); >> + qio_channel_set_name(ioc, name); >> + return qemu_file_new_output(ioc); >> +} >> + >> +void cpr_exec_persist_state(QEMUFile *f) >> +{ >> + QIOChannelFile *fioc = QIO_CHANNEL_FILE(qemu_file_get_ioc(f)); >> + int mfd = dup(fioc->fd); >> + char val[16]; >> + >> + /* Remember mfd in environment for post-exec load */ >> + qemu_clear_cloexec(mfd); >> + snprintf(val, sizeof(val), "%d", mfd); >> + g_setenv(CPR_EXEC_STATE_NAME, val, 1); >> +} >> + >> +static int cpr_exec_find_state(void) >> +{ >> + const char *val = g_getenv(CPR_EXEC_STATE_NAME); >> + int mfd; >> + >> + assert(val); >> + g_unsetenv(CPR_EXEC_STATE_NAME); >> + assert(!qemu_strtoi(val, NULL, 10, &mfd)); >> + return mfd; >> +} >> + >> +bool cpr_exec_has_state(void) >> +{ >> + return g_getenv(CPR_EXEC_STATE_NAME) != NULL; >> +} >> + >> +void cpr_exec_unpersist_state(void) >> +{ >> + int mfd; >> + const char *val = g_getenv(CPR_EXEC_STATE_NAME); >> + >> + g_unsetenv(CPR_EXEC_STATE_NAME); >> + assert(val); >> + assert(!qemu_strtoi(val, NULL, 10, &mfd)); >> + close(mfd); >> +} >> + >> +QEMUFile *cpr_exec_output(Error **errp) >> +{ >> + int mfd = memfd_create(CPR_EXEC_STATE_NAME, 0); > > The build should be adjusted for Linux only. > > Thanks, > > C. > > > >> + >> + if (mfd < 0) { >> + error_setg_errno(errp, errno, "memfd_create failed"); >> + return NULL; >> + } >> + >> + return qemu_file_new_fd_output(mfd, CPR_EXEC_STATE_NAME); >> +} >> + >> +QEMUFile *cpr_exec_input(Error **errp) >> +{ >> + int mfd = cpr_exec_find_state(); >> + >> + lseek(mfd, 0, SEEK_SET); >> + return qemu_file_new_fd_input(mfd, CPR_EXEC_STATE_NAME); >> +} >> diff --git a/migration/meson.build b/migration/meson.build >> index 0f71544..16909d5 100644 >> --- a/migration/meson.build >> +++ b/migration/meson.build >> @@ -16,6 +16,7 @@ system_ss.add(files( >> 'channel-block.c', >> 'cpr.c', >> 'cpr-transfer.c', >> + 'cpr-exec.c', >> 'cpu-throttle.c', >> 'dirtyrate.c', >> 'exec.c', >
On 9/24/25 20:16, Steven Sistare wrote: > On 9/22/2025 12:00 PM, Cédric Le Goater wrote: >> On 9/22/25 15:49, Steve Sistare wrote: >>> To preserve CPR state across exec, create a QEMUFile based on a memfd, and >>> keep the memfd open across exec. Save the value of the memfd in an >>> environment variable so post-exec QEMU can find it. >> >> Couldn't we preserve some memory to hand off to QEMU ? Like firmwares >> An environment variable is a limited method. > > There is no upside in making this more complicated. We only need to > pass one tidbit of information -- the file descriptor number of the memfd > that contains all other information. Please adjust the build for windows, memfd is Linux only. >> Thanks, >> >> C. >> >> That's a short term hack right ? it's not even documented. > > It is an implementation detail, known only to the matched saving > and loading functions inside qemu. No one else needs to know, so > no documentation. ok. Fair enough. Thanks, C. > > - Steve > >> I am sure >> you something else in mind. >> >>> These new functions are called in a subsequent patch. >>> >>> Signed-off-by: Steve Sistare <steven.sistare@oracle.com> >>> --- >>> include/migration/cpr.h | 5 +++ >>> migration/cpr-exec.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++ >>> migration/meson.build | 1 + >>> 3 files changed, 100 insertions(+) >>> create mode 100644 migration/cpr-exec.c >>> >>> diff --git a/include/migration/cpr.h b/include/migration/cpr.h >>> index 2b074d7..b84389f 100644 >>> --- a/include/migration/cpr.h >>> +++ b/include/migration/cpr.h >>> @@ -53,4 +53,9 @@ int cpr_get_fd_param(const char *name, const char *fdname, int index, >>> QEMUFile *cpr_transfer_output(MigrationChannel *channel, Error **errp); >>> QEMUFile *cpr_transfer_input(MigrationChannel *channel, Error **errp); >>> +QEMUFile *cpr_exec_output(Error **errp); >>> +QEMUFile *cpr_exec_input(Error **errp); >>> +void cpr_exec_persist_state(QEMUFile *f); >>> +bool cpr_exec_has_state(void); >>> +void cpr_exec_unpersist_state(void); >>> #endif >>> diff --git a/migration/cpr-exec.c b/migration/cpr-exec.c >>> new file mode 100644 >>> index 0000000..2c32e9c >>> --- /dev/null >>> +++ b/migration/cpr-exec.c >>> @@ -0,0 +1,94 @@ >>> +/* >>> + * Copyright (c) 2021-2025 Oracle and/or its affiliates. >>> + * >>> + * SPDX-License-Identifier: GPL-2.0-or-later >>> + */ >>> + >>> +#include "qemu/osdep.h" >>> +#include "qemu/cutils.h" >>> +#include "qemu/memfd.h" >>> +#include "qapi/error.h" >>> +#include "io/channel-file.h" >>> +#include "io/channel-socket.h" >>> +#include "migration/cpr.h" >>> +#include "migration/qemu-file.h" >>> +#include "migration/misc.h" >>> +#include "migration/vmstate.h" >>> +#include "system/runstate.h" >>> + >>> +#define CPR_EXEC_STATE_NAME "QEMU_CPR_EXEC_STATE" >>> + >>> +static QEMUFile *qemu_file_new_fd_input(int fd, const char *name) >>> +{ >>> + g_autoptr(QIOChannelFile) fioc = qio_channel_file_new_fd(fd); >>> + QIOChannel *ioc = QIO_CHANNEL(fioc); >>> + qio_channel_set_name(ioc, name); >>> + return qemu_file_new_input(ioc); >>> +} >>> + >>> +static QEMUFile *qemu_file_new_fd_output(int fd, const char *name) >>> +{ >>> + g_autoptr(QIOChannelFile) fioc = qio_channel_file_new_fd(fd); >>> + QIOChannel *ioc = QIO_CHANNEL(fioc); >>> + qio_channel_set_name(ioc, name); >>> + return qemu_file_new_output(ioc); >>> +} >>> + >>> +void cpr_exec_persist_state(QEMUFile *f) >>> +{ >>> + QIOChannelFile *fioc = QIO_CHANNEL_FILE(qemu_file_get_ioc(f)); >>> + int mfd = dup(fioc->fd); >>> + char val[16]; >>> + >>> + /* Remember mfd in environment for post-exec load */ >>> + qemu_clear_cloexec(mfd); >>> + snprintf(val, sizeof(val), "%d", mfd); >>> + g_setenv(CPR_EXEC_STATE_NAME, val, 1); >>> +} >>> + >>> +static int cpr_exec_find_state(void) >>> +{ >>> + const char *val = g_getenv(CPR_EXEC_STATE_NAME); >>> + int mfd; >>> + >>> + assert(val); >>> + g_unsetenv(CPR_EXEC_STATE_NAME); >>> + assert(!qemu_strtoi(val, NULL, 10, &mfd)); >>> + return mfd; >>> +} >>> + >>> +bool cpr_exec_has_state(void) >>> +{ >>> + return g_getenv(CPR_EXEC_STATE_NAME) != NULL; >>> +} >>> + >>> +void cpr_exec_unpersist_state(void) >>> +{ >>> + int mfd; >>> + const char *val = g_getenv(CPR_EXEC_STATE_NAME); >>> + >>> + g_unsetenv(CPR_EXEC_STATE_NAME); >>> + assert(val); >>> + assert(!qemu_strtoi(val, NULL, 10, &mfd)); >>> + close(mfd); >>> +} >>> + >>> +QEMUFile *cpr_exec_output(Error **errp) >>> +{ >>> + int mfd = memfd_create(CPR_EXEC_STATE_NAME, 0); >> >> The build should be adjusted for Linux only. >> >> Thanks, >> >> C. >> >> >> >>> + >>> + if (mfd < 0) { >>> + error_setg_errno(errp, errno, "memfd_create failed"); >>> + return NULL; >>> + } >>> + >>> + return qemu_file_new_fd_output(mfd, CPR_EXEC_STATE_NAME); >>> +} >>> + >>> +QEMUFile *cpr_exec_input(Error **errp) >>> +{ >>> + int mfd = cpr_exec_find_state(); >>> + >>> + lseek(mfd, 0, SEEK_SET); >>> + return qemu_file_new_fd_input(mfd, CPR_EXEC_STATE_NAME); >>> +} >>> diff --git a/migration/meson.build b/migration/meson.build >>> index 0f71544..16909d5 100644 >>> --- a/migration/meson.build >>> +++ b/migration/meson.build >>> @@ -16,6 +16,7 @@ system_ss.add(files( >>> 'channel-block.c', >>> 'cpr.c', >>> 'cpr-transfer.c', >>> + 'cpr-exec.c', >>> 'cpu-throttle.c', >>> 'dirtyrate.c', >>> 'exec.c', >> >
On 9/25/2025 3:11 AM, Cédric Le Goater wrote: > On 9/24/25 20:16, Steven Sistare wrote: >> On 9/22/2025 12:00 PM, Cédric Le Goater wrote: >>> On 9/22/25 15:49, Steve Sistare wrote: >>>> To preserve CPR state across exec, create a QEMUFile based on a memfd, and >>>> keep the memfd open across exec. Save the value of the memfd in an >>>> environment variable so post-exec QEMU can find it. >>> >>> Couldn't we preserve some memory to hand off to QEMU ? Like firmwares >>> An environment variable is a limited method. >> >> There is no upside in making this more complicated. We only need to >> pass one tidbit of information -- the file descriptor number of the memfd >> that contains all other information. > > Please adjust the build for windows, memfd is Linux only. Will do, thanks. I will call qemu_memfd_create, which is defined for posix and windows but returns error for the latter, instead of memfd_create. - Steve >>> That's a short term hack right ? it's not even documented. >> >> It is an implementation detail, known only to the matched saving >> and loading functions inside qemu. No one else needs to know, so >> no documentation. > > ok. Fair enough. > > Thanks, > > C. > > >> >> - Steve >> >>> I am sure >>> you something else in mind. >>> >>>> These new functions are called in a subsequent patch. >>>> >>>> Signed-off-by: Steve Sistare <steven.sistare@oracle.com> >>>> --- >>>> include/migration/cpr.h | 5 +++ >>>> migration/cpr-exec.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++ >>>> migration/meson.build | 1 + >>>> 3 files changed, 100 insertions(+) >>>> create mode 100644 migration/cpr-exec.c >>>> >>>> diff --git a/include/migration/cpr.h b/include/migration/cpr.h >>>> index 2b074d7..b84389f 100644 >>>> --- a/include/migration/cpr.h >>>> +++ b/include/migration/cpr.h >>>> @@ -53,4 +53,9 @@ int cpr_get_fd_param(const char *name, const char *fdname, int index, >>>> QEMUFile *cpr_transfer_output(MigrationChannel *channel, Error **errp); >>>> QEMUFile *cpr_transfer_input(MigrationChannel *channel, Error **errp); >>>> +QEMUFile *cpr_exec_output(Error **errp); >>>> +QEMUFile *cpr_exec_input(Error **errp); >>>> +void cpr_exec_persist_state(QEMUFile *f); >>>> +bool cpr_exec_has_state(void); >>>> +void cpr_exec_unpersist_state(void); >>>> #endif >>>> diff --git a/migration/cpr-exec.c b/migration/cpr-exec.c >>>> new file mode 100644 >>>> index 0000000..2c32e9c >>>> --- /dev/null >>>> +++ b/migration/cpr-exec.c >>>> @@ -0,0 +1,94 @@ >>>> +/* >>>> + * Copyright (c) 2021-2025 Oracle and/or its affiliates. >>>> + * >>>> + * SPDX-License-Identifier: GPL-2.0-or-later >>>> + */ >>>> + >>>> +#include "qemu/osdep.h" >>>> +#include "qemu/cutils.h" >>>> +#include "qemu/memfd.h" >>>> +#include "qapi/error.h" >>>> +#include "io/channel-file.h" >>>> +#include "io/channel-socket.h" >>>> +#include "migration/cpr.h" >>>> +#include "migration/qemu-file.h" >>>> +#include "migration/misc.h" >>>> +#include "migration/vmstate.h" >>>> +#include "system/runstate.h" >>>> + >>>> +#define CPR_EXEC_STATE_NAME "QEMU_CPR_EXEC_STATE" >>>> + >>>> +static QEMUFile *qemu_file_new_fd_input(int fd, const char *name) >>>> +{ >>>> + g_autoptr(QIOChannelFile) fioc = qio_channel_file_new_fd(fd); >>>> + QIOChannel *ioc = QIO_CHANNEL(fioc); >>>> + qio_channel_set_name(ioc, name); >>>> + return qemu_file_new_input(ioc); >>>> +} >>>> + >>>> +static QEMUFile *qemu_file_new_fd_output(int fd, const char *name) >>>> +{ >>>> + g_autoptr(QIOChannelFile) fioc = qio_channel_file_new_fd(fd); >>>> + QIOChannel *ioc = QIO_CHANNEL(fioc); >>>> + qio_channel_set_name(ioc, name); >>>> + return qemu_file_new_output(ioc); >>>> +} >>>> + >>>> +void cpr_exec_persist_state(QEMUFile *f) >>>> +{ >>>> + QIOChannelFile *fioc = QIO_CHANNEL_FILE(qemu_file_get_ioc(f)); >>>> + int mfd = dup(fioc->fd); >>>> + char val[16]; >>>> + >>>> + /* Remember mfd in environment for post-exec load */ >>>> + qemu_clear_cloexec(mfd); >>>> + snprintf(val, sizeof(val), "%d", mfd); >>>> + g_setenv(CPR_EXEC_STATE_NAME, val, 1); >>>> +} >>>> + >>>> +static int cpr_exec_find_state(void) >>>> +{ >>>> + const char *val = g_getenv(CPR_EXEC_STATE_NAME); >>>> + int mfd; >>>> + >>>> + assert(val); >>>> + g_unsetenv(CPR_EXEC_STATE_NAME); >>>> + assert(!qemu_strtoi(val, NULL, 10, &mfd)); >>>> + return mfd; >>>> +} >>>> + >>>> +bool cpr_exec_has_state(void) >>>> +{ >>>> + return g_getenv(CPR_EXEC_STATE_NAME) != NULL; >>>> +} >>>> + >>>> +void cpr_exec_unpersist_state(void) >>>> +{ >>>> + int mfd; >>>> + const char *val = g_getenv(CPR_EXEC_STATE_NAME); >>>> + >>>> + g_unsetenv(CPR_EXEC_STATE_NAME); >>>> + assert(val); >>>> + assert(!qemu_strtoi(val, NULL, 10, &mfd)); >>>> + close(mfd); >>>> +} >>>> + >>>> +QEMUFile *cpr_exec_output(Error **errp) >>>> +{ >>>> + int mfd = memfd_create(CPR_EXEC_STATE_NAME, 0); >>> >>> The build should be adjusted for Linux only. >>> >>> Thanks, >>> >>> C. >>> >>> >>> >>>> + >>>> + if (mfd < 0) { >>>> + error_setg_errno(errp, errno, "memfd_create failed"); >>>> + return NULL; >>>> + } >>>> + >>>> + return qemu_file_new_fd_output(mfd, CPR_EXEC_STATE_NAME); >>>> +} >>>> + >>>> +QEMUFile *cpr_exec_input(Error **errp) >>>> +{ >>>> + int mfd = cpr_exec_find_state(); >>>> + >>>> + lseek(mfd, 0, SEEK_SET); >>>> + return qemu_file_new_fd_input(mfd, CPR_EXEC_STATE_NAME); >>>> +} >>>> diff --git a/migration/meson.build b/migration/meson.build >>>> index 0f71544..16909d5 100644 >>>> --- a/migration/meson.build >>>> +++ b/migration/meson.build >>>> @@ -16,6 +16,7 @@ system_ss.add(files( >>>> 'channel-block.c', >>>> 'cpr.c', >>>> 'cpr-transfer.c', >>>> + 'cpr-exec.c', >>>> 'cpu-throttle.c', >>>> 'dirtyrate.c', >>>> 'exec.c', >>> >> >
© 2016 - 2025 Red Hat, Inc.