Skip to contentSkip to conversation

migration dirtybitmap support ARMv7

PATCH In review Mario Smarduch 3 participants 5 messages Apr 15, 2014 – Apr 16, 2014

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 3/3 migration dirtybitmap support ARMv7

- support QEMU interface for initial VM Write Protect
- QEMU Dirty bit map log retrieval

---
 arch/arm/kvm/arm.c |   62 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 61 insertions(+), 1 deletion(-)
arch/arm/kvm/arm.c +61 -1
index bd18bb8..9076e3d 100644
@@ -241,6 +241,8 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
 				   const struct kvm_memory_slot *old,
 				   enum kvm_mr_change change)
 {
+	if ((change != KVM_MR_DELETE) && (mem->flags & KVM_MEM_LOG_DIRTY_PAGES))
+		kvm_mmu_slot_remove_write_access(kvm, mem->slot);
 }
 
 void kvm_arch_flush_shadow_all(struct kvm *kvm)
@@ -773,9 +775,67 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 	}
 }
 
+/*
+ * Walks the memslot dirty bitmap, write protects dirty pages for next rount,
+ * and stores the dirty bitmap fo QEMU retrieval.
+ *
+ */
 int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
 {
-	return -EINVAL;
+	int r;
+	struct kvm_memory_slot *memslot;
+	unsigned long n, i;
+	unsigned long *dirty_bitmap;
+	unsigned long *dirty_bitmap_buffer;
+	bool is_dirty = false;
+	gfn_t offset;
+
+	mutex_lock(&kvm->slots_lock);
+	r = -EINVAL;
+
+	if (log->slot >= KVM_USER_MEM_SLOTS)
+		goto out;
+
+	memslot = id_to_memslot(kvm->memslots, log->slot);
+	dirty_bitmap = memslot->dirty_bitmap;
+
+	r = -ENOENT;
+	if (!dirty_bitmap)
+		goto out;
+
+	n = kvm_dirty_bitmap_bytes(memslot);
+	dirty_bitmap_buffer = dirty_bitmap + n / sizeof(long);
+	memset(dirty_bitmap_buffer, 0, n);
+
+	spin_lock(&kvm->mmu_lock);
+	for (i = 0; i < n / sizeof(long); i++) {
+		unsigned long mask;
+
+		if (!dirty_bitmap[i])
+			continue;
+
+		is_dirty = true;
+		offset = i * BITS_PER_LONG;
+		kvm_mmu_write_protect_pt_masked(kvm, memslot, offset,
+							dirty_bitmap[i]);
+		mask = dirty_bitmap[i];
+		dirty_bitmap_buffer[i] = mask;
+		dirty_bitmap[i] = 0;
+	}
+
+	if (is_dirty)
+		kvm_tlb_flush_vmid(kvm);
+
+	spin_unlock(&kvm->mmu_lock);
+	r = -EFAULT;
+
+	if (copy_to_user(log->dirty_bitmap, dirty_bitmap_buffer, n))
+		goto out;
+
+	r = 0;
+out:
+	mutex_unlock(&kvm->slots_lock);
+	return r;
 }
 
 static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
Signature · 1 line
1.7.9.5
#1 lore raw
Quoted 15 lines · Mario Smarduch

- support QEMU interface for initial VM Write Protect
- QEMU Dirty bit map log retrieval

---
 arch/arm/kvm/arm.c |   62 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 61 insertions(+), 1 deletion(-)
arch/arm/kvm/arm.c +0 -0
index bd18bb8..9076e3d 100644

arch/arm/kvm/arm.c void kvm_arch_commit_memory_region(struct kvm *kvm, · line 246

Quoted 6 lines
arch/arm/kvm/arm.c +2 -0
@@ -241,6 +241,8 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
 				   const struct kvm_memory_slot *old,
 				   enum kvm_mr_change change)
 {
+	if ((change != KVM_MR_DELETE) && (mem->flags & KVM_MEM_LOG_DIRTY_PAGES))
+		kvm_mmu_slot_remove_write_access(kvm, mem->slot);
 }

There is a patch by Eric Auger doing the same thing. Please use it as a dependency.

