Support munmap multiple single VMA chunks with remaining ranges
This commit is contained in:
parent
5c10af738e
commit
f87ee7c7a4
@ -257,36 +257,24 @@ impl VMManager {
|
|||||||
chunk.unwrap().clone()
|
chunk.unwrap().clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Case 1: the overlapping chunk IS NOT a super set of munmap range
|
||||||
if !chunk.range().is_superset_of(&munmap_range) {
|
if !chunk.range().is_superset_of(&munmap_range) {
|
||||||
// munmap range spans multiple chunks
|
// munmap range spans multiple chunks
|
||||||
let munmap_single_vma_chunks = {
|
let overlapping_chunks = {
|
||||||
let current = current!();
|
let current = current!();
|
||||||
let mut process_mem_chunks = current.vm().mem_chunks().write().unwrap();
|
let process_mem_chunks = current.vm().mem_chunks().read().unwrap();
|
||||||
let munmap_single_vma_chunks = process_mem_chunks
|
process_mem_chunks
|
||||||
.drain_filter(|p_chunk| {
|
|
||||||
p_chunk.is_single_vma() && p_chunk.range().overlap_with(&munmap_range)
|
|
||||||
})
|
|
||||||
.collect::<Vec<ChunkRef>>();
|
|
||||||
if munmap_single_vma_chunks
|
|
||||||
.iter()
|
|
||||||
.find(|chunk| !munmap_range.is_superset_of(chunk.range()))
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
// TODO: Support munmap multiple single VMA chunk with remaining ranges.
|
|
||||||
return_errno!(
|
|
||||||
EINVAL,
|
|
||||||
"munmap multiple chunks with remaining ranges is not supported"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Munmap ranges in default chunks
|
|
||||||
for chunk in process_mem_chunks
|
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|p_chunk| p_chunk.range().overlap_with(&munmap_range))
|
.filter(|p_chunk| p_chunk.range().overlap_with(&munmap_range))
|
||||||
{
|
.cloned()
|
||||||
|
.collect::<Vec<ChunkRef>>()
|
||||||
|
};
|
||||||
|
|
||||||
|
for chunk in overlapping_chunks.iter() {
|
||||||
match chunk.internal() {
|
match chunk.internal() {
|
||||||
ChunkType::SingleVMA(_) => {
|
ChunkType::SingleVMA(_) => {
|
||||||
unreachable!() // single-vma chunks should be drained already
|
let mut internl_manager = self.internal();
|
||||||
|
internl_manager.munmap_chunk(chunk, Some(&munmap_range))?
|
||||||
}
|
}
|
||||||
ChunkType::MultiVMA(manager) => manager
|
ChunkType::MultiVMA(manager) => manager
|
||||||
.lock()
|
.lock()
|
||||||
@ -295,17 +283,11 @@ impl VMManager {
|
|||||||
.munmap_range(munmap_range)?,
|
.munmap_range(munmap_range)?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
munmap_single_vma_chunks
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut internl_manager = self.internal();
|
|
||||||
munmap_single_vma_chunks.iter().for_each(|p_chunk| {
|
|
||||||
internl_manager.munmap_chunk(p_chunk, None);
|
|
||||||
});
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Case 2: the overlapping chunk IS a super set of munmap range
|
||||||
|
debug_assert!(chunk.range().is_superset_of(&munmap_range));
|
||||||
match chunk.internal() {
|
match chunk.internal() {
|
||||||
ChunkType::MultiVMA(manager) => {
|
ChunkType::MultiVMA(manager) => {
|
||||||
return manager
|
return manager
|
||||||
@ -696,7 +678,9 @@ impl InternalVMManager {
|
|||||||
munmap_range.unwrap()
|
munmap_range.unwrap()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
debug_assert!(chunk.range().is_superset_of(munmap_range));
|
|
||||||
|
// Either the munmap range is a subset of the chunk range or the munmap range is
|
||||||
|
// a superset of the chunk range. We can handle both cases.
|
||||||
|
|
||||||
let mut vma = vma.lock().unwrap();
|
let mut vma = vma.lock().unwrap();
|
||||||
debug_assert!(chunk.range() == vma.range());
|
debug_assert!(chunk.range() == vma.range());
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#define ALIGN_UP(x, a) ALIGN_DOWN((x+(a-1)), (a))
|
#define ALIGN_UP(x, a) ALIGN_DOWN((x+(a-1)), (a))
|
||||||
|
|
||||||
#define MAX_MMAP_USED_MEMORY (4 * MB)
|
#define MAX_MMAP_USED_MEMORY (4 * MB)
|
||||||
|
#define DEFAULT_CHUNK_SIZE (32 * MB) // This is the default chunk size used in Occlum kernel.
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Helper functions
|
// Helper functions
|
||||||
@ -676,6 +677,49 @@ int test_munmap_whose_range_intersects_with_multiple_mmap_regions() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int test_munmap_whose_range_intersects_with_several_chunks() {
|
||||||
|
int prot = PROT_READ | PROT_WRITE;
|
||||||
|
int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
|
||||||
|
size_t len = 1 * MB;
|
||||||
|
|
||||||
|
// Allocate three continuous single vma chunks at the end of the default chunk
|
||||||
|
size_t hint_1 = HINT_BEGIN + DEFAULT_CHUNK_SIZE;
|
||||||
|
void *addr = mmap((void *)hint_1, len, prot, flags, -1, 0);
|
||||||
|
if ((size_t)addr != hint_1) {
|
||||||
|
THROW_ERROR("fixed mmap with good hint failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t hint_2 = hint_1 + len;
|
||||||
|
addr = mmap((void *)hint_2, len, prot, flags, -1, 0);
|
||||||
|
if ((size_t)addr != hint_2) {
|
||||||
|
THROW_ERROR("fixed mmap spans over two chunks failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t hint_3 = hint_2 + len;
|
||||||
|
addr = mmap((void *)hint_3, len, prot, flags, -1, 0);
|
||||||
|
if ((size_t)addr != hint_3) {
|
||||||
|
THROW_ERROR("fixed mmap spans over two chunks failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Munmap the range spans above three ranges
|
||||||
|
size_t munmap_start = hint_1 + len / 2;
|
||||||
|
size_t munmap_end = hint_3 + len / 2;
|
||||||
|
|
||||||
|
if (munmap((void *)munmap_start, munmap_end - munmap_start) < 0) {
|
||||||
|
THROW_ERROR("munmap failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_buf_is_munmapped((void *)munmap_start, munmap_end - munmap_start) < 0) {
|
||||||
|
THROW_ERROR("munmap does not really free the memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (munmap((void *)hint_1, 3 * len) < 0) {
|
||||||
|
THROW_ERROR("munmap remaining ranges failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int test_munmap_with_null_addr() {
|
int test_munmap_with_null_addr() {
|
||||||
// Set the address for munmap to NULL!
|
// Set the address for munmap to NULL!
|
||||||
//
|
//
|
||||||
@ -1328,6 +1372,7 @@ static test_case_t test_cases[] = {
|
|||||||
TEST_CASE(test_munmap_whose_range_intersects_with_a_mmap_region),
|
TEST_CASE(test_munmap_whose_range_intersects_with_a_mmap_region),
|
||||||
TEST_CASE(test_munmap_whose_range_intersects_with_no_mmap_regions),
|
TEST_CASE(test_munmap_whose_range_intersects_with_no_mmap_regions),
|
||||||
TEST_CASE(test_munmap_whose_range_intersects_with_multiple_mmap_regions),
|
TEST_CASE(test_munmap_whose_range_intersects_with_multiple_mmap_regions),
|
||||||
|
TEST_CASE(test_munmap_whose_range_intersects_with_several_chunks),
|
||||||
TEST_CASE(test_munmap_with_null_addr),
|
TEST_CASE(test_munmap_with_null_addr),
|
||||||
TEST_CASE(test_munmap_with_zero_len),
|
TEST_CASE(test_munmap_with_zero_len),
|
||||||
TEST_CASE(test_munmap_with_non_page_aligned_len),
|
TEST_CASE(test_munmap_with_non_page_aligned_len),
|
||||||
|
Loading…
Reference in New Issue
Block a user