summaryrefslogtreecommitdiffstats
path: root/accel/kvm/kvm-all.c
diff options
context:
space:
mode:
authorZenghui Yu2020-12-08 12:40:13 +0100
committerPaolo Bonzini2020-12-15 18:52:05 +0100
commit4054adbdd2f66d78f73cdce0092eb5513b3b3521 (patch)
treed37d9e0599b9990f6afaec4afc047464db4a0996 /accel/kvm/kvm-all.c
parentscsi: fix device removal race vs IO restart callback on resume (diff)
downloadqemu-4054adbdd2f66d78f73cdce0092eb5513b3b3521.tar.gz
qemu-4054adbdd2f66d78f73cdce0092eb5513b3b3521.tar.xz
qemu-4054adbdd2f66d78f73cdce0092eb5513b3b3521.zip
kvm: Take into account the unaligned section size when preparing bitmap
The kernel KVM_CLEAR_DIRTY_LOG interface has align requirement on both the start and the size of the given range of pages. We have been careful to handle the unaligned cases when performing CLEAR on one slot. But it seems that we forget to take the unaligned *size* case into account when preparing bitmap for the interface, and we may end up clearing dirty status for pages outside of [start, start + size). If the size is unaligned, let's go through the slow path to manipulate a temp bitmap for the interface so that we won't bother with those unaligned bits at the end of bitmap. I don't think this can happen in practice since the upper layer would provide us with the alignment guarantee. I'm not sure if kvm-all could rely on it. And this patch is mainly intended to address correctness of the specific algorithm used inside kvm_log_clear_one_slot(). Signed-off-by: Zenghui Yu <yuzenghui@huawei.com> Message-Id: <20201208114013.875-1-yuzenghui@huawei.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'accel/kvm/kvm-all.c')
-rw-r--r--accel/kvm/kvm-all.c7
1 files changed, 5 insertions, 2 deletions
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 666b9ab96c..389eaace72 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -745,7 +745,7 @@ static int kvm_log_clear_one_slot(KVMSlot *mem, int as_id, uint64_t start,
assert(bmap_start % BITS_PER_LONG == 0);
/* We should never do log_clear before log_sync */
assert(mem->dirty_bmap);
- if (start_delta) {
+ if (start_delta || bmap_npages - size / psize) {
/* Slow path - we need to manipulate a temp bitmap */
bmap_clear = bitmap_new(bmap_npages);
bitmap_copy_with_src_offset(bmap_clear, mem->dirty_bmap,
@@ -758,7 +758,10 @@ static int kvm_log_clear_one_slot(KVMSlot *mem, int as_id, uint64_t start,
bitmap_clear(bmap_clear, 0, start_delta);
d.dirty_bitmap = bmap_clear;
} else {
- /* Fast path - start address aligns well with BITS_PER_LONG */
+ /*
+ * Fast path - both start and size align well with BITS_PER_LONG
+ * (or the end of memory slot)
+ */
d.dirty_bitmap = mem->dirty_bmap + BIT_WORD(bmap_start);
}