xref: /DragonOS/kernel/src/driver/base/block/block_device.rs (revision b087521e07f601b30e3d48df788fcc2f09f19566)
1 /// 引入Module
2 use crate::{driver::base::device::Device, syscall::SystemError};
3 use alloc::{sync::Arc, vec::Vec};
4 use core::any::Any;
5 
6 use super::disk_info::Partition;
7 
8 /// 该文件定义了 Device 和 BlockDevice 的接口
9 /// Notice 设备错误码使用 Posix 规定的 int32_t 的错误码表示,而不是自己定义错误enum
10 
11 // 使用方法:
12 // 假设 blk_dev 是块设备
13 // <blk_dev as Device>::read_at() 调用的是Device的函数
14 // <blk_dev as BlockDevice>::read_at() 调用的是BlockDevice的函数
15 
16 /// 定义类型
17 pub type BlockId = usize;
18 
19 /// 定义常量
20 pub const BLK_SIZE_LOG2_LIMIT: u8 = 12; // 设定块设备的块大小不能超过 1 << 12.
21 /// 在DragonOS中,我们认为磁盘的每个LBA大小均为512字节。(注意,文件系统的1个扇区可能事实上是多个LBA)
22 pub const LBA_SIZE: usize = 512;
23 
24 /// @brief 块设备的迭代器
25 /// @usage 某次操作读/写块设备的[L,R]范围内的字节,
26 ///        那么可以使用此结构体进行迭代遍历,每次调用next()返回一个BlockRange
27 pub struct BlockIter {
28     pub begin: usize, // 迭代器的起始位置 -> 块设备的地址 (单位是字节)
29     pub end: usize,
30     pub blk_size_log2: u8,
31     pub multiblock: bool, // 是否启用连续整块同时遍历
32 }
33 
34 /// @brief Range搭配迭代器BlockIter使用,[L,R]区间被分割成多个小的Range
35 ///        Range要么是整块,要么是一块的某一部分
36 /// 细节: range = [begin, end) 左闭右开
37 pub struct BlockRange {
38     pub lba_start: usize, // 起始块的lba_id
39     pub lba_end: usize,   // 终止块的lba_id
40     pub begin: usize, // 起始位置在块内的偏移量, 如果BlockIter启用Multiblock,则是多个块的偏移量
41     pub end: usize,   // 结束位置在块内的偏移量,单位是字节
42     pub blk_size_log2: u8,
43 }
44 
45 impl BlockIter {
46     #[allow(dead_code)]
47     pub fn new(start_addr: usize, end_addr: usize, blk_size_log2: u8) -> BlockIter {
48         return BlockIter {
49             begin: start_addr,
50             end: end_addr,
51             blk_size_log2: blk_size_log2,
52             multiblock: false,
53         };
54     }
55     pub fn new_multiblock(start_addr: usize, end_addr: usize, blk_size_log2: u8) -> BlockIter {
56         return BlockIter {
57             begin: start_addr,
58             end: end_addr,
59             blk_size_log2: blk_size_log2,
60             multiblock: true,
61         };
62     }
63 
64     /// 获取下一个整块或者不完整的块
65     pub fn next_block(&mut self) -> BlockRange {
66         let blk_size_log2 = self.blk_size_log2;
67         let blk_size = 1usize << self.blk_size_log2;
68         let lba_id = self.begin / blk_size;
69         let begin = self.begin % blk_size;
70         let end = if lba_id == self.end / blk_size {
71             self.end % blk_size
72         } else {
73             blk_size
74         };
75 
76         self.begin += end - begin;
77 
78         return BlockRange {
79             lba_start: lba_id,
80             lba_end: lba_id + 1,
81             begin: begin,
82             end: end,
83             blk_size_log2: blk_size_log2,
84         };
85     }
86 
87     /// 如果能返回多个连续的整块,则返回;否则调用next_block()返回不完整的块
88     pub fn next_multiblock(&mut self) -> BlockRange {
89         let blk_size_log2 = self.blk_size_log2;
90         let blk_size = 1usize << self.blk_size_log2;
91         let lba_start = self.begin / blk_size;
92         let lba_end = self.end / blk_size;
93 
94         // 如果不是整块,先返回非整块的小部分
95         if __bytes_to_lba(self.begin, blk_size)
96             != __bytes_to_lba(self.begin + blk_size - 1, blk_size)
97             || lba_start == lba_end
98         {
99             return self.next_block();
100         }
101 
102         let begin = self.begin % blk_size; // 因为是多个整块,这里必然是0
103         let end = __lba_to_bytes(lba_end, blk_size) - self.begin;
104 
105         self.begin += end - begin;
106 
107         return BlockRange {
108             lba_start: lba_start,
109             lba_end: lba_end,
110             begin: begin,
111             end: end,
112             blk_size_log2: blk_size_log2,
113         };
114     }
115 }
116 
117 /// BlockIter 函数实现
118 impl Iterator for BlockIter {
119     type Item = BlockRange;
120 
121     fn next(&mut self) -> Option<<Self as Iterator>::Item> {
122         if self.begin >= self.end {
123             return None;
124         }
125         if self.multiblock {
126             return Some(self.next_multiblock());
127         } else {
128             return Some(self.next_block());
129         }
130     }
131 }
132 
133 /// BlockRange 函数实现
134 impl BlockRange {
135     #[allow(dead_code)]
136     pub fn is_empty(&self) -> bool {
137         return self.end == self.begin;
138     }
139     pub fn len(&self) -> usize {
140         return self.end - self.begin;
141     }
142     /// 判断是不是整块
143     pub fn is_full(&self) -> bool {
144         return self.len() == (1usize << self.blk_size_log2);
145     }
146     /// 判断是不是多个整块连在一起
147     pub fn is_multi(&self) -> bool {
148         return self.len() >= (1usize << self.blk_size_log2)
149             && (self.len() % (1usize << self.blk_size_log2) == 0);
150     }
151     /// 获取 BlockRange 在块设备内部的起始位置 (单位是字节)
152     pub fn origin_begin(&self) -> usize {
153         return (self.lba_start << self.blk_size_log2) + self.begin;
154     }
155     /// 获取 BlockRange 在块设备内部的结尾位置 (单位是字节)
156     pub fn origin_end(&self) -> usize {
157         return (self.lba_start << self.blk_size_log2) + self.end;
158     }
159 }
160 
161 /// 从字节地址转换到lba id
162 #[inline]
163 pub fn __bytes_to_lba(addr: usize, blk_size: usize) -> BlockId {
164     return addr / blk_size;
165 }
166 
167 /// 从lba id转换到字节地址, 返回lba_id的最左侧字节
168 #[inline]
169 pub fn __lba_to_bytes(lba_id: usize, blk_size: usize) -> BlockId {
170     return lba_id * blk_size;
171 }
172 
173 /// @brief 块设备应该实现的操作
174 pub trait BlockDevice: Device {
175     /// @brief: 在块设备中,从第lba_id_start个块开始,读取count个块数据,存放到buf中
176     ///
177     /// @parameter lba_id_start: 起始块
178     /// @parameter count: 读取块的数量
179     /// @parameter buf: 目标数组
180     /// @return: 如果操作成功,返回 Ok(操作的长度) 其中单位是字节;
181     ///          否则返回Err(错误码),其中错误码为负数;
182     ///          如果操作异常,但是并没有检查出什么错误,将返回Err(已操作的长度)
183     fn read_at(
184         &self,
185         lba_id_start: BlockId,
186         count: usize,
187         buf: &mut [u8],
188     ) -> Result<usize, SystemError>;
189 
190     /// @brief: 在块设备中,从第lba_id_start个块开始,把buf中的count个块数据,存放到设备中
191     /// @parameter lba_id_start: 起始块
192     /// @parameter count: 写入块的数量
193     /// @parameter buf: 目标数组
194     /// @return: 如果操作成功,返回 Ok(操作的长度) 其中单位是字节;
195     ///          否则返回Err(错误码),其中错误码为负数;
196     ///          如果操作异常,但是并没有检查出什么错误,将返回Err(已操作的长度)
197     fn write_at(
198         &self,
199         lba_id_start: BlockId,
200         count: usize,
201         buf: &[u8],
202     ) -> Result<usize, SystemError>;
203 
204     /// @brief: 同步磁盘信息,把所有的dirty数据写回硬盘 - 待实现
205     fn sync(&self) -> Result<(), SystemError>;
206 
207     /// @brief: 每个块设备都必须固定自己块大小,而且该块大小必须是2的幂次
208     /// @return: 返回一个固定量,硬编码(编程的时候固定的常量).
209     fn blk_size_log2(&self) -> u8;
210 
211     // TODO: 待实现 open, close
212 
213     /// @brief 本函数用于实现动态转换。
214     /// 具体的文件系统在实现本函数时,最简单的方式就是:直接返回self
215     fn as_any_ref(&self) -> &dyn Any;
216 
217     /// @brief 本函数用于将BlockDevice转换为Device。
218     /// 由于实现了BlockDevice的结构体,本身也实现了Device Trait, 因此转换是可能的。
219     /// 思路:在BlockDevice的结构体中新增一个self_ref变量,返回self_ref.upgrade()即可。
220     fn device(&self) -> Arc<dyn Device>;
221 
222     /// @brief 返回块设备的块大小(单位:字节)
223     fn block_size(&self) -> usize;
224 
225     /// @brief 返回当前磁盘上的所有分区的Arc指针数组
226     fn partitions(&self) -> Vec<Arc<Partition>>;
227 
228     fn write_at_bytes(&self, offset: usize, len: usize, buf: &[u8]) -> Result<usize, SystemError> {
229         // assert!(len <= buf.len());
230         if len > buf.len() {
231             return Err(SystemError::E2BIG);
232         }
233 
234         let iter = BlockIter::new_multiblock(offset, offset + len, self.blk_size_log2());
235         let multi = iter.multiblock;
236 
237         for range in iter {
238             let buf_begin = range.origin_begin() - offset; // 本次读操作的起始位置/已经读了这么多字节
239             let buf_end = range.origin_end() - offset;
240             let buf_slice = &buf[buf_begin..buf_end];
241             let count: usize = (range.lba_end - range.lba_start).try_into().unwrap();
242             let full = multi && range.is_multi() || !multi && range.is_full();
243 
244             if full {
245                 self.write_at(range.lba_start, count, buf_slice)?;
246             } else {
247                 if self.blk_size_log2() > BLK_SIZE_LOG2_LIMIT {
248                     return Err(SystemError::E2BIG);
249                 }
250 
251                 let mut temp = Vec::new();
252                 temp.resize(1usize << self.blk_size_log2(), 0);
253                 // 由于块设备每次读写都是整块的,在不完整写入之前,必须把不完整的地方补全
254                 self.write_at(range.lba_start, 1, &mut temp[..])?;
255                 // 把数据从临时buffer复制到目标buffer
256                 temp[range.begin..range.end].copy_from_slice(&buf_slice);
257                 self.write_at(range.lba_start, 1, &temp[..])?;
258             }
259         }
260         return Ok(len);
261         //self.0.lock().write_at(lba_id_start, count, buf)
262     }
263 
264     fn read_at_bytes(
265         &self,
266         offset: usize,
267         len: usize,
268         buf: &mut [u8],
269     ) -> Result<usize, SystemError> {
270         if len > buf.len() {
271             return Err(SystemError::E2BIG);
272         }
273 
274         let iter = BlockIter::new_multiblock(offset, offset + len, self.blk_size_log2());
275         let multi = iter.multiblock;
276 
277         // 枚举每一个range
278         for range in iter {
279             let buf_begin = range.origin_begin() - offset; // 本次读操作的起始位置/已经读了这么多字节
280             let buf_end = range.origin_end() - offset;
281             let buf_slice = &mut buf[buf_begin..buf_end];
282             let count: usize = (range.lba_end - range.lba_start).try_into().unwrap();
283             let full = multi && range.is_multi() || !multi && range.is_full();
284 
285             if full {
286                 // 调用 BlockDevice::read_at() 直接把引用传进去,不是把整个数组move进去
287                 self.read_at(range.lba_start, count, buf)?;
288             } else {
289                 // 判断块的长度不能超过最大值
290                 if self.blk_size_log2() > BLK_SIZE_LOG2_LIMIT {
291                     return Err(SystemError::E2BIG);
292                 }
293 
294                 let mut temp = Vec::new();
295                 temp.resize(1usize << self.blk_size_log2(), 0);
296                 self.read_at(range.lba_start, 1, &mut temp[..])?;
297 
298                 // 把数据从临时buffer复制到目标buffer
299                 buf_slice.copy_from_slice(&temp[range.begin..range.end]);
300             }
301         }
302         return Ok(len);
303 
304         // kdebug!(
305         //     "ahci read at {lba_id_start}, count={count}, lock={:?}",
306         //     self.0
307         // );
308     }
309 }
310