* Added VMAddressSpace::ResizeArea{Head,Tail}() to adjust an area's base
and size.
* Made VMArea::Set{Base,Size}() private and made VMAddressSpace a friend.
In vm.cpp the new VMAddressSpace::ResizeArea{Head,Tail}() are used
instead.
Finally all address space changes happen in VMAddressSpace only. *phew*
Now it's ready to be thoroughly butchered. :-)
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34467 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -66,6 +66,8 @@ public:
|
||||
status_t InsertArea(void** _address, uint32 addressSpec,
|
||||
addr_t size, VMArea* area);
|
||||
void RemoveArea(VMArea* area);
|
||||
status_t ResizeAreaHead(VMArea* area, size_t size);
|
||||
status_t ResizeAreaTail(VMArea* area, size_t size);
|
||||
|
||||
inline Iterator GetIterator();
|
||||
|
||||
|
||||
@@ -42,9 +42,6 @@ struct VMArea {
|
||||
addr_t Base() const { return fBase; }
|
||||
size_t Size() const { return fSize; }
|
||||
|
||||
void SetBase(addr_t base) { fBase = base; }
|
||||
void SetSize(size_t size) { fSize = size; }
|
||||
|
||||
bool ContainsAddress(addr_t address) const
|
||||
{ return address >= fBase
|
||||
&& address <= fBase + (fSize - 1); }
|
||||
@@ -60,6 +57,13 @@ struct VMArea {
|
||||
const DoublyLinkedListLink<VMArea>& AddressSpaceLink() const
|
||||
{ return fAddressSpaceLink; }
|
||||
|
||||
private:
|
||||
friend class VMAddressSpace;
|
||||
|
||||
private:
|
||||
void SetBase(addr_t base) { fBase = base; }
|
||||
void SetSize(size_t size) { fSize = size; }
|
||||
|
||||
private:
|
||||
DoublyLinkedListLink<VMArea> fAddressSpaceLink;
|
||||
addr_t fBase;
|
||||
|
||||
@@ -361,6 +361,33 @@ VMAddressSpace::RemoveArea(VMArea* area)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
VMAddressSpace::ResizeAreaHead(VMArea* area, size_t size)
|
||||
{
|
||||
size_t oldSize = area->Size();
|
||||
if (size == oldSize)
|
||||
return B_OK;
|
||||
|
||||
area->SetBase(area->Base() + oldSize - size);
|
||||
area->SetSize(size);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
VMAddressSpace::ResizeAreaTail(VMArea* area, size_t size)
|
||||
{
|
||||
size_t oldSize = area->Size();
|
||||
if (size == oldSize)
|
||||
return B_OK;
|
||||
|
||||
area->SetSize(size);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
VMAddressSpace::Dump() const
|
||||
{
|
||||
|
||||
+38
-20
@@ -335,37 +335,46 @@ cut_area(VMAddressSpace* addressSpace, VMArea* area, addr_t address,
|
||||
|
||||
// Cut the end only?
|
||||
if (areaLast <= lastAddress) {
|
||||
addr_t newSize = address - area->Base();
|
||||
size_t oldSize = area->Size();
|
||||
size_t newSize = address - area->Base();
|
||||
|
||||
status_t error = addressSpace->ResizeAreaTail(area, newSize);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// unmap pages
|
||||
vm_unmap_pages(area, address, area->Size() - newSize, false);
|
||||
vm_unmap_pages(area, address, oldSize - newSize, false);
|
||||
|
||||
// If no one else uses the area's cache, we can resize it, too.
|
||||
if (cache->areas == area && area->cache_next == NULL
|
||||
&& list_is_empty(&cache->consumers)) {
|
||||
status_t error = cache->Resize(cache->virtual_base + newSize);
|
||||
if (error != B_OK)
|
||||
error = cache->Resize(cache->virtual_base + newSize);
|
||||
if (error != B_OK) {
|
||||
addressSpace->ResizeAreaTail(area, oldSize);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
area->SetSize(newSize);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Cut the beginning only?
|
||||
if (area->Base() >= address) {
|
||||
addr_t oldBase = area->Base();
|
||||
addr_t newBase = lastAddress + 1;
|
||||
addr_t newSize = areaLast - lastAddress;
|
||||
size_t newSize = areaLast - lastAddress;
|
||||
|
||||
// unmap pages
|
||||
vm_unmap_pages(area, area->Base(), newBase - area->Base(), false);
|
||||
vm_unmap_pages(area, oldBase, newBase - oldBase, false);
|
||||
|
||||
// resize the area
|
||||
status_t error = addressSpace->ResizeAreaHead(area, newSize);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// TODO: If no one else uses the area's cache, we should resize it, too!
|
||||
|
||||
area->cache_offset += newBase - area->Base();
|
||||
area->SetBase(newBase);
|
||||
area->SetSize(newSize);
|
||||
area->cache_offset += newBase - oldBase;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -383,7 +392,9 @@ cut_area(VMAddressSpace* addressSpace, VMArea* area, addr_t address,
|
||||
|
||||
// resize the area
|
||||
addr_t oldSize = area->Size();
|
||||
area->SetSize(firstNewSize);
|
||||
status_t error = addressSpace->ResizeAreaTail(area, firstNewSize);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// TODO: If no one else uses the area's cache, we might want to create a
|
||||
// new cache for the second area, transfer the concerned pages from the
|
||||
@@ -392,12 +403,12 @@ cut_area(VMAddressSpace* addressSpace, VMArea* area, addr_t address,
|
||||
// map the second area
|
||||
VMArea* secondArea;
|
||||
void* secondBaseAddress = (void*)secondBase;
|
||||
status_t error = map_backing_store(addressSpace, cache, &secondBaseAddress,
|
||||
error = map_backing_store(addressSpace, cache, &secondBaseAddress,
|
||||
area->cache_offset + (secondBase - area->Base()), secondSize,
|
||||
B_EXACT_ADDRESS, area->wiring, area->protection, REGION_NO_PRIVATE_MAP,
|
||||
&secondArea, area->name, false, kernel);
|
||||
if (error != B_OK) {
|
||||
area->SetSize(oldSize);
|
||||
addressSpace->ResizeAreaTail(area, oldSize);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -4283,8 +4294,8 @@ vm_resize_area(area_id areaID, size_t newSize, bool kernel)
|
||||
next->address_space->RemoveArea(next);
|
||||
free(next);
|
||||
} else {
|
||||
next->SetSize(next->Size() - offset);
|
||||
next->SetBase(next->Base() + offset);
|
||||
next->address_space->ResizeAreaHead(next,
|
||||
next->Size() - offset);
|
||||
}
|
||||
} else {
|
||||
panic("resize situation for area %p has changed although we "
|
||||
@@ -4294,7 +4305,9 @@ vm_resize_area(area_id areaID, size_t newSize, bool kernel)
|
||||
}
|
||||
}
|
||||
|
||||
current->SetSize(newSize);
|
||||
status = current->address_space->ResizeAreaTail(current, newSize);
|
||||
if (status != B_OK)
|
||||
break;
|
||||
|
||||
// We also need to unmap all pages beyond the new size, if the area has
|
||||
// shrinked
|
||||
@@ -4308,11 +4321,16 @@ vm_resize_area(area_id areaID, size_t newSize, bool kernel)
|
||||
if (status == B_OK && newSize < oldSize)
|
||||
status = cache->Resize(cache->virtual_base + newSize);
|
||||
|
||||
if (status < B_OK) {
|
||||
// This shouldn't really be possible, but hey, who knows
|
||||
if (status != B_OK) {
|
||||
// Something failed -- resize the areas back to their original size.
|
||||
// This can fail, too, in which case we're seriously screwed.
|
||||
for (VMArea* current = cache->areas; current != NULL;
|
||||
current = current->cache_next) {
|
||||
current->SetSize(oldSize);
|
||||
if (current->address_space->ResizeAreaTail(current, oldSize)
|
||||
!= B_OK) {
|
||||
panic("vm_resize_area(): Failed and not being able to restore "
|
||||
"original state.");
|
||||
}
|
||||
}
|
||||
|
||||
cache->Resize(cache->virtual_base + oldSize);
|
||||
|
||||
Reference in New Issue
Block a user