All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC v2 3/6] KVM: introduce a wrapper function to copy dirty
@ 2010-04-20 10:59 ` Takuya Yoshikawa
  0 siblings, 0 replies; 141+ messages in thread
From: Takuya Yoshikawa @ 2010-04-20 10:59 UTC (permalink / raw)
  To: kvm-ia64

We will replace copy_to_user() to copy_in_user() when we move
the dirty bitmaps to user space.

But sadly, we have copy_in_user() only for 64 bits architectures.
So this function should work as a wrapper to hide ifdefs from outside.
Once we get copy_in_user() for 32 bits architectures, we can remove
this wrapper and use copy_in_user() directly.

Signed-off-by: Takuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp>
Signed-off-by: Fernando Luis Vazquez Cao <fernando@oss.ntt.co.jp>
---
 arch/x86/kvm/x86.c       |    4 +---
 include/linux/kvm_host.h |    3 +++
 virt/kvm/kvm_main.c      |   12 +++++++++++-
 3 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 76b23ed..6f0b706 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2771,9 +2771,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
 		kfree(old_slots);
 	}
 
-	r = 0;
-	if (copy_to_user(log->dirty_bitmap, dirty_bitmap, n))
-		r = -EFAULT;
+	r = kvm_copy_dirty_bitmap(log->dirty_bitmap, dirty_bitmap, n);
 out_free:
 	vfree(dirty_bitmap);
 out:
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 4446622..42b7161 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -330,6 +330,9 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 
 int kvm_dev_ioctl_check_extension(long ext);
 
+int kvm_copy_dirty_bitmap(unsigned long __user *to,
+			  const unsigned long *from,
+			  unsigned long bytes);
 int kvm_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log);
 int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
 				struct kvm_dirty_log *log);
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 40a6888..6908304 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -777,6 +777,16 @@ int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
 	return kvm_set_memory_region(kvm, mem, user_alloc);
 }
 
+int kvm_copy_dirty_bitmap(unsigned long __user *to,
+			  const unsigned long *from,
+			  unsigned long bytes)
+{
+	if (copy_to_user(to, from, bytes))
+		return -EFAULT;
+
+	return 0;
+}
+
 int kvm_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
 {
 	struct kvm_memory_slot *memslot;
@@ -795,7 +805,7 @@ int kvm_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
 	n = kvm_dirty_bitmap_bytes(memslot);
 
 	r = -EFAULT;
-	if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n))
+	if (kvm_copy_dirty_bitmap(log->dirty_bitmap, memslot->dirty_bitmap, n))
 		goto out;
 
 	r = 0;
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 141+ messages in thread
* [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty
@ 2010-04-20 11:03 ` Takuya Yoshikawa
  0 siblings, 0 replies; 141+ messages in thread
From: Takuya Yoshikawa @ 2010-04-20 11:03 UTC (permalink / raw)
  To: kvm-ia64

We can now export the addree of the bitmap created by do_mmap()
to user space. For the sake of this, we introduce a new API:

  KVM_SWITCH_DIRTY_LOG: application can use this to trigger the
  switch of the bitmaps and get the address of the bitmap which
  has been used until now. This reduces the copy of the dirty
  bitmap from the kernel.

Signed-off-by: Takuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp>
Cc: Fernando Luis Vazquez Cao <fernando@oss.ntt.co.jp>
---
 Documentation/kvm/api.txt |   23 +++++++++++++++++++++++
 arch/ia64/kvm/kvm-ia64.c  |   19 ++++++++++++++-----
 arch/powerpc/kvm/book3s.c |   19 ++++++++++++++-----
 arch/x86/kvm/x86.c        |   32 ++++++++++++++++++++++++++------
 include/linux/kvm.h       |    6 ++++--
 include/linux/kvm_host.h  |    7 ++++---
 virt/kvm/kvm_main.c       |   41 ++++++++++++++++++++++++++++++++++++-----
 7 files changed, 121 insertions(+), 26 deletions(-)

diff --git a/Documentation/kvm/api.txt b/Documentation/kvm/api.txt
index baa8fde..f3d1c2a 100644
--- a/Documentation/kvm/api.txt
+++ b/Documentation/kvm/api.txt
@@ -848,6 +848,29 @@ function properly, this is the place to put them.
        __u8  pad[64];
 };
 
+4.37 KVM_SWITCH_DIRTY_LOG (vm ioctl)
+
+Capability: basic
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_dirty_log (in/out)
+Returns: 0 on success, -1 on error
+
+/* for KVM_SWITCH_DIRTY_LOG */
+struct kvm_dirty_log {
+	__u32 slot;
+	__u32 padding;
+	union {
+		void __user *dirty_bitmap; /* one bit per page */
+		__u64 addr;
+	};
+};
+
+Given a memory slot, return the address of a bitmap containing any
+pages dirtied since the last call to this ioctl.  Bit 0 is the first
+page in the memory slot.  Ensure the entire structure is cleared to
+avoid padding issues.
+
 5. The kvm_run structure
 
 Application code obtains a pointer to the kvm_run structure by
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index c3f0b70..04fbb1c 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -1843,8 +1843,8 @@ out:
 	return r;
 }
 
-int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
-		struct kvm_dirty_log *log)
+static int kvm_ia64_update_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log,
+				     bool need_copy)
 {
 	int r;
 	unsigned long n;
@@ -1857,7 +1857,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
 	if (r)
 		goto out;
 
-	r = kvm_get_dirty_log(kvm, log);
+	r = kvm_update_dirty_log(kvm, log, need_copy);
 	if (r)
 		goto out;
 
@@ -1865,10 +1865,9 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
 	/* If nothing is dirty, don't bother messing with page tables. */
 	if (memslot->is_dirty) {
 		kvm_flush_remote_tlbs(kvm);
-		n = kvm_dirty_bitmap_bytes(memslot);
-		clear_user(memslot->dirty_bitmap, n);
 		memslot->is_dirty = false;
 	}
+
 	r = 0;
 out:
 	mutex_unlock(&kvm->slots_lock);
@@ -1876,6 +1875,16 @@ out:
 	return r;
 }
 
+int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
+{
+	return kvm_ia64_update_dirty_log(kvm, log, true);
+}
+
+int kvm_vm_ioctl_switch_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
+{
+	return kvm_ia64_update_dirty_log(kvm, log, false);
+}
+
 int kvm_arch_hardware_setup(void)
 {
 	return 0;
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index b074e19..d813dca 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -1112,8 +1112,9 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
 /*
  * Get (and clear) the dirty memory log for a memory slot.
  */
-int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
-				      struct kvm_dirty_log *log)
+static int kvmppc_update_dirty_log(struct kvm *kvm,
+				   struct kvm_dirty_log *log,
+				   bool need_copy)
 {
 	struct kvm_memory_slot *memslot;
 	struct kvm_vcpu *vcpu;
@@ -1123,7 +1124,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
 
 	mutex_lock(&kvm->slots_lock);
 
-	r = kvm_get_dirty_log(kvm, log);
+	r = kvm_update_dirty_log(kvm, log, need_copy);
 	if (r)
 		goto out;
 
@@ -1136,8 +1137,6 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
 		kvm_for_each_vcpu(n, vcpu, kvm)
 			kvmppc_mmu_pte_pflush(vcpu, ga, ga_end);
 
-		n = kvm_dirty_bitmap_bytes(memslot);
-		clear_user(memslot->dirty_bitmap, n);
 		memslot->is_dirty = false;
 	}
 
