[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v3 12/14] migration: Add support for 'fixed-ram' migration restor
From: |
Nikolay Borisov |
Subject: |
[PATCH v3 12/14] migration: Add support for 'fixed-ram' migration restore |
Date: |
Fri, 28 Oct 2022 13:39:12 +0300 |
Add the necessary code to parse the format changes for 'fixed-ram'
capability. One of the more notable changes in behavior is that in the
'fixed-ram' case ram pages are restored in one go rather than constantly
looping through the migration stream. Also due to idiosyncrasies of the
format I have added the 'ram_migrated' since it was easier to simply
return directly from ->load_state rather than introducing more
conditionals around the code to prevent ->load_state being called
multiple times (from
qemu_loadvm_section_start_full/qemu_loadvm_section_part_end i.e. from
multiple QEMU_VM_SECTION_(PART|END) flags).
Signed-off-by: Nikolay Borisov <nborisov@suse.com>
---
migration/migration.h | 2 +
migration/ram.c | 95 ++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 95 insertions(+), 2 deletions(-)
diff --git a/migration/migration.h b/migration/migration.h
index 9aab1b16f407..7a832d072415 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -96,6 +96,8 @@ struct MigrationIncomingState {
bool have_listen_thread;
QemuThread listen_thread;
+ bool ram_migrated;
+
/* For the kernel to send us notifications */
int userfault_fd;
/* To notify the fault_thread to wake, e.g., when need to quit */
diff --git a/migration/ram.c b/migration/ram.c
index 1dd68c221667..e085a2431f88 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -4330,6 +4330,90 @@ static int parse_ramblocks(QEMUFile *f, ram_addr_t
total_ram_bytes)
return ret;
}
+
+static int parse_ramblocks_fixed_ram(QEMUFile *f)
+{
+ int ret = 0;
+
+ while (!ret) {
+ char id[256];
+ RAMBlock *block;
+ ram_addr_t length;
+ unsigned long clear_bit_idx;
+ long num_pages, bitmap_size;
+ int len = qemu_get_byte(f);
+ g_autofree unsigned long *dirty_bitmap = NULL;
+
+ qemu_get_buffer(f, (uint8_t *)id, len);
+ id[len] = 0;
+ length = qemu_get_be64(f);
+
+ block = qemu_ram_block_by_name(id);
+ if (block) {
+ ret = parse_ramblock(f, block, length);
+ if (ret < 0) {
+ return ret;
+ }
+ } else {
+ error_report("Unknown ramblock \"%s\", cannot accept "
+ "migration", id);
+ ret = -EINVAL;
+ continue;
+ }
+
+ /* 1. read the bitmap size */
+ num_pages = length >> TARGET_PAGE_BITS;
+ bitmap_size = qemu_get_be32(f);
+
+ assert(bitmap_size == BITS_TO_LONGS(num_pages)*sizeof(unsigned long));
+
+ block->pages_offset = qemu_get_be64(f);
+
+ /* 2. read the actual bitmap */
+ dirty_bitmap = g_malloc0(bitmap_size);
+ if (qemu_get_buffer(f, (uint8_t *)dirty_bitmap, bitmap_size) !=
bitmap_size) {
+ error_report("Error parsing dirty bitmap");
+ return -EINVAL;
+ }
+
+#define BUFSIZE (4*1024*1024)
+ for (unsigned long set_bit_idx = find_first_bit(dirty_bitmap,
num_pages);
+ set_bit_idx < num_pages;
+ set_bit_idx = find_next_bit(dirty_bitmap, num_pages,
clear_bit_idx + 1)) {
+
+ clear_bit_idx = find_next_zero_bit(dirty_bitmap, num_pages,
set_bit_idx + 1);
+ unsigned long len = TARGET_PAGE_SIZE * (clear_bit_idx -
set_bit_idx);
+ ram_addr_t offset = set_bit_idx << TARGET_PAGE_BITS;
+
+ for (size_t read = 0, completed = 0; completed < len; offset +=
read) {
+ void *host = host_from_ram_block_offset(block, offset);
+ size_t read_len = MIN(len, BUFSIZE);
+
+ read = qemu_get_buffer_at(f, host, read_len,
+ block->pages_offset + offset);
+ completed += read;
+ }
+ }
+
+ /* Skip pages array */
+ qemu_set_offset(f, block->pages_offset + length, SEEK_SET);
+
+ /* Check if this is the last ramblock */
+ if (qemu_get_be64(f) == RAM_SAVE_FLAG_EOS) {
+ ret = 1;
+ } else {
+ /*
+ * If not, adjust the internal file index to account for the
+ * previous 64 bit read
+ */
+ qemu_file_skip(f, -8);
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
/**
* ram_load_precopy: load pages in precopy case
*
@@ -4349,7 +4433,7 @@ static int ram_load_precopy(QEMUFile *f)
invalid_flags |= RAM_SAVE_FLAG_COMPRESS_PAGE;
}
- while (!ret && !(flags & RAM_SAVE_FLAG_EOS)) {
+ while (!ret && !(flags & RAM_SAVE_FLAG_EOS) && !mis->ram_migrated) {
ram_addr_t addr;
void *host = NULL, *host_bak = NULL;
uint8_t ch;
@@ -4421,7 +4505,14 @@ static int ram_load_precopy(QEMUFile *f)
switch (flags & ~RAM_SAVE_FLAG_CONTINUE) {
case RAM_SAVE_FLAG_MEM_SIZE:
- ret = parse_ramblocks(f, addr);
+ if (migrate_fixed_ram()) {
+ ret = parse_ramblocks_fixed_ram(f);
+ if (ret == 1) {
+ mis->ram_migrated = true;
+ }
+ } else {
+ ret = parse_ramblocks(f, addr);
+ }
break;
case RAM_SAVE_FLAG_ZERO:
--
2.34.1
- [PATCH v3 01/14] migration: support file: uri for source migration, (continued)
- [PATCH v3 01/14] migration: support file: uri for source migration, Nikolay Borisov, 2022/10/28
- [PATCH v3 09/14] migration: add qemu_get_buffer_at, Nikolay Borisov, 2022/10/28
- [PATCH v3 04/14] io: Add generic pwritev/preadv interface, Nikolay Borisov, 2022/10/28
- [PATCH v3 03/14] migration: Initial support of fixed-ram feature for analyze-migration.py, Nikolay Borisov, 2022/10/28
- [PATCH v3 07/14] migration/qemu-file: add utility methods for working with seekable channels, Nikolay Borisov, 2022/10/28
- [PATCH v3 06/14] io: add and implement QIO_CHANNEL_FEATURE_SEEKABLE for channel file, Nikolay Borisov, 2022/10/28
- [PATCH v3 05/14] io: implement io_pwritev for QIOChannelFile, Nikolay Borisov, 2022/10/28
- [PATCH v3 08/14] io: Add preadv support to QIOChannelFile, Nikolay Borisov, 2022/10/28
- [PATCH v3 14/14] tests/qtest: migration-test: Add tests for file-based migration, Nikolay Borisov, 2022/10/28
- [PATCH v3 11/14] migration: Refactor precopy ram loading code, Nikolay Borisov, 2022/10/28
- [PATCH v3 12/14] migration: Add support for 'fixed-ram' migration restore,
Nikolay Borisov <=
- [PATCH v3 10/14] migration/ram: Introduce 'fixed-ram' migration stream capability, Nikolay Borisov, 2022/10/28
- [PATCH v3 13/14] tests: Add migrate_incoming_qmp helper, Nikolay Borisov, 2022/10/28