From c6a262d2157a02ca917205d3291a1ec271a3faf3 Mon Sep 17 00:00:00 2001 From: Yifan Wu <shinbokuow@163.com> Date: Sun, 21 Feb 2021 09:28:50 +0800 Subject: [PATCH 1/5] Close all pipes in pipetest. --- user/src/bin/pipetest.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/user/src/bin/pipetest.rs b/user/src/bin/pipetest.rs index 58237847..c151fbdd 100644 --- a/user/src/bin/pipetest.rs +++ b/user/src/bin/pipetest.rs @@ -23,6 +23,8 @@ pub fn main() -> i32 { close(pipe_fd[1]); let mut buffer = [0u8; 32]; let len_read = read(pipe_fd[0], &mut buffer) as usize; + // close read_end + close(pipe_fd[0]); assert_eq!(core::str::from_utf8(&buffer[..len_read]).unwrap(), STR); println!("Read OK, child process exited!"); 0 From e8a0682cf8d2f533711cf2fe99f015ce6462ac4e Mon Sep 17 00:00:00 2001 From: Yifan Wu <shinbokuow@163.com> Date: Wed, 24 Feb 2021 03:42:45 +0800 Subject: [PATCH 2/5] Refactor easy-fs --- .gitignore | 4 + easy-fs-fuse/Cargo.toml | 12 ++ {easy-fs/src/bin => easy-fs-fuse/src}/main.rs | 48 +++-- easy-fs/Cargo.toml | 3 +- easy-fs/build.rs | 6 - easy-fs/src/bitmap.rs | 54 +++--- easy-fs/src/block_cache.rs | 116 ++++++++---- easy-fs/src/dirty.rs | 44 ----- easy-fs/src/efs.rs | 91 ++++++---- easy-fs/src/layout.rs | 52 +++--- easy-fs/src/lib.rs | 4 +- easy-fs/src/vfs.rs | 169 ++++++++++-------- os/Makefile | 2 +- user/Makefile | 2 +- 14 files changed, 329 insertions(+), 278 deletions(-) create mode 100644 easy-fs-fuse/Cargo.toml rename {easy-fs/src/bin => easy-fs-fuse/src}/main.rs (77%) delete mode 100644 easy-fs/build.rs delete mode 100644 easy-fs/src/dirty.rs diff --git a/.gitignore b/.gitignore index 3327607d..74b65454 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,8 @@ os/Cargo.lock user/target/* user/.idea/* user/Cargo.lock +easy-fs/Cargo.lock +easy-fs/target/* +easy-fs-fuse/Cargo.lock +easy-fs-fuse/target/* tools/ diff --git a/easy-fs-fuse/Cargo.toml b/easy-fs-fuse/Cargo.toml new file mode 100644 index 00000000..ee0ef971 --- /dev/null +++ b/easy-fs-fuse/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "easy-fs-fuse" +version = "0.1.0" +authors = ["Yifan Wu <shinbokuow@163.com>"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = "2.33.3" +easy-fs = { path = "../easy-fs" } +rand = "0.8.0" \ No newline at end of file diff --git a/easy-fs/src/bin/main.rs b/easy-fs-fuse/src/main.rs similarity index 77% rename from easy-fs/src/bin/main.rs rename to easy-fs-fuse/src/main.rs index af972ddf..04f74f00 100644 --- a/easy-fs/src/bin/main.rs +++ b/easy-fs-fuse/src/main.rs @@ -1,6 +1,3 @@ -extern crate easy_fs; -extern crate alloc; - use easy_fs::{ BlockDevice, EasyFileSystem, @@ -8,7 +5,8 @@ use easy_fs::{ use std::fs::{File, OpenOptions, read_dir}; use std::io::{Read, Write, Seek, SeekFrom}; use std::sync::Mutex; -use alloc::sync::Arc; +use std::sync::Arc; +use clap::{Arg, App}; const BLOCK_SZ: usize = 512; @@ -34,15 +32,30 @@ fn main() { easy_fs_pack().expect("Error when packing easy-fs!"); } -static TARGET_PATH: &str = "../user/target/riscv64gc-unknown-none-elf/release/"; - fn easy_fs_pack() -> std::io::Result<()> { + let matches = App::new("EasyFileSystem packer") + .arg(Arg::with_name("source") + .short("s") + .long("source") + .takes_value(true) + .help("Executable source dir(with backslash)") + ) + .arg(Arg::with_name("target") + .short("t") + .long("target") + .takes_value(true) + .help("Executable target dir(with backslash)") + ) + .get_matches(); + let src_path = matches.value_of("source").unwrap(); + let target_path = matches.value_of("target").unwrap(); + println!("src_path = {}\ntarget_path = {}", src_path, target_path); let block_file = Arc::new(BlockFile(Mutex::new({ let f = OpenOptions::new() .read(true) .write(true) .create(true) - .open(format!("{}{}", TARGET_PATH, "fs.img"))?; + .open(format!("{}{}", target_path, "fs.img"))?; f.set_len(8192 * 512).unwrap(); f }))); @@ -53,7 +66,7 @@ fn easy_fs_pack() -> std::io::Result<()> { 1, ); let root_inode = Arc::new(EasyFileSystem::root_inode(&efs)); - let apps: Vec<_> = read_dir("../user/src/bin") + let apps: Vec<_> = read_dir(src_path) .unwrap() .into_iter() .map(|dir_entry| { @@ -64,7 +77,7 @@ fn easy_fs_pack() -> std::io::Result<()> { .collect(); for app in apps { // load app data from host file system - let mut host_file = File::open(format!("{}{}", TARGET_PATH, app)).unwrap(); + let mut host_file = File::open(format!("{}{}", target_path, app)).unwrap(); let mut all_data: Vec<u8> = Vec::new(); host_file.read_to_end(&mut all_data).unwrap(); // create a file in easy-fs @@ -79,22 +92,24 @@ fn easy_fs_pack() -> std::io::Result<()> { Ok(()) } -/* #[test] fn efs_test() -> std::io::Result<()> { - let block_file = Arc::new(BlockFile(Mutex::new( - OpenOptions::new() + let block_file = Arc::new(BlockFile(Mutex::new({ + let f = OpenOptions::new() .read(true) .write(true) - .open("target/fs.img")? - ))); + .create(true) + .open("target/fs.img")?; + f.set_len(8192 * 512).unwrap(); + f + }))); EasyFileSystem::create( block_file.clone(), 4096, 1, ); let efs = EasyFileSystem::open(block_file.clone()); - let mut root_inode = EasyFileSystem::root_inode(&efs); + let root_inode = EasyFileSystem::root_inode(&efs); root_inode.create("filea"); root_inode.create("fileb"); for name in root_inode.ls() { @@ -146,5 +161,4 @@ fn efs_test() -> std::io::Result<()> { random_str_test((12 + 128) * BLOCK_SZ); Ok(()) -} - */ \ No newline at end of file +} \ No newline at end of file diff --git a/easy-fs/Cargo.toml b/easy-fs/Cargo.toml index f32c49f7..6e7cd925 100644 --- a/easy-fs/Cargo.toml +++ b/easy-fs/Cargo.toml @@ -8,5 +8,4 @@ edition = "2018" [dependencies] spin = "0.7.0" -lazy_static = { version = "1.4.0", features = ["spin_no_std"] } -#rand = "0.8.0" \ No newline at end of file +lazy_static = { version = "1.4.0", features = ["spin_no_std"] } \ No newline at end of file diff --git a/easy-fs/build.rs b/easy-fs/build.rs deleted file mode 100644 index 5529b4fe..00000000 --- a/easy-fs/build.rs +++ /dev/null @@ -1,6 +0,0 @@ -static TARGET_PATH: &str = "../user/target/riscv64gc-unknown-none-elf/release/"; - -fn main() { - println!("cargo:rerun-if-changed=../user/src/"); - println!("cargo:rerun-if-changed={}", TARGET_PATH); -} diff --git a/easy-fs/src/bitmap.rs b/easy-fs/src/bitmap.rs index 87f8d297..4feaa9cf 100644 --- a/easy-fs/src/bitmap.rs +++ b/easy-fs/src/bitmap.rs @@ -1,7 +1,9 @@ use alloc::sync::Arc; -use super::BlockDevice; -use super::Dirty; -use super::BLOCK_SZ; +use super::{ + BlockDevice, + BLOCK_SZ, + get_block_cache, +}; type BitmapBlock = [u64; 64]; @@ -26,41 +28,45 @@ impl Bitmap { blocks, } } + pub fn alloc(&self, block_device: &Arc<dyn BlockDevice>) -> Option<usize> { for block_id in 0..self.blocks { - let mut dirty_bitmap_block: Dirty<BitmapBlock> = Dirty::new( + let pos = get_block_cache( block_id + self.start_block_id as usize, - 0, - block_device.clone() - ); - let bitmap_block = dirty_bitmap_block.get_mut(); - if let Some((bits64_pos, inner_pos)) = bitmap_block - .iter() - .enumerate() - .find(|(_, bits64)| **bits64 != u64::MAX) - .map(|(bits64_pos, bits64)| { - (bits64_pos, bits64.trailing_ones() as usize) - }) { - // modify cache - bitmap_block[bits64_pos] |= 1u64 << inner_pos; - return Some(block_id * BLOCK_BITS + bits64_pos * 64 + inner_pos as usize); - // after dirty is dropped, data will be written back automatically + Arc::clone(block_device), + ).lock().modify(0, |bitmap_block: &mut BitmapBlock| { + if let Some((bits64_pos, inner_pos)) = bitmap_block + .iter() + .enumerate() + .find(|(_, bits64)| **bits64 != u64::MAX) + .map(|(bits64_pos, bits64)| { + (bits64_pos, bits64.trailing_ones() as usize) + }) { + // modify cache + bitmap_block[bits64_pos] |= 1u64 << inner_pos; + Some(block_id * BLOCK_BITS + bits64_pos * 64 + inner_pos as usize) + } else { + None + } + }); + if pos.is_some() { + return pos; } } None } + pub fn dealloc(&self, block_device: &Arc<dyn BlockDevice>, bit: usize) { let (block_pos, bits64_pos, inner_pos) = decomposition(bit); - let mut dirty_bitmap_block: Dirty<BitmapBlock> = Dirty::new( + get_block_cache( block_pos + self.start_block_id, - 0, - block_device.clone(), - ); - dirty_bitmap_block.modify(|bitmap_block| { + Arc::clone(block_device) + ).lock().modify(0, |bitmap_block: &mut BitmapBlock| { assert!(bitmap_block[bits64_pos] & (1u64 << inner_pos) > 0); bitmap_block[bits64_pos] -= 1u64 << inner_pos; }); } + pub fn maximum(&self) -> usize { self.blocks * BLOCK_BITS } diff --git a/easy-fs/src/block_cache.rs b/easy-fs/src/block_cache.rs index 34450f63..57265812 100644 --- a/easy-fs/src/block_cache.rs +++ b/easy-fs/src/block_cache.rs @@ -1,9 +1,9 @@ use super::{ - BlockDevice, BLOCK_SZ, + BlockDevice, }; -use alloc::sync::{Arc, Weak}; -use alloc::collections::BTreeMap; +use alloc::collections::VecDeque; +use alloc::sync::Arc; use lazy_static::*; use spin::Mutex; @@ -11,76 +11,118 @@ pub struct BlockCache { cache: [u8; BLOCK_SZ], block_id: usize, block_device: Arc<dyn BlockDevice>, + modified: bool, } impl BlockCache { - pub fn new(block_id: usize, block_device: Arc<dyn BlockDevice>) -> Self { + /// Load a new BlockCache from disk. + pub fn new( + block_id: usize, + block_device: Arc<dyn BlockDevice> + ) -> Self { let mut cache = [0u8; BLOCK_SZ]; block_device.read_block(block_id, &mut cache); Self { cache, block_id, block_device, + modified: false, } } - pub fn start_addr(&self, offset: usize) -> usize { + + fn addr_of_offset(&self, offset: usize) -> usize { &self.cache[offset] as *const _ as usize } + + pub fn get_ref<T>(&self, offset: usize) -> &T where T: Sized { + let type_size = core::mem::size_of::<T>(); + assert!(offset + type_size <= BLOCK_SZ); + let addr = self.addr_of_offset(offset); + unsafe { &*(addr as *const T) } + } + + pub fn get_mut<T>(&mut self, offset: usize) -> &mut T where T: Sized { + let type_size = core::mem::size_of::<T>(); + assert!(offset + type_size <= BLOCK_SZ); + self.modified = true; + let addr = self.addr_of_offset(offset); + unsafe { &mut *(addr as *mut T) } + } + + pub fn read<T, V>(&self, offset: usize, f: impl FnOnce(&T) -> V) -> V { + f(self.get_ref(offset)) + } + + pub fn modify<T, V>(&mut self, offset:usize, f: impl FnOnce(&mut T) -> V) -> V { + f(self.get_mut(offset)) + } + + pub fn sync(&mut self) { + if self.modified { + self.modified = false; + self.block_device.write_block(self.block_id, &self.cache); + } + } } impl Drop for BlockCache { fn drop(&mut self) { - // write back - self.block_device.write_block(self.block_id, &self.cache); - // invalid in block cache manager - BLOCK_CACHE_MANAGER.lock().invalid(self.block_id); + self.sync() } } -pub struct BlockCacheManager { - map: BTreeMap<usize, Weak<BlockCache>>, -} +const BLOCK_CACHE_SIZE: usize = 16; -lazy_static! { - static ref BLOCK_CACHE_MANAGER: Mutex<BlockCacheManager> = Mutex::new( - BlockCacheManager::new() - ); +pub struct BlockCacheManager { + queue: VecDeque<(usize, Arc<Mutex<BlockCache>>)>, } impl BlockCacheManager { pub fn new() -> Self { - Self { map: BTreeMap::new() } + Self { queue: VecDeque::new() } } - pub fn get( + + pub fn get_block_cache( &mut self, block_id: usize, - block_device: Arc<dyn BlockDevice> - ) -> Arc<BlockCache> { - if let Some(block_cache) = self.map.get(&block_id) { - // return cloned - block_cache.upgrade().unwrap().clone() + block_device: Arc<dyn BlockDevice>, + ) -> Arc<Mutex<BlockCache>> { + if let Some(pair) = self.queue + .iter() + .find(|pair| pair.0 == block_id) { + Arc::clone(&pair.1) } else { - // fetch from disk - let block_cache = Arc::new(BlockCache::new( - block_id, - block_device.clone() + // substitute + if self.queue.len() == BLOCK_CACHE_SIZE { + // from front to tail + if let Some((idx, _)) = self.queue + .iter() + .enumerate() + .find(|(_, pair)| Arc::strong_count(&pair.1) == 1) { + self.queue.drain(idx..=idx); + } else { + panic!("Run out of BlockCache!"); + } + } + // load block into mem and push back + let block_cache = Arc::new(Mutex::new( + BlockCache::new(block_id, Arc::clone(&block_device)) )); - self.map.insert( - block_id, - Arc::downgrade(&block_cache), - ); - // return + self.queue.push_back((block_id, Arc::clone(&block_cache))); block_cache } } - pub fn invalid(&mut self, block_id: usize) { - assert!(self.map.remove(&block_id).is_some()); - } +} + +lazy_static! { + pub static ref BLOCK_CACHE_MANAGER: Mutex<BlockCacheManager> = Mutex::new( + BlockCacheManager::new() + ); } pub fn get_block_cache( block_id: usize, block_device: Arc<dyn BlockDevice> -) -> Arc<BlockCache> { - BLOCK_CACHE_MANAGER.lock().get(block_id, block_device) +) -> Arc<Mutex<BlockCache>> { + BLOCK_CACHE_MANAGER.lock().get_block_cache(block_id, block_device) } \ No newline at end of file diff --git a/easy-fs/src/dirty.rs b/easy-fs/src/dirty.rs deleted file mode 100644 index 8aa41e35..00000000 --- a/easy-fs/src/dirty.rs +++ /dev/null @@ -1,44 +0,0 @@ -use super::{ - BlockDevice, - BLOCK_SZ, - BlockCache, - get_block_cache, -}; -use alloc::sync::Arc; -use core::marker::PhantomData; - -pub struct Dirty<T> { - block_cache: Arc<BlockCache>, - offset: usize, - phantom: PhantomData<T>, -} - -impl<T> Dirty<T> where T: Sized { - pub fn new(block_id: usize, offset: usize, block_device: Arc<dyn BlockDevice>) -> Self { - Self { - block_cache: get_block_cache(block_id, block_device.clone()), - offset, - phantom: PhantomData, - } - } - pub fn get_mut(&mut self) -> &mut T { - let type_size = core::mem::size_of::<T>(); - // assert that the struct is inside a block - assert!(self.offset + type_size <= BLOCK_SZ); - let start_addr = self.block_cache.start_addr(self.offset); - unsafe { &mut *(start_addr as *mut T) } - } - pub fn get_ref(&self) -> &T { - let type_size = core::mem::size_of::<T>(); - // assert that the struct is inside a block - assert!(self.offset + type_size <= BLOCK_SZ); - let start_addr = self.block_cache.start_addr(self.offset); - unsafe { &*(start_addr as *const T) } - } - pub fn read<V>(&self, f: impl FnOnce(&T) -> V) -> V { - f(self.get_ref()) - } - pub fn modify<V>(&mut self, f: impl FnOnce(&mut T) -> V) -> V { - f(self.get_mut()) - } -} diff --git a/easy-fs/src/efs.rs b/easy-fs/src/efs.rs index f2103740..caf4d8cb 100644 --- a/easy-fs/src/efs.rs +++ b/easy-fs/src/efs.rs @@ -6,8 +6,8 @@ use super::{ SuperBlock, DiskInode, DiskInodeType, - Dirty, Inode, + get_block_cache, }; use crate::BLOCK_SZ; @@ -41,7 +41,7 @@ impl EasyFileSystem { data_bitmap_blocks as usize, ); let mut efs = Self { - block_device, + block_device: Arc::clone(&block_device), inode_bitmap, data_bitmap, inode_area_start_block: 1 + inode_bitmap_blocks, @@ -49,14 +49,19 @@ impl EasyFileSystem { }; // clear all blocks for i in 0..total_blocks { - efs.get_block(i).modify(|data_block| { - for byte in data_block.iter_mut() { - *byte = 0; - } + get_block_cache( + i as usize, + Arc::clone(&block_device) + ) + .lock() + .modify(0, |data_block: &mut DataBlock| { + for byte in data_block.iter_mut() { *byte = 0; } }); } // initialize SuperBlock - efs.get_super_block().modify(|super_block| { + get_block_cache(0, Arc::clone(&block_device)) + .lock() + .modify(0, |super_block: &mut SuperBlock| { super_block.initialize( total_blocks, inode_bitmap_blocks, @@ -68,10 +73,15 @@ impl EasyFileSystem { // write back immediately // create a inode for root node "/" assert_eq!(efs.alloc_inode(), 0); - efs.get_disk_inode(0).modify(|disk_inode| { + let (root_inode_block_id, root_inode_offset) = efs.get_disk_inode_pos(0); + get_block_cache( + root_inode_block_id as usize, + Arc::clone(&block_device) + ) + .lock() + .modify(root_inode_offset, |disk_inode: &mut DiskInode| { disk_inode.initialize( - DiskInodeType::Directory, - efs.alloc_data(), + DiskInodeType::Directory,efs.alloc_data() ); }); Arc::new(Mutex::new(efs)) @@ -79,54 +89,56 @@ impl EasyFileSystem { pub fn open(block_device: Arc<dyn BlockDevice>) -> Arc<Mutex<Self>> { // read SuperBlock - let super_block_dirty: Dirty<SuperBlock> = Dirty::new(0, 0, block_device.clone()); - let super_block = super_block_dirty.get_ref(); - assert!(super_block.is_valid(), "Error loading EFS!"); - let inode_total_blocks = - super_block.inode_bitmap_blocks + super_block.inode_area_blocks; - let efs = Self { - block_device, - inode_bitmap: Bitmap::new( - 1, - super_block.inode_bitmap_blocks as usize - ), - data_bitmap: Bitmap::new( - (1 + inode_total_blocks) as usize, - super_block.data_bitmap_blocks as usize, - ), - inode_area_start_block: 1 + super_block.inode_bitmap_blocks, - data_area_start_block: 1 + inode_total_blocks + super_block.data_bitmap_blocks, - }; - Arc::new(Mutex::new(efs)) + get_block_cache(0, Arc::clone(&block_device)) + .lock() + .read(0, |super_block: &SuperBlock| { + assert!(super_block.is_valid(), "Error loading EFS!"); + let inode_total_blocks = + super_block.inode_bitmap_blocks + super_block.inode_area_blocks; + let efs = Self { + block_device, + inode_bitmap: Bitmap::new( + 1, + super_block.inode_bitmap_blocks as usize + ), + data_bitmap: Bitmap::new( + (1 + inode_total_blocks) as usize, + super_block.data_bitmap_blocks as usize, + ), + inode_area_start_block: 1 + super_block.inode_bitmap_blocks, + data_area_start_block: 1 + inode_total_blocks + super_block.data_bitmap_blocks, + }; + Arc::new(Mutex::new(efs)) + }) } pub fn root_inode(efs: &Arc<Mutex<Self>>) -> Inode { + let block_device = Arc::clone(&efs.lock().block_device); Inode::new( 0, - efs.clone(), - efs.lock().block_device.clone(), + Arc::clone(efs), + block_device, ) } + /* fn get_super_block(&self) -> Dirty<SuperBlock> { Dirty::new(0, 0, self.block_device.clone()) } + */ - pub fn get_disk_inode(&self, inode_id: u32) -> Dirty<DiskInode> { + pub fn get_disk_inode_pos(&self, inode_id: u32) -> (u32, usize) { let inode_size = core::mem::size_of::<DiskInode>(); let inodes_per_block = (BLOCK_SZ / inode_size) as u32; let block_id = self.inode_area_start_block + inode_id / inodes_per_block; - Dirty::new( - block_id as usize, - (inode_id % inodes_per_block) as usize * inode_size, - self.block_device.clone(), - ) + (block_id, (inode_id % inodes_per_block) as usize * inode_size) } - pub fn get_data_block(&self, data_block_id: u32) -> Dirty<DataBlock> { - self.get_block(self.data_area_start_block + data_block_id) + pub fn get_data_block_id(&self, data_block_id: u32) -> u32 { + self.data_area_start_block + data_block_id } + /* fn get_block(&self, block_id: u32) -> Dirty<DataBlock> { Dirty::new( block_id as usize, @@ -134,6 +146,7 @@ impl EasyFileSystem { self.block_device.clone(), ) } + */ pub fn alloc_inode(&mut self) -> u32 { self.inode_bitmap.alloc(&self.block_device).unwrap() as u32 diff --git a/easy-fs/src/layout.rs b/easy-fs/src/layout.rs index 725c1e44..ace1ced8 100644 --- a/easy-fs/src/layout.rs +++ b/easy-fs/src/layout.rs @@ -2,7 +2,7 @@ use core::fmt::{Debug, Formatter, Result}; use super::{ BLOCK_SZ, BlockDevice, - Dirty, + get_block_cache, }; use alloc::sync::Arc; use alloc::vec::Vec; @@ -87,6 +87,7 @@ impl DiskInode { pub fn is_dir(&self) -> bool { self.type_ == DiskInodeType::Directory } + #[allow(unused)] pub fn is_file(&self) -> bool { self.type_ == DiskInodeType::File } @@ -102,14 +103,11 @@ impl DiskInode { self.direct[inner_id] } else { // only support indirect1 now - Dirty::<IndirectBlock>::new( - self.indirect1 as usize, - 0, - block_device.clone() - ).read(|indirect_block| { - // it will panic if file is too large - indirect_block[inner_id - INODE_DIRECT_COUNT] - }) + get_block_cache(self.indirect1 as usize, Arc::clone(block_device)) + .lock() + .read(0, |indirect_block: &IndirectBlock| { + indirect_block[inner_id - INODE_DIRECT_COUNT] + }) } } pub fn blocks_num_needed(&self, new_size: u32) -> u32 { @@ -126,11 +124,12 @@ impl DiskInode { let last_blocks = self.blocks(); self.size = new_size; let current_blocks = self.blocks(); - Dirty::<IndirectBlock>::new( + get_block_cache( self.indirect1 as usize, - 0, - block_device.clone() - ).modify(|indirect_block| { + Arc::clone(block_device) + ) + .lock() + .modify(0, |indirect_block: &mut IndirectBlock| { for i in 0..current_blocks - last_blocks { let inner_id = (last_blocks + i) as usize; let new_block = new_blocks[i as usize]; @@ -152,11 +151,12 @@ impl DiskInode { self.direct[i] = 0; } if blocks > INODE_DIRECT_COUNT { - Dirty::<IndirectBlock>::new( + get_block_cache( self.indirect1 as usize, - 0, - block_device.clone(), - ).modify(|indirect_block| { + Arc::clone(block_device), + ) + .lock() + .modify(0, |indirect_block: &mut IndirectBlock| { for i in 0..blocks - INODE_DIRECT_COUNT { v.push(indirect_block[i]); indirect_block[i] = 0; @@ -185,11 +185,12 @@ impl DiskInode { // read and update read size let block_read_size = end_current_block - start; let dst = &mut buf[read_size..read_size + block_read_size]; - Dirty::<DataBlock>::new( + get_block_cache( self.get_block_id(start_block as u32, block_device) as usize, - 0, - block_device.clone() - ).read(|data_block| { + Arc::clone(block_device), + ) + .lock() + .read(0, |data_block: &DataBlock| { let src = &data_block[start % BLOCK_SZ..start % BLOCK_SZ + block_read_size]; dst.copy_from_slice(src); }); @@ -219,11 +220,12 @@ impl DiskInode { end_current_block = end_current_block.min(end); // write and update write size let block_write_size = end_current_block - start; - Dirty::<DataBlock>::new( + get_block_cache( self.get_block_id(start_block as u32, block_device) as usize, - 0, - block_device.clone() - ).modify(|data_block| { + Arc::clone(block_device) + ) + .lock() + .modify(0, |data_block: &mut DataBlock| { let src = &buf[write_size..write_size + block_write_size]; let dst = &mut data_block[start % BLOCK_SZ..start % BLOCK_SZ + block_write_size]; dst.copy_from_slice(src); diff --git a/easy-fs/src/lib.rs b/easy-fs/src/lib.rs index 961efa65..10a5af76 100644 --- a/easy-fs/src/lib.rs +++ b/easy-fs/src/lib.rs @@ -5,7 +5,6 @@ extern crate alloc; mod block_dev; mod layout; mod efs; -mod dirty; mod bitmap; mod vfs; mod block_cache; @@ -15,6 +14,5 @@ pub use block_dev::BlockDevice; pub use efs::EasyFileSystem; pub use vfs::Inode; use layout::*; -use dirty::Dirty; use bitmap::Bitmap; -use block_cache::{BlockCache, get_block_cache}; \ No newline at end of file +use block_cache::get_block_cache; \ No newline at end of file diff --git a/easy-fs/src/vfs.rs b/easy-fs/src/vfs.rs index d7631354..a98fd607 100644 --- a/easy-fs/src/vfs.rs +++ b/easy-fs/src/vfs.rs @@ -1,12 +1,12 @@ use super::{ BlockDevice, - Dirty, DiskInode, DiskInodeType, DirEntry, DirentBytes, EasyFileSystem, DIRENT_SZ, + get_block_cache, }; use alloc::sync::Arc; use alloc::string::String; @@ -14,7 +14,8 @@ use alloc::vec::Vec; use spin::{Mutex, MutexGuard}; pub struct Inode { - inode_id: u32, + block_id: usize, + block_offset: usize, fs: Arc<Mutex<EasyFileSystem>>, block_device: Arc<dyn BlockDevice>, } @@ -25,37 +26,51 @@ impl Inode { fs: Arc<Mutex<EasyFileSystem>>, block_device: Arc<dyn BlockDevice>, ) -> Self { + let (block_id, block_offset) = fs.lock().get_disk_inode_pos(inode_id); Self { - inode_id, + block_id: block_id as usize, + block_offset, fs, block_device, } } + fn read_disk_inode<V>(&self, f: impl FnOnce(&DiskInode) -> V) -> V { + get_block_cache( + self.block_id, + Arc::clone(&self.block_device) + ).lock().read(self.block_offset, f) + } + + fn modify_disk_inode<V>(&self, f: impl FnOnce(&mut DiskInode) -> V) -> V { + get_block_cache( + self.block_id, + Arc::clone(&self.block_device) + ).lock().modify(self.block_offset, f) + } + + /* fn get_disk_inode(&self, fs: &mut MutexGuard<EasyFileSystem>) -> Dirty<DiskInode> { fs.get_disk_inode(self.inode_id) } + */ fn find_inode_id( &self, name: &str, - inode: &Dirty<DiskInode>, + disk_inode: &DiskInode, ) -> Option<u32> { // assert it is a directory - assert!(inode.read(|inode| inode.is_dir())); - let file_count = inode.read(|inode| { - inode.size as usize - }) / DIRENT_SZ; + assert!(disk_inode.is_dir()); + let file_count = (disk_inode.size as usize) / DIRENT_SZ; let mut dirent_space: DirentBytes = Default::default(); for i in 0..file_count { assert_eq!( - inode.read(|inode| { - inode.read_at( - DIRENT_SZ * i, - &mut dirent_space, - &self.block_device, - ) - }), + disk_inode.read_at( + DIRENT_SZ * i, + &mut dirent_space, + &self.block_device, + ), DIRENT_SZ, ); let dirent = DirEntry::from_bytes(&dirent_space); @@ -67,9 +82,9 @@ impl Inode { } pub fn find(&self, name: &str) -> Option<Arc<Inode>> { - let mut fs = self.fs.lock(); - let inode = self.get_disk_inode(&mut fs); - self.find_inode_id(name, &inode) + let _ = self.fs.lock(); + self.read_disk_inode(|disk_inode| { + self.find_inode_id(name, disk_inode) .map(|inode_id| { Arc::new(Self::new( inode_id, @@ -77,68 +92,69 @@ impl Inode { self.block_device.clone(), )) }) + }) } fn increase_size( &self, new_size: u32, - inode: &mut Dirty<DiskInode>, + disk_inode: &mut DiskInode, fs: &mut MutexGuard<EasyFileSystem>, ) { - let size = inode.read(|inode| inode.size); - if new_size < size { + if new_size < disk_inode.size { return; } - let blocks_needed = inode.read(|inode| { - inode.blocks_num_needed(new_size) - }); + let blocks_needed = disk_inode.blocks_num_needed(new_size); let mut v: Vec<u32> = Vec::new(); for _ in 0..blocks_needed { v.push(fs.alloc_data()); } - inode.modify(|inode| { - inode.increase_size(new_size, v, &self.block_device); - }); + disk_inode.increase_size(new_size, v, &self.block_device); } pub fn create(&self, name: &str) -> Option<Arc<Inode>> { let mut fs = self.fs.lock(); - let mut inode = self.get_disk_inode(&mut fs); - // assert it is a directory - assert!(inode.read(|inode| inode.is_dir())); - // has the file been created? - if let Some(_) = self.find_inode_id(name, &inode) { + if self.modify_disk_inode(|root_inode| { + // assert it is a directory + assert!(root_inode.is_dir()); + // has the file been created? + self.find_inode_id(name, root_inode) + }).is_some() { return None; } - + //println!("same file does not exist in Inode::create."); // create a new file // alloc a inode with an indirect block let new_inode_id = fs.alloc_inode(); let indirect1 = fs.alloc_data(); // initialize inode - fs.get_disk_inode(new_inode_id).modify(|inode| { - inode.initialize( - DiskInodeType::File, - indirect1, - ) + let (new_inode_block_id, new_inode_block_offset) + = fs.get_disk_inode_pos(new_inode_id); + //println!("new_inode_id={} ({},{})", new_inode_id, new_inode_block_id, new_inode_block_offset); + get_block_cache( + new_inode_block_id as usize, + Arc::clone(&self.block_device) + ).lock().modify(new_inode_block_offset, |new_inode: &mut DiskInode| { + new_inode.initialize(DiskInodeType::File, indirect1); }); - - // append file in the dirent - let file_count = - inode.read(|inode| inode.size as usize) / DIRENT_SZ; - let new_size = (file_count + 1) * DIRENT_SZ; - // increase size - self.increase_size(new_size as u32, &mut inode, &mut fs); - // write dirent - let dirent = DirEntry::new(name, new_inode_id); - inode.modify(|inode| { - inode.write_at( + //println!("new inode has been initialized."); + self.modify_disk_inode(|root_inode| { + // append file in the dirent + let file_count = (root_inode.size as usize) / DIRENT_SZ; + let new_size = (file_count + 1) * DIRENT_SZ; + // increase size + self.increase_size(new_size as u32, root_inode, &mut fs); + // write dirent + let dirent = DirEntry::new(name, new_inode_id); + root_inode.write_at( file_count * DIRENT_SZ, dirent.into_bytes(), &self.block_device, ); }); - + //println!("new file has been inserted into root inode."); + // release efs lock manually because we will acquire it again in Inode::new + drop(fs); // return inode Some(Arc::new(Self::new( new_inode_id, @@ -148,53 +164,48 @@ impl Inode { } pub fn ls(&self) -> Vec<String> { - let mut fs = self.fs.lock(); - let inode = self.get_disk_inode(&mut fs); - let file_count = inode.read(|inode| { - (inode.size as usize) / DIRENT_SZ - }); - let mut v: Vec<String> = Vec::new(); - for i in 0..file_count { - let mut dirent_bytes: DirentBytes = Default::default(); - assert_eq!( - inode.read(|inode| { - inode.read_at( + let _ = self.fs.lock(); + self.read_disk_inode(|disk_inode| { + let file_count = (disk_inode.size as usize) / DIRENT_SZ; + let mut v: Vec<String> = Vec::new(); + for i in 0..file_count { + let mut dirent_bytes: DirentBytes = Default::default(); + assert_eq!( + disk_inode.read_at( i * DIRENT_SZ, &mut dirent_bytes, &self.block_device, - ) - }), - DIRENT_SZ, - ); - v.push(String::from(DirEntry::from_bytes(&dirent_bytes).name())); - } - v + ), + DIRENT_SZ, + ); + v.push(String::from(DirEntry::from_bytes(&dirent_bytes).name())); + } + v + }) } pub fn read_at(&self, offset: usize, buf: &mut [u8]) -> usize { - let mut fs = self.fs.lock(); - self.get_disk_inode(&mut fs).modify(|disk_inode| { + let _ = self.fs.lock(); + self.read_disk_inode(|disk_inode| { disk_inode.read_at(offset, buf, &self.block_device) }) } pub fn write_at(&self, offset: usize, buf: &[u8]) -> usize { let mut fs = self.fs.lock(); - let mut inode = self.get_disk_inode(&mut fs); - self.increase_size((offset + buf.len()) as u32, &mut inode, &mut fs); - inode.modify(|disk_inode| { + self.modify_disk_inode(|disk_inode| { + self.increase_size((offset + buf.len()) as u32, disk_inode, &mut fs); disk_inode.write_at(offset, buf, &self.block_device) }) } pub fn clear(&self) { let mut fs = self.fs.lock(); - let mut inode = self.get_disk_inode(&mut fs); - let data_blocks_dealloc = inode.modify(|disk_inode| { - disk_inode.clear_size(&self.block_device) + self.modify_disk_inode(|disk_inode| { + let data_blocks_dealloc = disk_inode.clear_size(&self.block_device); + for data_block in data_blocks_dealloc.into_iter() { + fs.dealloc_data(data_block); + } }); - for data_block in data_blocks_dealloc.into_iter() { - fs.dealloc_data(data_block); - } } } diff --git a/os/Makefile b/os/Makefile index f1813146..568a2779 100644 --- a/os/Makefile +++ b/os/Makefile @@ -50,7 +50,7 @@ $(KERNEL_BIN): kernel $(FS_IMG): $(APPS) @cd ../user && make build - @cd ../easy-fs && cargo run --release + @cd ../easy-fs-fuse && cargo run --release -- -s ../user/src/bin/ -t ../user/target/riscv64gc-unknown-none-elf/release/ $(APPS): diff --git a/user/Makefile b/user/Makefile index 5e0f87c3..e2eaf994 100644 --- a/user/Makefile +++ b/user/Makefile @@ -20,4 +20,4 @@ build: binary clean: @cargo clean -.PHONY: elf binary build clean \ No newline at end of file +.PHONY: elf binary build clean From 35cc3d6e2fb73acd4e7d874ca8227c0bd50eedd0 Mon Sep 17 00:00:00 2001 From: Yifan Wu <shinbokuow@163.com> Date: Wed, 24 Feb 2021 03:50:59 +0800 Subject: [PATCH 3/5] Fix overflow bug when ceiling va --- os/src/mm/address.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/os/src/mm/address.rs b/os/src/mm/address.rs index 05d04abd..f9e02805 100644 --- a/os/src/mm/address.rs +++ b/os/src/mm/address.rs @@ -73,7 +73,7 @@ impl From<VirtPageNum> for usize { impl VirtAddr { pub fn floor(&self) -> VirtPageNum { VirtPageNum(self.0 / PAGE_SIZE) } - pub fn ceil(&self) -> VirtPageNum { VirtPageNum((self.0 + PAGE_SIZE - 1) / PAGE_SIZE) } + pub fn ceil(&self) -> VirtPageNum { VirtPageNum((self.0 - 1 + PAGE_SIZE) / PAGE_SIZE) } pub fn page_offset(&self) -> usize { self.0 & (PAGE_SIZE - 1) } pub fn aligned(&self) -> bool { self.page_offset() == 0 } } @@ -88,7 +88,7 @@ impl From<VirtPageNum> for VirtAddr { } impl PhysAddr { pub fn floor(&self) -> PhysPageNum { PhysPageNum(self.0 / PAGE_SIZE) } - pub fn ceil(&self) -> PhysPageNum { PhysPageNum((self.0 + PAGE_SIZE - 1) / PAGE_SIZE) } + pub fn ceil(&self) -> PhysPageNum { PhysPageNum((self.0 - 1 + PAGE_SIZE) / PAGE_SIZE) } pub fn page_offset(&self) -> usize { self.0 & (PAGE_SIZE - 1) } pub fn aligned(&self) -> bool { self.page_offset() == 0 } } From cfa3819bee0419250c4049c5143b954a7596abde Mon Sep 17 00:00:00 2001 From: Yifan Wu <shinbokuow@163.com> Date: Sun, 28 Feb 2021 06:34:15 +0800 Subject: [PATCH 4/5] Add Ubuntu18.04 docker --- .dockerignore | 1 + Dockerfile | 40 ++++++++++++++++++++++++++++++++++++++++ Makefile | 8 ++++++++ README.md | 2 +- 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 Makefile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..df3359dd --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +*/* \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..ac784bc2 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,40 @@ +FROM ubuntu:18.04 +LABEL maintainer="dinghao188" \ + version="1.1" \ + description="ubuntu 18.04 with tools for tsinghua's rCore-Tutorial-V3" + +#install some deps +RUN set -x \ + && apt-get update \ + && apt-get install -y curl wget autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev \ + gawk build-essential bison flex texinfo gperf libtool patchutils bc xz-utils \ + zlib1g-dev libexpat-dev pkg-config libglib2.0-dev libpixman-1-dev git tmux python3 + +#install rust and qemu +RUN set -x; \ + RUSTUP='/root/rustup.sh' \ + && cd $HOME \ + #install rust + && curl https://sh.rustup.rs -sSf > $RUSTUP && chmod +x $RUSTUP \ + && $RUSTUP -y --default-toolchain nightly --profile minimal \ + + #compile qemu + && wget https://ftp.osuosl.org/pub/blfs/conglomeration/qemu/qemu-5.0.0.tar.xz \ + && tar xvJf qemu-5.0.0.tar.xz \ + && cd qemu-5.0.0 \ + && ./configure --target-list=riscv64-softmmu,riscv64-linux-user \ + && make -j$(nproc) install \ + && cd $HOME && rm -rf qemu-5.0.0 qemu-5.0.0.tar.xz + +#for chinese network +RUN set -x; \ + APT_CONF='/etc/apt/sources.list'; \ + CARGO_CONF='/root/.cargo/config'; \ + BASHRC='/root/.bashrc' \ + && echo 'export RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static' >> $BASHRC \ + && echo 'export RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup' >> $BASHRC \ + && touch $CARGO_CONF \ + && echo '[source.crates-io]' > $CARGO_CONF \ + && echo "replace-with = 'ustc'" >> $CARGO_CONF \ + && echo '[source.ustc]' >> $CARGO_CONF \ + && echo 'registry = "git://mirrors.ustc.edu.cn/crates.io-index"' >> $CARGO_CONF \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..2e339762 --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +DOCKER_NAME ?= dinghao188/rcore-tutorial +.PHONY: docker build_docker + +docker: + docker run --rm -it --mount type=bind,source=$(shell pwd),destination=/mnt ${DOCKER_NAME} + +build_docker: + docker build -t ${DOCKER_NAME} . diff --git a/README.md b/README.md index 50834482..dd356b5f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ # rCore-Tutorial-v3 -rCore-Tutorial version 3. +rCore-Tutorial version 3. \ No newline at end of file From 67372ac84d6618c369f402c4c269728102bfc3ae Mon Sep 17 00:00:00 2001 From: Yifan Wu <shinbokuow@163.com> Date: Sun, 28 Feb 2021 06:38:13 +0800 Subject: [PATCH 5/5] Merge updates from ch7 --- easy-fs-fuse/src/main.rs | 6 +- easy-fs/src/efs.rs | 12 +- easy-fs/src/layout.rs | 238 ++++++++++++++++++++++++++++++---- easy-fs/src/vfs.rs | 9 +- os/Makefile | 2 +- os/src/mm/address.rs | 5 + os/src/mm/mod.rs | 1 + os/src/mm/page_table.rs | 11 +- os/src/syscall/fs.rs | 15 +++ os/src/syscall/mod.rs | 4 +- os/src/syscall/process.rs | 20 ++- os/src/task/task.rs | 41 +++++- os/src/trap/context.rs | 1 + os/src/trap/mod.rs | 1 + user/src/bin/cat.rs | 34 +++++ user/src/bin/cmdline_args.rs | 16 +++ user/src/bin/initproc.rs | 2 +- user/src/bin/run_pipe_test.rs | 2 +- user/src/bin/user_shell.rs | 82 +++++++++++- user/src/bin/usertests.rs | 2 +- user/src/lib.rs | 26 +++- user/src/syscall.rs | 9 +- 22 files changed, 477 insertions(+), 62 deletions(-) create mode 100644 user/src/bin/cat.rs create mode 100644 user/src/bin/cmdline_args.rs diff --git a/easy-fs-fuse/src/main.rs b/easy-fs-fuse/src/main.rs index 04f74f00..498b61ec 100644 --- a/easy-fs-fuse/src/main.rs +++ b/easy-fs-fuse/src/main.rs @@ -118,7 +118,8 @@ fn efs_test() -> std::io::Result<()> { let filea = root_inode.find("filea").unwrap(); let greet_str = "Hello, world!"; filea.write_at(0, greet_str.as_bytes()); - let mut buffer = [0u8; 512]; + //let mut buffer = [0u8; 512]; + let mut buffer = [0u8; 233]; let len = filea.read_at(0, &mut buffer); assert_eq!( greet_str, @@ -159,6 +160,9 @@ fn efs_test() -> std::io::Result<()> { random_str_test(100 * BLOCK_SZ); random_str_test(70 * BLOCK_SZ + BLOCK_SZ / 7); random_str_test((12 + 128) * BLOCK_SZ); + random_str_test(400 * BLOCK_SZ); + random_str_test(1000 * BLOCK_SZ); + random_str_test(2000 * BLOCK_SZ); Ok(()) } \ No newline at end of file diff --git a/easy-fs/src/efs.rs b/easy-fs/src/efs.rs index caf4d8cb..9e4445df 100644 --- a/easy-fs/src/efs.rs +++ b/easy-fs/src/efs.rs @@ -80,9 +80,7 @@ impl EasyFileSystem { ) .lock() .modify(root_inode_offset, |disk_inode: &mut DiskInode| { - disk_inode.initialize( - DiskInodeType::Directory,efs.alloc_data() - ); + disk_inode.initialize(DiskInodeType::Directory); }); Arc::new(Mutex::new(efs)) } @@ -158,6 +156,14 @@ impl EasyFileSystem { } pub fn dealloc_data(&mut self, block_id: u32) { + get_block_cache( + block_id as usize, + Arc::clone(&self.block_device) + ) + .lock() + .modify(0, |data_block: &mut DataBlock| { + data_block.iter_mut().for_each(|p| { *p = 0; }) + }); self.data_bitmap.dealloc( &self.block_device, (block_id - self.data_area_start_block) as usize diff --git a/easy-fs/src/layout.rs b/easy-fs/src/layout.rs index ace1ced8..7d14de46 100644 --- a/easy-fs/src/layout.rs +++ b/easy-fs/src/layout.rs @@ -8,8 +8,14 @@ use alloc::sync::Arc; use alloc::vec::Vec; const EFS_MAGIC: u32 = 0x3b800001; -const INODE_DIRECT_COUNT: usize = 60; +const INODE_DIRECT_COUNT: usize = 28; const NAME_LENGTH_LIMIT: usize = 27; +const INODE_INDIRECT1_COUNT: usize = BLOCK_SZ / 4; +const INODE_INDIRECT2_COUNT: usize = INODE_INDIRECT1_COUNT * INODE_INDIRECT1_COUNT; +const DIRECT_BOUND: usize = INODE_DIRECT_COUNT; +const INDIRECT1_BOUND: usize = DIRECT_BOUND + INODE_INDIRECT1_COUNT; +#[allow(unused)] +const INDIRECT2_BOUND: usize = INDIRECT1_BOUND + INODE_INDIRECT2_COUNT; #[repr(C)] pub struct SuperBlock { @@ -76,11 +82,11 @@ pub struct DiskInode { } impl DiskInode { - /// indirect1 block is allocated when the file is created. - pub fn initialize(&mut self, type_: DiskInodeType, indirect1: u32) { + /// indirect1 and indirect2 block are allocated only when they are needed. + pub fn initialize(&mut self, type_: DiskInodeType) { self.size = 0; self.direct.iter_mut().for_each(|v| *v = 0); - self.indirect1 = indirect1; + self.indirect1 = 0; self.indirect2 = 0; self.type_ = type_; } @@ -91,57 +97,146 @@ impl DiskInode { pub fn is_file(&self) -> bool { self.type_ == DiskInodeType::File } - pub fn blocks(&self) -> u32 { - Self::_blocks(self.size) + /// Return block number correspond to size. + pub fn data_blocks(&self) -> u32 { + Self::_data_blocks(self.size) } - fn _blocks(size: u32) -> u32 { + fn _data_blocks(size: u32) -> u32 { (size + BLOCK_SZ as u32 - 1) / BLOCK_SZ as u32 } + /// Return number of blocks needed include indirect1/2. + pub fn total_blocks(size: u32) -> u32 { + let data_blocks = Self::_data_blocks(size) as usize; + let mut total = data_blocks as usize; + // indirect1 + if data_blocks > INODE_DIRECT_COUNT { + total += 1; + } + // indirect2 + if data_blocks > INDIRECT1_BOUND { + total += 1; + // sub indirect1 + total += (data_blocks - INDIRECT1_BOUND + INODE_INDIRECT1_COUNT - 1) / INODE_INDIRECT1_COUNT; + } + total as u32 + } + pub fn blocks_num_needed(&self, new_size: u32) -> u32 { + assert!(new_size >= self.size); + Self::total_blocks(new_size) - Self::total_blocks(self.size) + } pub fn get_block_id(&self, inner_id: u32, block_device: &Arc<dyn BlockDevice>) -> u32 { let inner_id = inner_id as usize; if inner_id < INODE_DIRECT_COUNT { self.direct[inner_id] - } else { - // only support indirect1 now + } else if inner_id < INDIRECT1_BOUND { get_block_cache(self.indirect1 as usize, Arc::clone(block_device)) .lock() .read(0, |indirect_block: &IndirectBlock| { indirect_block[inner_id - INODE_DIRECT_COUNT] }) + } else { + let last = inner_id - INDIRECT1_BOUND; + let indirect1 = get_block_cache( + self.indirect2 as usize, + Arc::clone(block_device) + ) + .lock() + .read(0, |indirect2: &IndirectBlock| { + indirect2[last / INODE_INDIRECT1_COUNT] + }); + get_block_cache( + indirect1 as usize, + Arc::clone(block_device) + ) + .lock() + .read(0, |indirect1: &IndirectBlock| { + indirect1[last % INODE_INDIRECT1_COUNT] + }) } } - pub fn blocks_num_needed(&self, new_size: u32) -> u32 { - assert!(new_size >= self.size); - Self::_blocks(new_size) - self.blocks() - } pub fn increase_size( &mut self, new_size: u32, new_blocks: Vec<u32>, block_device: &Arc<dyn BlockDevice>, ) { - assert_eq!(new_blocks.len() as u32, self.blocks_num_needed(new_size)); - let last_blocks = self.blocks(); + let mut current_blocks = self.data_blocks(); self.size = new_size; - let current_blocks = self.blocks(); + let mut total_blocks = self.data_blocks(); + let mut new_blocks = new_blocks.into_iter(); + // fill direct + while current_blocks < total_blocks.min(INODE_DIRECT_COUNT as u32) { + self.direct[current_blocks as usize] = new_blocks.next().unwrap(); + current_blocks += 1; + } + // alloc indirect1 + if total_blocks > INODE_DIRECT_COUNT as u32{ + if current_blocks == INODE_DIRECT_COUNT as u32 { + self.indirect1 = new_blocks.next().unwrap(); + } + current_blocks -= INODE_DIRECT_COUNT as u32; + total_blocks -= INODE_DIRECT_COUNT as u32; + } else { + return; + } + // fill indirect1 get_block_cache( self.indirect1 as usize, Arc::clone(block_device) ) .lock() - .modify(0, |indirect_block: &mut IndirectBlock| { - for i in 0..current_blocks - last_blocks { - let inner_id = (last_blocks + i) as usize; - let new_block = new_blocks[i as usize]; - if inner_id < INODE_DIRECT_COUNT { - self.direct[inner_id] = new_block; - } else { - indirect_block[inner_id - INODE_DIRECT_COUNT] = new_block; - } + .modify(0, |indirect1: &mut IndirectBlock| { + while current_blocks < total_blocks.min(INODE_INDIRECT1_COUNT as u32) { + indirect1[current_blocks as usize] = new_blocks.next().unwrap(); + current_blocks += 1; } }); + // alloc indirect2 + if total_blocks > INODE_INDIRECT1_COUNT as u32 { + if current_blocks == INODE_INDIRECT1_COUNT as u32 { + self.indirect2 = new_blocks.next().unwrap(); + } + current_blocks -= INODE_INDIRECT1_COUNT as u32; + total_blocks -= INODE_INDIRECT1_COUNT as u32; + } else { + return; + } + // fill indirect2 from (a0, b0) -> (a1, b1) + let mut a0 = current_blocks as usize / INODE_INDIRECT1_COUNT; + let mut b0 = current_blocks as usize % INODE_INDIRECT1_COUNT; + let a1 = total_blocks as usize / INODE_INDIRECT1_COUNT; + let b1 = total_blocks as usize % INODE_INDIRECT1_COUNT; + // alloc low-level indirect1 + get_block_cache( + self.indirect2 as usize, + Arc::clone(block_device) + ) + .lock() + .modify(0, |indirect2: &mut IndirectBlock| { + while (a0 < a1) || (a0 == a1 && b0 < b1) { + if b0 == 0 { + indirect2[a0] = new_blocks.next().unwrap(); + } + // fill current + get_block_cache( + indirect2[a0] as usize, + Arc::clone(block_device) + ) + .lock() + .modify(0, |indirect1: &mut IndirectBlock| { + indirect1[b0] = new_blocks.next().unwrap(); + }); + // move to next + b0 += 1; + if b0 == INODE_INDIRECT1_COUNT { + b0 = 0; + a0 += 1; + } + } + }); } - /// Clear size to zero and return blocks that should be deallocated. + + /* pub fn clear_size(&mut self, block_device: &Arc<dyn BlockDevice>) -> Vec<u32> { let mut v: Vec<u32> = Vec::new(); let blocks = self.blocks() as usize; @@ -165,6 +260,97 @@ impl DiskInode { } v } + */ + + /// Clear size to zero and return blocks that should be deallocated. + /// + /// We will clear the block contents to zero later. + pub fn clear_size(&mut self, block_device: &Arc<dyn BlockDevice>) -> Vec<u32> { + let mut v: Vec<u32> = Vec::new(); + let mut data_blocks = self.data_blocks() as usize; + self.size = 0; + let mut current_blocks = 0usize; + // direct + while current_blocks < data_blocks.min(INODE_DIRECT_COUNT) { + v.push(self.direct[current_blocks]); + self.direct[current_blocks] = 0; + current_blocks += 1; + } + // indirect1 block + if data_blocks > INODE_DIRECT_COUNT { + v.push(self.indirect1); + data_blocks -= INODE_DIRECT_COUNT; + current_blocks = 0; + } else { + return v; + } + // indirect1 + get_block_cache( + self.indirect1 as usize, + Arc::clone(block_device), + ) + .lock() + .modify(0, |indirect1: &mut IndirectBlock| { + while current_blocks < data_blocks.min(INODE_INDIRECT1_COUNT) { + v.push(indirect1[current_blocks]); + //indirect1[current_blocks] = 0; + current_blocks += 1; + } + }); + self.indirect1 = 0; + // indirect2 block + if data_blocks > INODE_INDIRECT1_COUNT { + v.push(self.indirect2); + data_blocks -= INODE_INDIRECT1_COUNT; + } else { + return v; + } + // indirect2 + assert!(data_blocks <= INODE_INDIRECT2_COUNT); + let a1 = data_blocks / INODE_INDIRECT1_COUNT; + let b1 = data_blocks % INODE_INDIRECT1_COUNT; + get_block_cache( + self.indirect2 as usize, + Arc::clone(block_device), + ) + .lock() + .modify(0, |indirect2: &mut IndirectBlock| { + // full indirect1 blocks + for i in 0..a1 { + v.push(indirect2[i]); + get_block_cache( + indirect2[i] as usize, + Arc::clone(block_device), + ) + .lock() + .modify(0, |indirect1: &mut IndirectBlock| { + for j in 0..INODE_INDIRECT1_COUNT { + v.push(indirect1[j]); + //indirect1[j] = 0; + } + }); + //indirect2[i] = 0; + } + // last indirect1 block + if b1 > 0 { + v.push(indirect2[a1]); + get_block_cache( + indirect2[a1] as usize, + Arc::clone(block_device), + ) + .lock() + .modify(0, |indirect1: &mut IndirectBlock| { + for j in 0..b1 { + v.push(indirect1[j]); + //indirect1[j] = 0; + } + }); + //indirect2[a1] = 0; + } + }); + self.indirect2 = 0; + v + } pub fn read_at( &self, offset: usize, diff --git a/easy-fs/src/vfs.rs b/easy-fs/src/vfs.rs index a98fd607..f10a8c8a 100644 --- a/easy-fs/src/vfs.rs +++ b/easy-fs/src/vfs.rs @@ -122,22 +122,18 @@ impl Inode { }).is_some() { return None; } - //println!("same file does not exist in Inode::create."); // create a new file // alloc a inode with an indirect block let new_inode_id = fs.alloc_inode(); - let indirect1 = fs.alloc_data(); // initialize inode let (new_inode_block_id, new_inode_block_offset) = fs.get_disk_inode_pos(new_inode_id); - //println!("new_inode_id={} ({},{})", new_inode_id, new_inode_block_id, new_inode_block_offset); get_block_cache( new_inode_block_id as usize, Arc::clone(&self.block_device) ).lock().modify(new_inode_block_offset, |new_inode: &mut DiskInode| { - new_inode.initialize(DiskInodeType::File, indirect1); + new_inode.initialize(DiskInodeType::File); }); - //println!("new inode has been initialized."); self.modify_disk_inode(|root_inode| { // append file in the dirent let file_count = (root_inode.size as usize) / DIRENT_SZ; @@ -152,7 +148,6 @@ impl Inode { &self.block_device, ); }); - //println!("new file has been inserted into root inode."); // release efs lock manually because we will acquire it again in Inode::new drop(fs); // return inode @@ -202,7 +197,9 @@ impl Inode { pub fn clear(&self) { let mut fs = self.fs.lock(); self.modify_disk_inode(|disk_inode| { + let size = disk_inode.size; let data_blocks_dealloc = disk_inode.clear_size(&self.block_device); + assert!(data_blocks_dealloc.len() == DiskInode::total_blocks(size) as usize); for data_block in data_blocks_dealloc.into_iter() { fs.dealloc_data(data_block); } diff --git a/os/Makefile b/os/Makefile index 568a2779..4d86c124 100644 --- a/os/Makefile +++ b/os/Makefile @@ -6,7 +6,7 @@ KERNEL_BIN := $(KERNEL_ELF).bin DISASM_TMP := target/$(TARGET)/$(MODE)/asm FS_IMG := ../user/target/$(TARGET)/$(MODE)/fs.img SDCARD := /dev/sdb -APPS := ../user/src/bin +APPS := ../user/src/bin/* # BOARD BOARD ?= qemu diff --git a/os/src/mm/address.rs b/os/src/mm/address.rs index f9e02805..d5828ed2 100644 --- a/os/src/mm/address.rs +++ b/os/src/mm/address.rs @@ -115,6 +115,11 @@ impl VirtPageNum { } impl PhysAddr { + pub fn get_ref<T>(&self) -> &'static T { + unsafe { + (self.0 as *const T).as_ref().unwrap() + } + } pub fn get_mut<T>(&self) -> &'static mut T { unsafe { (self.0 as *mut T).as_mut().unwrap() diff --git a/os/src/mm/mod.rs b/os/src/mm/mod.rs index 2242eecb..dbd47fe7 100644 --- a/os/src/mm/mod.rs +++ b/os/src/mm/mod.rs @@ -13,6 +13,7 @@ pub use page_table::{ PageTableEntry, translated_byte_buffer, translated_str, + translated_ref, translated_refmut, UserBuffer, UserBufferIterator, diff --git a/os/src/mm/page_table.rs b/os/src/mm/page_table.rs index 47f39a76..b1a227fa 100644 --- a/os/src/mm/page_table.rs +++ b/os/src/mm/page_table.rs @@ -174,6 +174,7 @@ pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<& v } +/// Load a string from other address spaces into kernel space without an end `\0`. pub fn translated_str(token: usize, ptr: *const u8) -> String { let page_table = PageTable::from_token(token); let mut string = String::new(); @@ -182,14 +183,18 @@ pub fn translated_str(token: usize, ptr: *const u8) -> String { let ch: u8 = *(page_table.translate_va(VirtAddr::from(va)).unwrap().get_mut()); if ch == 0 { break; - } else { - string.push(ch as char); - va += 1; } + string.push(ch as char); + va += 1; } string } +pub fn translated_ref<T>(token: usize, ptr: *const T) -> &'static T { + let page_table = PageTable::from_token(token); + page_table.translate_va(VirtAddr::from(ptr as usize)).unwrap().get_ref() +} + pub fn translated_refmut<T>(token: usize, ptr: *mut T) -> &'static mut T { let page_table = PageTable::from_token(token); let va = ptr as usize; diff --git a/os/src/syscall/fs.rs b/os/src/syscall/fs.rs index 577e4a0a..79eac32a 100644 --- a/os/src/syscall/fs.rs +++ b/os/src/syscall/fs.rs @@ -6,6 +6,7 @@ use crate::mm::{ }; use crate::task::{current_user_token, current_task}; use crate::fs::{make_pipe, OpenFlags, open_file}; +use alloc::sync::Arc; pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize { let token = current_user_token(); @@ -93,4 +94,18 @@ pub fn sys_pipe(pipe: *mut usize) -> isize { *translated_refmut(token, pipe) = read_fd; *translated_refmut(token, unsafe { pipe.add(1) }) = write_fd; 0 +} + +pub fn sys_dup(fd: usize) -> isize { + let task = current_task().unwrap(); + let mut inner = task.acquire_inner_lock(); + if fd >= inner.fd_table.len() { + return -1; + } + if inner.fd_table[fd].is_none() { + return -1; + } + let new_fd = inner.alloc_fd(); + inner.fd_table[new_fd] = Some(Arc::clone(inner.fd_table[fd].as_ref().unwrap())); + new_fd as isize } \ No newline at end of file diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index f4a67538..4683d055 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -1,3 +1,4 @@ +const SYSCALL_DUP: usize = 24; const SYSCALL_OPEN: usize = 56; const SYSCALL_CLOSE: usize = 57; const SYSCALL_PIPE: usize = 59; @@ -19,6 +20,7 @@ use process::*; pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { match syscall_id { + SYSCALL_DUP=> sys_dup(args[0]), SYSCALL_OPEN => sys_open(args[0] as *const u8, args[1] as u32), SYSCALL_CLOSE => sys_close(args[0]), SYSCALL_PIPE => sys_pipe(args[0] as *mut usize), @@ -29,7 +31,7 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { SYSCALL_GET_TIME => sys_get_time(), SYSCALL_GETPID => sys_getpid(), SYSCALL_FORK => sys_fork(), - SYSCALL_EXEC => sys_exec(args[0] as *const u8), + SYSCALL_EXEC => sys_exec(args[0] as *const u8, args[1] as *const usize), SYSCALL_WAITPID => sys_waitpid(args[0] as isize, args[1] as *mut i32), _ => panic!("Unsupported syscall_id: {}", syscall_id), } diff --git a/os/src/syscall/process.rs b/os/src/syscall/process.rs index 370ae9cb..bfd592d6 100644 --- a/os/src/syscall/process.rs +++ b/os/src/syscall/process.rs @@ -9,12 +9,15 @@ use crate::timer::get_time_ms; use crate::mm::{ translated_str, translated_refmut, + translated_ref, }; use crate::fs::{ open_file, OpenFlags, }; use alloc::sync::Arc; +use alloc::vec::Vec; +use alloc::string::String; pub fn sys_exit(exit_code: i32) -> ! { exit_current_and_run_next(exit_code); @@ -48,14 +51,25 @@ pub fn sys_fork() -> isize { new_pid as isize } -pub fn sys_exec(path: *const u8) -> isize { +pub fn sys_exec(path: *const u8, mut args: *const usize) -> isize { let token = current_user_token(); let path = translated_str(token, path); + let mut args_vec: Vec<String> = Vec::new(); + loop { + let arg_str_ptr = *translated_ref(token, args); + if arg_str_ptr == 0 { + break; + } + args_vec.push(translated_str(token, arg_str_ptr as *const u8)); + unsafe { args = args.add(1); } + } if let Some(app_inode) = open_file(path.as_str(), OpenFlags::RDONLY) { let all_data = app_inode.read_all(); let task = current_task().unwrap(); - task.exec(all_data.as_slice()); - 0 + let argc = args_vec.len(); + task.exec(all_data.as_slice(), args_vec); + // return argc because cx.x[10] will be covered with it later + argc as isize } else { -1 } diff --git a/os/src/task/task.rs b/os/src/task/task.rs index 1c733da1..4edd5cef 100644 --- a/os/src/task/task.rs +++ b/os/src/task/task.rs @@ -1,4 +1,10 @@ -use crate::mm::{MemorySet, PhysPageNum, KERNEL_SPACE, VirtAddr}; +use crate::mm::{ + MemorySet, + PhysPageNum, + KERNEL_SPACE, + VirtAddr, + translated_refmut, +}; use crate::trap::{TrapContext, trap_handler}; use crate::config::{TRAP_CONTEXT}; use super::TaskContext; @@ -6,6 +12,7 @@ use super::{PidHandle, pid_alloc, KernelStack}; use alloc::sync::{Weak, Arc}; use alloc::vec; use alloc::vec::Vec; +use alloc::string::String; use spin::{Mutex, MutexGuard}; use crate::fs::{File, Stdin, Stdout}; @@ -106,13 +113,35 @@ impl TaskControlBlock { ); task_control_block } - pub fn exec(&self, elf_data: &[u8]) { + pub fn exec(&self, elf_data: &[u8], args: Vec<String>) { // memory_set with elf program headers/trampoline/trap context/user stack - let (memory_set, user_sp, entry_point) = MemorySet::from_elf(elf_data); + let (memory_set, mut user_sp, entry_point) = MemorySet::from_elf(elf_data); let trap_cx_ppn = memory_set .translate(VirtAddr::from(TRAP_CONTEXT).into()) .unwrap() .ppn(); + // push arguments on user stack + user_sp -= (args.len() + 1) * core::mem::size_of::<usize>(); + let argv_base = user_sp; + let mut argv: Vec<_> = (0..=args.len()) + .map(|arg| { + translated_refmut( + memory_set.token(), + (argv_base + arg * core::mem::size_of::<usize>()) as *mut usize + ) + }) + .collect(); + *argv[args.len()] = 0; + for i in 0..args.len() { + user_sp -= args[i].len() + 1; + *argv[i] = user_sp; + let mut p = user_sp; + for c in args[i].as_bytes() { + *translated_refmut(memory_set.token(), p as *mut u8) = *c; + p += 1; + } + *translated_refmut(memory_set.token(), p as *mut u8) = 0; + } // **** hold current PCB lock let mut inner = self.acquire_inner_lock(); @@ -121,14 +150,16 @@ impl TaskControlBlock { // update trap_cx ppn inner.trap_cx_ppn = trap_cx_ppn; // initialize trap_cx - let trap_cx = inner.get_trap_cx(); - *trap_cx = TrapContext::app_init_context( + let mut trap_cx = TrapContext::app_init_context( entry_point, user_sp, KERNEL_SPACE.lock().token(), self.kernel_stack.get_top(), trap_handler as usize, ); + trap_cx.x[10] = args.len(); + trap_cx.x[11] = argv_base; + *inner.get_trap_cx() = trap_cx; // **** release current PCB lock } pub fn fork(self: &Arc<TaskControlBlock>) -> Arc<TaskControlBlock> { diff --git a/os/src/trap/context.rs b/os/src/trap/context.rs index 8c5175f7..16f81415 100644 --- a/os/src/trap/context.rs +++ b/os/src/trap/context.rs @@ -1,6 +1,7 @@ use riscv::register::sstatus::{Sstatus, self, SPP}; #[repr(C)] +#[derive(Debug)] pub struct TrapContext { pub x: [usize; 32], pub sstatus: Sstatus, diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs index 4f5126b2..f83560b2 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -88,6 +88,7 @@ pub fn trap_handler() -> ! { panic!("Unsupported trap {:?}, stval = {:#x}!", scause.cause(), stval); } } + //println!("before trap_return"); trap_return(); } diff --git a/user/src/bin/cat.rs b/user/src/bin/cat.rs new file mode 100644 index 00000000..988164d3 --- /dev/null +++ b/user/src/bin/cat.rs @@ -0,0 +1,34 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use user_lib::{ + open, + OpenFlags, + close, + read, +}; +use alloc::string::String; + +#[no_mangle] +pub fn main(argc: usize, argv: &[&str]) -> i32 { + assert!(argc == 2); + let fd = open(argv[1], OpenFlags::RDONLY); + if fd == -1 { + panic!("Error occured when opening file"); + } + let fd = fd as usize; + let mut buf = [0u8; 16]; + let mut s = String::new(); + loop { + let size = read(fd, &mut buf) as usize; + if size == 0 { break; } + s.push_str(core::str::from_utf8(&buf[..size]).unwrap()); + } + println!("{}", s); + close(fd); + 0 +} \ No newline at end of file diff --git a/user/src/bin/cmdline_args.rs b/user/src/bin/cmdline_args.rs new file mode 100644 index 00000000..b49ec332 --- /dev/null +++ b/user/src/bin/cmdline_args.rs @@ -0,0 +1,16 @@ +#![no_std] +#![no_main] + +extern crate alloc; + +#[macro_use] +extern crate user_lib; + +#[no_mangle] +pub fn main(argc: usize, argv: &[&str]) -> i32 { + println!("argc = {}", argc); + for i in 0..argc { + println!("argv[{}] = {}", i, argv[i]); + } + 0 +} \ No newline at end of file diff --git a/user/src/bin/initproc.rs b/user/src/bin/initproc.rs index 6d30fdb6..99563f47 100644 --- a/user/src/bin/initproc.rs +++ b/user/src/bin/initproc.rs @@ -14,7 +14,7 @@ use user_lib::{ #[no_mangle] fn main() -> i32 { if fork() == 0 { - exec("user_shell\0"); + exec("user_shell\0", &[0 as *const u8]); } else { loop { let mut exit_code: i32 = 0; diff --git a/user/src/bin/run_pipe_test.rs b/user/src/bin/run_pipe_test.rs index ca2afd15..000b82d5 100644 --- a/user/src/bin/run_pipe_test.rs +++ b/user/src/bin/run_pipe_test.rs @@ -10,7 +10,7 @@ use user_lib::{fork, exec, wait}; pub fn main() -> i32 { for i in 0..1000 { if fork() == 0 { - exec("pipe_large_test\0"); + exec("pipe_large_test\0", &[0 as *const u8]); } else { let mut _unused: i32 = 0; wait(&mut _unused); diff --git a/user/src/bin/user_shell.rs b/user/src/bin/user_shell.rs index 796bddb5..b2c33f2d 100644 --- a/user/src/bin/user_shell.rs +++ b/user/src/bin/user_shell.rs @@ -12,7 +12,16 @@ const DL: u8 = 0x7fu8; const BS: u8 = 0x08u8; use alloc::string::String; -use user_lib::{fork, exec, waitpid}; +use alloc::vec::Vec; +use user_lib::{ + fork, + exec, + waitpid, + open, + OpenFlags, + close, + dup, +}; use user_lib::console::getchar; #[no_mangle] @@ -26,11 +35,78 @@ pub fn main() -> i32 { LF | CR => { println!(""); if !line.is_empty() { - line.push('\0'); + let args: Vec<_> = line.as_str().split(' ').collect(); + let mut args_copy: Vec<String> = args + .iter() + .map(|&arg| { + let mut string = String::new(); + string.push_str(arg); + string + }) + .collect(); + + args_copy + .iter_mut() + .for_each(|string| { + string.push('\0'); + }); + + // redirect input + let mut input = String::new(); + if let Some((idx, _)) = args_copy + .iter() + .enumerate() + .find(|(_, arg)| arg.as_str() == "<\0") { + input = args_copy[idx + 1].clone(); + args_copy.drain(idx..=idx + 1); + } + + // redirect output + let mut output = String::new(); + if let Some((idx, _)) = args_copy + .iter() + .enumerate() + .find(|(_, arg)| arg.as_str() == ">\0") { + output = args_copy[idx + 1].clone(); + args_copy.drain(idx..=idx + 1); + } + + let mut args_addr: Vec<*const u8> = args_copy + .iter() + .map(|arg| arg.as_ptr()) + .collect(); + args_addr.push(0 as *const u8); let pid = fork(); if pid == 0 { + // input redirection + if !input.is_empty() { + let input_fd = open(input.as_str(), OpenFlags::RDONLY); + if input_fd == -1 { + println!("Error when opening file {}", input); + return -4; + } + let input_fd = input_fd as usize; + close(0); + assert_eq!(dup(input_fd), 0); + close(input_fd); + } + // output redirection + if !output.is_empty() { + let output_fd = open( + output.as_str(), + OpenFlags::CREATE | OpenFlags::WRONLY + ); + if output_fd == -1 { + println!("Error when opening file {}", output); + return -4; + } + let output_fd = output_fd as usize; + close(1); + assert_eq!(dup(output_fd), 1); + close(output_fd); + } // child process - if exec(line.as_str()) == -1 { + if exec(args_copy[0].as_str(), args_addr.as_slice()) == -1 { println!("Error when executing!"); return -4; } diff --git a/user/src/bin/usertests.rs b/user/src/bin/usertests.rs index 7a4a6d7b..e8be6c45 100644 --- a/user/src/bin/usertests.rs +++ b/user/src/bin/usertests.rs @@ -26,7 +26,7 @@ pub fn main() -> i32 { println!("Usertests: Running {}", test); let pid = fork(); if pid == 0 { - exec(*test); + exec(*test, &[0 as *const u8]); panic!("unreachable!"); } else { let mut exit_code: i32 = Default::default(); diff --git a/user/src/lib.rs b/user/src/lib.rs index 244baaea..0ef03bfb 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -15,8 +15,9 @@ extern crate bitflags; use syscall::*; use buddy_system_allocator::LockedHeap; +use alloc::vec::Vec; -const USER_HEAP_SIZE: usize = 16384; +const USER_HEAP_SIZE: usize = 32768; static mut HEAP_SPACE: [u8; USER_HEAP_SIZE] = [0; USER_HEAP_SIZE]; @@ -30,17 +31,31 @@ pub fn handle_alloc_error(layout: core::alloc::Layout) -> ! { #[no_mangle] #[link_section = ".text.entry"] -pub extern "C" fn _start() -> ! { +pub extern "C" fn _start(argc: usize, argv: usize) -> ! { unsafe { HEAP.lock() .init(HEAP_SPACE.as_ptr() as usize, USER_HEAP_SIZE); } - exit(main()); + let mut v: Vec<&'static str> = Vec::new(); + for i in 0..argc { + let str_start = unsafe { + ((argv + i * core::mem::size_of::<usize>()) as *const usize).read_volatile() + }; + let len = (0usize..).find(|i| unsafe { + ((str_start + *i) as *const u8).read_volatile() == 0 + }).unwrap(); + v.push( + core::str::from_utf8(unsafe { + core::slice::from_raw_parts(str_start as *const u8, len) + }).unwrap() + ); + } + exit(main(argc, v.as_slice())); } #[linkage = "weak"] #[no_mangle] -fn main() -> i32 { +fn main(_argc: usize, _argv: &[&str]) -> i32 { panic!("Cannot find main!"); } @@ -54,6 +69,7 @@ bitflags! { } } +pub fn dup(fd: usize) -> isize { sys_dup(fd) } pub fn open(path: &str, flags: OpenFlags) -> isize { sys_open(path, flags.bits) } pub fn close(fd: usize) -> isize { sys_close(fd) } pub fn pipe(pipe_fd: &mut [usize]) -> isize { sys_pipe(pipe_fd) } @@ -64,7 +80,7 @@ pub fn yield_() -> isize { sys_yield() } pub fn get_time() -> isize { sys_get_time() } pub fn getpid() -> isize { sys_getpid() } pub fn fork() -> isize { sys_fork() } -pub fn exec(path: &str) -> isize { sys_exec(path) } +pub fn exec(path: &str, args: &[*const u8]) -> isize { sys_exec(path, args) } pub fn wait(exit_code: &mut i32) -> isize { loop { match sys_waitpid(-1, exit_code as *mut _) { diff --git a/user/src/syscall.rs b/user/src/syscall.rs index a1101e1b..1cd30f84 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -1,3 +1,4 @@ +const SYSCALL_DUP: usize = 24; const SYSCALL_OPEN: usize = 56; const SYSCALL_CLOSE: usize = 57; const SYSCALL_PIPE: usize = 59; @@ -24,6 +25,10 @@ fn syscall(id: usize, args: [usize; 3]) -> isize { ret } +pub fn sys_dup(fd: usize) -> isize { + syscall(SYSCALL_DUP, [fd, 0, 0]) +} + pub fn sys_open(path: &str, flags: u32) -> isize { syscall(SYSCALL_OPEN, [path.as_ptr() as usize, flags as usize, 0]) } @@ -65,8 +70,8 @@ pub fn sys_fork() -> isize { syscall(SYSCALL_FORK, [0, 0, 0]) } -pub fn sys_exec(path: &str) -> isize { - syscall(SYSCALL_EXEC, [path.as_ptr() as usize, 0, 0]) +pub fn sys_exec(path: &str, args: &[*const u8]) -> isize { + syscall(SYSCALL_EXEC, [path.as_ptr() as usize, args.as_ptr() as usize, 0]) } pub fn sys_waitpid(pid: isize, exit_code: *mut i32) -> isize {