On Mon, Apr 29, 2024 at 08:55:29AM -0700, Steve Sistare wrote: > Add the cpr-exec migration mode. Usage: > qemu-system-$arch -machine memfd-alloc=on ... > migrate_set_parameter mode cpr-exec > migrate_set_parameter cpr-exec-args \ > <arg1> <arg2> ... -incoming <uri> > migrate -d <uri> > > The migrate command stops the VM, saves state to the URI, > directly exec's a new version of QEMU on the same host, > replacing the original process while retaining its PID, and > loads state from the URI. Guest RAM is preserved in place, > albeit with new virtual addresses. > > Arguments for the new QEMU process are taken from the > @cpr-exec-args parameter. The first argument should be the > path of a new QEMU binary, or a prefix command that exec's the > new QEMU binary. > > Because old QEMU terminates when new QEMU starts, one cannot > stream data between the two, so the URI must be a type, such as > a file, that reads all data before old QEMU exits. > > Memory backend objects must have the share=on attribute, and > must be mmap'able in the new QEMU process. For example, > memory-backend-file is acceptable, but memory-backend-ram is > not. > > The VM must be started with the '-machine memfd-alloc=on' > option. This causes implicit ram blocks (those not explicitly > described by a memory-backend object) to be allocated by > mmap'ing a memfd. Examples include VGA, ROM, and even guest > RAM when it is specified without a memory-backend object. > > The implementation saves precreate vmstate at the end of normal > migration in migrate_fd_cleanup, and tells the main loop to call > cpr_exec. Incoming qemu loads preceate state early, before objects > are created. The memfds are kept open across exec by clearing the > close-on-exec flag, their values are saved in precreate vmstate, > and they are mmap'd in new qemu. > > Note that the memfd-alloc option is not related to memory-backend-memfd. > Later patches add support for memory-backend-memfd, and for additional > devices, including vfio, chardev, and more. > > Signed-off-by: Steve Sistare <steven.sist...@oracle.com> > --- > include/migration/cpr.h | 14 +++++ > include/migration/misc.h | 3 ++ > migration/cpr.c | 131 > +++++++++++++++++++++++++++++++++++++++++++++++ > migration/meson.build | 1 + > migration/migration.c | 21 ++++++++ > migration/migration.h | 5 +- > migration/ram.c | 1 + > qapi/migration.json | 30 ++++++++++- > system/physmem.c | 2 + > system/vl.c | 4 ++ > 10 files changed, 210 insertions(+), 2 deletions(-) > create mode 100644 include/migration/cpr.h > create mode 100644 migration/cpr.c >
> + > +void cpr_exec(char **argv) > +{ > + MigrationState *s = migrate_get_current(); > + Error *err = NULL; > + > + /* > + * Clear the close-on-exec flag for all preserved fd's. We cannot do so > + * earlier because they should not persist across miscellaneous fork and > + * exec calls that are performed during normal operation. > + */ > + cpr_preserve_fds(); > + > + execvp(argv[0], argv); > + > + error_setg_errno(&err, errno, "execvp %s failed", argv[0]); This is where you could give a more direct message about the sandbox. eg if (errno == EPERM) { error_append_hint("sandbox is blocking ability to exec"); } this would also benefit the case where an external sandbox is used, rather than qemu's built-in sandbox. > + error_report_err(err); > + migrate_set_state(&s->state, s->state, MIGRATION_STATUS_FAILED); > + migrate_set_error(s, err); > + migration_precreate_unsave(); > +} With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|