Prasad Pandit <[email protected]> writes:
> From: Prasad Pandit <[email protected]>
>
> Enable Multifd and Postcopy migration together.
> The migration_ioc_process_incoming() routine
> checks magic value sent on each channel and
> helps to properly setup multifd and postcopy
> channels.
>
> The Precopy and Multifd threads work during the
> initial guest RAM transfer. When migration moves
> to the Postcopy phase, the multifd threads cease
> to send data on multifd channels and Postcopy
> threads on the destination request/pull data from
> the source side.
>
> Signed-off-by: Prasad Pandit <[email protected]>
> ---
> migration/multifd-nocomp.c | 3 ++-
> migration/multifd.c | 7 +++++++
> migration/options.c | 5 -----
> migration/ram.c | 7 +++----
> 4 files changed, 12 insertions(+), 10 deletions(-)
>
> v8:
> - Separate this patch out from earlier patch-2.
>
> v7:
> -
> https://lore.kernel.org/qemu-devel/[email protected]/T/#t
>
> diff --git a/migration/multifd-nocomp.c b/migration/multifd-nocomp.c
> index ffe75256c9..02f8bf8ce8 100644
> --- a/migration/multifd-nocomp.c
> +++ b/migration/multifd-nocomp.c
> @@ -17,6 +17,7 @@
> #include "migration-stats.h"
> #include "multifd.h"
> #include "options.h"
> +#include "migration.h"
> #include "qapi/error.h"
> #include "qemu/cutils.h"
> #include "qemu/error-report.h"
> @@ -399,7 +400,7 @@ int multifd_ram_flush_and_sync(QEMUFile *f)
> MultiFDSyncReq req;
> int ret;
>
> - if (!migrate_multifd()) {
> + if (!migrate_multifd() || migration_in_postcopy()) {
> return 0;
> }
>
> diff --git a/migration/multifd.c b/migration/multifd.c
> index 6139cabe44..074d16d07d 100644
> --- a/migration/multifd.c
> +++ b/migration/multifd.c
> @@ -1379,6 +1379,13 @@ static void *multifd_recv_thread(void *opaque)
> }
>
> if (has_data) {
> + /*
> + * multifd thread should not be active and receive data
> + * when migration is in the Postcopy phase. Two threads
> + * writing the same memory area could easily corrupt
> + * the guest state.
> + */
> + assert(!migration_in_postcopy());
> if (is_device_state) {
> assert(use_packets);
> ret = multifd_device_state_recv(p, &local_err);
> diff --git a/migration/options.c b/migration/options.c
> index b0ac2ea408..48aa6076de 100644
> --- a/migration/options.c
> +++ b/migration/options.c
> @@ -491,11 +491,6 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps,
> Error **errp)
> error_setg(errp, "Postcopy is not compatible with
> ignore-shared");
> return false;
> }
> -
> - if (new_caps[MIGRATION_CAPABILITY_MULTIFD]) {
> - error_setg(errp, "Postcopy is not yet compatible with multifd");
> - return false;
> - }
> }
>
> if (new_caps[MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT]) {
> diff --git a/migration/ram.c b/migration/ram.c
> index 424df6d9f1..6fd88cbf2a 100644
> --- a/migration/ram.c
> +++ b/migration/ram.c
> @@ -1297,7 +1297,7 @@ static int find_dirty_block(RAMState *rs,
> PageSearchStatus *pss)
> pss->page = 0;
> pss->block = QLIST_NEXT_RCU(pss->block, next);
> if (!pss->block) {
> - if (multifd_ram_sync_per_round()) {
> + if (multifd_ram_sync_per_round() && !migration_in_postcopy()) {
I'd rather not put this check here. multifd_ram_flush_and_sync() will
already return 0 if in postcopy.
> QEMUFile *f = rs->pss[RAM_CHANNEL_PRECOPY].pss_channel;
> int ret = multifd_ram_flush_and_sync(f);
> if (ret < 0) {
> @@ -1976,9 +1976,8 @@ static int ram_save_target_page(RAMState *rs,
> PageSearchStatus *pss)
> }
> }
>
> - if (migrate_multifd()) {
> - RAMBlock *block = pss->block;
> - return ram_save_multifd_page(block, offset);
> + if (migrate_multifd() && !migration_in_postcopy()) {
> + return ram_save_multifd_page(pss->block, offset);
> }
>
> return ram_save_page(rs, pss);