diff options
-rw-r--r-- | arch/powerpc/kvm/book3s_64_mmu_hv.c | 33 |
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 | ||
1063 | static 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 | */ | ||
1067 | static 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 | ||
1118 | static void harvest_vpa_dirty(struct kvmppc_vpa *vpa, | 1126 | static void harvest_vpa_dirty(struct kvmppc_vpa *vpa, |
@@ -1136,15 +1144,22 @@ static void harvest_vpa_dirty(struct kvmppc_vpa *vpa, | |||
1136 | long kvmppc_hv_get_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot, | 1144 | long 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 | ||