@@ -1147,6 +1146,16 @@ out:
 	return r;
 }
 
+int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
+{
+	return kvmppc_update_dirty_log(kvm, log, true);
+}
+
+int kvm_vm_ioctl_switch_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
+{
+	return kvmppc_update_dirty_log(kvm, log, false);
+}
+
 int kvmppc_core_check_processor_compat(void)
 {
 	return 0;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index ad55353..45b728c 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2718,11 +2718,9 @@ static int kvm_vm_ioctl_reinject(struct kvm *kvm,
 	return 0;
 }
 
-/*
- * Get (and clear) the dirty memory log for a memory slot.
- */
-int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
-				      struct kvm_dirty_log *log)
+static int kvm_x86_update_dirty_log(struct kvm *kvm,
+				    struct kvm_dirty_log *log,
+				    bool need_copy)
 {
 	int r;
 	struct kvm_memory_slot *memslot;
@@ -2773,12 +2771,34 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
 		dirty_bitmap_old = dirty_bitmap;
 	}
 
-	r = kvm_copy_dirty_bitmap(log->dirty_bitmap, dirty_bitmap_old, n);
+	if (need_copy) {
+		r = kvm_copy_dirty_bitmap(log->dirty_bitmap,
+					  dirty_bitmap_old, n);
+	} else {
+		log->addr = (unsigned long)dirty_bitmap_old;
+		r = 0;
+	}
 out:
 	mutex_unlock(&kvm->slots_lock);
 	return r;
 }
 
+/*
+ * Get (and clear) the dirty memory log for a memory slot.
+ */
+int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
+{
+	return kvm_x86_update_dirty_log(kvm, log, true);
+}
+
+/*
+ * Switch to the next dirty bitmap and return the address of the old one.
+ */
+int kvm_vm_ioctl_switch_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
+{
+	return kvm_x86_update_dirty_log(kvm, log, false);
+}
+
 long kvm_arch_vm_ioctl(struct file *filp,
 		       unsigned int ioctl, unsigned long arg)
 {
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 23ea022..9fa6f1e 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -12,7 +12,7 @@
 #include <linux/ioctl.h>
 #include <asm/kvm.h>
 
-#define KVM_API_VERSION 12
+#define KVM_API_VERSION 13
 
 /* *** Deprecated interfaces *** */
 
@@ -318,7 +318,7 @@ struct kvm_dirty_log {
 	__u32 padding1;
 	union {
 		void __user *dirty_bitmap; /* one bit per page */
-		__u64 padding2;
+		__u64 addr;
 	};
 };
 
@@ -524,6 +524,7 @@ struct kvm_enable_cap {
 #define KVM_CAP_PPC_OSI 52
 #define KVM_CAP_PPC_UNSET_IRQ 53
 #define KVM_CAP_ENABLE_CAP 54
+#define KVM_CAP_USER_DIRTY_BITMAP 55
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -620,6 +621,7 @@ struct kvm_clock_data {
 					struct kvm_userspace_memory_region)
 #define KVM_SET_TSS_ADDR          _IO(KVMIO,   0x47)
 #define KVM_SET_IDENTITY_MAP_ADDR _IOW(KVMIO,  0x48, __u64)
+#define KVM_SWITCH_DIRTY_LOG      _IOW(KVMIO,  0x49, struct kvm_dirty_log)
 /* Device model IOC */
 #define KVM_CREATE_IRQCHIP        _IO(KVMIO,   0x60)
 #define KVM_IRQ_LINE              _IOW(KVMIO,  0x61, struct kvm_irq_level)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index d4d217a..addecee 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -334,9 +334,10 @@ int kvm_dev_ioctl_check_extension(long ext);
 int kvm_copy_dirty_bitmap(unsigned long __user *to,
 			  const unsigned long __user *from,
 			  unsigned long bytes);
-int kvm_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log);
-int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
-				struct kvm_dirty_log *log);
+int kvm_update_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log,
+			 bool need_copy);
+int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log);
+int kvm_vm_ioctl_switch_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log);
 
 int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
 				   struct
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 9323639..cba133d 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -844,7 +844,8 @@ out_fault:
 #endif
 }
 
-int kvm_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
+int kvm_update_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log,
+			 bool need_copy)
 {
 	struct kvm_memory_slot *memslot;
 	int r;
@@ -861,9 +862,23 @@ int kvm_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
 
 	n = kvm_dirty_bitmap_bytes(memslot);
 
-	r = -EFAULT;
-	if (kvm_copy_dirty_bitmap(log->dirty_bitmap, memslot->dirty_bitmap, n))
-		goto out;
+	if (need_copy) {
+		r = -EFAULT;
+		if (kvm_copy_dirty_bitmap(log->dirty_bitmap,
+					  memslot->dirty_bitmap, n))
+			goto out;
+
+		if (memslot->is_dirty)
+			clear_user(memslot->dirty_bitmap, n);
+	} else {
+		unsigned long __user *dirty_bitmap;
+
+		dirty_bitmap = memslot->dirty_bitmap;
+		clear_user(memslot->dirty_bitmap_old, n);
+		memslot->dirty_bitmap = memslot->dirty_bitmap_old;
+		memslot->dirty_bitmap_old = dirty_bitmap;
+		log->addr = (unsigned long)dirty_bitmap;
+	}
 
 	r = 0;
 out:
@@ -1699,6 +1714,21 @@ static long kvm_vm_ioctl(struct file *filp,
 			goto out;
 		break;
 	}
+	case KVM_SWITCH_DIRTY_LOG: {
+		struct kvm_dirty_log log;
+
+		r = -EFAULT;
+		if (copy_from_user(&log, argp, sizeof log))
+			goto out;
+		r = kvm_vm_ioctl_switch_dirty_log(kvm, &log);
+		if (r)
+			goto out;
+		r = -EFAULT;
+		if (copy_to_user(argp, &log, sizeof log))
+			goto out;
+		r = 0;
+		break;
+	}
 #ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
 	case KVM_REGISTER_COALESCED_MMIO: {
 		struct kvm_coalesced_mmio_zone zone;
@@ -1790,7 +1820,7 @@ static long kvm_vm_compat_ioctl(struct file *filp,
 			goto out;
 		log.slot	 = compat_log.slot;
 		log.padding1	 = compat_log.padding1;
-		log.padding2	 = compat_log.padding2;
+		log.addr	 = compat_log.padding2;
 		log.dirty_bitmap = compat_ptr(compat_log.dirty_bitmap);
 
 		r = kvm_vm_ioctl_get_dirty_log(kvm, &log);
@@ -1879,6 +1909,7 @@ static long kvm_dev_ioctl_check_extension_generic(long arg)
 	case KVM_CAP_SET_BOOT_CPU_ID:
 #endif
 	case KVM_CAP_INTERNAL_ERROR_DATA:
+	case KVM_CAP_USER_DIRTY_BITMAP:
 		return 1;
 #ifdef CONFIG_HAVE_KVM_IRQCHIP
 	case KVM_CAP_IRQ_ROUTING:
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 141+ messages in thread
* [PATCH RFC v2 5/6] KVM: moving dirty bitmaps to user space
@ 2010-04-20 10:58 ` Takuya Yoshikawa
  0 siblings, 0 replies; 141+ messages in thread
From: Takuya Yoshikawa @ 2010-04-20 10:58 UTC (permalink / raw)
  To: kvm-ia64

We move dirty bitmaps to user space.

 - Allocation and destruction: we use do_mmap() and do_munmap().
   The new bitmap space is twice longer than the original one and we
   use the additional space for double buffering: this makes it
   possible to update the active bitmap while letting the user space
   read the other one safely.

 - Bitmap manipulations: we replace all functions which access dirty
   bitmaps to *_user() functions. Note that some of these should be
   optimized later.

 - For ia64: moving the dirty bitmaps of memory slots does not effect
   much to ia64 because it's using a different space to store bitmaps
   which is directly updated: all we have to change are sync and get
   of dirty log, so we don't need set_bit_user like function for ia64.

Signed-off-by: Takuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp>
Signed-off-by: Fernando Luis Vazquez Cao <fernando@oss.ntt.co.jp>
---
 arch/ia64/kvm/kvm-ia64.c  |   12 ++++-
 arch/powerpc/kvm/book3s.c |    2 +-
 arch/x86/kvm/x86.c        |   24 +++++-----
 include/linux/kvm_host.h  |    5 +-
 virt/kvm/kvm_main.c       |  101 ++++++++++++++++++++++++++++++++++++++++-----
 5 files changed, 116 insertions(+), 28 deletions(-)

diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index d60dafe..c3f0b70 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -1823,11 +1823,19 @@ static int kvm_ia64_sync_dirty_log(struct kvm *kvm,
 	n = kvm_dirty_bitmap_bytes(memslot);
 	base = memslot->base_gfn / BITS_PER_LONG;
 
+	r = -EFAULT;
+	if (!access_ok(VERIFY_WRITE, memslot->dirty_bitmap, n))
+		goto out;
+
 	for (i = 0; i < n/sizeof(long); ++i) {
 		if (dirty_bitmap[base + i])
 			memslot->is_dirty = true;
 
-		memslot->dirty_bitmap[i] = dirty_bitmap[base + i];
+		if (__put_user(dirty_bitmap[base + i],
+			       &memslot->dirty_bitmap[i])) {
+			r = -EFAULT;
+			goto out;
+		}
 		dirty_bitmap[base + i] = 0;
 	}
 	r = 0;
@@ -1858,7 +1866,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
 	if (memslot->is_dirty) {
 		kvm_flush_remote_tlbs(kvm);
 		n = kvm_dirty_bitmap_bytes(memslot);
-		memset(memslot->dirty_bitmap, 0, n);
+		clear_user(memslot->dirty_bitmap, n);
 		memslot->is_dirty = false;
 	}
 	r = 0;
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index 53b45cf..b074e19 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -1137,7 +1137,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
 			kvmppc_mmu_pte_pflush(vcpu, ga, ga_end);
 
 		n = kvm_dirty_bitmap_bytes(memslot);
-		memset(memslot->dirty_bitmap, 0, n);
+		clear_user(memslot->dirty_bitmap, n);
 		memslot->is_dirty = false;
 	}
 
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 6f0b706..ad55353 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2727,7 +2727,8 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
 	int r;
 	struct kvm_memory_slot *memslot;
 	unsigned long n;
-	unsigned long *dirty_bitmap = NULL;
+	unsigned long __user *dirty_bitmap;
+	unsigned long __user *dirty_bitmap_old;
 
 	mutex_lock(&kvm->slots_lock);
 
@@ -2742,11 +2743,9 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
 
 	n = kvm_dirty_bitmap_bytes(memslot);
 
-	r = -ENOMEM;
-	dirty_bitmap = vmalloc(n);
-	if (!dirty_bitmap)
-		goto out;
-	memset(dirty_bitmap, 0, n);
+	dirty_bitmap = memslot->dirty_bitmap;
+	dirty_bitmap_old = memslot->dirty_bitmap_old;
+	clear_user(dirty_bitmap_old, n);
 
 	/* If nothing is dirty, don't bother messing with page tables. */
 	if (memslot->is_dirty) {
@@ -2756,24 +2755,25 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
 		kvm_mmu_slot_remove_write_access(kvm, log->slot);
 		spin_unlock(&kvm->mmu_lock);
 
+		r = -ENOMEM;
 		slots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL);
 		if (!slots)
-			goto out_free;
+			goto out;
 
 		memcpy(slots, kvm->memslots, sizeof(struct kvm_memslots));
-		slots->memslots[log->slot].dirty_bitmap = dirty_bitmap;
+		slots->memslots[log->slot].dirty_bitmap = dirty_bitmap_old;
+		slots->memslots[log->slot].dirty_bitmap_old = dirty_bitmap;
 		slots->memslots[log->slot].is_dirty = false;
 
 		old_slots = kvm->memslots;
 		rcu_assign_pointer(kvm->memslots, slots);
 		synchronize_srcu_expedited(&kvm->srcu);
-		dirty_bitmap = old_slots->memslots[log->slot].dirty_bitmap;
 		kfree(old_slots);
+
+		dirty_bitmap_old = dirty_bitmap;
 	}
 
-	r = kvm_copy_dirty_bitmap(log->dirty_bitmap, dirty_bitmap, n);
-out_free:
-	vfree(dirty_bitmap);
+	r = kvm_copy_dirty_bitmap(log->dirty_bitmap, dirty_bitmap_old, n);
 out:
 	mutex_unlock(&kvm->slots_lock);
 	return r;
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 42b7161..d4d217a 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -116,7 +116,8 @@ struct kvm_memory_slot {
 	unsigned long npages;
 	unsigned long flags;
 	unsigned long *rmap;
-	unsigned long *dirty_bitmap;
+	unsigned long __user *dirty_bitmap;
+	unsigned long __user *dirty_bitmap_old;
 	bool is_dirty;
 	struct {
 		unsigned long rmap_pde;
@@ -331,7 +332,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 int kvm_dev_ioctl_check_extension(long ext);
 
 int kvm_copy_dirty_bitmap(unsigned long __user *to,
-			  const unsigned long *from,
+			  const unsigned long __user *from,
 			  unsigned long bytes);
 int kvm_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log);
 int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 66c4daf..9323639 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -433,8 +433,20 @@ out_err_nodisable:
 
 static void kvm_destroy_dirty_bitmap(struct kvm_memory_slot *memslot)
 {
-	vfree(memslot->dirty_bitmap);
+	unsigned long user_addr;
+	unsigned long n = kvm_dirty_bitmap_bytes(memslot);
+
+	if (!memslot->dirty_bitmap)
+		return;
+
+	user_addr = min((unsigned long)memslot->dirty_bitmap,
+			(unsigned long)memslot->dirty_bitmap_old);
+	down_write(&current->mm->mmap_sem);
+	do_munmap(current->mm, user_addr, 2 * n);
+	up_write(&current->mm->mmap_sem);
+
 	memslot->dirty_bitmap = NULL;
+	memslot->dirty_bitmap_old = NULL;
 }
 
 /*
@@ -468,8 +480,12 @@ void kvm_free_physmem(struct kvm *kvm)
 	int i;
 	struct kvm_memslots *slots = kvm->memslots;
 
-	for (i = 0; i < slots->nmemslots; ++i)
+	for (i = 0; i < slots->nmemslots; ++i) {
+		/* We don't munmap dirty bitmaps by ourselves. */
+		slots->memslots[i].dirty_bitmap = NULL;
+		slots->memslots[i].dirty_bitmap_old = NULL;
 		kvm_free_physmem_slot(&slots->memslots[i], NULL);
+	}
 
 	kfree(kvm->memslots);
 }
@@ -523,13 +539,22 @@ static int kvm_vm_release(struct inode *inode, struct file *filp)
 
 static int kvm_create_dirty_bitmap(struct kvm_memory_slot *memslot)
 {
-	unsigned long dirty_bytes = kvm_dirty_bitmap_bytes(memslot);
+	unsigned long user_addr;
+	unsigned long n = kvm_dirty_bitmap_bytes(memslot);
 
-	memslot->dirty_bitmap = vmalloc(dirty_bytes);
-	if (!memslot->dirty_bitmap)
-		return -ENOMEM;
+	down_write(&current->mm->mmap_sem);
+	user_addr = do_mmap(NULL, 0, 2 * n,
+			    PROT_READ | PROT_WRITE,
+			    MAP_PRIVATE | MAP_ANONYMOUS, 0);
+	up_write(&current->mm->mmap_sem);
+
+	if (IS_ERR((void *)user_addr))
+		return PTR_ERR((void *)user_addr);
+
+	memslot->dirty_bitmap = (unsigned long __user *)user_addr;
+	memslot->dirty_bitmap_old = (unsigned long __user *)(user_addr + n);
+	clear_user(memslot->dirty_bitmap, 2 * n);
 
-	memset(memslot->dirty_bitmap, 0, dirty_bytes);
 	return 0;
 }
 
@@ -778,13 +803,45 @@ int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
 }
 
 int kvm_copy_dirty_bitmap(unsigned long __user *to,
-			  const unsigned long *from,
+			  const unsigned long __user *from,
 			  unsigned long bytes)
 {
-	if (copy_to_user(to, from, bytes))
+#if defined(CONFIG_X86_64) || defined(CONFIG_PPC64) || defined(CONFIG_IA64)
+	if (copy_in_user(to, from, bytes)) {
+		printk(KERN_WARNING "%s: copy_in_user failed.\n", __func__);
 		return -EFAULT;
+	}
+	return 0;
+#else
+	int num, bufbytes;
+	unsigned long buf[32];
 
+	if (!access_ok(VERIFY_READ, from, bytes) ||
+	    !access_ok(VERIFY_WRITE, to, bytes)) {
+		goto out_fault;
+	}
+
+	bufbytes = sizeof(buf);
+	num = bufbytes / sizeof(buf[0]);
+
+	for (; bytes > bufbytes; bytes -= bufbytes, to += num, from += num) {
+		if (__copy_from_user(buf, from, bufbytes))
+			goto out_fault;
+		if (__copy_to_user(to, buf, bufbytes))
+			goto out_fault;
+	}
+	if (bytes > 0) {
+		if (__copy_from_user(buf, from, bytes))
+			goto out_fault;
+		if (__copy_to_user(to, buf, bytes))
+			goto out_fault;
+	}
 	return 0;
+
+out_fault:
+	printk(KERN_WARNING "%s: copy to(from) user failed.\n", __func__);
+	return -EFAULT;
+#endif
 }
 
 int kvm_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
@@ -1194,13 +1251,35 @@ int kvm_clear_guest(struct kvm *kvm, gpa_t gpa, unsigned long len)
 }
 EXPORT_SYMBOL_GPL(kvm_clear_guest);
 
+/*
+ * Please use generic *_user bitops once they become available.
+ * Be careful setting the bit won't be done atomically.
+ */
 static int __mark_page_dirty(unsigned long nr,
-			     unsigned long *dirty_bitmap)
+			     unsigned long __user *dirty_bitmap)
 {
+	unsigned long user_addr;
+	u8 val;
+
 #ifdef __BIG_ENDIAN
 	nr = nr ^ BITOP_LE_SWIZZLE;
 #endif
-	__set_bit(nr, dirty_bitmap);
+	user_addr = (unsigned long)dirty_bitmap + nr / 8;
+	if (!access_ok(VERIFY_WRITE, user_addr, 1))
+		goto out_fault;
+
+	if (__get_user(val, (u8 __user *)user_addr))
+		goto out_fault;
+
+	val |= 1U << (nr % 8);
+	if (__put_user(val, (u8 __user *)user_addr))
+		goto out_fault;
+
+	return 0;
+
+out_fault:
+	printk(KERN_WARNING "%s: setting user bit failed.\n", __func__);
+	return -EFAULT;
 }
 
 void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 141+ messages in thread
* [PATCH RFC v2 2/6] KVM: introduce wrapper functions to create and
  2010-04-20 10:53 ` Takuya Yoshikawa
  (?)
@ 2010-04-20 10:57 ` Takuya Yoshikawa
  -1 siblings, 0 replies; 141+ messages in thread
From: Takuya Yoshikawa @ 2010-04-20 10:57 UTC (permalink / raw)
  To: kvm-ia64

We will change the vmalloc() and vfree() to do_mmap() and do_munmap()
later. This patch makes it easy and cleanup the code.

Signed-off-by: Takuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp>
Signed-off-by: Fernando Luis Vazquez Cao <fernando@oss.ntt.co.jp>
---
 virt/kvm/kvm_main.c |   27 ++++++++++++++++++++-------
 1 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index cc78e07..40a6888 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -431,6 +431,12 @@ out_err_nodisable:
 	return ERR_PTR(r);
 }
 
+static void kvm_destroy_dirty_bitmap(struct kvm_memory_slot *memslot)
+{
+	vfree(memslot->dirty_bitmap);
+	memslot->dirty_bitmap = NULL;
+}
+
 /*
  * Free any memory in @free but not in @dont.
  */
@@ -443,7 +449,7 @@ static void kvm_free_physmem_slot(struct kvm_memory_slot *free,
 		vfree(free->rmap);
 
 	if (!dont || free->dirty_bitmap != dont->dirty_bitmap)
-		vfree(free->dirty_bitmap);
+		kvm_destroy_dirty_bitmap(free);
 
 
 	for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
@@ -454,7 +460,6 @@ static void kvm_free_physmem_slot(struct kvm_memory_slot *free,
 	}
 
 	free->npages = 0;
-	free->dirty_bitmap = NULL;
 	free->rmap = NULL;
 }
 
@@ -516,6 +521,18 @@ static int kvm_vm_release(struct inode *inode, struct file *filp)
 	return 0;
 }
 
+static int kvm_create_dirty_bitmap(struct kvm_memory_slot *memslot)
+{
+	unsigned long dirty_bytes = kvm_dirty_bitmap_bytes(memslot);
+
+	memslot->dirty_bitmap = vmalloc(dirty_bytes);
+	if (!memslot->dirty_bitmap)
+		return -ENOMEM;
+
+	memset(memslot->dirty_bitmap, 0, dirty_bytes);
+	return 0;
+}
+
 /*
  * Allocate some memory and give it an address in the guest physical address
  * space.
@@ -649,12 +666,8 @@ skip_lpage:
 
 	/* Allocate page dirty bitmap if needed */
 	if ((new.flags & KVM_MEM_LOG_DIRTY_PAGES) && !new.dirty_bitmap) {
-		unsigned long dirty_bytes = kvm_dirty_bitmap_bytes(&new);
-
-		new.dirty_bitmap = vmalloc(dirty_bytes);
-		if (!new.dirty_bitmap)
+		if (kvm_create_dirty_bitmap(&new) < 0)
 			goto out_free;
-		memset(new.dirty_bitmap, 0, dirty_bytes);
 		/* destroy any largepage mappings for dirty tracking */
 		if (old.npages)
 			flush_shadow = 1;
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 141+ messages in thread
* [PATCH RFC v2 4/6] KVM: change mark_page_dirty() to handle endian
  2010-04-20 10:53 ` Takuya Yoshikawa
  (?)
@ 2010-04-20 10:57 ` Takuya Yoshikawa
  -1 siblings, 0 replies; 141+ messages in thread
From: Takuya Yoshikawa @ 2010-04-20 10:57 UTC (permalink / raw)
  To: kvm-ia64

We are now using generic___set_le_bit() to make dirty bitmaps le.
Though this works well, we have to replace __set_bit() to appropriate
uaccess function to move dirty bitmaps to user space. So this patch
splits generic___set_le_bit() and prepares for that.

Signed-off-by: Takuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp>
Signed-off-by: Fernando Luis Vazquez Cao <fernando@oss.ntt.co.jp>
---
 virt/kvm/kvm_main.c |   16 +++++++++++-----
 1 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 6908304..66c4daf 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1194,6 +1194,15 @@ int kvm_clear_guest(struct kvm *kvm, gpa_t gpa, unsigned long len)
 }
 EXPORT_SYMBOL_GPL(kvm_clear_guest);
 
+static int __mark_page_dirty(unsigned long nr,
+			     unsigned long *dirty_bitmap)
+{
+#ifdef __BIG_ENDIAN
+	nr = nr ^ BITOP_LE_SWIZZLE;
+#endif
+	__set_bit(nr, dirty_bitmap);
+}
+
 void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
 {
 	struct kvm_memory_slot *memslot;
@@ -1203,11 +1212,8 @@ void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
 	if (memslot && memslot->dirty_bitmap) {
 		unsigned long rel_gfn = gfn - memslot->base_gfn;
 
-		/* avoid RMW */
-		if (!generic_test_le_bit(rel_gfn, memslot->dirty_bitmap)) {
-			generic___set_le_bit(rel_gfn, memslot->dirty_bitmap);
-			memslot->is_dirty = true;
-		}
+		__mark_page_dirty(rel_gfn, memslot->dirty_bitmap);
+		memslot->is_dirty = true;
 	}
 }
 
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 141+ messages in thread
* [PATCH RFC v2 1/6] KVM: introduce slot level dirty state management
  2010-04-20 10:53 ` Takuya Yoshikawa
  (?)
@ 2010-04-20 10:56 ` Takuya Yoshikawa
  -1 siblings, 0 replies; 141+ messages in thread
From: Takuya Yoshikawa @ 2010-04-20 10:56 UTC (permalink / raw)
  To: kvm-ia64

This patch introduces is_dirty member for each memory slot.
Using this member, we remove the dirty bitmap scan which is
done in the get_dirty_log function.

This also helps us when we move the dirty bitmaps to user space:
we don't have any good way to check the bitmaps in user space with
low cost, so scanning bitmaps for checking memory slot dirtiness
will not be acceptable.

When we mark the slot dirty:
 - x86 and ppc: at the timing of mark_page_dirty()
 - ia64: at the timing of kvm_ia64_sync_dirty_log()
ia64 uses a different place to store the dirty bitmap and synchronize
it right before the get_dirty_log(). So we use this timing to update
the dirtiness of a memory slot.

Signed-off-by: Takuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp>
Signed-off-by: Fernando Luis Vazquez Cao <fernando@oss.ntt.co.jp>
---
 arch/ia64/kvm/kvm-ia64.c  |   11 +++++++----
 arch/powerpc/kvm/book3s.c |    9 ++++-----
 arch/x86/kvm/x86.c        |    9 +++------
 include/linux/kvm_host.h  |    4 ++--
 virt/kvm/kvm_main.c       |   16 +++++-----------
 5 files changed, 21 insertions(+), 28 deletions(-)

diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index d7bac1f..d60dafe 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -1824,6 +1824,9 @@ static int kvm_ia64_sync_dirty_log(struct kvm *kvm,
 	base = memslot->base_gfn / BITS_PER_LONG;
 
 	for (i = 0; i < n/sizeof(long); ++i) {
+		if (dirty_bitmap[base + i])
+			memslot->is_dirty = true;
+
 		memslot->dirty_bitmap[i] = dirty_bitmap[base + i];
 		dirty_bitmap[base + i] = 0;
 	}
@@ -1838,7 +1841,6 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
 	int r;
 	unsigned long n;
 	struct kvm_memory_slot *memslot;
-	int is_dirty = 0;
 
 	mutex_lock(&kvm->slots_lock);
 	spin_lock(&kvm->arch.dirty_log_lock);
@@ -1847,16 +1849,17 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
 	if (r)
 		goto out;
 
-	r = kvm_get_dirty_log(kvm, log, &is_dirty);
+	r = kvm_get_dirty_log(kvm, log);
 	if (r)
 		goto out;
 
+	memslot = &kvm->memslots->memslots[log->slot];
 	/* If nothing is dirty, don't bother messing with page tables. */
-	if (is_dirty) {
+	if (memslot->is_dirty) {
 		kvm_flush_remote_tlbs(kvm);
-		memslot = &kvm->memslots->memslots[log->slot];
 		n = kvm_dirty_bitmap_bytes(memslot);
 		memset(memslot->dirty_bitmap, 0, n);
+		memslot->is_dirty = false;
 	}
 	r = 0;
 out:
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index 41c23b6..53b45cf 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -1118,20 +1118,18 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
 	struct kvm_memory_slot *memslot;
 	struct kvm_vcpu *vcpu;
 	ulong ga, ga_end;
-	int is_dirty = 0;
 	int r;
 	unsigned long n;
 
 	mutex_lock(&kvm->slots_lock);
 
-	r = kvm_get_dirty_log(kvm, log, &is_dirty);
+	r = kvm_get_dirty_log(kvm, log);
 	if (r)
 		goto out;
 
+	memslot = &kvm->memslots->memslots[log->slot];
 	/* If nothing is dirty, don't bother messing with page tables. */
-	if (is_dirty) {
-		memslot = &kvm->memslots->memslots[log->slot];
-
+	if (memslot->is_dirty) {
 		ga = memslot->base_gfn << PAGE_SHIFT;
 		ga_end = ga + (memslot->npages << PAGE_SHIFT);
 
@@ -1140,6 +1138,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
 
 		n = kvm_dirty_bitmap_bytes(memslot);
 		memset(memslot->dirty_bitmap, 0, n);
+		memslot->is_dirty = false;
 	}
 
 	r = 0;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 58a96e6..76b23ed 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2724,10 +2724,9 @@ static int kvm_vm_ioctl_reinject(struct kvm *kvm,
 int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
 				      struct kvm_dirty_log *log)
 {
-	int r, i;
+	int r;
 	struct kvm_memory_slot *memslot;
 	unsigned long n;
-	unsigned long is_dirty = 0;
 	unsigned long *dirty_bitmap = NULL;
 
 	mutex_lock(&kvm->slots_lock);
@@ -2749,11 +2748,8 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
 		goto out;
 	memset(dirty_bitmap, 0, n);
 
-	for (i = 0; !is_dirty && i < n/sizeof(long); i++)
-		is_dirty = memslot->dirty_bitmap[i];
-
 	/* If nothing is dirty, don't bother messing with page tables. */
-	if (is_dirty) {
+	if (memslot->is_dirty) {
 		struct kvm_memslots *slots, *old_slots;
 
 		spin_lock(&kvm->mmu_lock);
@@ -2766,6 +2762,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
 
 		memcpy(slots, kvm->memslots, sizeof(struct kvm_memslots));
 		slots->memslots[log->slot].dirty_bitmap = dirty_bitmap;
+		slots->memslots[log->slot].is_dirty = false;
 
 		old_slots = kvm->memslots;
 		rcu_assign_pointer(kvm->memslots, slots);
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 5583063..4446622 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -117,6 +117,7 @@ struct kvm_memory_slot {
 	unsigned long flags;
 	unsigned long *rmap;
 	unsigned long *dirty_bitmap;
+	bool is_dirty;
 	struct {
 		unsigned long rmap_pde;
 		int write_count;
@@ -329,8 +330,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 
 int kvm_dev_ioctl_check_extension(long ext);
 
-int kvm_get_dirty_log(struct kvm *kvm,
-			struct kvm_dirty_log *log, int *is_dirty);
+int kvm_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log);
 int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
 				struct kvm_dirty_log *log);
 
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 3725605..cc78e07 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -764,13 +764,11 @@ int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
 	return kvm_set_memory_region(kvm, mem, user_alloc);
 }
 
-int kvm_get_dirty_log(struct kvm *kvm,
-			struct kvm_dirty_log *log, int *is_dirty)
+int kvm_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
 {
 	struct kvm_memory_slot *memslot;
-	int r, i;
+	int r;
 	unsigned long n;
-	unsigned long any = 0;
 
 	r = -EINVAL;
 	if (log->slot >= KVM_MEMORY_SLOTS)
@@ -783,16 +781,10 @@ int kvm_get_dirty_log(struct kvm *kvm,
 
 	n = kvm_dirty_bitmap_bytes(memslot);
 
-	for (i = 0; !any && i < n/sizeof(long); ++i)
-		any = memslot->dirty_bitmap[i];
-
 	r = -EFAULT;
 	if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n))
 		goto out;
 
-	if (any)
-		*is_dirty = 1;
-
 	r = 0;
 out:
 	return r;
@@ -1189,8 +1181,10 @@ void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
 		unsigned long rel_gfn = gfn - memslot->base_gfn;
 
 		/* avoid RMW */
-		if (!generic_test_le_bit(rel_gfn, memslot->dirty_bitmap))
+		if (!generic_test_le_bit(rel_gfn, memslot->dirty_bitmap)) {
 			generic___set_le_bit(rel_gfn, memslot->dirty_bitmap);
+			memslot->is_dirty = true;
+		}
 	}
 }
 
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 141+ messages in thread
* [PATCH RFC v2 0/6] KVM: moving dirty gitmaps to user space!
@ 2010-04-20 10:53 ` Takuya Yoshikawa
  0 siblings, 0 replies; 141+ messages in thread
From: Takuya Yoshikawa @ 2010-04-20 10:53 UTC (permalink / raw)
  To: kvm-ia64

Hi, this is the v2 of the "moving dirty gitmaps to user space!"

By this patch, I think everything we need becomes clear.
So we want to step forward to be ready for the final version in the
near future: of course, this is dependent on x86 and ppc asm issues.

BTW, by whom I can get ACK for ppc and ia64? I want to add to the Cc
list if possible, thank you.


Patch1: introduce slot level dirty state management
  This patch is independent from other patches and seems to be
  useful without the following parts.

Patch2: introduce wrapper functions to create and destroy dirty bitmaps
  Cleanup patch.

Patch3: introduce a wrapper function to copy dirty bitmaps to user space
  This is for dealing copy_in_user() things cleanly.

Patch4: change mark_page_dirty() to handle endian issues explicitly
  Later, __set_bit() part will be replaced with *_user function.

Patch5: moving dirty bitmaps to user space
  Replace dirty bitmap manipulations with *_user functions.

Patch6: introduce a new API for getting dirty bitmaps
  This is to access dirty bitmaps from user space.


Changelog:
 - suport for all architectures
   We have achived this without pinning.
 - one possible API suggestion
 - temporary copy_in_user like function
 - temporary set_bit_user like function with __get_user() and __put_user()
   We can use this as a generic set_bit_user_non_atomic().
   Of course, we need to optimize this part with arch specific one: we are
   testing some versions for x86 now.

What we are thinking about:
 - about set_bit_user_non_atomic()
   We noticed that ia64 won't need this: see patch1 and patch5.
   So all we have to do is to complete the implementations for x86 and ppc.
   ** x86 and ppc don't include asm-generic uaccess. So we have to put these
      into them separately.

 - about the new api
   There are many possible styles to make use of this work.
   E.g. if we export the both addresses of the two bitmaps,
   we don't need to export them at the switch timing: but we cannot
   reuse the current structures in this case. Which is better?


=
Appendix:

To test the patch 6, we are using the following patch for qemu-kvm.
---
 configure  |    2 +-
 qemu-kvm.c |   22 +++++++++++++++++-----
 2 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/configure b/configure
index be8dac4..0b2d017 100755
--- a/configure
+++ b/configure
@@ -1498,7 +1498,7 @@ fi
 if test "$kvm" != "no" ; then
     cat > $TMPC <<EOF
 #include <linux/kvm.h>
-#if !defined(KVM_API_VERSION) || KVM_API_VERSION < 12 || KVM_API_VERSION > 12
+#if !defined(KVM_API_VERSION) || KVM_API_VERSION < 13 || KVM_API_VERSION > 13
 #error Invalid KVM version
 #endif
 #if !defined(KVM_CAP_USER_MEMORY)
diff --git a/qemu-kvm.c b/qemu-kvm.c
index cc5b352..087adea 100644
--- a/qemu-kvm.c
+++ b/qemu-kvm.c
@@ -44,7 +44,7 @@
 #define BUS_MCEERR_AO 5
 #endif
 
-#define EXPECTED_KVM_API_VERSION 12
+#define EXPECTED_KVM_API_VERSION 13
 
 #if EXPECTED_KVM_API_VERSION != KVM_API_VERSION
 #error libkvm: userspace and kernel version mismatch
@@ -684,6 +684,21 @@ static int kvm_get_map(kvm_context_t kvm, int ioctl_num, int slot, void *buf)
     return 0;
 }
 
+static int kvm_switch_map(kvm_context_t kvm, int slot, void **buf)
+{
+    int r;
+    struct kvm_dirty_log log = {
+        .slot = slot,
+    };
+
+    r = kvm_vm_ioctl(kvm_state, KVM_SWITCH_DIRTY_LOG, &log);
+    if (r < 0)
+        return r;
+
+    *buf = (void *)log.addr;
+    return 0;
+}
+
 int kvm_get_dirty_pages(kvm_context_t kvm, unsigned long phys_addr, void *buf)
 {
     int slot;
@@ -706,14 +721,11 @@ int kvm_get_dirty_pages_range(kvm_context_t kvm, unsigned long phys_addr,
     for (i = 0; i < KVM_MAX_NUM_MEM_REGIONS; ++i) {
         if ((slots[i].len && (uint64_t) slots[i].phys_addr >= phys_addr)
             && ((uint64_t) slots[i].phys_addr + slots[i].len <= end_addr)) {
-            buf = qemu_malloc(BITMAP_SIZE(slots[i].len));
-            r = kvm_get_map(kvm, KVM_GET_DIRTY_LOG, i, buf);
+            r = kvm_switch_map(kvm, i, &buf);
             if (r) {
-                qemu_free(buf);
                 return r;
             }
             r = cb(slots[i].phys_addr, slots[i].len, buf, opaque);
-            qemu_free(buf);
             if (r)
                 return r;
         }
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 141+ messages in thread

end of thread, other threads:[~2010-04-23 13:20 UTC | newest]

Thread overview: 141+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-04-20 10:59 [PATCH RFC v2 3/6] KVM: introduce a wrapper function to copy dirty Takuya Yoshikawa
2010-04-20 10:59 ` [PATCH RFC v2 3/6] KVM: introduce a wrapper function to copy dirty bitmaps to user space Takuya Yoshikawa
2010-04-20 10:59 ` [PATCH RFC v2 3/6] KVM: introduce a wrapper function to copy dirty Takuya Yoshikawa
2010-04-21 11:12 ` [PATCH RFC v2 3/6] KVM: introduce a wrapper function to copy Avi Kivity
2010-04-21 11:12   ` [PATCH RFC v2 3/6] KVM: introduce a wrapper function to copy dirty bitmaps to user space Avi Kivity
2010-04-21 11:12   ` [PATCH RFC v2 3/6] KVM: introduce a wrapper function to copy Avi Kivity
2010-04-22  8:57 ` Takuya Yoshikawa
2010-04-22  8:57   ` [PATCH RFC v2 3/6] KVM: introduce a wrapper function to copy dirty bitmaps to user space Takuya Yoshikawa
2010-04-22  8:57   ` [PATCH RFC v2 3/6] KVM: introduce a wrapper function to copy Takuya Yoshikawa
2010-04-23 10:26 ` Avi Kivity
2010-04-23 10:26   ` [PATCH RFC v2 3/6] KVM: introduce a wrapper function to copy dirty bitmaps to user space Avi Kivity
2010-04-23 10:26   ` [PATCH RFC v2 3/6] KVM: introduce a wrapper function to copy Avi Kivity
  -- strict thread matches above, loose matches on Subject: below --
2010-04-20 11:03 [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty Takuya Yoshikawa
2010-04-20 11:03 ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty bitmaps Takuya Yoshikawa
2010-04-20 11:03 ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty Takuya Yoshikawa
2010-04-20 11:15 ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty bitmaps Alexander Graf
2010-04-20 11:15   ` Alexander Graf
2010-04-20 11:15   ` Alexander Graf
2010-04-20 11:33 ` Alexander Graf
2010-04-20 11:33   ` Alexander Graf
2010-04-20 11:33   ` Alexander Graf
2010-04-20 11:33 ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty Takuya Yoshikawa
2010-04-20 11:33   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty bitmaps Takuya Yoshikawa
2010-04-20 11:33   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty Takuya Yoshikawa
2010-04-20 11:44 ` Takuya Yoshikawa
2010-04-20 11:44   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty bitmaps Takuya Yoshikawa
2010-04-20 11:44   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty Takuya Yoshikawa
2010-04-21  8:29 ` 
2010-04-21  8:29   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty bitmaps Fernando Luis Vázquez Cao
2010-04-21  8:29   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty 
2010-04-21  9:41 ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty bitmaps Alexander Graf
2010-04-21  9:41   ` Alexander Graf
2010-04-21  9:41   ` Alexander Graf
2010-04-21 11:46 ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty Avi Kivity
2010-04-21 11:46   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty bitmaps Avi Kivity
2010-04-21 11:46   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty Avi Kivity
2010-04-22  2:45 ` 
2010-04-22  2:45   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty bitmaps Fernando Luis Vázquez Cao
2010-04-22  2:45   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty 
2010-04-22  6:09 ` 
2010-04-22  6:09   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty bitmaps Fernando Luis Vázquez Cao
2010-04-22  6:09   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty 
2010-04-22  9:34 ` Takuya Yoshikawa
2010-04-22  9:34   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty bitmaps Takuya Yoshikawa
2010-04-22  9:34   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty Takuya Yoshikawa
2010-04-22 23:29 ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty bitmaps Alexander Graf
2010-04-22 23:29   ` Alexander Graf
2010-04-22 23:29   ` Alexander Graf
2010-04-23 10:17 ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty 
2010-04-23 10:17   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty bitmaps Fernando Luis Vázquez Cao
2010-04-23 10:17   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty 
2010-04-23 10:20 ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty bitmaps Alexander Graf
2010-04-23 10:20   ` Alexander Graf
2010-04-23 10:20   ` Alexander Graf
2010-04-23 11:57 ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty Avi Kivity
2010-04-23 11:57   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty bitmaps Avi Kivity
2010-04-23 11:57   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty Avi Kivity
2010-04-23 11:58 ` Avi Kivity
2010-04-23 11:58   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty bitmaps Avi Kivity
2010-04-23 11:58   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty Avi Kivity
2010-04-23 12:26 ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty bitmaps Alexander Graf
2010-04-23 12:26   ` Alexander Graf
2010-04-23 12:26   ` Alexander Graf
2010-04-23 12:27 ` Arnd Bergmann
2010-04-23 12:27   ` Arnd Bergmann
2010-04-23 12:27   ` Arnd Bergmann
2010-04-23 12:42 ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty Avi Kivity
2010-04-23 12:42   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty bitmaps Avi Kivity
2010-04-23 12:42   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty Avi Kivity
2010-04-23 12:46 ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty bitmaps Arnd Bergmann
2010-04-23 12:46   ` Arnd Bergmann
2010-04-23 12:46   ` Arnd Bergmann
2010-04-23 12:53 ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty Avi Kivity
2010-04-23 12:53   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty bitmaps Avi Kivity
2010-04-23 12:53   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty Avi Kivity
2010-04-23 12:59 ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty bitmaps Alexander Graf
2010-04-23 12:59   ` Alexander Graf
2010-04-23 12:59   ` Alexander Graf
2010-04-23 13:12 ` Arnd Bergmann
2010-04-23 13:12   ` Arnd Bergmann
2010-04-23 13:12   ` Arnd Bergmann
2010-04-23 13:20 ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty Avi Kivity
2010-04-23 13:20   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty bitmaps Avi Kivity
2010-04-23 13:20   ` [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty Avi Kivity
2010-04-20 10:58 [PATCH RFC v2 5/6] KVM: moving dirty bitmaps to user space Takuya Yoshikawa
2010-04-20 11:02 ` Takuya Yoshikawa
2010-04-20 10:58 ` Takuya Yoshikawa
2010-04-20 11:10 ` Alexander Graf
2010-04-20 11:10   ` Alexander Graf
2010-04-20 11:10   ` Alexander Graf
2010-04-20 11:26 ` Takuya Yoshikawa
2010-04-20 11:26   ` Takuya Yoshikawa
2010-04-20 11:26   ` Takuya Yoshikawa
2010-04-21 11:26 ` Avi Kivity
2010-04-21 11:26   ` Avi Kivity
2010-04-21 11:26   ` Avi Kivity
2010-04-22  9:07 ` Takuya Yoshikawa
2010-04-22  9:07   ` Takuya Yoshikawa
2010-04-22  9:07   ` Takuya Yoshikawa
2010-04-23 10:28 ` Avi Kivity
2010-04-23 10:28   ` Avi Kivity
2010-04-23 10:28   ` Avi Kivity
2010-04-23 11:14 ` Takuya Yoshikawa
2010-04-23 11:14   ` Takuya Yoshikawa
2010-04-23 11:14   ` Takuya Yoshikawa
2010-04-23 11:29 ` Yoshiaki Tamura
2010-04-23 11:29   ` Yoshiaki Tamura
2010-04-23 11:29   ` Yoshiaki Tamura
2010-04-23 11:45 ` Avi Kivity
2010-04-23 11:45   ` Avi Kivity
2010-04-23 11:45   ` Avi Kivity
2010-04-20 10:57 [PATCH RFC v2 2/6] KVM: introduce wrapper functions to create and Takuya Yoshikawa
2010-04-20 10:57 ` [PATCH RFC v2 2/6] KVM: introduce wrapper functions to create and destroy dirty bitmaps Takuya Yoshikawa
2010-04-20 10:57 ` [PATCH RFC v2 2/6] KVM: introduce wrapper functions to create and Takuya Yoshikawa
2010-04-20 10:57 [PATCH RFC v2 4/6] KVM: change mark_page_dirty() to handle endian Takuya Yoshikawa
2010-04-20 11:00 ` [PATCH RFC v2 4/6] KVM: change mark_page_dirty() to handle endian issues explicitly Takuya Yoshikawa
2010-04-20 10:57 ` [PATCH RFC v2 4/6] KVM: change mark_page_dirty() to handle endian Takuya Yoshikawa
2010-04-20 11:00 ` [PATCH RFC v2 4/6] KVM: change mark_page_dirty() to handle endian issues explicitly Alexander Graf
2010-04-20 11:00   ` Alexander Graf
2010-04-20 11:00   ` Alexander Graf
2010-04-20 11:20 ` [PATCH RFC v2 4/6] KVM: change mark_page_dirty() to handle endian Takuya Yoshikawa
2010-04-20 11:20   ` [PATCH RFC v2 4/6] KVM: change mark_page_dirty() to handle endian issues explicitly Takuya Yoshikawa
2010-04-20 11:20   ` [PATCH RFC v2 4/6] KVM: change mark_page_dirty() to handle endian Takuya Yoshikawa
2010-04-21 11:15 ` Avi Kivity
2010-04-21 11:15   ` [PATCH RFC v2 4/6] KVM: change mark_page_dirty() to handle endian issues explicitly Avi Kivity
2010-04-21 11:15   ` [PATCH RFC v2 4/6] KVM: change mark_page_dirty() to handle endian Avi Kivity
2010-04-20 10:56 [PATCH RFC v2 1/6] KVM: introduce slot level dirty state management Takuya Yoshikawa
2010-04-20 10:56 ` Takuya Yoshikawa
2010-04-20 10:56 ` Takuya Yoshikawa
2010-04-20 10:53 [PATCH RFC v2 0/6] KVM: moving dirty gitmaps to user space! Takuya Yoshikawa
2010-04-20 10:53 ` Takuya Yoshikawa
2010-04-20 10:53 ` Takuya Yoshikawa
2010-04-20 10:54 ` Alexander Graf
2010-04-20 10:54   ` Alexander Graf
2010-04-20 10:54   ` Alexander Graf
2010-04-20 11:13 ` Takuya Yoshikawa
2010-04-20 11:13   ` Takuya Yoshikawa
2010-04-20 11:13   ` Takuya Yoshikawa
2010-04-20 12:05 ` Takuya Yoshikawa
2010-04-20 12:05   ` Takuya Yoshikawa
2010-04-20 12:05   ` Takuya Yoshikawa

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.