     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72

    use super::{get_block_cache, BlockDevice, BLOCK_SZ};
    use alloc::sync::Arc;

    type BitmapBlock = [u64; 64];

    const BLOCK_BITS: usize = BLOCK_SZ * 8;

    pub struct Bitmap {
        start_block_id: usize,
        blocks: usize,
    }

    /// Return (block_pos, bits64_pos, inner_pos)
    fn decomposition(mut bit: usize) -> (usize, usize, usize) {
        let block_pos = bit / BLOCK_BITS;
        bit %= BLOCK_BITS;
        (block_pos, bit / 64, bit % 64)
    }

    impl Bitmap {
        pub fn new(start_block_id: usize, blocks: usize) -> Self {
            kprintln!("[KERN EASYFS] bitmap::Bitmap::new() begin");
            Self {
                start_block_id,
                blocks,
            }
        }

        pub fn alloc(&self, block_device: &Arc<dyn BlockDevice>) -> Option<usize> {
            kprintln!("[KERN EASYFS] bitmap::Bitmap::alloc() begin");
            for block_id in 0..self.blocks {
                let pos = get_block_cache(
                    block_id + self.start_block_id as usize,
                    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) {
            kprintln!("[KERN EASYFS] bitmap::Bitmap::dealloc() begin");
            let (block_pos, bits64_pos, inner_pos) = decomposition(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;
                });
        }

        pub fn maximum(&self) -> usize {
            self.blocks * BLOCK_BITS
        }
    }