@@ -1152,6 +1152,20 @@ static void kvm_unpoison_all(void *param)
}
}
+bool kvm_hwpoisoned_page(RAMBlock *block, void *offset)
+{
+ HWPoisonPage *pg;
+ ram_addr_t ram_addr = (ram_addr_t) offset;
+
+ QLIST_FOREACH(pg, &hwpoison_page_list, list) {
+ if ((ram_addr >= pg->ram_addr) &&
+ (ram_addr - pg->ram_addr < block->page_size)) {
+ return true;
+ }
+ }
+ return false;
+}
+
void kvm_hwpoison_page_add(ram_addr_t ram_addr)
{
HWPoisonPage *page;
@@ -133,3 +133,8 @@ uint32_t kvm_dirty_ring_size(void)
{
return 0;
}
+
+bool kvm_hwpoisoned_page(RAMBlock *block, void *ram_addr)
+{
+ return false;
+}
@@ -570,4 +570,14 @@ bool kvm_arch_cpu_check_are_resettable(void);
bool kvm_dirty_ring_enabled(void);
uint32_t kvm_dirty_ring_size(void);
+
+/**
+ * kvm_hwpoisoned_page - indicate if the given page is poisoned
+ * @block: memory block of the given page
+ * @ram_addr: offset of the page
+ *
+ * Returns: true: page is poisoned
+ * false: page not yet poisoned
+ */
+bool kvm_hwpoisoned_page(RAMBlock *block, void *ram_addr);
#endif
@@ -34,6 +34,7 @@
#include "qemu/error-report.h"
#include "migration.h"
#include "options.h"
+#include "ram.h"
#include "io/channel-null.h"
#include "exec/target_page.h"
#include "exec/ramblock.h"
@@ -198,7 +199,7 @@ static CompressResult do_compress_ram_page(QEMUFile *f, z_stream *stream,
assert(qemu_file_buffer_empty(f));
- if (buffer_is_zero(p, page_size)) {
+ if (migration_buffer_is_zero(block, offset, page_size)) {
return RES_ZEROPAGE;
}
@@ -1137,6 +1137,26 @@ void ram_release_page(const char *rbname, uint64_t offset)
ram_discard_range(rbname, offset, TARGET_PAGE_SIZE);
}
+/**
+ * migration_buffer_is_zero: indicate if the page at the given
+ * location is entirely filled with zero, or is a poisoned page.
+ *
+ * @block: block that contains the page
+ * @offset: offset inside the block for the page
+ * @len: size to consider
+ */
+bool migration_buffer_is_zero(RAMBlock *block, ram_addr_t offset,
+ size_t len)
+{
+ uint8_t *p = block->host + offset;
+
+ if (kvm_enabled() && kvm_hwpoisoned_page(block, (void *)offset)) {
+ return true;
+ }
+
+ return buffer_is_zero(p, len);
+}
+
/**
* save_zero_page_to_file: send the zero page to the file
*
@@ -1150,10 +1170,9 @@ void ram_release_page(const char *rbname, uint64_t offset)
static int save_zero_page_to_file(PageSearchStatus *pss, QEMUFile *file,
RAMBlock *block, ram_addr_t offset)
{
- uint8_t *p = block->host + offset;
int len = 0;
- if (buffer_is_zero(p, TARGET_PAGE_SIZE)) {
+ if (migration_buffer_is_zero(block, offset, TARGET_PAGE_SIZE)) {
len += save_page_header(pss, file, block, offset | RAM_SAVE_FLAG_ZERO);
qemu_put_byte(file, 0);
len += 1;
@@ -1190,6 +1209,7 @@ static int save_zero_page(PageSearchStatus *pss, QEMUFile *f, RAMBlock *block,
* > 0 - number of pages written
*
* Return true if the pages has been saved, otherwise false is returned.
+ * TODO: hwpoison pages fail RDMA migration, should be handled.
*/
static bool control_save_page(PageSearchStatus *pss, RAMBlock *block,
ram_addr_t offset, int *pages)
@@ -65,6 +65,8 @@ void ram_handle_compressed(void *host, uint8_t ch, uint64_t size);
void ram_transferred_add(uint64_t bytes);
void ram_release_page(const char *rbname, uint64_t offset);
+bool migration_buffer_is_zero(RAMBlock *block, ram_addr_t offset, size_t len);
+
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);