On 2018年02月21日 05:29, Paolo Bonzini wrote: > On 17/02/2018 19:01, 丁卓成 wrote: >> In `set_spte`, where we prepare a new spte entry, we have this: >>> if (pte_access & ACC_WRITE_MASK) { >>> kvm_vcpu_mark_page_dirty(vcpu, gfn); >>> spte |= spte_shadow_dirty_mask(spte); >>> } >> And in `__direct_map`, we have this: >>> emulate = mmu_set_spte(vcpu, iterator.sptep, ACC_ALL, >>> write, level, gfn, pfn, prefault, >>> map_writable); >> If Guest issue a read to a page, and the corresponding spte is not present, >> `__direct_map` will be called to build the spte (and maybe parent sps as well) >> in EPT mode and SPT nonpaging mode. Since we pass ACC_ALL to `set_spte` in this >> case, even a read fault will cause the page to be marked dirty in dirty bitmap, >> and it will also set the D bit in spte. > > Hi, the "ACC_ALL" is fixed here in set_spte: > > if (host_writable) > spte |= SPTE_HOST_WRITEABLE; > else > pte_access &= ~ACC_WRITE_MASK; > > where host_writable is the last argument to mmu_set_spte. Ultimately, host_writable is set in try_async_pf (as the last argument), and it would be false only if: 1) Memory slot is readonly, or 2) Host page is readonly. So if the gfn is backed by writable host memory, a read fault to this gfn will still cause it to be marked dirty. -- Zhuocheng