* 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,
|
status_t InsertArea(void** _address, uint32 addressSpec,
|
||||||
addr_t size, VMArea* area);
|
addr_t size, VMArea* area);
|
||||||
void RemoveArea(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();
|
inline Iterator GetIterator();
|
||||||
|
|
||||||
|
|||||||
@@ -42,9 +42,6 @@ struct VMArea {
|
|||||||
addr_t Base() const { return fBase; }
|
addr_t Base() const { return fBase; }
|
||||||
size_t Size() const { return fSize; }
|
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
|
bool ContainsAddress(addr_t address) const
|
||||||
{ return address >= fBase
|
{ return address >= fBase
|
||||||
&& address <= fBase + (fSize - 1); }
|
&& address <= fBase + (fSize - 1); }
|
||||||
@@ -60,6 +57,13 @@ struct VMArea {
|
|||||||
const DoublyLinkedListLink<VMArea>& AddressSpaceLink() const
|
const DoublyLinkedListLink<VMArea>& AddressSpaceLink() const
|
||||||
{ return fAddressSpaceLink; }
|
{ return fAddressSpaceLink; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class VMAddressSpace;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SetBase(addr_t base) { fBase = base; }
|
||||||
|
void SetSize(size_t size) { fSize = size; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DoublyLinkedListLink<VMArea> fAddressSpaceLink;
|
DoublyLinkedListLink<VMArea> fAddressSpaceLink;
|
||||||
addr_t fBase;
|
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
|
void
|
||||||
VMAddressSpace::Dump() const
|
VMAddressSpace::Dump() const
|
||||||
{
|
{
|
||||||
|
|||||||
+38
-20
@@ -335,37 +335,46 @@ cut_area(VMAddressSpace* addressSpace, VMArea* area, addr_t address,
|
|||||||
|
|
||||||
// Cut the end only?
|
// Cut the end only?
|
||||||
if (areaLast <= lastAddress) {
|
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
|
// 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 no one else uses the area's cache, we can resize it, too.
|
||||||
if (cache->areas == area && area->cache_next == NULL
|
if (cache->areas == area && area->cache_next == NULL
|
||||||
&& list_is_empty(&cache->consumers)) {
|
&& list_is_empty(&cache->consumers)) {
|
||||||
status_t error = cache->Resize(cache->virtual_base + newSize);
|
error = cache->Resize(cache->virtual_base + newSize);
|
||||||
if (error != B_OK)
|
if (error != B_OK) {
|
||||||
|
addressSpace->ResizeAreaTail(area, oldSize);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
area->SetSize(newSize);
|
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cut the beginning only?
|
// Cut the beginning only?
|
||||||
if (area->Base() >= address) {
|
if (area->Base() >= address) {
|
||||||
|
addr_t oldBase = area->Base();
|
||||||
addr_t newBase = lastAddress + 1;
|
addr_t newBase = lastAddress + 1;
|
||||||
addr_t newSize = areaLast - lastAddress;
|
size_t newSize = areaLast - lastAddress;
|
||||||
|
|
||||||
// unmap pages
|
// 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!
|
// TODO: If no one else uses the area's cache, we should resize it, too!
|
||||||
|
|
||||||
area->cache_offset += newBase - area->Base();
|
area->cache_offset += newBase - oldBase;
|
||||||
area->SetBase(newBase);
|
|
||||||
area->SetSize(newSize);
|
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -383,7 +392,9 @@ cut_area(VMAddressSpace* addressSpace, VMArea* area, addr_t address,
|
|||||||
|
|
||||||
// resize the area
|
// resize the area
|
||||||
addr_t oldSize = area->Size();
|
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
|
// 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
|
// 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
|
// map the second area
|
||||||
VMArea* secondArea;
|
VMArea* secondArea;
|
||||||
void* secondBaseAddress = (void*)secondBase;
|
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,
|
area->cache_offset + (secondBase - area->Base()), secondSize,
|
||||||
B_EXACT_ADDRESS, area->wiring, area->protection, REGION_NO_PRIVATE_MAP,
|
B_EXACT_ADDRESS, area->wiring, area->protection, REGION_NO_PRIVATE_MAP,
|
||||||
&secondArea, area->name, false, kernel);
|
&secondArea, area->name, false, kernel);
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
area->SetSize(oldSize);
|
addressSpace->ResizeAreaTail(area, oldSize);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4283,8 +4294,8 @@ vm_resize_area(area_id areaID, size_t newSize, bool kernel)
|
|||||||
next->address_space->RemoveArea(next);
|
next->address_space->RemoveArea(next);
|
||||||
free(next);
|
free(next);
|
||||||
} else {
|
} else {
|
||||||
next->SetSize(next->Size() - offset);
|
next->address_space->ResizeAreaHead(next,
|
||||||
next->SetBase(next->Base() + offset);
|
next->Size() - offset);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
panic("resize situation for area %p has changed although we "
|
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
|
// We also need to unmap all pages beyond the new size, if the area has
|
||||||
// shrinked
|
// shrinked
|
||||||
@@ -4308,11 +4321,16 @@ vm_resize_area(area_id areaID, size_t newSize, bool kernel)
|
|||||||
if (status == B_OK && newSize < oldSize)
|
if (status == B_OK && newSize < oldSize)
|
||||||
status = cache->Resize(cache->virtual_base + newSize);
|
status = cache->Resize(cache->virtual_base + newSize);
|
||||||
|
|
||||||
if (status < B_OK) {
|
if (status != B_OK) {
|
||||||
// This shouldn't really be possible, but hey, who knows
|
// 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;
|
for (VMArea* current = cache->areas; current != NULL;
|
||||||
current = current->cache_next) {
|
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);
|
cache->Resize(cache->virtual_base + oldSize);
|
||||||
|
|||||||
Reference in New Issue
Block a user