diff --git a/headers/private/kernel/vm/VMAddressSpace.h b/headers/private/kernel/vm/VMAddressSpace.h index 1c226a4ae1..378fb6efe5 100644 --- a/headers/private/kernel/vm/VMAddressSpace.h +++ b/headers/private/kernel/vm/VMAddressSpace.h @@ -23,6 +23,7 @@ struct virtual_address_restrictions; struct VMAddressSpace { public: class AreaIterator; + class AreaRangeIterator; public: VMAddressSpace(team_id id, addr_t base, @@ -67,6 +68,8 @@ public: { fRandomizingEnabled = enabled; } inline AreaIterator GetAreaIterator(); + inline AreaRangeIterator GetAreaRangeIterator(addr_t address, + addr_t size); VMAddressSpace*& HashTableLink() { return fHashTableLink; } @@ -202,6 +205,54 @@ private: }; +class VMAddressSpace::AreaRangeIterator : public VMAddressSpace::AreaIterator { +public: + AreaRangeIterator() + { + } + + AreaRangeIterator(VMAddressSpace* addressSpace, addr_t address, addr_t size) + : + fAddressSpace(addressSpace), + fNext(NULL), + fAddress(address), + fEndAddress(address + size - 1) + { + Rewind(); + } + + bool HasNext() const + { + return fNext != NULL; + } + + VMArea* Next() + { + VMArea* result = fNext; + if (fNext != NULL) { + fNext = fAddressSpace->NextArea(fNext); + if (fNext != NULL && fNext->Base() > fEndAddress) + fNext = NULL; + } + + return result; + } + + void Rewind() + { + fNext = fAddressSpace->FindClosestArea(fAddress, true); + if (fNext != NULL && !fNext->ContainsAddress(fAddress)) + Next(); + } + +private: + VMAddressSpace* fAddressSpace; + VMArea* fNext; + addr_t fAddress; + addr_t fEndAddress; +}; + + inline VMAddressSpace::AreaIterator VMAddressSpace::GetAreaIterator() { @@ -209,6 +260,13 @@ VMAddressSpace::GetAreaIterator() } +inline VMAddressSpace::AreaRangeIterator +VMAddressSpace::GetAreaRangeIterator(addr_t address, addr_t size) +{ + return AreaRangeIterator(this, address, size); +} + + #ifdef __cplusplus extern "C" { #endif diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index a672595608..c43a18f333 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -833,26 +833,26 @@ unmap_address_range(VMAddressSpace* addressSpace, addr_t address, addr_t size, bool kernel) { size = PAGE_ALIGN(size); - addr_t lastAddress = address + (size - 1); // Check, whether the caller is allowed to modify the concerned areas. if (!kernel) { - for (VMAddressSpace::AreaIterator it = addressSpace->GetAreaIterator(); - VMArea* area = it.Next();) { - addr_t areaLast = area->Base() + (area->Size() - 1); - if (area->Base() < lastAddress && address < areaLast) { - if ((area->protection & B_KERNEL_AREA) != 0) { - dprintf("unmap_address_range: team %" B_PRId32 " tried to " - "unmap range of kernel area %" B_PRId32 " (%s)\n", - team_get_current_team_id(), area->id, area->name); - return B_NOT_ALLOWED; - } + for (VMAddressSpace::AreaRangeIterator it + = addressSpace->GetAreaRangeIterator(address, size); + VMArea* area = it.Next();) { + + if ((area->protection & B_KERNEL_AREA) != 0) { + dprintf("unmap_address_range: team %" B_PRId32 " tried to " + "unmap range of kernel area %" B_PRId32 " (%s)\n", + team_get_current_team_id(), area->id, area->name); + return B_NOT_ALLOWED; } } } - for (VMAddressSpace::AreaIterator it = addressSpace->GetAreaIterator(); - VMArea* area = it.Next();) { + for (VMAddressSpace::AreaRangeIterator it + = addressSpace->GetAreaRangeIterator(address, size); + VMArea* area = it.Next();) { + status_t error = cut_area(addressSpace, area, address, size, NULL, kernel); if (error != B_OK) @@ -1092,15 +1092,9 @@ static inline bool wait_if_address_range_is_wired(VMAddressSpace* addressSpace, addr_t base, size_t size, LockerType* locker) { - addr_t end = base + size - 1; - for (VMAddressSpace::AreaIterator it = addressSpace->GetAreaIterator(); + for (VMAddressSpace::AreaRangeIterator it + = addressSpace->GetAreaRangeIterator(base, size); VMArea* area = it.Next();) { - // TODO: Introduce a VMAddressSpace method to get a close iterator! - if (area->Base() > end) - return false; - - if (base >= area->Base() + area->Size() - 1) - continue; AreaCacheLocker cacheLocker(vm_area_get_locked_cache(area));