Add an interface to register a blocker for cpr-save for one or more modes. Devices and options that do not support a cpr mode can register a blocker, and cpr-save will fail with a descriptive error message. Conversely, if such a device is deleted and un-registers its blocker, cpr will be allowed again.
Signed-off-by: Steve Sistare <steven.sist...@oracle.com> --- MAINTAINERS | 1 + include/migration/cpr.h | 6 ++++ migration/cpr.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++ stubs/cpr.c | 23 ++++++++++++++ stubs/meson.build | 1 + 5 files changed, 110 insertions(+) create mode 100644 stubs/cpr.c diff --git a/MAINTAINERS b/MAINTAINERS index 9273891..1e4e72f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3159,6 +3159,7 @@ S: Maintained F: include/migration/cpr.h F: migration/cpr.c F: qapi/cpr.json +F: stubs/cpr.c Record/replay M: Pavel Dovgalyuk <pavel.dovga...@ispras.ru> diff --git a/include/migration/cpr.h b/include/migration/cpr.h index 1b6c82f..dfe5a1d 100644 --- a/include/migration/cpr.h +++ b/include/migration/cpr.h @@ -13,4 +13,10 @@ void cpr_set_mode(CprMode mode); CprMode cpr_get_mode(void); +#define CPR_MODE_ALL CPR_MODE__MAX + +int cpr_add_blocker(Error **reasonp, Error **errp, CprMode mode, ...); +int cpr_add_blocker_str(const char *reason, Error **errp, CprMode mode, ...); +void cpr_del_blocker(Error **reasonp); + #endif diff --git a/migration/cpr.c b/migration/cpr.c index 24b0bcc..c1da784 100644 --- a/migration/cpr.c +++ b/migration/cpr.c @@ -29,12 +29,91 @@ void cpr_set_mode(CprMode mode) cpr_mode = mode; } +static GSList *cpr_blockers[CPR_MODE__MAX]; + +/* + * Add blocker for each mode in varargs list, or for all modes if CPR_MODE_ALL + * is specified. Caller terminates the list with 0 or CPR_MODE_ALL. This + * function takes ownership of *reasonp, and frees it on error, or in + * cpr_del_blocker. errp is set in a later patch. + */ +int cpr_add_blocker(Error **reasonp, Error **errp, CprMode mode, ...) +{ + int modes = 0; + va_list ap; + ERRP_GUARD(); + + va_start(ap, mode); + while (mode != CPR_MODE_NONE && mode != CPR_MODE_ALL) { + assert(mode > CPR_MODE_NONE && mode < CPR_MODE__MAX); + modes |= BIT(mode); + mode = va_arg(ap, CprMode); + } + va_end(ap); + if (mode == CPR_MODE_ALL) { + modes = BIT(CPR_MODE__MAX) - 1; + } + + for (mode = 0; mode < CPR_MODE__MAX; mode++) { + if (modes & BIT(mode)) { + cpr_blockers[mode] = g_slist_prepend(cpr_blockers[mode], *reasonp); + } + } + return 0; +} + +/* + * Delete the blocker from all modes it is associated with. + */ +void cpr_del_blocker(Error **reasonp) +{ + CprMode mode; + + if (*reasonp) { + for (mode = 0; mode < CPR_MODE__MAX; mode++) { + cpr_blockers[mode] = g_slist_remove(cpr_blockers[mode], *reasonp); + } + error_free(*reasonp); + *reasonp = NULL; + } +} + +/* + * Add a blocker which will not be deleted. Simpler for some callers. + */ +int cpr_add_blocker_str(const char *msg, Error **errp, CprMode mode, ...) +{ + int ret; + va_list ap; + Error *reason = NULL; + + error_setg(&reason, "%s", msg); + va_start(ap, mode); + ret = cpr_add_blocker(&reason, errp, mode, ap); + va_end(ap); + return ret; +} + +static bool cpr_is_blocked(Error **errp, CprMode mode) +{ + if (cpr_blockers[mode]) { + error_propagate(errp, error_copy(cpr_blockers[mode]->data)); + return true; + } + + return false; +} + void qmp_cpr_save(const char *filename, CprMode mode, Error **errp) { int ret; QEMUFile *f; int saved_vm_running = runstate_is_running(); + if (cpr_is_blocked(errp, mode)) { + return; + } + if (global_state_store()) { error_setg(errp, "Error saving global state"); return; diff --git a/stubs/cpr.c b/stubs/cpr.c new file mode 100644 index 0000000..06a9a1c --- /dev/null +++ b/stubs/cpr.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "migration/cpr.h" + +int cpr_add_blocker(Error **reasonp, Error **errp, CprMode mode, ...) +{ + return 0; +} + +int cpr_add_blocker_str(const char *reason, Error **errp, CprMode mode, ...) +{ + return 0; +} + +void cpr_del_blocker(Error **reasonp) +{ +} diff --git a/stubs/meson.build b/stubs/meson.build index 6f80fec..0d7565b 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -4,6 +4,7 @@ stub_ss.add(files('blk-exp-close-all.c')) stub_ss.add(files('blockdev-close-all-bdrv-states.c')) stub_ss.add(files('change-state-handler.c')) stub_ss.add(files('cmos.c')) +stub_ss.add(files('cpr.c')) stub_ss.add(files('cpu-get-clock.c')) stub_ss.add(files('cpus-get-virtual-clock.c')) stub_ss.add(files('qemu-timer-notify-cb.c')) -- 1.8.3.1