586cba
From 5ea59b17866add54e5ae8c76d3cb472c67e1fa91 Mon Sep 17 00:00:00 2001
586cba
From: Thomas Huth <thuth@redhat.com>
586cba
Date: Tue, 2 Aug 2022 08:19:49 +0200
586cba
Subject: [PATCH 32/32] Revert "migration: Simplify unqueue_page()"
586cba
586cba
RH-Author: Thomas Huth <thuth@redhat.com>
586cba
RH-MergeRequest: 112: Fix postcopy migration on s390x
586cba
RH-Commit: [2/2] 3913c9ed3f27f4b66245913da29d0c46db0c6567 (thuth/qemu-kvm-cs9)
586cba
RH-Bugzilla: 2099934
586cba
RH-Acked-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
586cba
RH-Acked-by: Cornelia Huck <cohuck@redhat.com>
586cba
RH-Acked-by: David Hildenbrand <david@redhat.com>
586cba
RH-Acked-by: Peter Xu <peterx@redhat.com>
586cba
586cba
This reverts commit cfd66f30fb0f735df06ff4220e5000290a43dad3.
586cba
586cba
The simplification of unqueue_page() introduced a bug that sometimes
586cba
breaks migration on s390x hosts.
586cba
586cba
The problem is not fully understood yet, but since we are already in
586cba
the freeze for QEMU 7.1 and we need something working there, let's
586cba
revert this patch for the upcoming release. The optimization can be
586cba
redone later again in a proper way if necessary.
586cba
586cba
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2099934
586cba
Signed-off-by: Thomas Huth <thuth@redhat.com>
586cba
Message-Id: <20220802061949.331576-1-thuth@redhat.com>
586cba
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
586cba
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
586cba
(cherry picked from commit 777f53c75983dd10756f5dbfc8af50fe11da81c1)
586cba
Conflicts:
586cba
	migration/trace-events
586cba
	(trivial contextual conflict)
586cba
Signed-off-by: Thomas Huth <thuth@redhat.com>
586cba
---
586cba
 migration/ram.c        | 37 ++++++++++++++++++++++++++-----------
586cba
 migration/trace-events |  3 ++-
586cba
 2 files changed, 28 insertions(+), 12 deletions(-)
586cba
586cba
diff --git a/migration/ram.c b/migration/ram.c
586cba
index fb6db54642..ee40e4a718 100644
586cba
--- a/migration/ram.c
586cba
+++ b/migration/ram.c
586cba
@@ -1548,7 +1548,6 @@ static RAMBlock *unqueue_page(RAMState *rs, ram_addr_t *offset)
586cba
 {
586cba
     struct RAMSrcPageRequest *entry;
586cba
     RAMBlock *block = NULL;
586cba
-    size_t page_size;
586cba
 
586cba
     if (!postcopy_has_request(rs)) {
586cba
         return NULL;
586cba
@@ -1565,13 +1564,10 @@ static RAMBlock *unqueue_page(RAMState *rs, ram_addr_t *offset)
586cba
     entry = QSIMPLEQ_FIRST(&rs->src_page_requests);
586cba
     block = entry->rb;
586cba
     *offset = entry->offset;
586cba
-    page_size = qemu_ram_pagesize(block);
586cba
-    /* Each page request should only be multiple page size of the ramblock */
586cba
-    assert((entry->len % page_size) == 0);
586cba
 
586cba
-    if (entry->len > page_size) {
586cba
-        entry->len -= page_size;
586cba
-        entry->offset += page_size;
586cba
+    if (entry->len > TARGET_PAGE_SIZE) {
586cba
+        entry->len -= TARGET_PAGE_SIZE;
586cba
+        entry->offset += TARGET_PAGE_SIZE;
586cba
     } else {
586cba
         memory_region_unref(block->mr);
586cba
         QSIMPLEQ_REMOVE_HEAD(&rs->src_page_requests, next_req);
586cba
@@ -1579,9 +1575,6 @@ static RAMBlock *unqueue_page(RAMState *rs, ram_addr_t *offset)
586cba
         migration_consume_urgent_request();
586cba
     }
586cba
 
586cba
-    trace_unqueue_page(block->idstr, *offset,
586cba
-                       test_bit((*offset >> TARGET_PAGE_BITS), block->bmap));
586cba
-
586cba
     return block;
586cba
 }
586cba
 
586cba
@@ -1956,8 +1949,30 @@ static bool get_queued_page(RAMState *rs, PageSearchStatus *pss)
586cba
 {
586cba
     RAMBlock  *block;
586cba
     ram_addr_t offset;
586cba
+    bool dirty;
586cba
+
586cba
+    do {
586cba
+        block = unqueue_page(rs, &offset);
586cba
+        /*
586cba
+         * We're sending this page, and since it's postcopy nothing else
586cba
+         * will dirty it, and we must make sure it doesn't get sent again
586cba
+         * even if this queue request was received after the background
586cba
+         * search already sent it.
586cba
+         */
586cba
+        if (block) {
586cba
+            unsigned long page;
586cba
+
586cba
+            page = offset >> TARGET_PAGE_BITS;
586cba
+            dirty = test_bit(page, block->bmap);
586cba
+            if (!dirty) {
586cba
+                trace_get_queued_page_not_dirty(block->idstr, (uint64_t)offset,
586cba
+                                                page);
586cba
+            } else {
586cba
+                trace_get_queued_page(block->idstr, (uint64_t)offset, page);
586cba
+            }
586cba
+        }
586cba
 
586cba
-    block = unqueue_page(rs, &offset);
586cba
+    } while (block && !dirty);
586cba
 
586cba
     if (!block) {
586cba
         /*
586cba
diff --git a/migration/trace-events b/migration/trace-events
586cba
index 1aec580e92..09d61ed1f4 100644
586cba
--- a/migration/trace-events
586cba
+++ b/migration/trace-events
586cba
@@ -85,6 +85,8 @@ put_qlist_end(const char *field_name, const char *vmsd_name) "%s(%s)"
586cba
 qemu_file_fclose(void) ""
586cba
 
586cba
 # ram.c
586cba
+get_queued_page(const char *block_name, uint64_t tmp_offset, unsigned long page_abs) "%s/0x%" PRIx64 " page_abs=0x%lx"
586cba
+get_queued_page_not_dirty(const char *block_name, uint64_t tmp_offset, unsigned long page_abs) "%s/0x%" PRIx64 " page_abs=0x%lx"
586cba
 migration_bitmap_sync_start(void) ""
586cba
 migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64
586cba
 migration_bitmap_clear_dirty(char *str, uint64_t start, uint64_t size, unsigned long page) "rb %s start 0x%"PRIx64" size 0x%"PRIx64" page 0x%lx"
586cba
@@ -110,7 +112,6 @@ ram_save_iterate_big_wait(uint64_t milliconds, int iterations) "big wait: %" PRI
586cba
 ram_load_complete(int ret, uint64_t seq_iter) "exit_code %d seq iteration %" PRIu64
586cba
 ram_write_tracking_ramblock_start(const char *block_id, size_t page_size, void *addr, size_t length) "%s: page_size: %zu addr: %p length: %zu"
586cba
 ram_write_tracking_ramblock_stop(const char *block_id, size_t page_size, void *addr, size_t length) "%s: page_size: %zu addr: %p length: %zu"
586cba
-unqueue_page(char *block, uint64_t offset, bool dirty) "ramblock '%s' offset 0x%"PRIx64" dirty %d"
586cba
 
586cba
 # multifd.c
586cba
 multifd_new_send_channel_async(uint8_t id) "channel %u"
586cba
-- 
586cba
2.31.1
586cba