Kernel: Implement proper memory region splitting

Memory regions are now splitted when they get munmapped, mprotected, or
mmapped with MAP_FIXED. This is used by couple of ports, and without
this we were just leaking up memory or straight up crashing programs.
This commit is contained in:
2025-11-10 19:57:26 +02:00
parent a39aa73e21
commit 9537922acc
10 changed files with 145 additions and 46 deletions

View File

@@ -232,4 +232,33 @@ namespace Kernel
return BAN::UniqPtr<MemoryRegion>(BAN::move(result));
}
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> FileBackedRegion::split(size_t offset)
{
ASSERT(offset && offset < m_size);
ASSERT(offset % PAGE_SIZE == 0);
const bool has_dirty_pages = (m_type == Type::PRIVATE);
BAN::Vector<paddr_t> dirty_pages;
if (has_dirty_pages)
{
TRY(dirty_pages.resize(BAN::Math::div_round_up<size_t>(m_size - offset, PAGE_SIZE)));
for (size_t i = 0; i < dirty_pages.size(); i++)
dirty_pages[i] = m_dirty_pages[i + offset / PAGE_SIZE];
}
auto* new_region = new FileBackedRegion(m_inode, m_page_table, m_offset + offset, m_size - offset, m_type, m_flags, m_status_flags);
if (new_region == nullptr)
return BAN::Error::from_errno(ENOTSUP);
new_region->m_vaddr = m_vaddr + offset;
new_region->m_shared_data = m_shared_data;
new_region->m_dirty_pages = BAN::move(dirty_pages);
m_size = offset;
if (has_dirty_pages)
MUST(m_dirty_pages.resize(offset / PAGE_SIZE));
return BAN::UniqPtr<MemoryRegion>::adopt(new_region);
}
}

View File

@@ -82,6 +82,21 @@ namespace Kernel
return BAN::UniqPtr<MemoryRegion>(BAN::move(result));
}
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> MemoryBackedRegion::split(size_t offset)
{
ASSERT(offset && offset < m_size);
ASSERT(offset % PAGE_SIZE == 0);
auto* new_region = new MemoryBackedRegion(m_page_table, m_size - offset, m_type, m_flags, m_status_flags);
if (new_region == nullptr)
return BAN::Error::from_errno(ENOMEM);
new_region->m_vaddr = m_vaddr + offset;
m_size = offset;
return BAN::UniqPtr<MemoryRegion>::adopt(new_region);
}
BAN::ErrorOr<void> MemoryBackedRegion::copy_data_to_region(size_t offset_into_region, const uint8_t* buffer, size_t buffer_size)
{
ASSERT(offset_into_region + buffer_size <= m_size);

View File

@@ -87,6 +87,13 @@ namespace Kernel
return BAN::UniqPtr<MemoryRegion>(BAN::move(region));
}
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> SharedMemoryObject::split(size_t offset)
{
(void)offset;
dwarnln("TODO: SharedMemoryObject::split");
return BAN::Error::from_errno(ENOTSUP);
}
BAN::ErrorOr<bool> SharedMemoryObject::allocate_page_containing_impl(vaddr_t address, bool wants_write)
{
ASSERT(contains(address));