xref: /DragonOS/kernel/src/driver/base/block/manager.rs (revision 2b7818e80e00fcfe4d03533f587cc125ea5e4bec)
1 use core::fmt::Formatter;
2 
3 use alloc::sync::Arc;
4 use hashbrown::HashMap;
5 use system_error::SystemError;
6 use unified_init::macros::unified_init;
7 
8 use crate::{
9     driver::base::block::gendisk::GenDisk,
10     filesystem::mbr::MbrDiskPartionTable,
11     init::initcall::INITCALL_POSTCORE,
12     libs::spinlock::{SpinLock, SpinLockGuard},
13 };
14 
15 use super::{
16     block_device::{BlockDevName, BlockDevice, GeneralBlockRange},
17     gendisk::GenDiskMap,
18 };
19 
20 static mut BLOCK_DEV_MANAGER: Option<BlockDevManager> = None;
21 
22 #[inline]
23 pub fn block_dev_manager() -> &'static BlockDevManager {
24     unsafe { BLOCK_DEV_MANAGER.as_ref().unwrap() }
25 }
26 
27 #[unified_init(INITCALL_POSTCORE)]
28 pub fn block_dev_manager_init() -> Result<(), SystemError> {
29     unsafe {
30         BLOCK_DEV_MANAGER = Some(BlockDevManager::new());
31     }
32     Ok(())
33 }
34 
35 /// 磁盘设备管理器
36 pub struct BlockDevManager {
37     inner: SpinLock<InnerBlockDevManager>,
38 }
39 
40 struct InnerBlockDevManager {
41     disks: HashMap<BlockDevName, Arc<dyn BlockDevice>>,
42 }
43 impl BlockDevManager {
44     pub fn new() -> Self {
45         BlockDevManager {
46             inner: SpinLock::new(InnerBlockDevManager {
47                 disks: HashMap::new(),
48             }),
49         }
50     }
51 
52     fn inner(&self) -> SpinLockGuard<InnerBlockDevManager> {
53         self.inner.lock()
54     }
55 
56     /// 注册磁盘设备
57     pub fn register(&self, dev: Arc<dyn BlockDevice>) -> Result<(), SystemError> {
58         let mut inner = self.inner();
59         let dev_name = dev.dev_name();
60         if inner.disks.contains_key(dev_name) {
61             return Err(SystemError::EEXIST);
62         }
63         inner.disks.insert(dev_name.clone(), dev.clone());
64 
65         let mut out_remove = || {
66             inner.disks.remove(dev_name);
67         };
68 
69         // 检测分区表,并创建gendisk
70         self.check_partitions(&dev).inspect_err(|_| out_remove())?;
71         Ok(())
72     }
73 
74     /// 检测分区表,并创建gendisk
75     fn check_partitions(&self, dev: &Arc<dyn BlockDevice>) -> Result<(), SystemError> {
76         if self.check_mbr(dev).is_ok() {
77             return Ok(());
78         }
79 
80         // use entire disk as a gendisk
81         self.register_entire_disk_as_gendisk(dev)
82     }
83 
84     fn check_mbr(&self, dev: &Arc<dyn BlockDevice>) -> Result<(), SystemError> {
85         let mbr = MbrDiskPartionTable::from_disk(dev.clone())?;
86         let piter = mbr.partitions_raw();
87         for p in piter {
88             self.register_gendisk_with_range(dev, p.try_into()?)?;
89         }
90         Ok(())
91     }
92 
93     /// 将整个磁盘注册为gendisk
94     fn register_entire_disk_as_gendisk(
95         &self,
96         dev: &Arc<dyn BlockDevice>,
97     ) -> Result<(), SystemError> {
98         let range = dev.disk_range();
99         self.register_gendisk_with_range(dev, range)
100     }
101 
102     fn register_gendisk_with_range(
103         &self,
104         dev: &Arc<dyn BlockDevice>,
105         range: GeneralBlockRange,
106     ) -> Result<(), SystemError> {
107         let weak_dev = Arc::downgrade(dev);
108         let gendisk = GenDisk::new(
109             weak_dev,
110             range,
111             Some(dev.blkdev_meta().inner().gendisks.alloc_idx()),
112         );
113         self.register_gendisk(dev, gendisk)
114     }
115 
116     fn register_gendisk(
117         &self,
118         dev: &Arc<dyn BlockDevice>,
119         gendisk: Arc<GenDisk>,
120     ) -> Result<(), SystemError> {
121         let blk_meta = dev.blkdev_meta();
122         let idx = gendisk.idx();
123         let mut meta_inner = blk_meta.inner();
124         // 检查是否重复
125         if meta_inner.gendisks.intersects(gendisk.range()) {
126             return Err(SystemError::EEXIST);
127         }
128 
129         meta_inner.gendisks.insert(idx, gendisk.clone());
130         dev.callback_gendisk_registered(&gendisk).inspect_err(|_| {
131             meta_inner.gendisks.remove(&idx);
132         })?;
133         Ok(())
134     }
135 
136     /// 卸载磁盘设备
137     pub fn unregister(&self, dev: &Arc<dyn BlockDevice>) {
138         let mut inner = self.inner();
139         inner.disks.remove(dev.dev_name());
140         // todo: 这里应该callback一下磁盘设备,但是现在还没实现热插拔,所以暂时没做这里
141         todo!("BlockDevManager: unregister disk")
142     }
143 
144     /// 通过路径查找gendisk
145     ///
146     /// # 参数
147     ///
148     /// - `path`: 分区路径 `/dev/sda1` 或者 `sda1`,或者是`/dev/sda`
149     pub fn lookup_gendisk_by_path(&self, path: &str) -> Option<Arc<GenDisk>> {
150         let (devname, partno) = self.path2devname(path)?;
151         let inner = self.inner();
152         for dev in inner.disks.values() {
153             if dev.dev_name().as_str() == devname {
154                 return dev.blkdev_meta().inner().gendisks.get(&partno).cloned();
155             }
156         }
157         None
158     }
159 
160     /// 打印所有的gendisk的路径
161     pub fn print_gendisks(&self) {
162         let mut disks = alloc::vec::Vec::new();
163 
164         let inner = self.inner();
165         for dev in inner.disks.values() {
166             let meta = dev.blkdev_meta().inner();
167             for idx in meta.gendisks.keys() {
168                 if idx == &GenDisk::ENTIRE_DISK_IDX {
169                     disks.push(format!("/dev/{}", dev.dev_name()));
170                 } else {
171                     disks.push(format!("/dev/{}{}", dev.dev_name(), idx));
172                 }
173             }
174         }
175 
176         log::debug!("All gendisks: {:?}", disks);
177     }
178 
179     /// 将路径转换为设备名以及分区号
180     ///
181     /// 例如: sda1 -> (sda, 1)  nvme0n1p1 -> (nvme0n1, 1)
182     fn path2devname<'a>(&self, mut path: &'a str) -> Option<(&'a str, u32)> {
183         // 去除开头的"/dev/"
184         if path.starts_with("/dev/") {
185             path = path.strip_prefix("/dev/")?;
186         }
187 
188         let mut partno = GenDisk::ENTIRE_DISK_IDX;
189         // 截取末尾数字
190         let mut last_digit = path.len();
191         while last_digit > 0 && path.chars().nth(last_digit - 1).unwrap().is_ascii_digit() {
192             last_digit -= 1;
193         }
194         if last_digit == 0 {
195             return (path, GenDisk::ENTIRE_DISK_IDX).into();
196         }
197 
198         if last_digit < path.len() {
199             partno = path[last_digit..].parse().ok()?;
200         }
201 
202         let path = &path[..last_digit];
203 
204         Some((path, partno))
205     }
206 }
207 
208 pub struct BlockDevMeta {
209     pub devname: BlockDevName,
210     inner: SpinLock<InnerBlockDevMeta>,
211 }
212 
213 pub struct InnerBlockDevMeta {
214     pub gendisks: GenDiskMap,
215 }
216 
217 impl BlockDevMeta {
218     pub fn new(devname: BlockDevName) -> Self {
219         BlockDevMeta {
220             devname,
221             inner: SpinLock::new(InnerBlockDevMeta {
222                 gendisks: GenDiskMap::new(),
223             }),
224         }
225     }
226 
227     fn inner(&self) -> SpinLockGuard<InnerBlockDevMeta> {
228         self.inner.lock()
229     }
230 }
231 
232 impl core::fmt::Debug for BlockDevMeta {
233     fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
234         f.debug_struct("BlockDevMeta")
235             .field("devname", &self.devname)
236             .finish()
237     }
238 }
239