diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2019-07-15 15:19:54 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2019-07-15 15:19:54 +0100 |
commit | a68725f930a0d186fe3f8941941e2047e03589d4 (patch) | |
tree | ad73c6f9fde9efe06d2d9817de8726733ca3709a /include | |
parent | 0dc6284710afa2342fbe3932f4a73c41204da8e9 (diff) | |
parent | 40c4d4a835453452a262f32450a0449886aa19ce (diff) | |
download | qemu-a68725f930a0d186fe3f8941941e2047e03589d4.zip qemu-a68725f930a0d186fe3f8941941e2047e03589d4.tar.gz qemu-a68725f930a0d186fe3f8941941e2047e03589d4.tar.bz2 |
Merge remote-tracking branch 'remotes/juanquintela/tags/migration-pull-request' into staging
Pull request
# gpg: Signature made Mon 15 Jul 2019 14:49:41 BST
# gpg: using RSA key 1899FF8EDEBF58CCEE034B82F487EF185872D723
# gpg: Good signature from "Juan Quintela <quintela@redhat.com>" [full]
# gpg: aka "Juan Quintela <quintela@trasno.org>" [full]
# Primary key fingerprint: 1899 FF8E DEBF 58CC EE03 4B82 F487 EF18 5872 D723
* remotes/juanquintela/tags/migration-pull-request: (21 commits)
migration: always initial RAMBlock.bmap to 1 for new migration
migration/postcopy: remove redundant cpu_synchronize_all_post_init
migration/postcopy: fix document of postcopy_send_discard_bm_ram()
migration: allow private destination ram with x-ignore-shared
migration: Split log_clear() into smaller chunks
kvm: Support KVM_CLEAR_DIRTY_LOG
kvm: Introduce slots lock for memory listener
kvm: Persistent per kvmslot dirty bitmap
kvm: Update comments for sync_dirty_bitmap
memory: Introduce memory listener hook log_clear()
memory: Pass mr into snapshot_and_clear_dirty
bitmap: Add bitmap_copy_with_{src|dst}_offset()
memory: Don't set migration bitmap when without migration
migration: No need to take rcu during sync_dirty_bitmap
migration/ram.c: reset complete_round when we gets a queued page
migration/multifd: sync packet_num after all thread are done
cutils: remove one unnecessary pointer operation
migration/xbzrle: update cache and current_data in one place
migration/multifd: call multifd_send_sync_main when sending RAM_SAVE_FLAG_EOS
migration-test: rename parameter to parameter_int
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'include')
-rw-r--r-- | include/exec/memory.h | 19 | ||||
-rw-r--r-- | include/exec/ram_addr.h | 92 | ||||
-rw-r--r-- | include/qemu/bitmap.h | 9 | ||||
-rw-r--r-- | include/sysemu/kvm_int.h | 4 |
4 files changed, 119 insertions, 5 deletions
diff --git a/include/exec/memory.h b/include/exec/memory.h index 2c5cdff..bb0961d 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -46,6 +46,8 @@ OBJECT_GET_CLASS(IOMMUMemoryRegionClass, (obj), \ TYPE_IOMMU_MEMORY_REGION) +extern bool global_dirty_log; + typedef struct MemoryRegionOps MemoryRegionOps; typedef struct MemoryRegionMmio MemoryRegionMmio; @@ -414,6 +416,7 @@ struct MemoryListener { void (*log_stop)(MemoryListener *listener, MemoryRegionSection *section, int old, int new); void (*log_sync)(MemoryListener *listener, MemoryRegionSection *section); + void (*log_clear)(MemoryListener *listener, MemoryRegionSection *section); void (*log_global_start)(MemoryListener *listener); void (*log_global_stop)(MemoryListener *listener); void (*eventfd_add)(MemoryListener *listener, MemoryRegionSection *section, @@ -1268,6 +1271,22 @@ void memory_region_set_dirty(MemoryRegion *mr, hwaddr addr, hwaddr size); /** + * memory_region_clear_dirty_bitmap - clear dirty bitmap for memory range + * + * This function is called when the caller wants to clear the remote + * dirty bitmap of a memory range within the memory region. This can + * be used by e.g. KVM to manually clear dirty log when + * KVM_CAP_MANUAL_DIRTY_LOG_PROTECT is declared support by the host + * kernel. + * + * @mr: the memory region to clear the dirty log upon + * @start: start address offset within the memory region + * @len: length of the memory region to clear dirty bitmap + */ +void memory_region_clear_dirty_bitmap(MemoryRegion *mr, hwaddr start, + hwaddr len); + +/** * memory_region_snapshot_and_clear_dirty: Get a snapshot of the dirty * bitmap and clear it. * diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index f96777b..b7b2e60 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -51,8 +51,70 @@ struct RAMBlock { unsigned long *unsentmap; /* bitmap of already received pages in postcopy */ unsigned long *receivedmap; + + /* + * bitmap to track already cleared dirty bitmap. When the bit is + * set, it means the corresponding memory chunk needs a log-clear. + * Set this up to non-NULL to enable the capability to postpone + * and split clearing of dirty bitmap on the remote node (e.g., + * KVM). The bitmap will be set only when doing global sync. + * + * NOTE: this bitmap is different comparing to the other bitmaps + * in that one bit can represent multiple guest pages (which is + * decided by the `clear_bmap_shift' variable below). On + * destination side, this should always be NULL, and the variable + * `clear_bmap_shift' is meaningless. + */ + unsigned long *clear_bmap; + uint8_t clear_bmap_shift; }; +/** + * clear_bmap_size: calculate clear bitmap size + * + * @pages: number of guest pages + * @shift: guest page number shift + * + * Returns: number of bits for the clear bitmap + */ +static inline long clear_bmap_size(uint64_t pages, uint8_t shift) +{ + return DIV_ROUND_UP(pages, 1UL << shift); +} + +/** + * clear_bmap_set: set clear bitmap for the page range + * + * @rb: the ramblock to operate on + * @start: the start page number + * @size: number of pages to set in the bitmap + * + * Returns: None + */ +static inline void clear_bmap_set(RAMBlock *rb, uint64_t start, + uint64_t npages) +{ + uint8_t shift = rb->clear_bmap_shift; + + bitmap_set_atomic(rb->clear_bmap, start >> shift, + clear_bmap_size(npages, shift)); +} + +/** + * clear_bmap_test_and_clear: test clear bitmap for the page, clear if set + * + * @rb: the ramblock to operate on + * @page: the page number to check + * + * Returns: true if the bit was set, false otherwise + */ +static inline bool clear_bmap_test_and_clear(RAMBlock *rb, uint64_t page) +{ + uint8_t shift = rb->clear_bmap_shift; + + return bitmap_test_and_clear_atomic(rb->clear_bmap, page >> shift, 1); +} + static inline bool offset_in_ramblock(RAMBlock *b, ram_addr_t offset) { return (b && b->host && offset < b->used_length) ? true : false; @@ -349,8 +411,13 @@ static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap, if (bitmap[k]) { unsigned long temp = leul_to_cpu(bitmap[k]); - atomic_or(&blocks[DIRTY_MEMORY_MIGRATION][idx][offset], temp); atomic_or(&blocks[DIRTY_MEMORY_VGA][idx][offset], temp); + + if (global_dirty_log) { + atomic_or(&blocks[DIRTY_MEMORY_MIGRATION][idx][offset], + temp); + } + if (tcg_enabled()) { atomic_or(&blocks[DIRTY_MEMORY_CODE][idx][offset], temp); } @@ -367,6 +434,11 @@ static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap, xen_hvm_modified_memory(start, pages << TARGET_PAGE_BITS); } else { uint8_t clients = tcg_enabled() ? DIRTY_CLIENTS_ALL : DIRTY_CLIENTS_NOCODE; + + if (!global_dirty_log) { + clients &= ~(1 << DIRTY_MEMORY_MIGRATION); + } + /* * bitmap-traveling is faster than memory-traveling (for addr...) * especially when most of the memory is not dirty. @@ -394,7 +466,7 @@ bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start, unsigned client); DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty - (ram_addr_t start, ram_addr_t length, unsigned client); + (MemoryRegion *mr, hwaddr offset, hwaddr length, unsigned client); bool cpu_physical_memory_snapshot_get_dirty(DirtyBitmapSnapshot *snap, ram_addr_t start, @@ -409,6 +481,7 @@ static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start, } +/* Called with RCU critical section */ static inline uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb, ram_addr_t start, @@ -432,8 +505,6 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb, DIRTY_MEMORY_BLOCK_SIZE); unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS); - rcu_read_lock(); - src = atomic_rcu_read( &ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION])->blocks; @@ -454,7 +525,18 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb, } } - rcu_read_unlock(); + if (rb->clear_bmap) { + /* + * Postpone the dirty bitmap clear to the point before we + * really send the pages, also we will split the clear + * dirty procedure into smaller chunks. + */ + clear_bmap_set(rb, start >> TARGET_PAGE_BITS, + length >> TARGET_PAGE_BITS); + } else { + /* Slow path - still do that in a huge chunk */ + memory_region_clear_dirty_bitmap(rb->mr, start, length); + } } else { ram_addr_t offset = rb->offset; diff --git a/include/qemu/bitmap.h b/include/qemu/bitmap.h index 5c31334..82a1d2f 100644 --- a/include/qemu/bitmap.h +++ b/include/qemu/bitmap.h @@ -41,6 +41,10 @@ * bitmap_find_next_zero_area(buf, len, pos, n, mask) Find bit free area * bitmap_to_le(dst, src, nbits) Convert bitmap to little endian * bitmap_from_le(dst, src, nbits) Convert bitmap from little endian + * bitmap_copy_with_src_offset(dst, src, offset, nbits) + * *dst = *src (with an offset into src) + * bitmap_copy_with_dst_offset(dst, src, offset, nbits) + * *dst = *src (with an offset into dst) */ /* @@ -271,4 +275,9 @@ void bitmap_to_le(unsigned long *dst, const unsigned long *src, void bitmap_from_le(unsigned long *dst, const unsigned long *src, long nbits); +void bitmap_copy_with_src_offset(unsigned long *dst, const unsigned long *src, + unsigned long offset, unsigned long nbits); +void bitmap_copy_with_dst_offset(unsigned long *dst, const unsigned long *src, + unsigned long shift, unsigned long nbits); + #endif /* BITMAP_H */ diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h index f838412..31df465 100644 --- a/include/sysemu/kvm_int.h +++ b/include/sysemu/kvm_int.h @@ -21,10 +21,14 @@ typedef struct KVMSlot int slot; int flags; int old_flags; + /* Dirty bitmap cache for the slot */ + unsigned long *dirty_bmap; } KVMSlot; typedef struct KVMMemoryListener { MemoryListener listener; + /* Protects the slots and all inside them */ + QemuMutex slots_lock; KVMSlot *slots; int as_id; } KVMMemoryListener; |