mirror of https://github.com/proxmox/mirror_qemu
migration/multifd: Support incoming mapped-ram stream format
For the incoming mapped-ram migration we need to read the ramblock headers, get the pages bitmap and send the host address of each non-zero page to the multifd channel thread for writing. Usage on HMP is: (qemu) migrate_set_capability multifd on (qemu) migrate_set_capability mapped-ram on (qemu) migrate_incoming file:migfile (the ram.h include needs to move because we've been previously relying on it being included from migration.c. Now file.h will start including multifd.h before migration.o is processed) Reviewed-by: Peter Xu <peterx@redhat.com> Signed-off-by: Fabiano Rosas <farosas@suse.de> Link: https://lore.kernel.org/r/20240229153017.2221-22-farosas@suse.de Signed-off-by: Peter Xu <peterx@redhat.com>master
parent
f427d90b98
commit
a49d15a38d
|
@ -13,7 +13,6 @@
|
||||||
#include "channel.h"
|
#include "channel.h"
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "migration.h"
|
#include "migration.h"
|
||||||
#include "multifd.h"
|
|
||||||
#include "io/channel-file.h"
|
#include "io/channel-file.h"
|
||||||
#include "io/channel-util.h"
|
#include "io/channel-util.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
|
@ -204,3 +203,20 @@ int file_write_ramblock_iov(QIOChannel *ioc, const struct iovec *iov,
|
||||||
|
|
||||||
return (ret < 0) ? ret : 0;
|
return (ret < 0) ? ret : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int multifd_file_recv_data(MultiFDRecvParams *p, Error **errp)
|
||||||
|
{
|
||||||
|
MultiFDRecvData *data = p->data;
|
||||||
|
size_t ret;
|
||||||
|
|
||||||
|
ret = qio_channel_pread(p->c, (char *) data->opaque,
|
||||||
|
data->size, data->file_offset, errp);
|
||||||
|
if (ret != data->size) {
|
||||||
|
error_prepend(errp,
|
||||||
|
"multifd recv (%u): read 0x%zx, expected 0x%zx",
|
||||||
|
p->id, ret, data->size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "qapi/qapi-types-migration.h"
|
#include "qapi/qapi-types-migration.h"
|
||||||
#include "io/task.h"
|
#include "io/task.h"
|
||||||
#include "channel.h"
|
#include "channel.h"
|
||||||
|
#include "multifd.h"
|
||||||
|
|
||||||
void file_start_incoming_migration(FileMigrationArgs *file_args, Error **errp);
|
void file_start_incoming_migration(FileMigrationArgs *file_args, Error **errp);
|
||||||
|
|
||||||
|
@ -21,4 +22,5 @@ void file_cleanup_outgoing_migration(void);
|
||||||
bool file_send_channel_create(gpointer opaque, Error **errp);
|
bool file_send_channel_create(gpointer opaque, Error **errp);
|
||||||
int file_write_ramblock_iov(QIOChannel *ioc, const struct iovec *iov,
|
int file_write_ramblock_iov(QIOChannel *ioc, const struct iovec *iov,
|
||||||
int niov, RAMBlock *block, Error **errp);
|
int niov, RAMBlock *block, Error **errp);
|
||||||
|
int multifd_file_recv_data(MultiFDRecvParams *p, Error **errp);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "ram.h"
|
|
||||||
#include "migration.h"
|
#include "migration.h"
|
||||||
#include "migration-stats.h"
|
#include "migration-stats.h"
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
|
@ -251,7 +250,7 @@ static int nocomp_recv(MultiFDRecvParams *p, Error **errp)
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
|
|
||||||
if (!multifd_use_packets()) {
|
if (!multifd_use_packets()) {
|
||||||
return 0;
|
return multifd_file_recv_data(p, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK;
|
flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK;
|
||||||
|
@ -1331,22 +1330,48 @@ void multifd_recv_cleanup(void)
|
||||||
void multifd_recv_sync_main(void)
|
void multifd_recv_sync_main(void)
|
||||||
{
|
{
|
||||||
int thread_count = migrate_multifd_channels();
|
int thread_count = migrate_multifd_channels();
|
||||||
|
bool file_based = !multifd_use_packets();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!migrate_multifd() || !multifd_use_packets()) {
|
if (!migrate_multifd()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* File-based channels don't use packets and therefore need to
|
||||||
|
* wait for more work. Release them to start the sync.
|
||||||
|
*/
|
||||||
|
if (file_based) {
|
||||||
|
for (i = 0; i < thread_count; i++) {
|
||||||
|
MultiFDRecvParams *p = &multifd_recv_state->params[i];
|
||||||
|
|
||||||
|
trace_multifd_recv_sync_main_signal(p->id);
|
||||||
|
qemu_sem_post(&p->sem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initiate the synchronization by waiting for all channels.
|
* Initiate the synchronization by waiting for all channels.
|
||||||
|
*
|
||||||
* For socket-based migration this means each channel has received
|
* For socket-based migration this means each channel has received
|
||||||
* the SYNC packet on the stream.
|
* the SYNC packet on the stream.
|
||||||
|
*
|
||||||
|
* For file-based migration this means each channel is done with
|
||||||
|
* the work (pending_job=false).
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < thread_count; i++) {
|
for (i = 0; i < thread_count; i++) {
|
||||||
trace_multifd_recv_sync_main_wait(i);
|
trace_multifd_recv_sync_main_wait(i);
|
||||||
qemu_sem_wait(&multifd_recv_state->sem_sync);
|
qemu_sem_wait(&multifd_recv_state->sem_sync);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (file_based) {
|
||||||
|
/*
|
||||||
|
* For file-based loading is done in one iteration. We're
|
||||||
|
* done.
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sync done. Release the channels for the next iteration.
|
* Sync done. Release the channels for the next iteration.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
#ifndef QEMU_MIGRATION_MULTIFD_H
|
#ifndef QEMU_MIGRATION_MULTIFD_H
|
||||||
#define QEMU_MIGRATION_MULTIFD_H
|
#define QEMU_MIGRATION_MULTIFD_H
|
||||||
|
|
||||||
|
#include "ram.h"
|
||||||
|
|
||||||
typedef struct MultiFDRecvData MultiFDRecvData;
|
typedef struct MultiFDRecvData MultiFDRecvData;
|
||||||
|
|
||||||
bool multifd_send_setup(void);
|
bool multifd_send_setup(void);
|
||||||
|
|
|
@ -3952,6 +3952,22 @@ void colo_flush_ram_cache(void)
|
||||||
trace_colo_flush_ram_cache_end();
|
trace_colo_flush_ram_cache_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t ram_load_multifd_pages(void *host_addr, size_t size,
|
||||||
|
uint64_t offset)
|
||||||
|
{
|
||||||
|
MultiFDRecvData *data = multifd_get_recv_data();
|
||||||
|
|
||||||
|
data->opaque = host_addr;
|
||||||
|
data->file_offset = offset;
|
||||||
|
data->size = size;
|
||||||
|
|
||||||
|
if (!multifd_recv()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
static bool read_ramblock_mapped_ram(QEMUFile *f, RAMBlock *block,
|
static bool read_ramblock_mapped_ram(QEMUFile *f, RAMBlock *block,
|
||||||
long num_pages, unsigned long *bitmap,
|
long num_pages, unsigned long *bitmap,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
|
@ -3981,8 +3997,14 @@ static bool read_ramblock_mapped_ram(QEMUFile *f, RAMBlock *block,
|
||||||
|
|
||||||
size = MIN(unread, MAPPED_RAM_LOAD_BUF_SIZE);
|
size = MIN(unread, MAPPED_RAM_LOAD_BUF_SIZE);
|
||||||
|
|
||||||
read = qemu_get_buffer_at(f, host, size,
|
if (migrate_multifd()) {
|
||||||
block->pages_offset + offset);
|
read = ram_load_multifd_pages(host, size,
|
||||||
|
block->pages_offset + offset);
|
||||||
|
} else {
|
||||||
|
read = qemu_get_buffer_at(f, host, size,
|
||||||
|
block->pages_offset + offset);
|
||||||
|
}
|
||||||
|
|
||||||
if (!read) {
|
if (!read) {
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue