xref: /DragonOS/kernel/src/driver/base/block/block_device.rs (revision fae6e9ade46a52976ad5d099643d51cc20876448)
1 /// 引入Module
2 use crate::driver::{
3     base::{
4         device::{
5             device_number::{DeviceNumber, Major},
6             Device, DeviceError, IdTable, BLOCKDEVS,
7         },
8         map::{
9             DeviceStruct, DEV_MAJOR_DYN_END, DEV_MAJOR_DYN_EXT_END, DEV_MAJOR_DYN_EXT_START,
10             DEV_MAJOR_HASH_SIZE, DEV_MAJOR_MAX,
11         },
12     },
13     block::cache::{cached_block_device::BlockCache, BlockCacheError, BLOCK_SIZE},
14 };
15 
16 use alloc::{string::String, sync::Arc, vec::Vec};
17 use core::{any::Any, fmt::Display, ops::Deref};
18 use log::error;
19 use system_error::SystemError;
20 
21 use super::{disk_info::Partition, gendisk::GenDisk, manager::BlockDevMeta};
22 
23 /// 该文件定义了 Device 和 BlockDevice 的接口
24 /// Notice 设备错误码使用 Posix 规定的 int32_t 的错误码表示,而不是自己定义错误enum
25 
26 // 使用方法:
27 // 假设 blk_dev 是块设备
28 // <blk_dev as Device>::read_at() 调用的是Device的函数
29 // <blk_dev as BlockDevice>::read_at() 调用的是BlockDevice的函数
30 
31 /// 定义类型
32 pub type BlockId = usize;
33 
34 /// 定义常量
35 pub const BLK_SIZE_LOG2_LIMIT: u8 = 12; // 设定块设备的块大小不能超过 1 << 12.
36 /// 在DragonOS中,我们认为磁盘的每个LBA大小均为512字节。(注意,文件系统的1个扇区可能事实上是多个LBA)
37 pub const LBA_SIZE: usize = 512;
38 
39 #[derive(Debug, Clone, Copy)]
40 pub struct GeneralBlockRange {
41     pub lba_start: usize,
42     pub lba_end: usize,
43 }
44 
45 impl GeneralBlockRange {
46     pub fn new(lba_start: usize, lba_end: usize) -> Option<Self> {
47         if lba_start >= lba_end {
48             return None;
49         }
50         return Some(GeneralBlockRange { lba_start, lba_end });
51     }
52 
53     #[inline]
54     pub fn len(&self) -> usize {
55         return self.lba_end - self.lba_start;
56     }
57 
58     /// 取交集
59     pub fn intersects_with(&self, rhs: &Self) -> Option<Self> {
60         // 检查是否相交
61         if self.lba_start <= rhs.lba_end && self.lba_end >= rhs.lba_start {
62             // 计算相交部分的起始和结束 LBA
63             let start = usize::max(self.lba_start, rhs.lba_start);
64             let end = usize::min(self.lba_end, rhs.lba_end);
65             // 返回相交部分
66             GeneralBlockRange::new(start, end)
67         } else {
68             // 不相交,返回 None
69             None
70         }
71     }
72 }
73 
74 /// @brief 块设备的迭代器
75 /// @usage 某次操作读/写块设备的[L,R]范围内的字节,
76 ///        那么可以使用此结构体进行迭代遍历,每次调用next()返回一个BlockRange
77 pub struct BlockIter {
78     pub begin: usize, // 迭代器的起始位置 -> 块设备的地址 (单位是字节)
79     pub end: usize,
80     pub blk_size_log2: u8,
81     pub multiblock: bool, // 是否启用连续整块同时遍历
82 }
83 
84 /// @brief Range搭配迭代器BlockIter使用,[L,R]区间被分割成多个小的Range
85 ///        Range要么是整块,要么是一块的某一部分
86 /// 细节: range = [begin, end) 左闭右开
87 pub struct BlockRange {
88     pub lba_start: usize, // 起始块的lba_id
89     pub lba_end: usize,   // 终止块的lba_id
90     pub begin: usize, // 起始位置在块内的偏移量, 如果BlockIter启用Multiblock,则是多个块的偏移量
91     pub end: usize,   // 结束位置在块内的偏移量,单位是字节
92     pub blk_size_log2: u8,
93 }
94 
95 impl BlockIter {
96     #[allow(dead_code)]
97     pub fn new(start_addr: usize, end_addr: usize, blk_size_log2: u8) -> BlockIter {
98         return BlockIter {
99             begin: start_addr,
100             end: end_addr,
101             blk_size_log2,
102             multiblock: false,
103         };
104     }
105     pub fn new_multiblock(start_addr: usize, end_addr: usize, blk_size_log2: u8) -> BlockIter {
106         return BlockIter {
107             begin: start_addr,
108             end: end_addr,
109 
110             blk_size_log2,
111             multiblock: true,
112         };
113     }
114 
115     /// 获取下一个整块或者不完整的块
116     pub fn next_block(&mut self) -> BlockRange {
117         let blk_size_log2 = self.blk_size_log2;
118         let blk_size = 1usize << self.blk_size_log2;
119         let lba_id = self.begin / blk_size;
120         let begin = self.begin % blk_size;
121         let end = if lba_id == self.end / blk_size {
122             self.end % blk_size
123         } else {
124             blk_size
125         };
126 
127         self.begin += end - begin;
128 
129         return BlockRange {
130             lba_start: lba_id,
131             lba_end: lba_id + 1,
132             begin,
133             end,
134             blk_size_log2,
135         };
136     }
137 
138     /// 如果能返回多个连续的整块,则返回;否则调用next_block()返回不完整的块
139     pub fn next_multiblock(&mut self) -> BlockRange {
140         let blk_size_log2 = self.blk_size_log2;
141         let blk_size = 1usize << self.blk_size_log2;
142         let lba_start = self.begin / blk_size;
143         let lba_end = self.end / blk_size;
144 
145         // 如果不是整块,先返回非整块的小部分
146         if __bytes_to_lba(self.begin, blk_size)
147             != __bytes_to_lba(self.begin + blk_size - 1, blk_size)
148             || lba_start == lba_end
149         {
150             return self.next_block();
151         }
152 
153         let begin = self.begin % blk_size; // 因为是多个整块,这里必然是0
154         let end = __lba_to_bytes(lba_end, blk_size) - self.begin;
155 
156         self.begin += end - begin;
157 
158         return BlockRange {
159             lba_start,
160             lba_end,
161             begin,
162             end,
163             blk_size_log2,
164         };
165     }
166 }
167 
168 /// BlockIter 函数实现
169 impl Iterator for BlockIter {
170     type Item = BlockRange;
171 
172     fn next(&mut self) -> Option<<Self as Iterator>::Item> {
173         if self.begin >= self.end {
174             return None;
175         }
176         if self.multiblock {
177             return Some(self.next_multiblock());
178         } else {
179             return Some(self.next_block());
180         }
181     }
182 }
183 
184 /// BlockRange 函数实现
185 impl BlockRange {
186     #[allow(dead_code)]
187     pub fn is_empty(&self) -> bool {
188         return self.end == self.begin;
189     }
190     pub fn len(&self) -> usize {
191         return self.end - self.begin;
192     }
193     /// 判断是不是整块
194     pub fn is_full(&self) -> bool {
195         return self.len() == (1usize << self.blk_size_log2);
196     }
197     /// 判断是不是多个整块连在一起
198     pub fn is_multi(&self) -> bool {
199         return self.len() >= (1usize << self.blk_size_log2)
200             && (self.len() % (1usize << self.blk_size_log2) == 0);
201     }
202     /// 获取 BlockRange 在块设备内部的起始位置 (单位是字节)
203     pub fn origin_begin(&self) -> usize {
204         return (self.lba_start << self.blk_size_log2) + self.begin;
205     }
206     /// 获取 BlockRange 在块设备内部的结尾位置 (单位是字节)
207     pub fn origin_end(&self) -> usize {
208         return (self.lba_start << self.blk_size_log2) + self.end;
209     }
210 }
211 
212 /// 从字节地址转换到lba id
213 #[inline]
214 pub fn __bytes_to_lba(addr: usize, blk_size: usize) -> BlockId {
215     return addr / blk_size;
216 }
217 
218 /// 从lba id转换到字节地址, 返回lba_id的最左侧字节
219 #[inline]
220 pub fn __lba_to_bytes(lba_id: usize, blk_size: usize) -> BlockId {
221     return lba_id * blk_size;
222 }
223 
224 /// 块设备的名字
225 pub struct BlockDevName {
226     name: Arc<String>,
227     id: usize,
228 }
229 
230 impl BlockDevName {
231     pub fn new(name: String, id: usize) -> Self {
232         return BlockDevName {
233             name: Arc::new(name),
234             id,
235         };
236     }
237 
238     #[inline]
239     pub fn id(&self) -> usize {
240         return self.id;
241     }
242 }
243 
244 impl core::fmt::Debug for BlockDevName {
245     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
246         return write!(f, "{}", self.name);
247     }
248 }
249 
250 impl Display for BlockDevName {
251     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
252         return write!(f, "{}", self.name);
253     }
254 }
255 
256 impl Clone for BlockDevName {
257     fn clone(&self) -> Self {
258         return BlockDevName {
259             name: self.name.clone(),
260             id: self.id,
261         };
262     }
263 }
264 
265 impl core::hash::Hash for BlockDevName {
266     fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
267         self.name.hash(state);
268     }
269 }
270 
271 impl Deref for BlockDevName {
272     type Target = String;
273 
274     fn deref(&self) -> &Self::Target {
275         return self.name.as_ref();
276     }
277 }
278 
279 impl PartialEq for BlockDevName {
280     fn eq(&self, other: &Self) -> bool {
281         return self.name == other.name;
282     }
283 }
284 
285 impl Eq for BlockDevName {}
286 
287 /// @brief 块设备应该实现的操作
288 pub trait BlockDevice: Device {
289     /// # dev_name
290     /// 返回块设备的名字
291     fn dev_name(&self) -> &BlockDevName;
292 
293     fn blkdev_meta(&self) -> &BlockDevMeta;
294 
295     /// 获取设备的扇区范围
296     fn disk_range(&self) -> GeneralBlockRange;
297 
298     /// @brief: 在块设备中,从第lba_id_start个块开始,读取count个块数据,存放到buf中
299     ///
300     /// @parameter lba_id_start: 起始块
301     /// @parameter count: 读取块的数量
302     /// @parameter buf: 目标数组
303     /// @return: 如果操作成功,返回 Ok(操作的长度) 其中单位是字节;
304     ///          否则返回Err(错误码),其中错误码为负数;
305     ///          如果操作异常,但是并没有检查出什么错误,将返回Err(已操作的长度)
306     fn read_at_sync(
307         &self,
308         lba_id_start: BlockId,
309         count: usize,
310         buf: &mut [u8],
311     ) -> Result<usize, SystemError>;
312 
313     /// @brief: 在块设备中,从第lba_id_start个块开始,把buf中的count个块数据,存放到设备中
314     /// @parameter lba_id_start: 起始块
315     /// @parameter count: 写入块的数量
316     /// @parameter buf: 目标数组
317     /// @return: 如果操作成功,返回 Ok(操作的长度) 其中单位是字节;
318     ///          否则返回Err(错误码),其中错误码为负数;
319     ///          如果操作异常,但是并没有检查出什么错误,将返回Err(已操作的长度)
320     fn write_at_sync(
321         &self,
322         lba_id_start: BlockId,
323         count: usize,
324         buf: &[u8],
325     ) -> Result<usize, SystemError>;
326 
327     /// @brief: 同步磁盘信息,把所有的dirty数据写回硬盘 - 待实现
328     fn sync(&self) -> Result<(), SystemError>;
329 
330     /// @brief: 每个块设备都必须固定自己块大小,而且该块大小必须是2的幂次
331     /// @return: 返回一个固定量,硬编码(编程的时候固定的常量).
332     fn blk_size_log2(&self) -> u8;
333 
334     // TODO: 待实现 open, close
335 
336     /// @brief 本函数用于实现动态转换。
337     /// 具体的文件系统在实现本函数时,最简单的方式就是:直接返回self
338     fn as_any_ref(&self) -> &dyn Any;
339 
340     /// @brief 本函数用于将BlockDevice转换为Device。
341     /// 由于实现了BlockDevice的结构体,本身也实现了Device Trait, 因此转换是可能的。
342     /// 思路:在BlockDevice的结构体中新增一个self_ref变量,返回self_ref.upgrade()即可。
343     fn device(&self) -> Arc<dyn Device>;
344 
345     /// @brief 返回块设备的块大小(单位:字节)
346     fn block_size(&self) -> usize;
347 
348     /// @brief 返回当前磁盘上的所有分区的Arc指针数组
349     fn partitions(&self) -> Vec<Arc<Partition>>;
350 
351     /// # 函数的功能
352     /// 经由Cache对块设备的读操作
353     fn read_at(
354         &self,
355         lba_id_start: BlockId,
356         count: usize,
357         buf: &mut [u8],
358     ) -> Result<usize, SystemError> {
359         self.cache_read(lba_id_start, count, buf)
360     }
361 
362     /// # 函数的功能
363     ///  经由Cache对块设备的写操作
364     fn write_at(
365         &self,
366         lba_id_start: BlockId,
367         count: usize,
368         buf: &[u8],
369     ) -> Result<usize, SystemError> {
370         self.cache_write(lba_id_start, count, buf)
371     }
372 
373     /// # 函数的功能
374     /// 其功能对外而言和read_at函数完全一致,但是加入blockcache的功能
375     fn cache_read(
376         &self,
377         lba_id_start: BlockId,
378         count: usize,
379         buf: &mut [u8],
380     ) -> Result<usize, SystemError> {
381         let cache_response = BlockCache::read(lba_id_start, count, buf);
382         if let Err(e) = cache_response {
383             match e {
384                 BlockCacheError::StaticParameterError => {
385                     BlockCache::init();
386                     let ans = self.read_at_sync(lba_id_start, count, buf)?;
387                     return Ok(ans);
388                 }
389                 BlockCacheError::BlockFaultError(fail_vec) => {
390                     let ans = self.read_at_sync(lba_id_start, count, buf)?;
391                     let _ = BlockCache::insert(fail_vec, buf);
392                     return Ok(ans);
393                 }
394                 _ => {
395                     let ans = self.read_at_sync(lba_id_start, count, buf)?;
396                     return Ok(ans);
397                 }
398             }
399         } else {
400             return Ok(count * BLOCK_SIZE);
401         }
402     }
403 
404     /// # 函数功能
405     /// 其功能对外而言和write_at函数完全一致,但是加入blockcache的功能
406     fn cache_write(
407         &self,
408         lba_id_start: BlockId,
409         count: usize,
410         buf: &[u8],
411     ) -> Result<usize, SystemError> {
412         let _cache_response = BlockCache::immediate_write(lba_id_start, count, buf);
413         self.write_at_sync(lba_id_start, count, buf)
414     }
415 
416     fn write_at_bytes(&self, offset: usize, len: usize, buf: &[u8]) -> Result<usize, SystemError> {
417         if len > buf.len() {
418             return Err(SystemError::E2BIG);
419         }
420 
421         let iter = BlockIter::new_multiblock(offset, offset + len, self.blk_size_log2());
422         let multi = iter.multiblock;
423 
424         for range in iter {
425             let buf_begin = range.origin_begin() - offset; // 本次读操作的起始位置/已经读了这么多字节
426             let buf_end = range.origin_end() - offset;
427             let buf_slice = &buf[buf_begin..buf_end];
428             let count: usize = range.lba_end - range.lba_start;
429             let full = multi && range.is_multi() || !multi && range.is_full();
430 
431             if full {
432                 self.write_at(range.lba_start, count, buf_slice)?;
433             } else {
434                 if self.blk_size_log2() > BLK_SIZE_LOG2_LIMIT {
435                     return Err(SystemError::E2BIG);
436                 }
437 
438                 let mut temp = vec![0; 1usize << self.blk_size_log2()];
439                 // 由于块设备每次读写都是整块的,在不完整写入之前,必须把不完整的地方补全
440                 self.read_at(range.lba_start, 1, &mut temp[..])?;
441                 // 把数据从临时buffer复制到目标buffer
442                 temp[range.begin..range.end].copy_from_slice(buf_slice);
443                 self.write_at(range.lba_start, 1, &temp[..])?;
444             }
445         }
446         return Ok(len);
447     }
448 
449     fn read_at_bytes(
450         &self,
451         offset: usize,
452         len: usize,
453         buf: &mut [u8],
454     ) -> Result<usize, SystemError> {
455         if len > buf.len() {
456             return Err(SystemError::E2BIG);
457         }
458 
459         let iter = BlockIter::new_multiblock(offset, offset + len, self.blk_size_log2());
460         let multi = iter.multiblock;
461 
462         // 枚举每一个range
463         for range in iter {
464             let buf_begin = range.origin_begin() - offset; // 本次读操作的起始位置/已经读了这么多字节
465             let buf_end = range.origin_end() - offset;
466             let buf_slice = &mut buf[buf_begin..buf_end];
467             let count: usize = range.lba_end - range.lba_start;
468             let full = multi && range.is_multi() || !multi && range.is_full();
469 
470             // 读取整个block作为有效数据
471             if full {
472                 // 调用 BlockDevice::read_at() 直接把引用传进去,不是把整个数组move进去
473                 self.read_at(range.lba_start, count, buf_slice)?;
474             } else {
475                 // 判断块的长度不能超过最大值
476                 if self.blk_size_log2() > BLK_SIZE_LOG2_LIMIT {
477                     return Err(SystemError::E2BIG);
478                 }
479 
480                 let mut temp = vec![0; 1usize << self.blk_size_log2()];
481                 self.read_at(range.lba_start, 1, &mut temp[..])?;
482 
483                 // 把数据从临时buffer复制到目标buffer
484                 buf_slice.copy_from_slice(&temp[range.begin..range.end]);
485             }
486         }
487         return Ok(len);
488     }
489 
490     /// # gendisk注册成功的回调函数
491     fn callback_gendisk_registered(&self, _gendisk: &Arc<GenDisk>) -> Result<(), SystemError> {
492         Ok(())
493     }
494 }
495 
496 /// @brief 块设备框架函数集
497 pub struct BlockDeviceOps;
498 
499 impl BlockDeviceOps {
500     /// @brief: 主设备号转下标
501     /// @parameter: major: 主设备号
502     /// @return: 返回下标
503     #[allow(dead_code)]
504     fn major_to_index(major: Major) -> usize {
505         return (major.data() % DEV_MAJOR_HASH_SIZE) as usize;
506     }
507 
508     /// @brief: 动态获取主设备号
509     /// @parameter: None
510     /// @return: 如果成功,返回主设备号,否则,返回错误码
511     #[allow(dead_code)]
512     fn find_dynamic_major() -> Result<Major, SystemError> {
513         let blockdevs = BLOCKDEVS.lock();
514         // 寻找主设备号为234~255的设备
515         for index in ((DEV_MAJOR_DYN_END.data())..DEV_MAJOR_HASH_SIZE).rev() {
516             if let Some(item) = blockdevs.get(index as usize) {
517                 if item.is_empty() {
518                     return Ok(Major::new(index)); // 返回可用的主设备号
519                 }
520             }
521         }
522         // 寻找主设备号在384~511的设备
523         for index in
524             ((DEV_MAJOR_DYN_EXT_END.data() + 1)..(DEV_MAJOR_DYN_EXT_START.data() + 1)).rev()
525         {
526             if let Some(blockdevss) = blockdevs.get(Self::major_to_index(Major::new(index))) {
527                 let mut flag = true;
528                 for item in blockdevss {
529                     if item.device_number().major() == Major::new(index) {
530                         flag = false;
531                         break;
532                     }
533                 }
534                 if flag {
535                     // 如果数组中不存在主设备号等于index的设备
536                     return Ok(Major::new(index)); // 返回可用的主设备号
537                 }
538             }
539         }
540         return Err(SystemError::EBUSY);
541     }
542 
543     /// @brief: 注册设备号,该函数需要指定主设备号
544     /// @parameter: from: 主设备号
545     ///             count: 次设备号数量
546     ///             name: 字符设备名
547     /// @return: 如果注册成功,返回设备号,否则,返回错误码
548     #[allow(dead_code)]
549     pub fn register_blockdev_region(
550         from: DeviceNumber,
551         count: u32,
552         name: &'static str,
553     ) -> Result<DeviceNumber, SystemError> {
554         Self::__register_blockdev_region(from, count, name)
555     }
556 
557     /// @brief: 注册设备号,该函数自动分配主设备号
558     /// @parameter: baseminor: 主设备号
559     ///             count: 次设备号数量
560     ///             name: 字符设备名
561     /// @return: 如果注册成功,返回,否则,返回false
562     #[allow(dead_code)]
563     pub fn alloc_blockdev_region(
564         baseminor: u32,
565         count: u32,
566         name: &'static str,
567     ) -> Result<DeviceNumber, SystemError> {
568         Self::__register_blockdev_region(
569             DeviceNumber::new(Major::UNNAMED_MAJOR, baseminor),
570             count,
571             name,
572         )
573     }
574 
575     /// @brief: 注册设备号
576     /// @parameter: device_number: 设备号,主设备号如果为0,则动态分配
577     ///             minorct: 次设备号数量
578     ///             name: 字符设备名
579     /// @return: 如果注册成功,返回设备号,否则,返回错误码
580     fn __register_blockdev_region(
581         device_number: DeviceNumber,
582         minorct: u32,
583         name: &'static str,
584     ) -> Result<DeviceNumber, SystemError> {
585         let mut major = device_number.major();
586         let baseminor = device_number.minor();
587         if major >= DEV_MAJOR_MAX {
588             error!(
589                 "DEV {} major requested {:?} is greater than the maximum {}\n",
590                 name,
591                 major,
592                 DEV_MAJOR_MAX.data() - 1
593             );
594         }
595         if minorct > DeviceNumber::MINOR_MASK + 1 - baseminor {
596             error!("DEV {} minor range requested ({}-{}) is out of range of maximum range ({}-{}) for a single major\n",
597                 name, baseminor, baseminor + minorct - 1, 0, DeviceNumber::MINOR_MASK);
598         }
599         let blockdev = DeviceStruct::new(DeviceNumber::new(major, baseminor), minorct, name);
600         if major == Major::UNNAMED_MAJOR {
601             // 如果主设备号为0,则自动分配主设备号
602             major = Self::find_dynamic_major().expect("Find synamic major error.\n");
603         }
604         if let Some(items) = BLOCKDEVS.lock().get_mut(Self::major_to_index(major)) {
605             let mut insert_index: usize = 0;
606             for (index, item) in items.iter().enumerate() {
607                 insert_index = index;
608                 match item.device_number().major().cmp(&major) {
609                     core::cmp::Ordering::Less => continue,
610                     core::cmp::Ordering::Greater => {
611                         break; // 大于则向后插入
612                     }
613                     core::cmp::Ordering::Equal => {
614                         if item.device_number().minor() + item.minorct() <= baseminor {
615                             continue; // 下一个主设备号大于或者次设备号大于被插入的次设备号最大值
616                         }
617                         if item.base_minor() >= baseminor + minorct {
618                             break; // 在此处插入
619                         }
620                         return Err(SystemError::EBUSY); // 存在重合的次设备号
621                     }
622                 }
623             }
624             items.insert(insert_index, blockdev);
625         }
626 
627         return Ok(DeviceNumber::new(major, baseminor));
628     }
629 
630     /// @brief: 注销设备号
631     /// @parameter: major: 主设备号,如果为0,动态分配
632     ///             baseminor: 起始次设备号
633     ///             minorct: 次设备号数量
634     /// @return: 如果注销成功,返回(),否则,返回错误码
635     fn __unregister_blockdev_region(
636         device_number: DeviceNumber,
637         minorct: u32,
638     ) -> Result<(), SystemError> {
639         if let Some(items) = BLOCKDEVS
640             .lock()
641             .get_mut(Self::major_to_index(device_number.major()))
642         {
643             for (index, item) in items.iter().enumerate() {
644                 if item.device_number() == device_number && item.minorct() == minorct {
645                     // 设备号和数量都相等
646                     items.remove(index);
647                     return Ok(());
648                 }
649             }
650         }
651         return Err(SystemError::EBUSY);
652     }
653 
654     /// @brief: 块设备注册
655     /// @parameter: cdev: 字符设备实例
656     ///             dev_t: 字符设备号
657     ///             range: 次设备号范围
658     /// @return: none
659     #[allow(dead_code)]
660     pub fn bdev_add(_bdev: Arc<dyn BlockDevice>, id_table: IdTable) -> Result<(), DeviceError> {
661         if id_table.device_number().data() == 0 {
662             error!("Device number can't be 0!\n");
663         }
664         todo!("bdev_add")
665         // return device_manager().add_device(bdev.id_table(), bdev.device());
666     }
667 
668     /// @brief: block设备注销
669     /// @parameter: dev_t: 字符设备号
670     ///             range: 次设备号范围
671     /// @return: none
672     #[allow(dead_code)]
673     pub fn bdev_del(_devnum: DeviceNumber, _range: usize) {
674         unimplemented!();
675     }
676 }
677