From 464598633740a455b9f498b834996aa8fc5696dd Mon Sep 17 00:00:00 2001 From: Jianfeng Jiang Date: Wed, 1 Mar 2023 19:18:45 +0800 Subject: [PATCH] add vmo and vmar tests; forbid clone vmo --- src/Cargo.lock | 1 + .../comp-sys/component-macro/src/lib.rs | 2 +- .../libs/jinux-std/src/fs/utils/vnode.rs | 3 +- .../libs/jinux-std/src/vm/vmar/options.rs | 83 ++++++++++++++++ .../libs/jinux-std/src/vm/vmar/vm_mapping.rs | 2 +- .../libs/jinux-std/src/vm/vmo/dyn_cap.rs | 6 -- .../libs/jinux-std/src/vm/vmo/options.rs | 96 +++++++++++++++++++ 7 files changed, 183 insertions(+), 10 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index da8025f30..c3699b570 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -316,6 +316,7 @@ dependencies = [ "ascii", "bitflags", "controlled", + "cpio-decoder", "intrusive-collections", "jinux-block", "jinux-frame", diff --git a/src/services/comp-sys/component-macro/src/lib.rs b/src/services/comp-sys/component-macro/src/lib.rs index dc317a06a..5fb3c8f2b 100644 --- a/src/services/comp-sys/component-macro/src/lib.rs +++ b/src/services/comp-sys/component-macro/src/lib.rs @@ -57,7 +57,7 @@ pub fn init_component(_: TokenStream, input: TokenStream) -> proc_macro::TokenSt } /// Automatically generate all component information required by the component system. -/// +/// /// It mainly uses the output of the command `cargo metadata` to automatically generate information about all components, and also checks whether `Components.toml` contains all the components. /// /// It is often used with `component::init_all`. diff --git a/src/services/libs/jinux-std/src/fs/utils/vnode.rs b/src/services/libs/jinux-std/src/fs/utils/vnode.rs index 3c827cc67..c690a9f04 100644 --- a/src/services/libs/jinux-std/src/fs/utils/vnode.rs +++ b/src/services/libs/jinux-std/src/fs/utils/vnode.rs @@ -1,5 +1,4 @@ use crate::prelude::*; - use super::{DirentWriterContext, Inode, InodeMode, InodeType, Metadata, PageCacheManager}; use crate::rights::Rights; use crate::vm::vmo::{Vmo, VmoFlags, VmoOptions}; @@ -22,7 +21,7 @@ struct Inner { impl Vnode { pub fn new(inode: Arc) -> Result { let page_cache_manager = Arc::new(PageCacheManager::new(&Arc::downgrade(&inode))); - let page_cache = VmoOptions::::new(inode.len()) + let page_cache = VmoOptions::::new(inode.metadata().size) .flags(VmoFlags::RESIZABLE) .pager(page_cache_manager.clone()) .alloc()?; diff --git a/src/services/libs/jinux-std/src/vm/vmar/options.rs b/src/services/libs/jinux-std/src/vm/vmar/options.rs index 3f5cb4e71..63bb29515 100644 --- a/src/services/libs/jinux-std/src/vm/vmar/options.rs +++ b/src/services/libs/jinux-std/src/vm/vmar/options.rs @@ -131,3 +131,86 @@ impl VmarChildOptions { Ok(child_vmar) } } + +#[cfg(test)] +mod test { + use super::*; + use crate::vm::page_fault_handler::PageFaultHandler; + use crate::vm::perms::VmPerms; + use crate::vm::vmo::VmoRightsOp; + use crate::{ + rights::Full, + vm::{vmar::ROOT_VMAR_HIGHEST_ADDR, vmo::VmoOptions}, + }; + use jinux_frame::vm::VmIo; + + #[test] + fn root_vmar() { + let vmar = Vmar::::new_root().unwrap(); + assert!(vmar.size() == ROOT_VMAR_HIGHEST_ADDR); + } + + #[test] + fn child_vmar() { + let root_vmar = Vmar::::new_root().unwrap(); + let root_vmar_dup = root_vmar.dup().unwrap(); + let child_vmar = VmarChildOptions::new(root_vmar_dup, 10 * PAGE_SIZE) + .alloc() + .unwrap(); + assert!(child_vmar.size() == 10 * PAGE_SIZE); + let root_vmar_dup = root_vmar.dup().unwrap(); + let second_child = VmarChildOptions::new(root_vmar_dup, 9 * PAGE_SIZE) + .alloc() + .unwrap(); + let root_vmar_dup = root_vmar.dup().unwrap(); + assert!(VmarChildOptions::new(root_vmar_dup, 9 * PAGE_SIZE) + .offset(11 * PAGE_SIZE) + .alloc() + .is_err()); + } + + #[test] + fn map_vmo() { + let root_vmar = Vmar::::new_root().unwrap(); + let vmo = VmoOptions::::new(PAGE_SIZE).alloc().unwrap().to_dyn(); + let perms = VmPerms::READ | VmPerms::WRITE; + let map_offset = 0x1000_0000; + let vmo_dup = vmo.dup().unwrap(); + root_vmar + .new_map(vmo_dup, perms) + .unwrap() + .offset(map_offset) + .build() + .unwrap(); + root_vmar.write_val(map_offset, &100u8).unwrap(); + assert!(root_vmar.read_val::(map_offset).unwrap() == 100); + let another_map_offset = 0x1100_0000; + let vmo_dup = vmo.dup().unwrap(); + root_vmar + .new_map(vmo_dup, perms) + .unwrap() + .offset(another_map_offset) + .build() + .unwrap(); + assert!(root_vmar.read_val::(another_map_offset).unwrap() == 100); + } + + #[test] + fn handle_page_fault() { + const OFFSET: usize = 0x1000_0000; + let root_vmar = Vmar::::new_root().unwrap(); + // the page is not mapped by a vmo + assert!(root_vmar.handle_page_fault(OFFSET, true, true).is_err()); + // the page is mapped READ + let vmo = VmoOptions::::new(PAGE_SIZE).alloc().unwrap().to_dyn(); + let perms = VmPerms::READ; + let vmo_dup = vmo.dup().unwrap(); + root_vmar + .new_map(vmo_dup, perms) + .unwrap() + .offset(OFFSET) + .build() + .unwrap(); + root_vmar.handle_page_fault(OFFSET, true, false).unwrap(); + } +} diff --git a/src/services/libs/jinux-std/src/vm/vmar/vm_mapping.rs b/src/services/libs/jinux-std/src/vm/vmar/vm_mapping.rs index 97c2683ff..8c755a9e2 100644 --- a/src/services/libs/jinux-std/src/vm/vmar/vm_mapping.rs +++ b/src/services/libs/jinux-std/src/vm/vmar/vm_mapping.rs @@ -244,7 +244,7 @@ impl VmMapping { map_size, map_to_addr, } = self; - let parent_vmo = vmo.clone(); + let parent_vmo = vmo.dup().unwrap(); let vmo_size = parent_vmo.size(); let child_vmo = VmoChildOptions::new_cow(parent_vmo, 0..vmo_size).alloc()?; let parent_vmar = new_parent.upgrade().unwrap(); diff --git a/src/services/libs/jinux-std/src/vm/vmo/dyn_cap.rs b/src/services/libs/jinux-std/src/vm/vmo/dyn_cap.rs index 7c32a4ddd..1dbec4a51 100644 --- a/src/services/libs/jinux-std/src/vm/vmo/dyn_cap.rs +++ b/src/services/libs/jinux-std/src/vm/vmo/dyn_cap.rs @@ -149,12 +149,6 @@ impl Vmo { } } -impl Clone for Vmo { - fn clone(&self) -> Self { - Self(self.0.clone(), self.1.clone()) - } -} - impl VmIo for Vmo { fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> jinux_frame::Result<()> { self.check_rights(Rights::READ)?; diff --git a/src/services/libs/jinux-std/src/vm/vmo/options.rs b/src/services/libs/jinux-std/src/vm/vmo/options.rs index 31857f941..6addb829d 100644 --- a/src/services/libs/jinux-std/src/vm/vmo/options.rs +++ b/src/services/libs/jinux-std/src/vm/vmo/options.rs @@ -522,3 +522,99 @@ impl VmoChildType for VmoSliceChild {} #[derive(Copy, Clone, Debug)] pub struct VmoCowChild; impl VmoChildType for VmoCowChild {} + +#[cfg(test)] +mod test { + use super::*; + use crate::rights::Full; + use jinux_frame::vm::VmIo; + + #[test] + fn alloc_vmo() { + let vmo = VmoOptions::::new(PAGE_SIZE).alloc().unwrap(); + assert!(vmo.size() == PAGE_SIZE); + // the vmo is zeroed once allocated + assert!(vmo.read_val::(0).unwrap() == 0); + } + + #[test] + #[should_panic] + /// FIXME: alloc continuous frames is not supported now + fn alloc_continuous_vmo() { + let vmo = VmoOptions::::new(10 * PAGE_SIZE) + .flags(VmoFlags::CONTIGUOUS) + .alloc() + .unwrap(); + assert!(vmo.size() == 10 * PAGE_SIZE); + } + + #[test] + fn write_and_read() { + let vmo = VmoOptions::::new(PAGE_SIZE).alloc().unwrap(); + let val = 42u8; + // write val + vmo.write_val(111, &val).unwrap(); + let read_val: u8 = vmo.read_val(111).unwrap(); + assert!(val == read_val); + // bit endian + vmo.write_bytes(222, &[0x12, 0x34, 0x56, 0x78]).unwrap(); + let read_val: u32 = vmo.read_val(222).unwrap(); + assert!(read_val == 0x78563412) + } + + #[test] + fn slice_child() { + let parent = VmoOptions::::new(2 * PAGE_SIZE).alloc().unwrap(); + let parent_dup = parent.dup().unwrap(); + let slice_child = VmoChildOptions::new_slice(parent_dup, 0..PAGE_SIZE) + .alloc() + .unwrap(); + // write parent, read child + parent.write_val(1, &42u8).unwrap(); + assert!(slice_child.read_val::(1).unwrap() == 42); + // write child, read parent + slice_child.write_val(99, &0x1234u32).unwrap(); + assert!(parent.read_val::(99).unwrap() == 0x1234); + } + + #[test] + fn cow_child() { + let parent = VmoOptions::::new(2 * PAGE_SIZE).alloc().unwrap(); + let parent_dup = parent.dup().unwrap(); + let cow_child = VmoChildOptions::new_cow(parent_dup, 0..10 * PAGE_SIZE) + .alloc() + .unwrap(); + // write parent, read child + parent.write_val(1, &42u8).unwrap(); + assert!(cow_child.read_val::(1).unwrap() == 42); + // write child to trigger copy on write, read child and parent + cow_child.write_val(99, &0x1234u32).unwrap(); + assert!(cow_child.read_val::(99).unwrap() == 0x1234); + assert!(cow_child.read_val::(1).unwrap() == 42); + assert!(parent.read_val::(99).unwrap() == 0); + assert!(parent.read_val::(1).unwrap() == 42); + // write parent on already-copied page + parent.write_val(10, &123u8).unwrap(); + assert!(parent.read_val::(10).unwrap() == 123); + assert!(cow_child.read_val::(10).unwrap() == 0); + // write parent on not-copied page + parent.write_val(PAGE_SIZE + 10, &12345u32).unwrap(); + assert!(parent.read_val::(PAGE_SIZE + 10).unwrap() == 12345); + assert!(cow_child.read_val::(PAGE_SIZE + 10).unwrap() == 12345); + } + + #[test] + fn resize() { + let vmo = VmoOptions::::new(PAGE_SIZE) + .flags(VmoFlags::RESIZABLE) + .alloc() + .unwrap(); + vmo.write_val(10, &42u8).unwrap(); + vmo.resize(2 * PAGE_SIZE).unwrap(); + assert!(vmo.size() == 2 * PAGE_SIZE); + assert!(vmo.read_val::(10).unwrap() == 42); + vmo.write_val(PAGE_SIZE + 20, &123u8).unwrap(); + vmo.resize(PAGE_SIZE).unwrap(); + assert!(vmo.read_val::(10).unwrap() == 42); + } +}