Re: [PATCH 4/5] KVM: PPC: Book3s HV: Implement get_dirty_log using hardware changed bit
From: Alexander Graf <hidden>
Date: 2011-12-23 13:23:35
Also in:
kvm
On 15.12.2011, at 13:03, Paul Mackerras wrote:
This changes the implementation of kvm_vm_ioctl_get_dirty_log() for Book3s HV guests to use the hardware C (changed) bits in the guest hashed page table. Since this makes the implementation quite =
different
from the Book3s PR case, this moves the existing implementation from book3s.c to book3s_pr.c and creates a new implementation in =
book3s_hv.c.
That implementation calls kvmppc_hv_get_dirty_log() to do the actual work by calling kvm_test_clear_dirty on each page. It iterates over the HPTEs, clearing the C bit if set, and returns 1 if any C bit was set (including the saved C bit in the rmap entry). =20 Signed-off-by: Paul Mackerras <redacted> --- arch/powerpc/include/asm/kvm_book3s.h | 2 + arch/powerpc/kvm/book3s.c | 39 ------------------ arch/powerpc/kvm/book3s_64_mmu_hv.c | 69 =
+++++++++++++++++++++++++++++++++
quoted hunk ↗ jump to hunk
arch/powerpc/kvm/book3s_hv.c | 37 +++++++++++++++++ arch/powerpc/kvm/book3s_pr.c | 39 ++++++++++++++++++ 5 files changed, 147 insertions(+), 39 deletions(-) =20diff --git a/arch/powerpc/include/asm/kvm_book3s.h =
b/arch/powerpc/include/asm/kvm_book3s.h
quoted hunk ↗ jump to hunk
index 6ececb4..aa795cc 100644--- a/arch/powerpc/include/asm/kvm_book3s.h +++ b/arch/powerpc/include/asm/kvm_book3s.h@@ -158,6 +158,8 @@ extern long kvmppc_virtmode_h_enter(struct =
kvm_vcpu *vcpu, unsigned long flags,
long pte_index, unsigned long pteh, unsigned =
long ptel);
extern long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags, long pte_index, unsigned long pteh, unsigned =
long ptel);
quoted hunk ↗ jump to hunk
+extern long kvmppc_hv_get_dirty_log(struct kvm *kvm, + struct kvm_memory_slot *memslot); =20 extern void kvmppc_entry_trampoline(void); extern void kvmppc_hv_entry_trampoline(void);diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index 6bf7e05..7d54f4e 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c@@ -477,45 +477,6 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu =
*vcpu,
return 0;
}
=20
-/*
- * 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)
-{
- struct kvm_memory_slot *memslot;
- struct kvm_vcpu *vcpu;
- ulong ga, ga_end;
- int is_dirty =3D 0;
- int r;
- unsigned long n;
-
- mutex_lock(&kvm->slots_lock);
-
- r =3D kvm_get_dirty_log(kvm, log, &is_dirty);
- if (r)
- goto out;
-
- /* If nothing is dirty, don't bother messing with page tables. =*/
quoted hunk ↗ jump to hunk
- if (is_dirty) { - memslot =3D id_to_memslot(kvm->memslots, log->slot); - - ga =3D memslot->base_gfn << PAGE_SHIFT; - ga_end =3D ga + (memslot->npages << PAGE_SHIFT); - - kvm_for_each_vcpu(n, vcpu, kvm) - kvmppc_mmu_pte_pflush(vcpu, ga, ga_end); - - n =3D kvm_dirty_bitmap_bytes(memslot); - memset(memslot->dirty_bitmap, 0, n); - } - - r =3D 0; -out: - mutex_unlock(&kvm->slots_lock); - return r; -} - void kvmppc_decrementer_func(unsigned long data) { struct kvm_vcpu *vcpu =3D (struct kvm_vcpu *)data;diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c =
b/arch/powerpc/kvm/book3s_64_mmu_hv.c
quoted hunk ↗ jump to hunk
index 926e2b9..783cd35 100644--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c@@ -870,6 +870,75 @@ void kvm_set_spte_hva(struct kvm *kvm, unsigned =
long hva, pte_t pte)
kvm_handle_hva(kvm, hva, kvm_unmap_rmapp); } =20 +static int kvm_test_clear_dirty(struct kvm *kvm, unsigned long =
*rmapp)
+{
+ struct revmap_entry *rev =3D kvm->arch.revmap;
+ unsigned long head, i, j;
+ unsigned long *hptep;
+ int ret =3D 0;
+
+ retry:
+ lock_rmap(rmapp);
+ if (*rmapp & KVMPPC_RMAP_CHANGED) {
+ *rmapp &=3D ~KVMPPC_RMAP_CHANGED;
+ ret =3D 1;
+ }
+ if (!(*rmapp & KVMPPC_RMAP_PRESENT)) {
+ unlock_rmap(rmapp);
+ return ret;
+ }
+
+ i =3D head =3D *rmapp & KVMPPC_RMAP_INDEX;
+ do {
+ hptep =3D (unsigned long *) (kvm->arch.hpt_virt + (i << =4));
+ j =3D rev[i].forw;
+
+ if (!(hptep[1] & HPTE_R_C))
+ continue;
+
+ if (!try_lock_hpte(hptep, HPTE_V_HVLOCK)) {
+ /* unlock rmap before spinning on the HPTE lock =*/
+ unlock_rmap(rmapp); + while (hptep[0] & HPTE_V_HVLOCK) + cpu_relax(); + goto retry; + } + + /* Now check and modify the HPTE */ + if ((hptep[0] & HPTE_V_VALID) && (hptep[1] & HPTE_R_C)) =
{+ /* need to make it temporarily absent to clear C =
*/
+ hptep[0] |=3D HPTE_V_ABSENT; + kvmppc_invalidate_hpte(kvm, hptep, i); + hptep[1] &=3D ~HPTE_R_C; + eieio(); + hptep[0] =3D (hptep[0] & ~HPTE_V_ABSENT) | =
HPTE_V_VALID;
+ rev[i].guest_rpte |=3D HPTE_R_C; + ret =3D 1; + } + hptep[0] &=3D ~HPTE_V_HVLOCK; + } while ((i =3D j) !=3D head); + + unlock_rmap(rmapp); + return ret; +} + +long kvmppc_hv_get_dirty_log(struct kvm *kvm, struct kvm_memory_slot =
*memslot)
+{
+ unsigned long i;
+ unsigned long *rmapp, *map;
+
+ preempt_disable();
+ rmapp =3D memslot->rmap;
+ map =3D memslot->dirty_bitmap;
+ for (i =3D 0; i < memslot->npages; ++i) {
+ if (kvm_test_clear_dirty(kvm, rmapp))
+ __set_bit_le(i, map);So if I read things correctly, this is the only case you're setting = pages as dirty. What if you have the following: guest adds HTAB entry x guest writes to page mapped by x guest removes HTAB entry x host fetches dirty log You can replace "removes" by "is overwritten by another mapping" if you = like. Alex PS: Always CC kvm@vger for stuff that other might want to review = (basically all patches)