Quoted 58 lines
arch/arm/kvm/arm.c +50 -1
 void kvm_arch_flush_shadow_all(struct kvm *kvm)
@@ -773,9 +775,67 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 	}
 }
 
+/*
+ * Walks the memslot dirty bitmap, write protects dirty pages for next rount,
+ * and stores the dirty bitmap fo QEMU retrieval.
+ *
+ */
 int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
 {
-	return -EINVAL;
+	int r;
+	struct kvm_memory_slot *memslot;
+	unsigned long n, i;
+	unsigned long *dirty_bitmap;
+	unsigned long *dirty_bitmap_buffer;
+	bool is_dirty = false;
+	gfn_t offset;
+
+	mutex_lock(&kvm->slots_lock);
+	r = -EINVAL;
+
+	if (log->slot >= KVM_USER_MEM_SLOTS)
+		goto out;
+
+	memslot = id_to_memslot(kvm->memslots, log->slot);
+	dirty_bitmap = memslot->dirty_bitmap;
+
+	r = -ENOENT;
+	if (!dirty_bitmap)
+		goto out;
+
+	n = kvm_dirty_bitmap_bytes(memslot);
+	dirty_bitmap_buffer = dirty_bitmap + n / sizeof(long);
+	memset(dirty_bitmap_buffer, 0, n);
+
+	spin_lock(&kvm->mmu_lock);
+	for (i = 0; i < n / sizeof(long); i++) {
+		unsigned long mask;
+
+		if (!dirty_bitmap[i])
+			continue;
+
+		is_dirty = true;
+		offset = i * BITS_PER_LONG;
+		kvm_mmu_write_protect_pt_masked(kvm, memslot, offset,
+							dirty_bitmap[i]);
+		mask = dirty_bitmap[i];
+		dirty_bitmap_buffer[i] = mask;
+		dirty_bitmap[i] = 0;
+	}
+
+	if (is_dirty)
+		kvm_tlb_flush_vmid(kvm);
+
+	spin_unlock(&kvm->mmu_lock);

arch/arm/kvm/arm.c long kvm_arch_vcpu_ioctl(struct file *filp, · line 839

Quoted 10 lines
arch/arm/kvm/arm.c +9 -0
+	r = -EFAULT;
+
+	if (copy_to_user(log->dirty_bitmap, dirty_bitmap_buffer, n))
+		goto out;
+
+	r = 0;
+out:
+	mutex_unlock(&kvm->slots_lock);
+	return r;
 }

This is a direct copy of the x86 code. Please make it generic.

arch/arm/kvm/arm.c long kvm_arch_vcpu_ioctl(struct file *filp, · line 841

Quoted 2 lines
arch/arm/kvm/arm.c +0 -0
 static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
 

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#2 lore raw

Hi Eric, Mark -
what repository should I use to pick up Eric patches?

For kvm_vm_ioctl_get_dirty_log() not sure what to make generic it appears generic enough and it does what it needs to do?

Thanks,
Mario

Quoted 104 lines · Marc Zyngier
Quoted 15 lines · Mario Smarduch

- support QEMU interface for initial VM Write Protect
- QEMU Dirty bit map log retrieval

---
 arch/arm/kvm/arm.c |   62 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 61 insertions(+), 1 deletion(-)
arch/arm/kvm/arm.c +0 -0
index bd18bb8..9076e3d 100644

arch/arm/kvm/arm.c void kvm_arch_commit_memory_region(struct kvm *kvm, · line 246

Quoted 6 lines
arch/arm/kvm/arm.c +2 -0
@@ -241,6 +241,8 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
 				   const struct kvm_memory_slot *old,
 				   enum kvm_mr_change change)
 {
+	if ((change != KVM_MR_DELETE) && (mem->flags & KVM_MEM_LOG_DIRTY_PAGES))
+		kvm_mmu_slot_remove_write_access(kvm, mem->slot);
 }

There is a patch by Eric Auger doing the same thing. Please use it as a dependency.

Quoted 58 lines
arch/arm/kvm/arm.c +50 -1
 void kvm_arch_flush_shadow_all(struct kvm *kvm)
@@ -773,9 +775,67 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 	}
 }
 
+/*
+ * Walks the memslot dirty bitmap, write protects dirty pages for next rount,
+ * and stores the dirty bitmap fo QEMU retrieval.
+ *
+ */
 int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
 {
-	return -EINVAL;
+	int r;
+	struct kvm_memory_slot *memslot;
+	unsigned long n, i;
+	unsigned long *dirty_bitmap;
+	unsigned long *dirty_bitmap_buffer;
+	bool is_dirty = false;
+	gfn_t offset;
+
+	mutex_lock(&kvm->slots_lock);
+	r = -EINVAL;
+
+	if (log->slot >= KVM_USER_MEM_SLOTS)
+		goto out;
+
+	memslot = id_to_memslot(kvm->memslots, log->slot);
+	dirty_bitmap = memslot->dirty_bitmap;
+
+	r = -ENOENT;
+	if (!dirty_bitmap)
+		goto out;
+
+	n = kvm_dirty_bitmap_bytes(memslot);
+	dirty_bitmap_buffer = dirty_bitmap + n / sizeof(long);
+	memset(dirty_bitmap_buffer, 0, n);
+
+	spin_lock(&kvm->mmu_lock);
+	for (i = 0; i < n / sizeof(long); i++) {
+		unsigned long mask;
+
+		if (!dirty_bitmap[i])
+			continue;
+
+		is_dirty = true;
+		offset = i * BITS_PER_LONG;
+		kvm_mmu_write_protect_pt_masked(kvm, memslot, offset,
+							dirty_bitmap[i]);
+		mask = dirty_bitmap[i];
+		dirty_bitmap_buffer[i] = mask;
+		dirty_bitmap[i] = 0;
+	}
+
+	if (is_dirty)
+		kvm_tlb_flush_vmid(kvm);
+
+	spin_unlock(&kvm->mmu_lock);

arch/arm/kvm/arm.c long kvm_arch_vcpu_ioctl(struct file *filp, · line 839

Quoted 10 lines
arch/arm/kvm/arm.c +9 -0
+	r = -EFAULT;
+
+	if (copy_to_user(log->dirty_bitmap, dirty_bitmap_buffer, n))
+		goto out;
+
+	r = 0;
+out:
+	mutex_unlock(&kvm->slots_lock);
+	return r;
 }

This is a direct copy of the x86 code. Please make it generic.

arch/arm/kvm/arm.c long kvm_arch_vcpu_ioctl(struct file *filp, · line 841

Quoted 2 lines
arch/arm/kvm/arm.c +0 -0
 static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
 

Thanks,

	M.
#3 lore raw

Hi Mario,

Quoted 2 lines · Mario Smarduch

Hi Eric, Mark -
what repository should I use to pick up Eric patches?

The initial posting was there:

https://lists.cs.columbia.edu/pipermail/kvmarm/2014-April/008791.html

Reading Eric's patch again, it is not doing exactly the same thing, but actually dealing with a slightly different (but connected) case.

I suggest you both work together on a common patch (or patch series) that deals with the various memory region change thingy.

Quoted 2 lines

For kvm_vm_ioctl_get_dirty_log() not sure what to make generic it appears generic enough and it does what it needs to do?

What I'm saying is that it should be put in a common location (virt/kvm/kvm_main.c?), possibly as a weak symbol so it can be overridden by other architectures.

As much as possible, try to share code with other arches rather than duplicating it.

Thanks,

	M.
Quoted 110 lines

Thanks,
Mario

Quoted 104 lines · Marc Zyngier
Quoted 15 lines · Mario Smarduch

- support QEMU interface for initial VM Write Protect
- QEMU Dirty bit map log retrieval

---
 arch/arm/kvm/arm.c |   62 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 61 insertions(+), 1 deletion(-)
arch/arm/kvm/arm.c +0 -0
index bd18bb8..9076e3d 100644

arch/arm/kvm/arm.c void kvm_arch_commit_memory_region(struct kvm *kvm, · line 246

Quoted 6 lines
arch/arm/kvm/arm.c +2 -0
@@ -241,6 +241,8 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
 				   const struct kvm_memory_slot *old,
 				   enum kvm_mr_change change)
 {
+	if ((change != KVM_MR_DELETE) && (mem->flags & KVM_MEM_LOG_DIRTY_PAGES))
+		kvm_mmu_slot_remove_write_access(kvm, mem->slot);
 }

There is a patch by Eric Auger doing the same thing. Please use it as a dependency.

Quoted 58 lines
arch/arm/kvm/arm.c +50 -1
 void kvm_arch_flush_shadow_all(struct kvm *kvm)
@@ -773,9 +775,67 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 	}
 }
 
