From 68dcc611510a225d04130b9a4f1e7b1a81671718 Mon Sep 17 00:00:00 2001 From: mingzi Date: Tue, 27 May 2025 22:20:16 +0800 Subject: [PATCH 01/11] Add basic COW --- api/src/imp/task/clone.rs | 2 +- apps/oscomp/test_fork.c | 51 ++++++++++++++++++++++++++++++++++++ apps/oscomp/test_fork_mmap.c | 41 +++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 apps/oscomp/test_fork.c create mode 100644 apps/oscomp/test_fork_mmap.c diff --git a/api/src/imp/task/clone.rs b/api/src/imp/task/clone.rs index ea848d3a..da68cbf8 100644 --- a/api/src/imp/task/clone.rs +++ b/api/src/imp/task/clone.rs @@ -153,7 +153,7 @@ pub fn sys_clone( curr.task_ext().process_data().aspace.clone() } else { let mut aspace = curr.task_ext().process_data().aspace.lock(); - let mut aspace = aspace.clone_or_err()?; + let mut aspace = aspace.copy_with_cow()?; copy_from_kernel(&mut aspace)?; Arc::new(Mutex::new(aspace)) }; diff --git a/apps/oscomp/test_fork.c b/apps/oscomp/test_fork.c new file mode 100644 index 00000000..2222b9c5 --- /dev/null +++ b/apps/oscomp/test_fork.c @@ -0,0 +1,51 @@ +// Test that fork fails gracefully. +// Tiny executable so that the limit can be filling the proc table. +#include +#include +#include +#include + +#define N 1000 + + +void +forktest(void) +{ + int n, pid; + + printf("fork test\n"); + + for(n=0; n 0; n--){ + if(wait(0) < 0){ + printf("wait stopped early\n"); + exit(1); + } + } + + if(wait(0) != -1){ + printf("wait got too many\n"); + exit(1); + } + + printf("fork test OK\n"); +} + +int +main(void) +{ + forktest(); + exit(0); +} diff --git a/apps/oscomp/test_fork_mmap.c b/apps/oscomp/test_fork_mmap.c new file mode 100644 index 00000000..468e25fc --- /dev/null +++ b/apps/oscomp/test_fork_mmap.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include + +#define N 100 + +void test() { + int num_size = (10 * 1024 * 1024) / sizeof(int); + + int *ptr = mmap(NULL, sizeof(int) * num_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + int i = 0; + for (i = 0; i < num_size; i++) { + *(ptr + i) = i; + } + + int pid; + for (i = 0 ; i < N; i++) { + pid = fork(); + if (pid == 0) { + printf("i = %d sleep ....\n", i); + + sleep(5); + exit(0); + } else if (pid < 0) { + exit(1); + } + } + + for (i = 0; i < N; i++) { + wait(0); + } + + printf("pass!!!\n"); + exit(0); +} + +int main() { + test(); +} From 4959ab587d175ab6b80b0e428fc9b9a086e7a8fb Mon Sep 17 00:00:00 2001 From: mingzi Date: Tue, 3 Jun 2025 17:49:09 +0800 Subject: [PATCH 02/11] feat: add fork test suite to libc - Move fork tests from oscomp to libc - Add new forkcow test case - Update testcase_list and expected output --- apps/libc/c/forkcow/forkcow.c | 42 +++++++++++++++++++++++++++++ apps/libc/expect_off.out | 3 +++ apps/libc/testcase_list | 1 + apps/oscomp/test_fork.c | 51 ----------------------------------- apps/oscomp/test_fork_mmap.c | 41 ---------------------------- 5 files changed, 46 insertions(+), 92 deletions(-) create mode 100644 apps/libc/c/forkcow/forkcow.c delete mode 100644 apps/oscomp/test_fork.c delete mode 100644 apps/oscomp/test_fork_mmap.c diff --git a/apps/libc/c/forkcow/forkcow.c b/apps/libc/c/forkcow/forkcow.c new file mode 100644 index 00000000..27e1b7e3 --- /dev/null +++ b/apps/libc/c/forkcow/forkcow.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include + +#define N 150 + +void forktest(void) { + int n, pid; + + printf("fork test\n"); + + for (n = 0; n < N; n++) { + pid = fork(); + if (pid < 0) + break; + if (pid == 0) + exit(0); + } + + if (n == N) { + printf("fork test OK\n"); + exit(0); + } + + for (; n > 0; n--) { + if (wait(0) < 0) { + printf("wait stopped early\n"); + exit(1); + } + } + + if (wait(0) != -1) { + printf("wait got too many\n"); + exit(1); + } +} + +int main(void) { + forktest(); + exit(1); +} diff --git a/apps/libc/expect_off.out b/apps/libc/expect_off.out index 4e86961f..3c428cb4 100644 --- a/apps/libc/expect_off.out +++ b/apps/libc/expect_off.out @@ -22,3 +22,6 @@ test_sigwait ok3 test_sigsuspend ok1 test_sigsuspend ok2 test_sigsuspend ok3 + +fork test +fork test OK diff --git a/apps/libc/testcase_list b/apps/libc/testcase_list index 105ab97a..0b0ffa62 100644 --- a/apps/libc/testcase_list +++ b/apps/libc/testcase_list @@ -1,3 +1,4 @@ helloworld_c sleep_c signal_c +forkcow_c diff --git a/apps/oscomp/test_fork.c b/apps/oscomp/test_fork.c deleted file mode 100644 index 2222b9c5..00000000 --- a/apps/oscomp/test_fork.c +++ /dev/null @@ -1,51 +0,0 @@ -// Test that fork fails gracefully. -// Tiny executable so that the limit can be filling the proc table. -#include -#include -#include -#include - -#define N 1000 - - -void -forktest(void) -{ - int n, pid; - - printf("fork test\n"); - - for(n=0; n 0; n--){ - if(wait(0) < 0){ - printf("wait stopped early\n"); - exit(1); - } - } - - if(wait(0) != -1){ - printf("wait got too many\n"); - exit(1); - } - - printf("fork test OK\n"); -} - -int -main(void) -{ - forktest(); - exit(0); -} diff --git a/apps/oscomp/test_fork_mmap.c b/apps/oscomp/test_fork_mmap.c deleted file mode 100644 index 468e25fc..00000000 --- a/apps/oscomp/test_fork_mmap.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include -#include -#include -#include - -#define N 100 - -void test() { - int num_size = (10 * 1024 * 1024) / sizeof(int); - - int *ptr = mmap(NULL, sizeof(int) * num_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - int i = 0; - for (i = 0; i < num_size; i++) { - *(ptr + i) = i; - } - - int pid; - for (i = 0 ; i < N; i++) { - pid = fork(); - if (pid == 0) { - printf("i = %d sleep ....\n", i); - - sleep(5); - exit(0); - } else if (pid < 0) { - exit(1); - } - } - - for (i = 0; i < N; i++) { - wait(0); - } - - printf("pass!!!\n"); - exit(0); -} - -int main() { - test(); -} From 41bac14d11fd59b0fdc4bad7d44065e31a3d59b9 Mon Sep 17 00:00:00 2001 From: mingzi Date: Thu, 12 Jun 2025 16:26:21 +0800 Subject: [PATCH 03/11] chore: aspace.populate_area => aspace.ensure_region_mapped --- api/src/ptr.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/src/ptr.rs b/api/src/ptr.rs index 2c4d3b20..e3eb9d82 100644 --- a/api/src/ptr.rs +++ b/api/src/ptr.rs @@ -24,7 +24,11 @@ fn check_region(start: VirtAddr, layout: Layout, access_flags: MappingFlags) -> let page_start = start.align_down_4k(); let page_end = (start + layout.size()).align_up_4k(); - aspace.populate_area(page_start, page_end - page_start)?; + aspace.ensure_region_mapped( + page_start, + page_end - page_start, + access_flags.contains(MappingFlags::WRITE), + )?; Ok(()) } From 3fea7ef463eeeb7e713cad31550167d222eb5b89 Mon Sep 17 00:00:00 2001 From: mingzi Date: Mon, 16 Jun 2025 19:16:30 +0800 Subject: [PATCH 04/11] refactor: replace copy_with_cow with try_clone in process cloning - Rename ensure_region_mapped to populate_area - Simplify address space handling in clone syscall --- api/src/imp/task/clone.rs | 2 +- api/src/ptr.rs | 4 ++-- apps/libc/c/forkcow/forkcow.c | 9 +++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/api/src/imp/task/clone.rs b/api/src/imp/task/clone.rs index da68cbf8..5308a117 100644 --- a/api/src/imp/task/clone.rs +++ b/api/src/imp/task/clone.rs @@ -153,7 +153,7 @@ pub fn sys_clone( curr.task_ext().process_data().aspace.clone() } else { let mut aspace = curr.task_ext().process_data().aspace.lock(); - let mut aspace = aspace.copy_with_cow()?; + let mut aspace = aspace.try_clone()?; copy_from_kernel(&mut aspace)?; Arc::new(Mutex::new(aspace)) }; diff --git a/api/src/ptr.rs b/api/src/ptr.rs index e3eb9d82..3f9a05d0 100644 --- a/api/src/ptr.rs +++ b/api/src/ptr.rs @@ -24,10 +24,10 @@ fn check_region(start: VirtAddr, layout: Layout, access_flags: MappingFlags) -> let page_start = start.align_down_4k(); let page_end = (start + layout.size()).align_up_4k(); - aspace.ensure_region_mapped( + aspace.populate_area( page_start, page_end - page_start, - access_flags.contains(MappingFlags::WRITE), + access_flags, )?; Ok(()) diff --git a/apps/libc/c/forkcow/forkcow.c b/apps/libc/c/forkcow/forkcow.c index 27e1b7e3..fcb4d3d5 100644 --- a/apps/libc/c/forkcow/forkcow.c +++ b/apps/libc/c/forkcow/forkcow.c @@ -2,14 +2,23 @@ #include #include #include +#include #define N 150 +#define LEN (1024 * 1024) void forktest(void) { int n, pid; printf("fork test\n"); + char *ptr = mmap(NULL, LEN * sizeof(char), PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + for (n = 0; n < LEN; n++) { + *(ptr + n) = 'a'; + } + for (n = 0; n < N; n++) { pid = fork(); if (pid < 0) From 397a35636d8f157f7b66c9cecc55a65bdbc811b5 Mon Sep 17 00:00:00 2001 From: mingzi Date: Mon, 16 Jun 2025 19:21:14 +0800 Subject: [PATCH 05/11] style: cargo fmt --- api/src/ptr.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/api/src/ptr.rs b/api/src/ptr.rs index 3f9a05d0..ff48c5ab 100644 --- a/api/src/ptr.rs +++ b/api/src/ptr.rs @@ -24,11 +24,7 @@ fn check_region(start: VirtAddr, layout: Layout, access_flags: MappingFlags) -> let page_start = start.align_down_4k(); let page_end = (start + layout.size()).align_up_4k(); - aspace.populate_area( - page_start, - page_end - page_start, - access_flags, - )?; + aspace.populate_area(page_start, page_end - page_start, access_flags)?; Ok(()) } From 98f3b7b3a9929e2d20adbe8fdc73e11d05c0f450 Mon Sep 17 00:00:00 2001 From: mingzi Date: Mon, 16 Jun 2025 19:38:59 +0800 Subject: [PATCH 06/11] build: cow features --- Cargo.lock | 11 ++++++++++- Cargo.toml | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 792887f0..c1fd0fb2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -349,11 +349,11 @@ dependencies = [ "axerrno", "axhal", "kspin", + "lazy_static", "lazyinit", "log", "memory_addr", "memory_set", - "page_table_multiarch", ] [[package]] @@ -829,6 +829,15 @@ dependencies = [ "kernel_guard", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + [[package]] name = "lazyinit" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index f5fd7f96..41ff9945 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ axconfig = { git = "https://github.com/oscomp/arceos.git" } axfs = { git = "https://github.com/oscomp/arceos.git" } axhal = { git = "https://github.com/oscomp/arceos.git", features = ["uspace"] } axlog = { git = "https://github.com/oscomp/arceos.git" } -axmm = { git = "https://github.com/oscomp/arceos.git" } +axmm = { git = "https://github.com/oscomp/arceos.git", features = ["cow"] } axnet = { git = "https://github.com/oscomp/arceos.git" } axns = { git = "https://github.com/oscomp/arceos.git", features = [ "thread-local", From 03af5090bd0bb55580d253a5dd3cc03841727f26 Mon Sep 17 00:00:00 2001 From: mingzi Date: Mon, 16 Jun 2025 19:39:18 +0800 Subject: [PATCH 07/11] build: adapt huge page --- api/src/imp/mm/mmap.rs | 7 +++++-- core/src/mm.rs | 13 ++++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/api/src/imp/mm/mmap.rs b/api/src/imp/mm/mmap.rs index 57958edb..44834a37 100644 --- a/api/src/imp/mm/mmap.rs +++ b/api/src/imp/mm/mmap.rs @@ -1,6 +1,6 @@ use alloc::vec; use axerrno::{LinuxError, LinuxResult}; -use axhal::paging::MappingFlags; +use axhal::paging::{MappingFlags, PageSize}; use axtask::{TaskExtRef, current}; use linux_raw_sys::general::{ MAP_ANONYMOUS, MAP_FIXED, MAP_NORESERVE, MAP_PRIVATE, MAP_SHARED, MAP_STACK, PROT_EXEC, @@ -108,11 +108,13 @@ pub fn sys_mmap( VirtAddr::from(start), aligned_length, VirtAddrRange::new(aspace.base(), aspace.end()), + PageSize::Size4K, ) .or(aspace.find_free_area( aspace.base(), aligned_length, VirtAddrRange::new(aspace.base(), aspace.end()), + PageSize::Size4K, )) .ok_or(LinuxError::ENOMEM)? }; @@ -128,6 +130,7 @@ pub fn sys_mmap( aligned_length, permission_flags.into(), populate, + PageSize::Size4K, )?; if populate { @@ -141,7 +144,7 @@ pub fn sys_mmap( let length = core::cmp::min(length, file_size - offset); let mut buf = vec![0u8; length]; file.read_at(offset as u64, &mut buf)?; - aspace.write(start_addr, &buf)?; + aspace.write(start_addr, PageSize::Size4K, &buf)?; } Ok(start_addr.as_usize() as _) } diff --git a/core/src/mm.rs b/core/src/mm.rs index 98cfb259..a99cc40f 100644 --- a/core/src/mm.rs +++ b/core/src/mm.rs @@ -4,7 +4,10 @@ use core::ffi::CStr; use alloc::{borrow::ToOwned, string::String, vec, vec::Vec}; use axerrno::{AxError, AxResult}; -use axhal::{mem::virt_to_phys, paging::MappingFlags}; +use axhal::{ + mem::virt_to_phys, + paging::{MappingFlags, PageSize}, +}; use axmm::{AddrSpace, kernel_aspace}; use kernel_elf_parser::{AuxvEntry, ELFParser, app_stack_region}; use memory_addr::{MemoryAddr, PAGE_SIZE_4K, VirtAddr}; @@ -38,6 +41,7 @@ pub fn map_trampoline(aspace: &mut AddrSpace) -> AxResult { signal_trampoline_paddr, PAGE_SIZE_4K, MappingFlags::READ | MappingFlags::EXECUTE | MappingFlags::USER, + PageSize::Size4K, )?; Ok(()) } @@ -77,12 +81,13 @@ fn map_elf(uspace: &mut AddrSpace, elf: &ElfFile) -> AxResult<(VirtAddr, [AuxvEn seg_align_size, segement.flags, true, + PageSize::Size4K, )?; let seg_data = elf .input .get(segement.offset..segement.offset + segement.filesz as usize) .ok_or(AxError::InvalidData)?; - uspace.write(segement.vaddr, seg_data)?; + uspace.write(segement.vaddr, PageSize::Size4K, seg_data)?; // TDOO: flush the I-cache } @@ -175,6 +180,7 @@ pub fn load_user_app( ustack_size, MappingFlags::READ | MappingFlags::WRITE | MappingFlags::USER, true, + PageSize::Size4K, )?; let heap_start = VirtAddr::from_usize(axconfig::plat::USER_HEAP_BASE); @@ -184,11 +190,12 @@ pub fn load_user_app( heap_size, MappingFlags::READ | MappingFlags::WRITE | MappingFlags::USER, true, + PageSize::Size4K, )?; let user_sp = ustack_end - stack_data.len(); - uspace.write(user_sp, stack_data.as_slice())?; + uspace.write(user_sp, PageSize::Size4K, stack_data.as_slice())?; Ok((entry, user_sp)) } From d3a106fbdbee7fb4d2fb94ff58e867e09f3e230c Mon Sep 17 00:00:00 2001 From: mingzi Date: Mon, 16 Jun 2025 20:02:02 +0800 Subject: [PATCH 08/11] build: update arceos commit --- scripts/get_deps.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/get_deps.sh b/scripts/get_deps.sh index 9b774a39..eea6e2f4 100755 --- a/scripts/get_deps.sh +++ b/scripts/get_deps.sh @@ -1,7 +1,7 @@ #!/bin/bash AX_ROOT=.arceos -COMMIT=c747ba8 +COMMIT=54d5739 test ! -d "$AX_ROOT" && echo "Cloning repositories ..." || true test ! -d "$AX_ROOT" && git clone https://github.com/oscomp/arceos "$AX_ROOT" || true From 800bf6ac71b127e8be378341733cd867e979dceb Mon Sep 17 00:00:00 2001 From: mingzi Date: Tue, 17 Jun 2025 17:18:11 +0800 Subject: [PATCH 09/11] build: Update `page_table_multiarch` to support `cow` --- Cargo.lock | 4 ++-- Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c1fd0fb2..7d624bcb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -992,7 +992,7 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "page_table_entry" version = "0.5.3" -source = "git+https://github.com/Mivik/page_table_multiarch.git?rev=19ededd#19ededdb806ab3b22efb4880661790524fa421a5" +source = "git+https://github.com/Mivik/page_table_multiarch.git?rev=5c222f2#5c222f2199a6c566e9009dca8d86a589b4f66757" dependencies = [ "aarch64-cpu", "bitflags 2.9.0", @@ -1003,7 +1003,7 @@ dependencies = [ [[package]] name = "page_table_multiarch" version = "0.5.3" -source = "git+https://github.com/Mivik/page_table_multiarch.git?rev=19ededd#19ededdb806ab3b22efb4880661790524fa421a5" +source = "git+https://github.com/Mivik/page_table_multiarch.git?rev=5c222f2#5c222f2199a6c566e9009dca8d86a589b4f66757" dependencies = [ "log", "memory_addr", diff --git a/Cargo.toml b/Cargo.toml index 264dd704..7c776b96 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -90,5 +90,5 @@ shlex = { version = "1.3.0", default-features = false } syscalls = { git = "https://github.com/jasonwhite/syscalls.git", rev = "92624de", default-features = false } [patch.crates-io] -page_table_multiarch = { git = "https://github.com/Mivik/page_table_multiarch.git", rev = "19ededd" } -page_table_entry = { git = "https://github.com/Mivik/page_table_multiarch.git", rev = "19ededd" } +page_table_multiarch = { git = "https://github.com/Mivik/page_table_multiarch.git", rev = "5c222f2" } +page_table_entry = { git = "https://github.com/Mivik/page_table_multiarch.git", rev = "5c222f2" } From 3b09be3e76fc40f1fa9bcf5d837264a8fd1602e6 Mon Sep 17 00:00:00 2001 From: mingzi Date: Tue, 17 Jun 2025 17:22:47 +0800 Subject: [PATCH 10/11] build: update arceos commit a634925 --- scripts/get_deps.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/get_deps.sh b/scripts/get_deps.sh index eea6e2f4..7bceed1d 100755 --- a/scripts/get_deps.sh +++ b/scripts/get_deps.sh @@ -1,7 +1,7 @@ #!/bin/bash AX_ROOT=.arceos -COMMIT=54d5739 +COMMIT=a634925 test ! -d "$AX_ROOT" && echo "Cloning repositories ..." || true test ! -d "$AX_ROOT" && git clone https://github.com/oscomp/arceos "$AX_ROOT" || true From 01150432bebe767e3a0fbc46e915b09ca8349dc2 Mon Sep 17 00:00:00 2001 From: mingzi Date: Tue, 17 Jun 2025 17:39:25 +0800 Subject: [PATCH 11/11] build: Adjust the order of the test programs `mmap` and `forkcow` --- apps/libc/testcase_list | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/libc/testcase_list b/apps/libc/testcase_list index 7ef36de6..97999977 100644 --- a/apps/libc/testcase_list +++ b/apps/libc/testcase_list @@ -1,5 +1,5 @@ helloworld_c sleep_c signal_c -mmap_c forkcow_c +mmap_c