Skip to content

Commit

Permalink
migration/multifd: solve zero page causing multiple page faults
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
yliu80 authored and xzpeter committed Apr 23, 2024
1 parent dd03167 commit 5ef7e26
Show file tree
Hide file tree
Showing 7 changed files with 12 additions and 2 deletions.
2 changes: 1 addition & 1 deletion include/exec/ramblock.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/*
Expand Down
4 changes: 3 additions & 1 deletion migration/multifd-zero-page.c
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
}
}
}
1 change: 1 addition & 0 deletions migration/multifd-zlib.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
1 change: 1 addition & 0 deletions migration/multifd-zstd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions migration/multifd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
4 changes: 4 additions & 0 deletions migration/ram.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)

/*
Expand Down
1 change: 1 addition & 0 deletions migration/ram.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 5ef7e26

Please sign in to comment.