From patchwork Tue Apr 20 11:03:53 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takuya Yoshikawa X-Patchwork-Id: 93653 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o3KB0G13008726 for ; Tue, 20 Apr 2010 11:00:16 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754433Ab0DTLAO (ORCPT ); Tue, 20 Apr 2010 07:00:14 -0400 Received: from serv2.oss.ntt.co.jp ([222.151.198.100]:47128 "EHLO serv2.oss.ntt.co.jp" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754190Ab0DTLAN (ORCPT ); Tue, 20 Apr 2010 07:00:13 -0400 Received: from serv2.oss.ntt.co.jp (localhost [127.0.0.1]) by serv2.oss.ntt.co.jp (Postfix) with ESMTP id 1C2E42481F2; Tue, 20 Apr 2010 20:00:11 +0900 (JST) Received: from serv1.oss.ntt.co.jp (serv1.oss.ntt.co.jp [172.19.0.2]) by serv2.oss.ntt.co.jp (Postfix) with ESMTP id 093502481B1; Tue, 20 Apr 2010 20:00:11 +0900 (JST) Received: from yshtky3.kern.oss.ntt.co.jp (unknown [172.17.1.144]) by serv1.oss.ntt.co.jp (Postfix) with SMTP id D6E2411C11D; Tue, 20 Apr 2010 20:00:10 +0900 (JST) Date: Tue, 20 Apr 2010 20:03:53 +0900 From: Takuya Yoshikawa To: avi@redhat.com, mtosatti@redhat.com Cc: kvm@vger.kernel.org, kvm-ia64@vger.kernel.org, kvm-ppc@vger.kernel.org, fernando@oss.ntt.co.jp Subject: [PATCH RFC v2 6/6] KVM: introduce a new API for getting dirty bitmaps Message-Id: <20100420200353.2d2a6dec.yoshikawa.takuya@oss.ntt.co.jp> In-Reply-To: <20100420195349.dab60b1d.yoshikawa.takuya@oss.ntt.co.jp> References: <20100420195349.dab60b1d.yoshikawa.takuya@oss.ntt.co.jp> X-Mailer: Sylpheed 2.6.0 (GTK+ 2.16.1; i486-pc-linux-gnu) Mime-Version: 1.0 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Tue, 20 Apr 2010 11:00:16 +0000 (UTC) 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 #include -#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: