mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-06 09:13:55 -06:00
Pull request
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEGJn/jt6/WMzuA0uC9IfvGFhy1yMFAl0shHUACgkQ9IfvGFhy 1yN2ThAAgo0o75GcC3p2pYM+jhZR+YpH5vffOa82bKRBS/toxzobXLyiD1jB627T oTr7WMWNxt0Tc6m4NEgnHCrFhu59aSELKWj/SY7gpjgUgtZBwU+BMEs6VPwXDpWz bXxNnp5O27pYLfYmN8p24cV9VgZV9e1J75H1w4zjJD4dN+T+f2+QZcxLZOVXe5v+ WnUgY9EGg9ruXb72MRZhhh/OgXKLOaj0nKQ8OgtkADbs0hj6mNpwxt2YxwOZhnYu drnVCEl/mS3kCFCpyyeRxYtgPJ+ykXVykkUEHNZLNZ96Tck379+gUhOLg0/wf1vn 7R/h22XzQtkoDkUfVn0XsGbsOLr//wljoYafl8cok77BFSfMVkOP1KpQvdzYhHWn 4Tl0cX4wk0qoDKX/T78+7RTq86G9KwDlg8wA0vXloVd+V3RBg3kWUVOMhIYxtOYX QbzNuR+rsSY2vx0ciGVuCRfynsb2Di66KiEtfSMv3pGjdz3g5CmlJr6sgI0no4EE prKdxifiP+2CJ7U9ffGbIlLY4dk+YWibYwmCxGDQL/hKWLIf2xUbpGszxlgGfTjB QPMh8FGLGcz9yraB9u0N2KaJX7baLMfIEztCj+xH3EsgCT2PjSO+Pooyg29waBUZ cs1Eb7RBZZCmJKTuvLjTyz0iCD6f1NMqu9VZOZmdcJxLd1QtZI8= =Gsak -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
a68725f930
18 changed files with 732 additions and 94 deletions
|
@ -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,
|
||||
|
@ -1267,6 +1270,22 @@ void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client);
|
|||
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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue