[haiku-commits] haiku: hrev48145 - src/system/kernel/vm headers/private/kernel/vm

  • From: ingo_weinhold@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Wed, 29 Oct 2014 12:37:33 +0100 (CET)

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));


Other related posts:

  • » [haiku-commits] haiku: hrev48145 - src/system/kernel/vm headers/private/kernel/vm - ingo_weinhold