Skip to content

Commit

Permalink
feat: add file system
Browse files Browse the repository at this point in the history
  • Loading branch information
Godones committed Jul 21, 2022
1 parent 05c4234 commit 7de0b4c
Show file tree
Hide file tree
Showing 52 changed files with 1,916 additions and 42 deletions.
85 changes: 85 additions & 0 deletions docs/实验手册.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,88 @@ TLB 表项的比较部分包括:

![image-20220707161012062](sourcepicture/image-20220707161012062.png)











# 第五章

### 问题1: 在用户程序`matrix`实现中,如果是如下的代码:

```rust
println!("pid {} is running ({} times)!.", getpid(), times);
```

则会造成页错误,如果改成如下的代码:

```rust
println!("yield began");
yield_();
println!("pid {} is running ({} times)!.", getpid(), times);
```

则会运行通过。



解决思路1: 在任务切换时是否正确进行了相关寄存器的设置?

实际效果: 以第一种代码为例,在设置正确寄存器后,虽然可以正常打印这句话,但是后面仍然会造成指令不存在的错误

解决思路2:删除掉第二中的添加的打印语句,改成如下的语句:

```rust
let mut i = 2;
yield_();
println!("pid {} is running ({} times {})!.", getpid(), times,i);
```

效果:

在这种情况下,将会发生访问的地址出现错误的情况,此时出错地址不在正常的地址空间中。

==debug过程:==

在TLB重填处理函数中将出错地址打印出来,通过观察,此地址应该属于内核区域,因此不会在对应的应用程序的地址空间找到对应的页表项。而应用程序这里出错的位置是打印函数`println`,因此推测可能是`print`函数实现有错误,再去查看rcore的源代码后发现`print/println`的实现确实有过更改,因此这里就暂时将实现修改,在测试后发现居然可以正常运行了,因此就需要仔细对比前后两者的实现了。

老版本实现:

```rust
#[macro_export]
macro_rules! print {
($($arg:tt)*) => ($crate::print::_print(format_args!($($arg)*)));
}
#[macro_export]
macro_rules! println {
() => ($crate::print!("\n"));
($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
}
```

新版本实现:

```rust
macro_rules! print {
($fmt: literal $(, $($arg: tt)+)?) => {
$crate::print::_print(format_args!($fmt $(, $($arg)+)?));
}
}

#[macro_export]
/// println string macro
macro_rules! println {
($fmt: literal $(, $($arg: tt)+)?) => {
$crate::print::_print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?));
}
}

```

两者实现差异:

13 changes: 13 additions & 0 deletions easy-fs-fuse/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
### Rust template
# Generated by Cargo
# will have compiled files and executables
debug/
target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

5 changes: 5 additions & 0 deletions easy-fs-fuse/.idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions easy-fs-fuse/.idea/easy-fs-fuse.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions easy-fs-fuse/.idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions easy-fs-fuse/.idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions easy-fs-fuse/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "easy-fs-fuse"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
clap = "3.0.14"
rand = "0.8.4"
easy-fs = {path = "../easy-fs"}
152 changes: 152 additions & 0 deletions easy-fs-fuse/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
use clap::{App, Arg};
use easy_fs::{BlockDevice, EasyFileSystem};
use std::fs::{read_dir, File, OpenOptions};
use std::io::{Read, Seek, SeekFrom, Write};
use std::sync::Arc;
use std::sync::Mutex;

const BLOCK_SZ: usize = 512;

struct BlockFile(Mutex<File>);

impl BlockDevice for BlockFile {
fn read_block(&self, block_id: usize, buf: &mut [u8]) {
let mut file = self.0.lock().unwrap();
file.seek(SeekFrom::Start((block_id * BLOCK_SZ) as u64))
.expect("Error when seeking!");
assert_eq!(file.read(buf).unwrap(), BLOCK_SZ, "Not a complete block!");
}

fn write_block(&self, block_id: usize, buf: &[u8]) {
let mut file = self.0.lock().unwrap();
file.seek(SeekFrom::Start((block_id * BLOCK_SZ) as u64))
.expect("Error when seeking!");
assert_eq!(file.write(buf).unwrap(), BLOCK_SZ, "Not a complete block!");
}
}


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"))?;
f.set_len(16 * 2048 * 512).unwrap();
f
})));
// 16MiB, at most 4095 files
let efs = EasyFileSystem::create(block_file, 16 * 2048, 1);
let root_inode = Arc::new(EasyFileSystem::root_inode(&efs));
let apps: Vec<_> = read_dir(src_path)
.unwrap()
.into_iter()
.map(|dir_entry| {
let mut name_with_ext = dir_entry.unwrap().file_name().into_string().unwrap();
name_with_ext.drain(name_with_ext.find('.').unwrap()..name_with_ext.len());
name_with_ext
})
.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 all_data: Vec<u8> = Vec::new();
host_file.read_to_end(&mut all_data).unwrap();
// create a file in easy-fs
let inode = root_inode.create(app.as_str()).unwrap();
// write data to easy-fs
inode.write_at(0, all_data.as_slice());
}
// list apps
for app in root_inode.ls() {
println!("{}", app);
}
Ok(())
}

#[test]
fn efs_test() -> std::io::Result<()> {
let block_file = Arc::new(BlockFile(Mutex::new({
let f = OpenOptions::new()
.read(true)
.write(true)
.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 root_inode = EasyFileSystem::root_inode(&efs);
root_inode.create("filea");
root_inode.create("fileb");
for name in root_inode.ls() {
println!("{}", name);
}
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; 233];
let len = filea.read_at(0, &mut buffer);
assert_eq!(greet_str, core::str::from_utf8(&buffer[..len]).unwrap(),);

let mut random_str_test = |len: usize| {
filea.clear();
assert_eq!(filea.read_at(0, &mut buffer), 0,);
let mut str = String::new();
use rand;
// random digit
for _ in 0..len {
str.push(char::from('0' as u8 + rand::random::<u8>() % 10));
}
filea.write_at(0, str.as_bytes());
let mut read_buffer = [0u8; 127];
let mut offset = 0usize;
let mut read_str = String::new();
loop {
let len = filea.read_at(offset, &mut read_buffer);
if len == 0 {
break;
}
offset += len;
read_str.push_str(core::str::from_utf8(&read_buffer[..len]).unwrap());
}
assert_eq!(str, read_str);
};

random_str_test(4 * BLOCK_SZ);
random_str_test(8 * BLOCK_SZ + BLOCK_SZ / 2);
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(())
}

fn main() {
easy_fs_pack().expect("Error when packing easy-fs!");
}
15 changes: 15 additions & 0 deletions easy-fs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
### Rust template
# Generated by Cargo
# will have compiled files and executables
debug/
target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk



5 changes: 5 additions & 0 deletions easy-fs/.idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions easy-fs/.idea/easy-fs.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions easy-fs/.idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions easy-fs/.idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions easy-fs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "easy-fs"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
spin = "0.9.2"
lazy_static = {version = "1.4.0", features = ["spin_no_std"]}


[profile.release]
debug = true
Loading

0 comments on commit 7de0b4c

Please sign in to comment.