[libos] Fix munmap conflict chunk range and vma range
This commit is contained in:
parent
61b9639081
commit
171faccea7
@ -54,6 +54,7 @@ impl Eq for Chunk {}
|
|||||||
|
|
||||||
impl Debug for Chunk {
|
impl Debug for Chunk {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "range = {:?}, ", self.range);
|
||||||
match self.internal() {
|
match self.internal() {
|
||||||
ChunkType::SingleVMA(vma) => write!(f, "Single VMA chunk: {:?}", vma),
|
ChunkType::SingleVMA(vma) => write!(f, "Single VMA chunk: {:?}", vma),
|
||||||
ChunkType::MultiVMA(internal_manager) => write!(f, "default chunk: {:?}", self.range()),
|
ChunkType::MultiVMA(internal_manager) => write!(f, "default chunk: {:?}", self.range()),
|
||||||
|
@ -240,8 +240,8 @@ impl VMManager {
|
|||||||
align_up(size, PAGE_SIZE)
|
align_up(size, PAGE_SIZE)
|
||||||
};
|
};
|
||||||
let munmap_range = { VMRange::new_with_size(addr, size) }?;
|
let munmap_range = { VMRange::new_with_size(addr, size) }?;
|
||||||
|
let current = current!();
|
||||||
let chunk = {
|
let chunk = {
|
||||||
let current = current!();
|
|
||||||
let process_mem_chunks = current.vm().mem_chunks().read().unwrap();
|
let process_mem_chunks = current.vm().mem_chunks().read().unwrap();
|
||||||
let chunk = process_mem_chunks
|
let chunk = process_mem_chunks
|
||||||
.iter()
|
.iter()
|
||||||
@ -260,8 +260,10 @@ impl VMManager {
|
|||||||
// Case 1: the overlapping chunk IS NOT a super set of munmap range
|
// 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
|
||||||
|
|
||||||
|
// Must lock the internal manager first here in case the chunk's range and vma are conflict when other threads are operating the VM
|
||||||
|
let mut internal_manager = self.internal();
|
||||||
let overlapping_chunks = {
|
let overlapping_chunks = {
|
||||||
let current = current!();
|
|
||||||
let process_mem_chunks = current.vm().mem_chunks().read().unwrap();
|
let process_mem_chunks = current.vm().mem_chunks().read().unwrap();
|
||||||
process_mem_chunks
|
process_mem_chunks
|
||||||
.iter()
|
.iter()
|
||||||
@ -273,8 +275,7 @@ impl VMManager {
|
|||||||
for chunk in overlapping_chunks.iter() {
|
for chunk in overlapping_chunks.iter() {
|
||||||
match chunk.internal() {
|
match chunk.internal() {
|
||||||
ChunkType::SingleVMA(_) => {
|
ChunkType::SingleVMA(_) => {
|
||||||
let mut internl_manager = self.internal();
|
internal_manager.munmap_chunk(chunk, Some(&munmap_range))?
|
||||||
internl_manager.munmap_chunk(chunk, Some(&munmap_range))?
|
|
||||||
}
|
}
|
||||||
ChunkType::MultiVMA(manager) => manager
|
ChunkType::MultiVMA(manager) => manager
|
||||||
.lock()
|
.lock()
|
||||||
@ -297,8 +298,22 @@ impl VMManager {
|
|||||||
.munmap_range(munmap_range);
|
.munmap_range(munmap_range);
|
||||||
}
|
}
|
||||||
ChunkType::SingleVMA(_) => {
|
ChunkType::SingleVMA(_) => {
|
||||||
|
// Single VMA Chunk could be updated during the release of internal manager lock. Get overlapping chunk again.
|
||||||
|
// This is done here because we don't want to acquire the big internal manager lock as soon as entering this function.
|
||||||
let mut internal_manager = self.internal();
|
let mut internal_manager = self.internal();
|
||||||
return internal_manager.munmap_chunk(&chunk, Some(&munmap_range));
|
let overlapping_chunk = {
|
||||||
|
let process_mem_chunks = current.vm().mem_chunks().read().unwrap();
|
||||||
|
process_mem_chunks
|
||||||
|
.iter()
|
||||||
|
.find(|&chunk| chunk.range().intersect(&munmap_range).is_some())
|
||||||
|
.map(|chunk| chunk.clone())
|
||||||
|
};
|
||||||
|
if let Some(overlapping_chunk) = overlapping_chunk {
|
||||||
|
return internal_manager.munmap_chunk(&overlapping_chunk, Some(&munmap_range));
|
||||||
|
} else {
|
||||||
|
warn!("no overlapping chunks anymore");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
include ../test_common.mk
|
include ../test_common.mk
|
||||||
|
|
||||||
EXTRA_C_FLAGS := -Wno-return-stack-address
|
EXTRA_C_FLAGS := -Wno-return-stack-address
|
||||||
EXTRA_LINK_FLAGS :=
|
EXTRA_LINK_FLAGS := -lpthread
|
||||||
BIN_ARGS :=
|
BIN_ARGS :=
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
|
#include <pthread.h>
|
||||||
#include "test_fs.h"
|
#include "test_fs.h"
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@ -677,6 +678,78 @@ int test_munmap_whose_range_intersects_with_multiple_mmap_regions() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void *child_routine(void *_arg) {
|
||||||
|
size_t len = 1 * MB;
|
||||||
|
void *old_addr = _arg;
|
||||||
|
void *new_addr = old_addr + 3 * len;
|
||||||
|
|
||||||
|
void *addr = mremap(old_addr, len, 2 * len, MREMAP_MAYMOVE | MREMAP_FIXED,
|
||||||
|
new_addr);
|
||||||
|
if (addr != new_addr) {
|
||||||
|
printf("mremap fail in client routine\n");
|
||||||
|
return (void *) -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = munmap(addr, 2 * len);
|
||||||
|
if (ret < 0) {
|
||||||
|
printf("munmap failed");
|
||||||
|
return (void *) -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_mremap_concurrent() {
|
||||||
|
int prot = PROT_READ | PROT_WRITE;
|
||||||
|
int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
|
||||||
|
size_t len = 1 * MB;
|
||||||
|
void *child_ret;
|
||||||
|
|
||||||
|
// Allocate 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a child thread to mremap chunk from hint_2 to address after the chunk which starts with hint_3
|
||||||
|
pthread_t child_thread = 0;
|
||||||
|
int ret = pthread_create(&child_thread, NULL, child_routine, (void *)hint_2);
|
||||||
|
if (ret < 0) {
|
||||||
|
THROW_ERROR("pthread create failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// mremap chunk from hint_1 to hint_3
|
||||||
|
size_t hint_3 = hint_2 + len;
|
||||||
|
void *ret_addr = mremap((void *)hint_1, len, len * 2, MREMAP_MAYMOVE | MREMAP_FIXED,
|
||||||
|
(void *)hint_3);
|
||||||
|
if (ret_addr != (void *)hint_3) {
|
||||||
|
THROW_ERROR("mremap failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = pthread_join(child_thread, &child_ret);
|
||||||
|
if (ret < 0 || child_ret != NULL) {
|
||||||
|
THROW_ERROR("pthread_join failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (munmap((void *)hint_3, len * 2) < 0) {
|
||||||
|
THROW_ERROR("munmap failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_buf_is_munmapped((void *)hint_1, len * 5) < 0) {
|
||||||
|
THROW_ERROR("munmap does not really free the memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int test_munmap_whose_range_intersects_with_several_chunks() {
|
int test_munmap_whose_range_intersects_with_several_chunks() {
|
||||||
int prot = PROT_READ | PROT_WRITE;
|
int prot = PROT_READ | PROT_WRITE;
|
||||||
int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
|
int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
|
||||||
@ -1390,6 +1463,7 @@ static test_case_t test_cases[] = {
|
|||||||
TEST_CASE(test_mprotect_with_non_page_aligned_size),
|
TEST_CASE(test_mprotect_with_non_page_aligned_size),
|
||||||
TEST_CASE(test_mprotect_multiple_vmas),
|
TEST_CASE(test_mprotect_multiple_vmas),
|
||||||
TEST_CASE(test_mprotect_grow_down),
|
TEST_CASE(test_mprotect_grow_down),
|
||||||
|
TEST_CASE(test_mremap_concurrent),
|
||||||
};
|
};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
Loading…
Reference in New Issue
Block a user