Skip to content

Commit

Permalink
lab6
Browse files Browse the repository at this point in the history
  • Loading branch information
TL-SN committed Jan 21, 2024
1 parent e9c42c8 commit d74c899
Show file tree
Hide file tree
Showing 28 changed files with 1,017 additions and 253 deletions.
143 changes: 81 additions & 62 deletions easy-fs-fuse/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use clap::{App, Arg};
use clap::{App,Arg};
use easy_fs::{BlockDevice, EasyFileSystem};
use std::fs::{read_dir, File, OpenOptions};
use std::io::{Read, Seek, SeekFrom, Write};
Expand All @@ -7,18 +7,19 @@ use std::sync::Mutex;

const BLOCK_SZ: usize = 512;

// std::file::File 由 Rust 标准库 std 提供,可以访问 Linux 上的一个文件。我们将它包装成 BlockFile 类型来模拟一块磁盘,为它实现 BlockDevice 接口
struct BlockFile(Mutex<File>);

impl BlockDevice for BlockFile {
impl BlockDevice for BlockFile { // read_block,读取某一块block
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))
file.seek(SeekFrom::Start((block_id * BLOCK_SZ) as u64)) // 1、seek定位
.expect("Error when seeking!");
assert_eq!(file.read(buf).unwrap(), BLOCK_SZ, "Not a complete block!");
assert_eq!(file.read(buf).unwrap(), BLOCK_SZ, "Not a complete block!"); //2、read读取
}

