Skip to content

Commit d720388

Browse files
committed
Kernel: Support partial munmap()
You can now munmap() a part of a region. The kernel will then create one or two new regions around the "hole" and re-map them using the same physical pages as before. This goes towards fixing #175, but not all the way since we don't yet do munmap() across multiple mappings.
1 parent 0e53b1d commit d720388

File tree

2 files changed

+62
-16
lines changed

2 files changed

+62
-16
lines changed

Kernel/Process.cpp

Lines changed: 58 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@
99
#include <Kernel/Arch/i386/PIT.h>
1010
#include <Kernel/Devices/NullDevice.h>
1111
#include <Kernel/FileSystem/Custody.h>
12-
#include <Kernel/FileSystem/Ext2FileSystem.h>
13-
#include <Kernel/FileSystem/ProcFS.h>
1412
#include <Kernel/FileSystem/DevPtsFS.h>
15-
#include <Kernel/FileSystem/TmpFS.h>
13+
#include <Kernel/FileSystem/Ext2FileSystem.h>
1614
#include <Kernel/FileSystem/FIFO.h>
1715
#include <Kernel/FileSystem/FileDescription.h>
1816
#include <Kernel/FileSystem/InodeWatcher.h>
17+
#include <Kernel/FileSystem/ProcFS.h>
1918
#include <Kernel/FileSystem/SharedMemory.h>
19+
#include <Kernel/FileSystem/TmpFS.h>
2020
#include <Kernel/FileSystem/VirtualFileSystem.h>
2121
#include <Kernel/IO.h>
2222
#include <Kernel/KBufferBuilder.h>
@@ -108,6 +108,12 @@ static unsigned prot_to_region_access_flags(int prot)
108108
return access;
109109
}
110110

111+
Region& Process::allocate_split_region(const Region& source_region, const Range& range)
112+
{
113+
m_regions.append(Region::create_user_accessible(range, source_region.name(), source_region.access()));
114+
return m_regions.last();
115+
}
116+
111117
Region* Process::allocate_region(VirtualAddress vaddr, size_t size, const String& name, int prot, bool commit)
112118
{
113119
auto range = allocate_range(vaddr, size);
@@ -154,11 +160,20 @@ bool Process::deallocate_region(Region& region)
154160
return false;
155161
}
156162

157-
Region* Process::region_from_range(VirtualAddress vaddr, size_t size)
163+
Region* Process::region_from_range(const Range& range)
164+
{
165+
size_t size = PAGE_ROUND_UP(range.size());
166+
for (auto& region : m_regions) {
167+
if (region.vaddr() == range.base() && region.size() == size)
168+
return &region;
169+
}
170+
return nullptr;
171+
}
172+
173+
Region* Process::region_containing(const Range& range)
158174
{
159-
size = PAGE_ROUND_UP(size);
160175
for (auto& region : m_regions) {
161-
if (region.vaddr() == vaddr && region.size() == size)
176+
if (region.contains(range))
162177
return &region;
163178
}
164179
return nullptr;
@@ -168,7 +183,7 @@ int Process::sys$set_mmap_name(void* addr, size_t size, const char* name)
168183
{
169184
if (!validate_read_str(name))
170185
return -EFAULT;
171-
auto* region = region_from_range(VirtualAddress((u32)addr), size);
186+
auto* region = region_from_range({ VirtualAddress((u32)addr), size });
172187
if (!region)
173188
return -EINVAL;
174189
region->set_name(String(name));
@@ -220,17 +235,46 @@ void* Process::sys$mmap(const Syscall::SC_mmap_params* params)
220235

221236
int Process::sys$munmap(void* addr, size_t size)
222237
{
223-
auto* region = region_from_range(VirtualAddress((u32)addr), size);
224-
if (!region)
225-
return -EINVAL;
226-
if (!deallocate_region(*region))
227-
return -EINVAL;
228-
return 0;
238+
Range range_to_unmap { VirtualAddress((u32)addr), size };
239+
if (auto* whole_region = region_from_range(range_to_unmap)) {
240+
bool success = deallocate_region(*whole_region);
241+
ASSERT(success);
242+
return 0;
243+
}
244+
245+
if (auto* old_region = region_containing(range_to_unmap)) {
246+
Range old_region_range = old_region->range();
247+
auto remaining_ranges_after_unmap = old_region_range.carve(range_to_unmap);
248+
ASSERT(!remaining_ranges_after_unmap.is_empty());
249+
auto make_replacement_region = [&](const Range& new_range) -> Region& {
250+
auto& new_region = allocate_split_region(*old_region, new_range);
251+
ASSERT(new_range.base() >= old_region_range.base());
252+
size_t new_range_offset_in_old_region = new_range.base().get() - old_region_range.base().get();
253+
size_t first_physical_page_of_new_region_in_old_region = new_range_offset_in_old_region / PAGE_SIZE;
254+
for (size_t i = 0; i < new_region.page_count(); ++i) {
255+
new_region.vmo().physical_pages()[i] = old_region->vmo().physical_pages()[first_physical_page_of_new_region_in_old_region + i];
256+
}
257+
return new_region;
258+
};
259+
Vector<Region*, 2> new_regions;
260+
for (auto& new_range : remaining_ranges_after_unmap) {
261+
new_regions.unchecked_append(&make_replacement_region(new_range));
262+
}
263+
deallocate_region(*old_region);
264+
for (auto* new_region : new_regions) {
265+
MM.map_region(*this, *new_region);
266+
}
267+
return 0;
268+
}
269+
270+
// FIXME: We should also support munmap() across multiple regions. (#175)
271+
272+
return -EINVAL;
229273
}
230274

231275
int Process::sys$mprotect(void* addr, size_t size, int prot)
232276
{
233-
auto* region = region_from_range(VirtualAddress((u32)addr), size);
277+
auto* region = region_from_range({ VirtualAddress((u32)addr), size });
234278
if (!region)
235279
return -EINVAL;
236280
region->set_writable(prot & PROT_WRITE);
@@ -2930,4 +2974,3 @@ int Process::sys$get_process_name(char* buffer, int buffer_size)
29302974
strncpy(buffer, m_name.characters(), buffer_size);
29312975
return 0;
29322976
}
2933-

Kernel/Process.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,8 @@ class Process : public InlineLinkedListNode<Process>
275275
Region* allocate_region(VirtualAddress, size_t, const String& name, int prot = PROT_READ | PROT_WRITE, bool commit = true);
276276
bool deallocate_region(Region& region);
277277

278+
Region& allocate_split_region(const Region& source_region, const Range&);
279+
278280
void set_being_inspected(bool b) { m_being_inspected = b; }
279281
bool is_being_inspected() const { return m_being_inspected; }
280282

@@ -348,7 +350,8 @@ class Process : public InlineLinkedListNode<Process>
348350

349351
TTY* m_tty { nullptr };
350352

351-
Region* region_from_range(VirtualAddress, size_t);
353+
Region* region_from_range(const Range&);
354+
Region* region_containing(const Range&);
352355

353356
NonnullRefPtrVector<Region> m_regions;
354357

0 commit comments

Comments
 (0)