]> git.proxmox.com Git - mirror_qemu.git/commitdiff
migration/multifd: solve zero page causing multiple page faults
authorYuan Liu <yuan1.liu@intel.com>
Mon, 1 Apr 2024 15:41:10 +0000 (23:41 +0800)
committerPeter Xu <peterx@redhat.com>
Tue, 23 Apr 2024 22:36:01 +0000 (18:36 -0400)
Implemented recvbitmap tracking of received pages in multifd.

If the zero page appears for the first time in the recvbitmap, this
page is not checked and set.

If the zero page has already appeared in the recvbitmap, there is no
need to check the data but directly set the data to 0, because it is
unlikely that the zero page will be migrated multiple times.

Signed-off-by: Yuan Liu <yuan1.liu@intel.com>
Reviewed-by: Fabiano Rosas <farosas@suse.de>
Link: https://lore.kernel.org/r/20240401154110.2028453-2-yuan1.liu@intel.com
[peterx: touch up the comment, as the bitmap is used outside postcopy now]
Signed-off-by: Peter Xu <peterx@redhat.com>
include/exec/ramblock.h
migration/multifd-zero-page.c
migration/multifd-zlib.c
migration/multifd-zstd.c
migration/multifd.c
migration/ram.c
migration/ram.h

index 848915ea5bfe3209b6f0d387ef00e090bf48af15..7062da380b7bbd8c9a95b95b0ea075c71d65a0b5 100644 (file)
@@ -57,7 +57,7 @@ struct RAMBlock {
     off_t bitmap_offset;
     uint64_t pages_offset;
 
-    /* bitmap of already received pages in postcopy */
+    /* Bitmap of already received pages.  Only used on destination side. */
     unsigned long *receivedmap;
 
     /*
index 1ba38be63613614db5a0eee9e71d5564dae2e7fd..e1b8370f88e1ef91d98eb2375b242327c7c5bdc4 100644 (file)
@@ -80,8 +80,10 @@ void multifd_recv_zero_page_process(MultiFDRecvParams *p)
 {
     for (int i = 0; i < p->zero_num; i++) {
         void *page = p->host + p->zero[i];
-        if (!buffer_is_zero(page, p->page_size)) {
+        if (ramblock_recv_bitmap_test_byte_offset(p->block, p->zero[i])) {
             memset(page, 0, p->page_size);
+        } else {
+            ramblock_recv_bitmap_set_offset(p->block, p->zero[i]);
         }
     }
 }
index 99821cd4d5ef5bf1eceb0d6f53316497754b8ba9..737a9645d2fe83c3bfb11580a5987b0fac75e5a1 100644 (file)
@@ -284,6 +284,7 @@ static int zlib_recv(MultiFDRecvParams *p, Error **errp)
         int flush = Z_NO_FLUSH;
         unsigned long start = zs->total_out;
 
+        ramblock_recv_bitmap_set_offset(p->block, p->normal[i]);
         if (i == p->normal_num - 1) {
             flush = Z_SYNC_FLUSH;
         }
index 02112255adcc7723b996235b664ebd07fb71e97a..256858df0a0a096895ed86c01098ae338fd04efe 100644 (file)
@@ -278,6 +278,7 @@ static int zstd_recv(MultiFDRecvParams *p, Error **errp)
     z->in.pos = 0;
 
     for (i = 0; i < p->normal_num; i++) {
+        ramblock_recv_bitmap_set_offset(p->block, p->normal[i]);
         z->out.dst = p->host + p->normal[i];
         z->out.size = p->page_size;
         z->out.pos = 0;
index 2802afe79d0d593091c59528b19b979a0c17b886..f317bff0774646b51825dab40ffd35b850016f57 100644 (file)
@@ -277,6 +277,7 @@ static int nocomp_recv(MultiFDRecvParams *p, Error **errp)
     for (int i = 0; i < p->normal_num; i++) {
         p->iov[i].iov_base = p->host + p->normal[i];
         p->iov[i].iov_len = p->page_size;
+        ramblock_recv_bitmap_set_offset(p->block, p->normal[i]);
     }
     return qio_channel_readv_all(p->c, p->iov, p->normal_num, errp);
 }
index daffcd82d4f15a2defc66059e967092ebc3ec055..a975c5af16f1239b5540e312b13f77149929c873 100644 (file)
@@ -275,6 +275,10 @@ void ramblock_recv_bitmap_set_range(RAMBlock *rb, void *host_addr,
                       nr);
 }
 
+void ramblock_recv_bitmap_set_offset(RAMBlock *rb, uint64_t byte_offset)
+{
+    set_bit_atomic(byte_offset >> TARGET_PAGE_BITS, rb->receivedmap);
+}
 #define  RAMBLOCK_RECV_BITMAP_ENDING  (0x0123456789abcdefULL)
 
 /*
index 08feecaf516df6832c6b5d899aad91867d0428a4..bc0318b8346220835fab7ffd3bd1472f283218c3 100644 (file)
@@ -69,6 +69,7 @@ int ramblock_recv_bitmap_test(RAMBlock *rb, void *host_addr);
 bool ramblock_recv_bitmap_test_byte_offset(RAMBlock *rb, uint64_t byte_offset);
 void ramblock_recv_bitmap_set(RAMBlock *rb, void *host_addr);
 void ramblock_recv_bitmap_set_range(RAMBlock *rb, void *host_addr, size_t nr);
+void ramblock_recv_bitmap_set_offset(RAMBlock *rb, uint64_t byte_offset);
 int64_t ramblock_recv_bitmap_send(QEMUFile *file,
                                   const char *block_name);
 bool ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *rb, Error **errp);