Skip to main content

tg_easy_fs/
efs.rs

1use super::{
2    block_cache_sync_all, get_block_cache, Bitmap, BlockDevice, DiskInode, DiskInodeType, Inode,
3    SuperBlock,
4};
5use crate::BLOCK_SZ;
6use alloc::sync::Arc;
7use spin::Mutex;
8///An easy file system on block
9pub struct EasyFileSystem {
10    ///Real device
11    pub block_device: Arc<dyn BlockDevice>,
12    ///Inode bitmap
13    pub inode_bitmap: Bitmap,
14    ///Data bitmap
15    pub data_bitmap: Bitmap,
16    inode_area_start_block: u32,
17    data_area_start_block: u32,
18}
19
20type DataBlock = [u8; BLOCK_SZ];
21/// An easy fs over a block device
22impl EasyFileSystem {
23    /// A data block of block size
24    pub fn create(
25        block_device: Arc<dyn BlockDevice>,
26        total_blocks: u32,
27        inode_bitmap_blocks: u32,
28    ) -> Arc<Mutex<Self>> {
29        // 第一步:计算各区域块数并初始化 bitmap
30        let inode_bitmap = Bitmap::new(1, inode_bitmap_blocks as usize);
31        let inode_num = inode_bitmap.maximum();
32        let inode_area_blocks =
33            (inode_num * core::mem::size_of::<DiskInode>()).div_ceil(BLOCK_SZ) as u32;
34        let inode_total_blocks = inode_bitmap_blocks + inode_area_blocks;
35        let data_total_blocks = total_blocks - 1 - inode_total_blocks;
36        let data_bitmap_blocks = data_total_blocks.div_ceil(4097);
37        let data_area_blocks = data_total_blocks - data_bitmap_blocks;
38        let data_bitmap = Bitmap::new(
39            (1 + inode_bitmap_blocks + inode_area_blocks) as usize,
40            data_bitmap_blocks as usize,
41        );
42        let mut efs = Self {
43            block_device: Arc::clone(&block_device),
44            inode_bitmap,
45            data_bitmap,
46            inode_area_start_block: 1 + inode_bitmap_blocks,
47            data_area_start_block: 1 + inode_total_blocks + data_bitmap_blocks,
48        };
49        // 第二步:清盘(教学实现中直接全盘置零,简单直观)
50        for i in 0..total_blocks {
51            get_block_cache(i as usize, Arc::clone(&block_device))
52                .lock()
53                .modify(0, |data_block: &mut DataBlock| {
54                    for byte in data_block.iter_mut() {
55                        *byte = 0;
56                    }
57                });
58        }
59        // 第三步:写入 SuperBlock
60        get_block_cache(0, Arc::clone(&block_device)).lock().modify(
61            0,
62            |super_block: &mut SuperBlock| {
63                super_block.initialize(
64                    total_blocks,
65                    inode_bitmap_blocks,
66                    inode_area_blocks,
67                    data_bitmap_blocks,
68                    data_area_blocks,
69                );
70            },
71        );
72        // 第四步:创建根目录 inode(固定为 inode 0)
73        assert_eq!(efs.alloc_inode(), 0);
74        let (root_inode_block_id, root_inode_offset) = efs.get_disk_inode_pos(0);
75        get_block_cache(root_inode_block_id as usize, Arc::clone(&block_device))
76            .lock()
77            .modify(root_inode_offset, |disk_inode: &mut DiskInode| {
78                disk_inode.initialize(DiskInodeType::Directory);
79            });
80        block_cache_sync_all();
81        Arc::new(Mutex::new(efs))
82    }
83    /// Open a block device as a filesystem
84    pub fn open(block_device: Arc<dyn BlockDevice>) -> Arc<Mutex<Self>> {
85        // 打开时先读 SuperBlock,恢复布局信息。
86        get_block_cache(0, Arc::clone(&block_device))
87            .lock()
88            .read(0, |super_block: &SuperBlock| {
89                assert!(super_block.is_valid(), "Error loading EFS!");
90                let inode_total_blocks =
91                    super_block.inode_bitmap_blocks + super_block.inode_area_blocks;
92                let efs = Self {
93                    block_device,
94                    inode_bitmap: Bitmap::new(1, super_block.inode_bitmap_blocks as usize),
95                    data_bitmap: Bitmap::new(
96                        (1 + inode_total_blocks) as usize,
97                        super_block.data_bitmap_blocks as usize,
98                    ),
99                    inode_area_start_block: 1 + super_block.inode_bitmap_blocks,
100                    data_area_start_block: 1 + inode_total_blocks + super_block.data_bitmap_blocks,
101                };
102                Arc::new(Mutex::new(efs))
103            })
104    }
105    /// Get the root inode of the filesystem
106    pub fn root_inode(efs: &Arc<Mutex<Self>>) -> Inode {
107        let block_device = Arc::clone(&efs.lock().block_device);
108        // acquire efs lock temporarily
109        let (block_id, block_offset) = efs.lock().get_disk_inode_pos(0);
110        // release efs lock
111        Inode::new(block_id, block_offset, Arc::clone(efs), block_device)
112    }
113    /// Get inode by id
114    pub fn get_disk_inode_pos(&self, inode_id: u32) -> (u32, usize) {
115        let inode_size = core::mem::size_of::<DiskInode>();
116        let inodes_per_block = (BLOCK_SZ / inode_size) as u32;
117        let block_id = self.inode_area_start_block + inode_id / inodes_per_block;
118        (
119            block_id,
120            (inode_id % inodes_per_block) as usize * inode_size,
121        )
122    }
123    /// Get data block by id
124    pub fn get_data_block_id(&self, data_block_id: u32) -> u32 {
125        self.data_area_start_block + data_block_id
126    }
127    /// Allocate a new inode
128    pub fn alloc_inode(&mut self) -> u32 {
129        self.inode_bitmap.alloc(&self.block_device).unwrap() as u32
130    }
131
132    /// Allocate a data block
133    pub fn alloc_data(&mut self) -> u32 {
134        self.data_bitmap.alloc(&self.block_device).unwrap() as u32 + self.data_area_start_block
135    }
136    /// Deallocate a data block
137    pub fn dealloc_data(&mut self, block_id: u32) {
138        get_block_cache(block_id as usize, Arc::clone(&self.block_device))
139            .lock()
140            .modify(0, |data_block: &mut DataBlock| {
141                data_block.iter_mut().for_each(|p| {
142                    *p = 0;
143                })
144            });
145        self.data_bitmap.dealloc(
146            &self.block_device,
147            (block_id - self.data_area_start_block) as usize,
148        )
149    }
150}