diff options
author | Avi Kivity <avi@redhat.com> | 2012-09-16 08:03:02 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2012-09-20 06:00:09 -0400 |
commit | b514c30f7729b66af481fde3c1225e832e339d5b (patch) | |
tree | 8d0744aa7f2fd57fd31e9aed72de177b74d7900d | |
parent | 71331a1da1e3a66d14bb3864f99e32d84ab5a76f (diff) |
KVM: MMU: Avoid access/dirty update loop if all is well
Keep track of accessed/dirty bits; if they are all set, do not
enter the accessed/dirty update loop.
Reviewed-by: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r-- | arch/x86/kvm/paging_tmpl.h | 26 |
1 files changed, 20 insertions, 6 deletions
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index 95a64d1dccc..810c1da2ee4 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h | |||
@@ -151,7 +151,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, | |||
151 | pt_element_t pte; | 151 | pt_element_t pte; |
152 | pt_element_t __user *uninitialized_var(ptep_user); | 152 | pt_element_t __user *uninitialized_var(ptep_user); |
153 | gfn_t table_gfn; | 153 | gfn_t table_gfn; |
154 | unsigned index, pt_access, pte_access; | 154 | unsigned index, pt_access, pte_access, accessed_dirty, shift; |
155 | gpa_t pte_gpa; | 155 | gpa_t pte_gpa; |
156 | int offset; | 156 | int offset; |
157 | const int write_fault = access & PFERR_WRITE_MASK; | 157 | const int write_fault = access & PFERR_WRITE_MASK; |
@@ -180,6 +180,7 @@ retry_walk: | |||
180 | ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) || | 180 | ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) || |
181 | (mmu->get_cr3(vcpu) & CR3_NONPAE_RESERVED_BITS) == 0); | 181 | (mmu->get_cr3(vcpu) & CR3_NONPAE_RESERVED_BITS) == 0); |
182 | 182 | ||
183 | accessed_dirty = PT_ACCESSED_MASK; | ||
183 | pt_access = pte_access = ACC_ALL; | 184 | pt_access = pte_access = ACC_ALL; |
184 | ++walker->level; | 185 | ++walker->level; |
185 | 186 | ||
@@ -224,6 +225,7 @@ retry_walk: | |||
224 | goto error; | 225 | goto error; |
225 | } | 226 | } |
226 | 227 | ||
228 | accessed_dirty &= pte; | ||
227 | pte_access = pt_access & gpte_access(vcpu, pte); | 229 | pte_access = pt_access & gpte_access(vcpu, pte); |
228 | 230 | ||
229 | walker->ptes[walker->level - 1] = pte; | 231 | walker->ptes[walker->level - 1] = pte; |
@@ -251,11 +253,23 @@ retry_walk: | |||
251 | if (!write_fault) | 253 | if (!write_fault) |
252 | protect_clean_gpte(&pte_access, pte); | 254 | protect_clean_gpte(&pte_access, pte); |
253 | 255 | ||
254 | ret = FNAME(update_accessed_dirty_bits)(vcpu, mmu, walker, write_fault); | 256 | /* |
255 | if (unlikely(ret < 0)) | 257 | * On a write fault, fold the dirty bit into accessed_dirty by shifting it one |
256 | goto error; | 258 | * place right. |
257 | else if (ret) | 259 | * |
258 | goto retry_walk; | 260 | * On a read fault, do nothing. |
261 | */ | ||
262 | shift = write_fault >> ilog2(PFERR_WRITE_MASK); | ||
263 | shift *= PT_DIRTY_SHIFT - PT_ACCESSED_SHIFT; | ||
264 | accessed_dirty &= pte >> shift; | ||
265 | |||
266 | if (unlikely(!accessed_dirty)) { | ||
267 | ret = FNAME(update_accessed_dirty_bits)(vcpu, mmu, walker, write_fault); | ||
268 | if (unlikely(ret < 0)) | ||
269 | goto error; | ||
270 | else if (ret) | ||
271 | goto retry_walk; | ||
272 | } | ||
259 | 273 | ||
260 | walker->pt_access = pt_access; | 274 | walker->pt_access = pt_access; |
261 | walker->pte_access = pte_access; | 275 | walker->pte_access = pte_access; |