add vmo and vmar tests; forbid clone vmo

This commit is contained in:
Jianfeng Jiang 2023-03-01 19:18:45 +08:00 committed by Tate, Hongliang Tian
parent 984a8259b2
commit 4645986337
7 changed files with 183 additions and 10 deletions

1
src/Cargo.lock generated
View File

@ -316,6 +316,7 @@ dependencies = [
"ascii",
"bitflags",
"controlled",
"cpio-decoder",
"intrusive-collections",
"jinux-block",
"jinux-frame",

View File

@ -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`.

View File

@ -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<dyn Inode>) -> Result<Self> {
let page_cache_manager = Arc::new(PageCacheManager::new(&Arc::downgrade(&inode)));
let page_cache = VmoOptions::<Rights>::new(inode.len())
let page_cache = VmoOptions::<Rights>::new(inode.metadata().size)
.flags(VmoFlags::RESIZABLE)
.pager(page_cache_manager.clone())
.alloc()?;

View File

@ -131,3 +131,86 @@ impl<R> VmarChildOptions<R> {
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::<Full>::new_root().unwrap();
assert!(vmar.size() == ROOT_VMAR_HIGHEST_ADDR);
}
#[test]
fn child_vmar() {
let root_vmar = Vmar::<Full>::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::<Full>::new_root().unwrap();
let vmo = VmoOptions::<Full>::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::<u8>(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::<u8>(another_map_offset).unwrap() == 100);
}
#[test]
fn handle_page_fault() {
const OFFSET: usize = 0x1000_0000;
let root_vmar = Vmar::<Full>::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::<Full>::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();
}
}

View File

@ -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();

View File

@ -149,12 +149,6 @@ impl Vmo<Rights> {
}
}
impl Clone for Vmo<Rights> {
fn clone(&self) -> Self {
Self(self.0.clone(), self.1.clone())
}
}
impl VmIo for Vmo<Rights> {
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> jinux_frame::Result<()> {
self.check_rights(Rights::READ)?;

View File

@ -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::<Full>::new(PAGE_SIZE).alloc().unwrap();
assert!(vmo.size() == PAGE_SIZE);
// the vmo is zeroed once allocated
assert!(vmo.read_val::<usize>(0).unwrap() == 0);
}
#[test]
#[should_panic]
/// FIXME: alloc continuous frames is not supported now
fn alloc_continuous_vmo() {
let vmo = VmoOptions::<Full>::new(10 * PAGE_SIZE)
.flags(VmoFlags::CONTIGUOUS)
.alloc()
.unwrap();
assert!(vmo.size() == 10 * PAGE_SIZE);
}
#[test]
fn write_and_read() {
let vmo = VmoOptions::<Full>::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::<Full>::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::<u8>(1).unwrap() == 42);
// write child, read parent
slice_child.write_val(99, &0x1234u32).unwrap();
assert!(parent.read_val::<u32>(99).unwrap() == 0x1234);
}
#[test]
fn cow_child() {
let parent = VmoOptions::<Full>::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::<u8>(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::<u32>(99).unwrap() == 0x1234);
assert!(cow_child.read_val::<u32>(1).unwrap() == 42);
assert!(parent.read_val::<u32>(99).unwrap() == 0);
assert!(parent.read_val::<u32>(1).unwrap() == 42);
// write parent on already-copied page
parent.write_val(10, &123u8).unwrap();
assert!(parent.read_val::<u32>(10).unwrap() == 123);
assert!(cow_child.read_val::<u32>(10).unwrap() == 0);
// write parent on not-copied page
parent.write_val(PAGE_SIZE + 10, &12345u32).unwrap();
assert!(parent.read_val::<u32>(PAGE_SIZE + 10).unwrap() == 12345);
assert!(cow_child.read_val::<u32>(PAGE_SIZE + 10).unwrap() == 12345);
}
#[test]
fn resize() {
let vmo = VmoOptions::<Full>::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::<u8>(10).unwrap() == 42);
vmo.write_val(PAGE_SIZE + 20, &123u8).unwrap();
vmo.resize(PAGE_SIZE).unwrap();
assert!(vmo.read_val::<u8>(10).unwrap() == 42);
}
}