+/*
+ * Walks the memslot dirty bitmap, write protects dirty pages for next rount,
+ * and stores the dirty bitmap fo QEMU retrieval.
+ *
+ */
 int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
 {
-	return -EINVAL;
+	int r;
+	struct kvm_memory_slot *memslot;
+	unsigned long n, i;
+	unsigned long *dirty_bitmap;
+	unsigned long *dirty_bitmap_buffer;
+	bool is_dirty = false;
+	gfn_t offset;
+
+	mutex_lock(&kvm->slots_lock);
+	r = -EINVAL;
+
+	if (log->slot >= KVM_USER_MEM_SLOTS)
+		goto out;
+
+	memslot = id_to_memslot(kvm->memslots, log->slot);
+	dirty_bitmap = memslot->dirty_bitmap;
+
+	r = -ENOENT;
+	if (!dirty_bitmap)
+		goto out;
+
+	n = kvm_dirty_bitmap_bytes(memslot);
+	dirty_bitmap_buffer = dirty_bitmap + n / sizeof(long);
+	memset(dirty_bitmap_buffer, 0, n);
+
+	spin_lock(&kvm->mmu_lock);
+	for (i = 0; i < n / sizeof(long); i++) {
+		unsigned long mask;
+
+		if (!dirty_bitmap[i])
+			continue;
+
+		is_dirty = true;
+		offset = i * BITS_PER_LONG;
+		kvm_mmu_write_protect_pt_masked(kvm, memslot, offset,
+							dirty_bitmap[i]);
+		mask = dirty_bitmap[i];
+		dirty_bitmap_buffer[i] = mask;
+		dirty_bitmap[i] = 0;
+	}
+
+	if (is_dirty)
+		kvm_tlb_flush_vmid(kvm);
+
+	spin_unlock(&kvm->mmu_lock);

arch/arm/kvm/arm.c long kvm_arch_vcpu_ioctl(struct file *filp, · line 839

Quoted 10 lines
arch/arm/kvm/arm.c +9 -0
+	r = -EFAULT;
+
+	if (copy_to_user(log->dirty_bitmap, dirty_bitmap_buffer, n))
+		goto out;
+
+	r = 0;
+out:
+	mutex_unlock(&kvm->slots_lock);
+	return r;
 }

This is a direct copy of the x86 code. Please make it generic.

arch/arm/kvm/arm.c long kvm_arch_vcpu_ioctl(struct file *filp, · line 841

Quoted 2 lines
arch/arm/kvm/arm.c +0 -0
 static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
 

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#4 lore raw
Quoted 16 lines · Marc Zyngier

Hi Mario,

Quoted 2 lines · Mario Smarduch

Hi Eric, Mark -
what repository should I use to pick up Eric patches?

The initial posting was there:

https://lists.cs.columbia.edu/pipermail/kvmarm/2014-April/008791.html

Reading Eric's patch again, it is not doing exactly the same thing, but actually dealing with a slightly different (but connected) case.

I suggest you both work together on a common patch (or patch series) that deals with the various memory region change thingy.

Quoted 6 lines
Quoted 2 lines

For kvm_vm_ioctl_get_dirty_log() not sure what to make generic it appears generic enough and it does what it needs to do?

What I'm saying is that it should be put in a common location (virt/kvm/kvm_main.c?), possibly as a weak symbol so it can be overridden by other architectures.

Yes, make it weak. The s390 implementation looks different.