aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/kvm/book3s_64_mmu_hv.c33
1 files changed, 24 insertions, 9 deletions
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index 4e22ecbcf93f..96c90447d4bf 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -1060,22 +1060,27 @@ void kvm_set_spte_hva_hv(struct kvm *kvm, unsigned long hva, pte_t pte)
1060 kvm_handle_hva(kvm, hva, kvm_unmap_rmapp); 1060 kvm_handle_hva(kvm, hva, kvm_unmap_rmapp);
1061} 1061}
1062 1062
1063static int kvm_test_clear_dirty(struct kvm *kvm, unsigned long *rmapp) 1063/*
1064 * Returns the number of system pages that are dirty.
1065 * This can be more than 1 if we find a huge-page HPTE.
1066 */
1067static int kvm_test_clear_dirty_npages(struct kvm *kvm, unsigned long *rmapp)
1064{ 1068{
1065 struct revmap_entry *rev = kvm->arch.revmap; 1069 struct revmap_entry *rev = kvm->arch.revmap;
1066 unsigned long head, i, j; 1070 unsigned long head, i, j;
1071 unsigned long n;
1067 unsigned long *hptep; 1072 unsigned long *hptep;
1068 int ret = 0; 1073 int npages_dirty = 0;
1069 1074
1070 retry: 1075 retry:
1071 lock_rmap(rmapp); 1076 lock_rmap(rmapp);
1072 if (*rmapp & KVMPPC_RMAP_CHANGED) { 1077 if (*rmapp & KVMPPC_RMAP_CHANGED) {
1073 *rmapp &= ~KVMPPC_RMAP_CHANGED; 1078 *rmapp &= ~KVMPPC_RMAP_CHANGED;
1074 ret = 1; 1079 npages_dirty = 1;
1075 } 1080 }
1076 if (!(*rmapp & KVMPPC_RMAP_PRESENT)) { 1081 if (!(*rmapp & KVMPPC_RMAP_PRESENT)) {
1077 unlock_rmap(rmapp); 1082 unlock_rmap(rmapp);
1078 return ret; 1083 return npages_dirty;
1079 } 1084 }
1080 1085
1081 i = head = *rmapp & KVMPPC_RMAP_INDEX; 1086 i = head = *rmapp & KVMPPC_RMAP_INDEX;
@@ -1106,13 +1111,16 @@ static int kvm_test_clear_dirty(struct kvm *kvm, unsigned long *rmapp)
1106 rev[i].guest_rpte |= HPTE_R_C; 1111 rev[i].guest_rpte |= HPTE_R_C;
1107 note_hpte_modification(kvm, &rev[i]); 1112 note_hpte_modification(kvm, &rev[i]);
1108 } 1113 }
1109 ret = 1; 1114 n = hpte_page_size(hptep[0], hptep[1]);
1115 n = (n + PAGE_SIZE - 1) >> PAGE_SHIFT;
1116 if (n > npages_dirty)
1117 npages_dirty = n;
1110 } 1118 }
1111 hptep[0] &= ~HPTE_V_HVLOCK; 1119 hptep[0] &= ~HPTE_V_HVLOCK;
1112 } while ((i = j) != head); 1120 } while ((i = j) != head);
1113 1121
1114 unlock_rmap(rmapp); 1122 unlock_rmap(rmapp);
1115 return ret; 1123 return npages_dirty;
1116} 1124}
1117 1125
1118static void harvest_vpa_dirty(struct kvmppc_vpa *vpa, 1126static void harvest_vpa_dirty(struct kvmppc_vpa *vpa,
@@ -1136,15 +1144,22 @@ static void harvest_vpa_dirty(struct kvmppc_vpa *vpa,
1136long kvmppc_hv_get_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot, 1144long kvmppc_hv_get_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot,
1137 unsigned long *map) 1145 unsigned long *map)
1138{ 1146{
1139 unsigned long i; 1147 unsigned long i, j;
1140 unsigned long *rmapp; 1148 unsigned long *rmapp;
1141 struct kvm_vcpu *vcpu; 1149 struct kvm_vcpu *vcpu;
1142 1150
1143 preempt_disable(); 1151 preempt_disable();
1144 rmapp = memslot->arch.rmap; 1152 rmapp = memslot->arch.rmap;
1145 for (i = 0; i < memslot->npages; ++i) { 1153 for (i = 0; i < memslot->npages; ++i) {
1146 if (kvm_test_clear_dirty(kvm, rmapp) && map) 1154 int npages = kvm_test_clear_dirty_npages(kvm, rmapp);
1147 __set_bit_le(i, map); 1155 /*
1156 * Note that if npages > 0 then i must be a multiple of npages,
1157 * since we always put huge-page HPTEs in the rmap chain
1158 * corresponding to their page base address.
1159 */
1160 if (npages && map)
1161 for (j = i; npages; ++j, --npages)
1162 __set_bit_le(j, map);
1148 ++rmapp; 1163 ++rmapp;
1149 } 1164 }
1150 1165