hrev48145 adds 2 changesets to branch 'master' old head: cf3c703b7ac57f097ae92a6173747f1dc2864941 new head: 7ca277b9caaec8e873309354e3c7fe8453c34b64 overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=7ca277b+%5Ecf3c703 ---------------------------------------------------------------------------- 078a965: vm_soft_fault(): Avoid deadlock waiting for wired ranges * VMArea::AddWaiterIfWired(): Replace the ignoreRange argument by a flags argument and introduce (currently only) flag IGNORE_WRITE_WIRED_RANGES. If specified, ranges wired for writing are ignored. Ignoring just a single specified range doesn't cut it in vm_soft_fault(), and there aren't any other users of that feature. * vm_soft_fault(): When having to unmap a page of a lower cache, this page cannot be wired for writing. So we can safely ignore all writed-wired ranges, instead of just our own. We even have to do that in case there's another thread that concurrently tries to write-wire the same page, since otherwise we'd deadlock waiting for each other. 7ca277b: vm_soft_fault(): remove unused wiredRange parameter [ Ingo Weinhold <ingo_weinhold@xxxxxx> ] ---------------------------------------------------------------------------- 3 files changed, 26 insertions(+), 18 deletions(-) headers/private/kernel/vm/VMArea.h | 11 +++++++++-- src/system/kernel/vm/VMArea.cpp | 13 +++++++------ src/system/kernel/vm/vm.cpp | 20 ++++++++++---------- ############################################################################ Commit: 078a965f65b5f56ecb3f0c72fc97a36238509ca8 URL: http://cgit.haiku-os.org/haiku/commit/?id=078a965 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Wed Oct 29 11:32:37 2014 UTC vm_soft_fault(): Avoid deadlock waiting for wired ranges * VMArea::AddWaiterIfWired(): Replace the ignoreRange argument by a flags argument and introduce (currently only) flag IGNORE_WRITE_WIRED_RANGES. If specified, ranges wired for writing are ignored. Ignoring just a single specified range doesn't cut it in vm_soft_fault(), and there aren't any other users of that feature. * vm_soft_fault(): When having to unmap a page of a lower cache, this page cannot be wired for writing. So we can safely ignore all writed-wired ranges, instead of just our own. We even have to do that in case there's another thread that concurrently tries to write-wire the same page, since otherwise we'd deadlock waiting for each other. ---------------------------------------------------------------------------- diff --git a/headers/private/kernel/vm/VMArea.h b/headers/private/kernel/vm/VMArea.h index 669c98a..7c4621c 100644 --- a/headers/private/kernel/vm/VMArea.h +++ b/headers/private/kernel/vm/VMArea.h @@ -89,6 +89,14 @@ struct VMPageWiringInfo { struct VMArea { +public: + enum { + // AddWaiterIfWired() flags + IGNORE_WRITE_WIRED_RANGES = 0x01, // ignore existing ranges that + // wire for writing + }; + +public: char* name; area_id id; uint32 protection; @@ -130,8 +138,7 @@ public: bool AddWaiterIfWired(VMAreaUnwiredWaiter* waiter); bool AddWaiterIfWired(VMAreaUnwiredWaiter* waiter, - addr_t base, size_t size, - VMAreaWiredRange* ignoreRange = NULL); + addr_t base, size_t size, uint32 flags = 0); protected: VMArea(VMAddressSpace* addressSpace, diff --git a/src/system/kernel/vm/VMArea.cpp b/src/system/kernel/vm/VMArea.cpp index b87b1d6..ffe111e 100644 --- a/src/system/kernel/vm/VMArea.cpp +++ b/src/system/kernel/vm/VMArea.cpp @@ -185,19 +185,20 @@ VMArea::AddWaiterIfWired(VMAreaUnwiredWaiter* waiter) that intersects with the given address range. \param base The base of the address range to check. \param size The size of the address range to check. - \param ignoreRange If given, this wired range of the area is not checked - whether it intersects with the given address range. Useful when the - caller has added the range and only wants to check intersection with - other ranges. + \param flags + - \c IGNORE_WRITE_WIRED_RANGES: Ignore ranges wired for writing. \return \c true, if the waiter has been added, \c false otherwise. */ bool VMArea::AddWaiterIfWired(VMAreaUnwiredWaiter* waiter, addr_t base, size_t size, - VMAreaWiredRange* ignoreRange) + uint32 flags) { for (VMAreaWiredRangeList::Iterator it = fWiredRanges.GetIterator(); VMAreaWiredRange* range = it.Next();) { - if (range != ignoreRange && range->IntersectsWith(base, size)) { + if ((flags & IGNORE_WRITE_WIRED_RANGES) != 0 && range->writable) + continue; + + if (range->IntersectsWith(base, size)) { waiter->area = this; waiter->base = base; waiter->size = size; diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index 4c65cae..5253a58 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -4681,10 +4681,14 @@ vm_soft_fault(VMAddressSpace* addressSpace, addr_t originalAddress, if (unmapPage) { // If the page is wired, we can't unmap it. Wait until it is unwired - // again and restart. + // again and restart. Note that the page cannot be wired for + // writing, since it it isn't in the topmost cache. So we can safely + // ignore ranges wired for writing (our own and other concurrent + // wiring attempts in progress) and in fact have to do that to avoid + // a deadlock. VMAreaUnwiredWaiter waiter; if (area->AddWaiterIfWired(&waiter, address, B_PAGE_SIZE, - wiredRange)) { + VMArea::IGNORE_WRITE_WIRED_RANGES)) { // unlock everything and wait if (context.pageAllocated) { // ... but since we allocated a page and inserted it into ############################################################################ Revision: hrev48145 Commit: 7ca277b9caaec8e873309354e3c7fe8453c34b64 URL: http://cgit.haiku-os.org/haiku/commit/?id=7ca277b Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Wed Oct 29 11:36:46 2014 UTC vm_soft_fault(): remove unused wiredRange parameter ---------------------------------------------------------------------------- diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index 5253a58..53875e4 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -268,8 +268,7 @@ static cache_info* sCacheInfoTable; static void delete_area(VMAddressSpace* addressSpace, VMArea* area, bool addressSpaceCleanup); static status_t vm_soft_fault(VMAddressSpace* addressSpace, addr_t address, - bool isWrite, bool isExecute, bool isUser, vm_page** wirePage, - VMAreaWiredRange* wiredRange = NULL); + bool isWrite, bool isExecute, bool isUser, vm_page** wirePage); static status_t map_backing_store(VMAddressSpace* addressSpace, VMCache* cache, off_t offset, const char* areaName, addr_t size, int wiring, int protection, int mapping, uint32 flags, @@ -4529,14 +4528,11 @@ fault_get_page(PageFaultContext& context) \param wirePage On success, if non \c NULL, the wired count of the page mapped at the given address is incremented and the page is returned via this parameter. - \param wiredRange If given, this wiredRange is ignored when checking whether - an already mapped page at the virtual address can be unmapped. \return \c B_OK on success, another error code otherwise. */ static status_t vm_soft_fault(VMAddressSpace* addressSpace, addr_t originalAddress, - bool isWrite, bool isExecute, bool isUser, vm_page** wirePage, - VMAreaWiredRange* wiredRange) + bool isWrite, bool isExecute, bool isUser, vm_page** wirePage) { FTRACE(("vm_soft_fault: thid 0x%" B_PRIx32 " address 0x%" B_PRIxADDR ", " "isWrite %d, isUser %d\n", thread_get_current_thread_id(), @@ -5415,7 +5411,7 @@ vm_wire_page(team_id team, addr_t address, bool writable, addressSpaceLocker.Unlock(); error = vm_soft_fault(addressSpace, pageAddress, writable, false, - isUser, &page, &info->range); + isUser, &page); if (error != B_OK) { // The page could not be mapped -- clean up. @@ -5595,7 +5591,7 @@ lock_memory_etc(team_id team, void* address, size_t numBytes, uint32 flags) addressSpaceLocker.Unlock(); error = vm_soft_fault(addressSpace, nextAddress, writable, - false, isUser, &page, range); + false, isUser, &page); addressSpaceLocker.Lock(); cacheChainLocker.SetTo(vm_area_get_locked_cache(area));