Forked from 破败王者之剑 / OSKernel2022-LOS
Source project has a limited visibility.
layout.rs 14.24 KiB
use super::{get_block_cache, BlockDevice, BLOCK_SZ};
use alloc::sync::Arc;
use alloc::vec::Vec;
use core::fmt::{Debug, Formatter, Result};
const EFS_MAGIC: u32 = 0x3b800001;
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 {
    magic: u32,
    pub total_blocks: u32,
    pub inode_bitmap_blocks: u32,
    pub inode_area_blocks: u32,
    pub data_bitmap_blocks: u32,
    pub data_area_blocks: u32,
impl Debug for SuperBlock {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        f.debug_struct("SuperBlock")
            .field("total_blocks", &self.total_blocks)
            .field("inode_bitmap_blocks", &self.inode_bitmap_blocks)
            .field("inode_area_blocks", &self.inode_area_blocks)
            .field("data_bitmap_blocks", &self.data_bitmap_blocks)
            .field("data_area_blocks", &self.data_area_blocks)
            .finish()
impl SuperBlock {
    pub fn initialize(
        &mut self,
        total_blocks: u32,
        inode_bitmap_blocks: u32,
        inode_area_blocks: u32,
        data_bitmap_blocks: u32,
        data_area_blocks: u32,
    ) {
        *self = Self {
            magic: EFS_MAGIC,
            total_blocks,
            inode_bitmap_blocks,
            inode_area_blocks,
            data_bitmap_blocks,
            data_area_blocks,
    pub fn is_valid(&self) -> bool {
        self.magic == EFS_MAGIC
#[derive(PartialEq, Copy, Clone)]
pub enum DiskInodeType {
    File,
    Directory,
type IndirectBlock = [u32; BLOCK_SZ / 4];
type DataBlock = [u8; BLOCK_SZ];
#[repr(C)]
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
pub struct DiskInode { pub size: u32, pub direct: [u32; INODE_DIRECT_COUNT], pub indirect1: u32, pub indirect2: u32, pub type_: DiskInodeType, } impl DiskInode { /// 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 = 0; self.indirect2 = 0; self.type_ = type_; } pub fn is_dir(&self) -> bool { self.type_ == DiskInodeType::Directory } #[allow(unused)] pub fn is_file(&self) -> bool { self.type_ == DiskInodeType::File } /// Return block number correspond to size. pub fn data_blocks(&self) -> u32 { Self::_data_blocks(self.size) } 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 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))