diff --git a/core/mmu.cc b/core/mmu.cc index 583a4e19ad130b1ace9b2446d8dc6be6157a2d48..572da488f14d974234436ba469473eb47e604e15 100644 --- a/core/mmu.cc +++ b/core/mmu.cc @@ -458,14 +458,20 @@ class populate : public vma_operation<allocate_intermediate_opt::yes, skip_empty private: map_page_ops* _pops; unsigned int perm; + bool _map_dirty; + pt_element dirty(pt_element pte) { + pte.set_dirty(_map_dirty); + return pte; + } public: - populate(map_page_ops* pops, unsigned int perm) : _pops(pops), perm(perm) { } + populate(map_page_ops* pops, unsigned int perm, bool map_dirty = true) : + _pops(pops), perm(perm), _map_dirty(map_dirty) { } void small_page(hw_ptep ptep, uintptr_t offset){ if (!ptep.read().empty()) { return; } phys page = virt_to_phys(_pops->alloc(offset)); - if (!ptep.compare_exchange(make_empty_pte(), make_normal_pte(page, perm))) { + if (!ptep.compare_exchange(make_empty_pte(), dirty(make_normal_pte(page, perm)))) { _pops->free(phys_to_virt(page), offset); } else { this->account(mmu::page_size); @@ -482,7 +488,7 @@ public: } phys page = virt_to_phys(vpage); - if (!ptep.compare_exchange(make_empty_pte(), make_large_pte(page, perm))) { + if (!ptep.compare_exchange(make_empty_pte(), dirty(make_large_pte(page, perm)))) { _pops->free(phys_to_virt(page), huge_page_size, offset); } else { this->account(mmu::huge_page_size); @@ -903,7 +909,7 @@ void* map_anon(void* addr, size_t size, unsigned flags, unsigned perm) std::lock_guard<mutex> guard(vma_list_mutex); auto v = (void*) allocate(vma, start, size, search); if (flags & mmap_populate) { - vma->operate_range(populate<>(vma->page_ops(), perm), v, size); + vma->operate_range(populate<>(vma->page_ops(), perm, vma->map_dirty()), v, size); } return v; } @@ -922,7 +928,7 @@ void* map_file(void* addr, size_t size, unsigned flags, unsigned perm, v = (void*) allocate(vma, start, asize, search); if (flags & mmap_populate) { map = vma->page_ops(); - vma->operate_range(populate<>(map, perm), v, asize); + vma->operate_range(populate<>(map, perm, vma->map_dirty()), v, asize); } } // call finalize outside of the lock so the file read will not happen under it @@ -1024,10 +1030,11 @@ void vm_fault(uintptr_t addr, exception_frame* ef) trace_mmu_vm_fault_ret(addr, ef->error_code); } -vma::vma(addr_range range, unsigned perm, unsigned flags, map_page_ops *page_ops) +vma::vma(addr_range range, unsigned perm, unsigned flags, bool map_dirty, map_page_ops *page_ops) : _range(align_down(range.start()), align_up(range.end())) , _perm(perm) , _flags(flags) + , _map_dirty(map_dirty) , _page_ops(page_ops) { } @@ -1098,6 +1105,11 @@ template<typename T> ulong vma::operate_range(T mapper) return mmu::operate_range(mapper, addr, addr, size()); } +bool vma::map_dirty() +{ + return _map_dirty; +} + void vma::fault(uintptr_t addr, exception_frame *ef) { auto hp_start = ::align_up(_range.start(), huge_page_size); @@ -1111,7 +1123,7 @@ void vma::fault(uintptr_t addr, exception_frame *ef) } map_page_ops *map = page_ops(); - auto total = operate_range(populate<account_opt::yes>(map, _perm), (void*)addr, size); + auto total = operate_range(populate<account_opt::yes>(map, _perm, map_dirty()), (void*)addr, size); map->finalize(); if (_flags & mmap_jvm_heap) { @@ -1129,7 +1141,7 @@ static map_anon_page page_ops_init; static map_page_ops *page_ops_noinitp = &page_ops_noinit, *page_ops_initp = &page_ops_init; anon_vma::anon_vma(addr_range range, unsigned perm, unsigned flags) - : vma(range, perm, flags, (_flags & mmap_uninitialized) ? page_ops_noinitp : page_ops_initp) + : vma(range, perm, flags, true, (_flags & mmap_uninitialized) ? page_ops_noinitp : page_ops_initp) { } @@ -1149,7 +1161,7 @@ error anon_vma::sync(uintptr_t start, uintptr_t end) } jvm_balloon_vma::jvm_balloon_vma(uintptr_t start, uintptr_t end, balloon *b, unsigned perm, unsigned flags) - : vma(addr_range(start, end), perm_rw, 0), _balloon(b), _real_perm(perm), _real_flags(flags) + : vma(addr_range(start, end), perm_rw, 0, true), _balloon(b), _real_perm(perm), _real_flags(flags) { } @@ -1239,7 +1251,7 @@ ulong map_jvm(void* addr, size_t size, balloon *b) } file_vma::file_vma(addr_range range, unsigned perm, fileref file, f_offset offset, bool shared) - : vma(range, perm, 0) + : vma(range, perm, 0, !shared) , _file(file) , _offset(offset) , _shared(shared) diff --git a/include/osv/mmu.hh b/include/osv/mmu.hh index fbd749ec9ed33e5d197634e8f5194649fd6900b6..8894b5f21020a49bd943d84faffc1783bfa0f588 100644 --- a/include/osv/mmu.hh +++ b/include/osv/mmu.hh @@ -81,7 +81,7 @@ struct map_page_ops; class vma { public: - vma(addr_range range, unsigned perm, unsigned flags, map_page_ops *page_ops = nullptr); + vma(addr_range range, unsigned perm, unsigned flags, bool map_dirty, map_page_ops *page_ops = nullptr); virtual ~vma(); void set(uintptr_t start, uintptr_t end); void protect(unsigned perm); @@ -100,11 +100,13 @@ public: bool has_flags(unsigned flag); template<typename T> ulong operate_range(T mapper, void *start, size_t size); template<typename T> ulong operate_range(T mapper); + bool map_dirty(); class addr_compare; protected: addr_range _range; unsigned _perm; unsigned _flags; + bool _map_dirty; map_page_ops *_page_ops; public: boost::intrusive::set_member_hook<> _vma_list_hook;