fn write_block(&self, block_id: usize, buf: &[u8]) {
let mut file = self.0.lock().unwrap();
fn write_block(&self, block_id: usize, buf: &[u8]) { // 1、seek定位
let mut file = self.0.lock().unwrap(); // 2、write写入
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!");
Expand All @@ -27,41 +28,47 @@ impl BlockDevice for BlockFile {

fn main() {
easy_fs_pack().expect("Error when packing easy-fs!");
// efs_test().expect("111");
}

// #[test]
fn easy_fs_pack() -> std::io::Result<()> {
let matches = App::new("EasyFileSystem packer")
.arg(
Arg::with_name("source")
.short("s")
.short("s") // -s 指定用户的源代码目录
.long("source")
.takes_value(true)
.help("Executable source dir(with backslash)"),
)
.arg(
Arg::with_name("target")
.short("t")
.short("t") // -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 src_path = matches.value_of("source").unwrap(); // 1、读取source路径,source就是用户的源码路径
let target_path = matches.value_of("target").unwrap(); // 2、读取target路径,target路径就是用户生成的程序路径
println!("----------------------------------------------------------------------------------");
println!("src_path = {}\ntarget_path = {}", src_path, target_path);
println!("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
let block_file = Arc::new(BlockFile(Mutex::new({ // 3、创建 \\fs.img对象
let f = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(format!("{}{}", target_path, "fs.img"))?;
f.set_len(16 * 2048 * 512).unwrap();
f.set_len(16 * 2048 * 512).unwrap(); //4、指定fs.img大小为16MIB
f
})));
// 5、创建efs文件系统对象
// 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)

let root_inode = Arc::new(EasyFileSystem::root_inode(&efs)); // 6、获取根目录 inode
let apps: Vec<_> = read_dir(src_path) // 7、获取source目录中的每个应用的源代码文件并去掉后缀名
.unwrap()
.into_iter()
.map(|dir_entry| {
Expand All @@ -70,17 +77,19 @@ fn easy_fs_pack() -> std::io::Result<()> {
name_with_ext
})
.collect();
for app in apps {
for app in apps { // 8、枚举 apps 中的每个应用,从放置应用执行程序的目录中找到对应应用的 ELF 文件
//(这是一个 Linux 上的文件),并将数据读入内存。接着需要在 easy-fs 中创建一个同名文件并将 ELF 数据写
// 入到这个文件中。这个过程相当于将 Linux 上的文件系统中的一个文件复制到我们的 easy-fs 中。
// 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(); // 8_1、这是把user app的全部数据都读入了
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();
let inode = root_inode.create(app.as_str()).unwrap(); // 8_2、在文件系统的根目录中创建file,并写入app数据
// write data to easy-fs
inode.write_at(0, all_data.as_slice());
}
// list apps
//list apps
// for app in root_inode.ls() {
// println!("{}", app);
// }
Expand All @@ -89,7 +98,7 @@ fn easy_fs_pack() -> std::io::Result<()> {

#[test]
fn efs_test() -> std::io::Result<()> {
let block_file = Arc::new(BlockFile(Mutex::new({
let block_file = Arc::new(BlockFile(Mutex::new({ // 第一步我们需要打开虚拟块设备。这里我们在 Linux 上创建文件 easy-fs-fuse/target/fs.img 来新建一个虚拟块设备,并将它的容量设置为 8192 个块即 4MiB 。在创建的时候需要将它的访问权限设置为可读可写。
let f = OpenOptions::new()
.read(true)
.write(true)
Expand All @@ -98,54 +107,64 @@ fn efs_test() -> std::io::Result<()> {
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");
EasyFileSystem::create(block_file.clone(), 4096, 1); // 1、创建文件系统
let efs = EasyFileSystem::open(block_file.clone()); // 2、open文件系统
let root_inode = EasyFileSystem::root_inode(&efs); // 3、获取根目录的 Inode
root_inode.create("filea"); // 4、创建文件 filea与fileb
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);
};
let inode = root_inode.find_inode_id_by_root("filea").unwrap();
// println!("{:?}",inode);
root_inode.delete_dir_enter_by_inode_and_name("filea",inode );

for name in root_inode.ls() {
println!("{}", name);
}
// let filea = root_inode.find("filea").unwrap(); // 5、在根目录下寻找文件 filea
// let greet_str = "Hello, world!";
// filea.write_at(0, greet_str.as_bytes()); // 6、在文件开头写入"Hello World"
// //let mut buffer = [0u8; 512];
// let mut buffer = [0u8; 233];
// let len = filea.read_at(0, &mut buffer); // 7、在文件开头读取数据
// 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);
// 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(())
}
1 change: 0 additions & 1 deletion easy-fs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ edition = "2018"
[dependencies]
spin = "0.7.0"
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }

[profile.release]
debug = true

Expand Down
29 changes: 17 additions & 12 deletions easy-fs/src/bitmap.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
use super::{get_block_cache, BlockDevice, BLOCK_SZ};
use alloc::sync::Arc;
/// A bitmap block
type BitmapBlock = [u64; 64];
type BitmapBlock = [u64; 64]; // BitmapBlock 是一个磁盘数据结构,它将位图区域中的一个磁盘块解释为长度为 64 的一个 u64 数组
// 每个 u64 打包了一组 64 bits
/// Number of bits in a block
const BLOCK_BITS: usize = BLOCK_SZ * 8;
/// A bitmap
/// 每个位图都由若干个块组成,每个块大小为 512 bytes,即 4096 bits。每个 bit 都代表一个索引节点/数据块的分配状态, 0 意味着未分配,而 1 则意味着已经分配出去。
pub struct Bitmap {
start_block_id: usize,
blocks: usize,
start_block_id: usize, // 区域的起始块编号
blocks: usize, // 区域长度
}
/// 这里一个Bitmap结构体包含了好几个块,每个块都用来做位视图
// Bitmap 自身是驻留在内存中的


/// Decompose bits into (block_pos, bits64_pos, inner_pos)
fn decomposition(mut bit: usize) -> (usize, usize, usize) {
fn decomposition(mut bit: usize) -> (usize, usize, usize) { // decomposition
let block_pos = bit / BLOCK_BITS;
bit %= BLOCK_BITS;
(block_pos, bit / 64, bit % 64)
Expand All @@ -26,9 +31,9 @@ impl Bitmap {
}
}
/// Allocate a new block from a block device
pub fn alloc(&self, block_device: &Arc<dyn BlockDevice>) -> Option<usize> {
pub fn alloc(&self, block_device: &Arc<dyn BlockDevice>) -> Option<usize> { // 0、返回值是bit相对于该BitMap的第几位
for block_id in 0..self.blocks {
let pos = get_block_cache(
let pos = get_block_cache( // 获取块缓冲 // 1、block_id + self.start_block_id 是为了遍历该BitMap的每个块
block_id + self.start_block_id as usize,
Arc::clone(block_device),
)
Expand All @@ -37,12 +42,12 @@ impl Bitmap {
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))
.find(|(_, bits64)| **bits64 != u64::MAX) //2、 **bits64 != u64::MAX的意思是找到一个尚未完全分配出去的组,若完全分配,那就是64个1了,即u64::MAX
.map(|(bits64_pos, bits64)| (bits64_pos, bits64.trailing_ones() as usize)) //3、 最后得到的 bits64_pos 是BLOCK的下表,inner_pos是,连续1开始的下表
{
// modify cache
bitmap_block[bits64_pos] |= 1u64 << inner_pos;
Some(block_id * BLOCK_BITS + bits64_pos * 64 + inner_pos as usize)
bitmap_block[bits64_pos] |= 1u64 << inner_pos; //4、在对应 BitmapBlock 中增加一个1bit(变1)
Some(block_id * BLOCK_BITS + bits64_pos * 64 + inner_pos as usize) //5、返回值是增加bit在这个Bitmap的的第几位,即返回分配的bit编号
} else {
None
}
Expand All @@ -55,12 +60,12 @@ impl Bitmap {
}
/// Deallocate a block
pub fn dealloc(&self, block_device: &Arc<dyn BlockDevice>, bit: usize) {
let (block_pos, bits64_pos, inner_pos) = decomposition(bit);
let (block_pos, bits64_pos, inner_pos) = decomposition(bit); // 把bit序列分解
get_block_cache(block_pos + self.start_block_id, 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;
bitmap_block[bits64_pos] -= 1u64 << inner_pos; // 复位
});
}
/// Get the max number of allocatable blocks
Expand Down
Loading

0 comments on commit d74c899

Please sign in to comment.