1 use core::{ 2 ops::{Deref, DerefMut}, 3 sync::atomic::{AtomicU32, Ordering}, 4 }; 5 6 use alloc::sync::{Arc, Weak}; 7 use hashbrown::HashMap; 8 use system_error::SystemError; 9 10 use super::block_device::{BlockDevice, BlockId, GeneralBlockRange, LBA_SIZE}; 11 12 #[derive(Debug)] 13 pub struct GenDisk { 14 bdev: Weak<dyn BlockDevice>, 15 range: GeneralBlockRange, 16 block_size_log2: u8, 17 idx: Option<u32>, 18 } 19 20 impl GenDisk { 21 /// 如果gendisk是整个磁盘,则idx为u32::MAX 22 pub const ENTIRE_DISK_IDX: u32 = u32::MAX; 23 24 pub fn new( 25 bdev: Weak<dyn BlockDevice>, 26 range: GeneralBlockRange, 27 idx: Option<u32>, 28 ) -> Arc<Self> { 29 let bsizelog2 = bdev.upgrade().unwrap().blk_size_log2(); 30 31 return Arc::new(GenDisk { 32 bdev, 33 range, 34 block_size_log2: bsizelog2, 35 idx, 36 }); 37 } 38 39 pub fn block_device(&self) -> Arc<dyn BlockDevice> { 40 return self.bdev.upgrade().unwrap(); 41 } 42 43 /// # read_at 44 /// 45 /// 读取分区内的数据 46 /// 47 /// ## 参数 48 /// 49 /// - buf: 输出缓冲区,大小必须为LBA_SIZE的整数倍,否则返回EINVAL 50 /// - start_block_offset: 分区内的块号 51 pub fn read_at( 52 &self, 53 buf: &mut [u8], 54 start_block_offset: BlockId, 55 ) -> Result<usize, SystemError> { 56 if (buf.len() & (LBA_SIZE - 1)) > 0 { 57 return Err(SystemError::EINVAL); 58 } 59 60 let blocks = buf.len() / (1 << self.block_size_log2 as usize); 61 let lba = self.block_offset_2_disk_blkid(start_block_offset); 62 63 return self.block_device().read_at(lba, blocks, buf); 64 } 65 66 /// # read_at_bytes 67 /// 68 /// 按字节偏移量从分区中读取数据 69 /// 70 /// ## 参数 71 /// 72 /// - buf: 输出缓冲区 73 /// - bytes_offset: 分区内的字节偏移量 74 pub fn read_at_bytes(&self, buf: &mut [u8], bytes_offset: usize) -> Result<usize, SystemError> { 75 let start_lba = self.range.lba_start; 76 let bytes_offset = self.disk_blkid_2_bytes(start_lba) + bytes_offset; 77 return self 78 .block_device() 79 .read_at_bytes(bytes_offset, buf.len(), buf); 80 } 81 82 /// # 分区内的字节偏移量转换为磁盘上的字节偏移量 83 pub fn disk_bytes_offset(&self, bytes_offset: usize) -> usize { 84 let start_lba = self.range.lba_start; 85 return self.disk_blkid_2_bytes(start_lba) + bytes_offset; 86 } 87 88 /// # write_at_bytes 89 /// 90 /// 按字节偏移量向分区写入数据 91 /// 92 /// ## 参数 93 /// 94 /// - buf: 输入缓冲区 95 /// - bytes_offset: 分区内的字节偏移量 96 pub fn write_at_bytes(&self, buf: &[u8], bytes_offset: usize) -> Result<usize, SystemError> { 97 let start_lba = self.range.lba_start; 98 let bytes_offset = self.disk_blkid_2_bytes(start_lba) + bytes_offset; 99 return self 100 .block_device() 101 .write_at_bytes(bytes_offset, buf.len(), buf); 102 } 103 104 /// # write_at 105 /// 106 /// 向分区内写入数据 107 /// 108 /// ## 参数 109 /// 110 /// - buf: 输入缓冲区,大小必须为LBA_SIZE的整数倍,否则返回EINVAL 111 /// - start_block_offset: 分区内的块号 112 pub fn write_at(&self, buf: &[u8], start_block_offset: BlockId) -> Result<usize, SystemError> { 113 if (buf.len() & (LBA_SIZE - 1)) > 0 { 114 return Err(SystemError::EINVAL); 115 } 116 117 let blocks = buf.len() / (1 << self.block_size_log2 as usize); 118 let lba = self.block_offset_2_disk_blkid(start_block_offset); 119 return self.block_device().write_at(lba, blocks, buf); 120 } 121 122 #[inline] 123 fn block_offset_2_disk_blkid(&self, block_offset: BlockId) -> BlockId { 124 self.range.lba_start + block_offset 125 } 126 127 #[inline] 128 fn disk_blkid_2_bytes(&self, disk_blkid: BlockId) -> usize { 129 disk_blkid * LBA_SIZE 130 } 131 132 #[inline] 133 pub fn idx(&self) -> u32 { 134 self.idx.unwrap_or(Self::ENTIRE_DISK_IDX) 135 } 136 137 #[inline] 138 pub fn range(&self) -> &GeneralBlockRange { 139 &self.range 140 } 141 142 /// # sync 143 /// 同步磁盘 144 pub fn sync(&self) -> Result<(), SystemError> { 145 self.block_device().sync() 146 } 147 } 148 149 #[derive(Default)] 150 pub struct GenDiskMap { 151 data: HashMap<u32, Arc<GenDisk>>, 152 max_idx: AtomicU32, 153 } 154 155 impl GenDiskMap { 156 pub fn new() -> Self { 157 GenDiskMap { 158 data: HashMap::new(), 159 max_idx: AtomicU32::new(1), 160 } 161 } 162 163 #[inline] 164 pub fn max_idx(&self) -> u32 { 165 self.max_idx.load(Ordering::SeqCst) 166 } 167 168 #[inline] 169 pub fn alloc_idx(&self) -> u32 { 170 self.max_idx.fetch_add(1, Ordering::SeqCst) 171 } 172 173 pub fn intersects(&self, range: &GeneralBlockRange) -> bool { 174 for (_, v) in self.iter() { 175 if range.intersects_with(&v.range).is_some() { 176 return true; 177 } 178 } 179 return false; 180 } 181 } 182 183 impl Deref for GenDiskMap { 184 type Target = HashMap<u32, Arc<GenDisk>>; 185 186 fn deref(&self) -> &Self::Target { 187 &self.data 188 } 189 } 190 191 impl DerefMut for GenDiskMap { 192 fn deref_mut(&mut self) -> &mut Self::Target { 193 &mut self.data 194 } 195 } 196