xref: /DragonOS/kernel/src/driver/base/block/gendisk.rs (revision 4dd4856f933be0b4624c7f7ffa9e3d0c8c218873)
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