diff --git a/kernel/src/device/mod.rs b/kernel/src/device/mod.rs index 8fbaa8a01..96be001f2 100644 --- a/kernel/src/device/mod.rs +++ b/kernel/src/device/mod.rs @@ -9,12 +9,12 @@ mod registry; mod shm; pub mod tty; -use device_id::DeviceId; pub use mem::{getrandom, geturandom}; pub use pty::{new_pty_pair, PtyMaster, PtySlave}; +pub use registry::lookup; use crate::{ - fs::{device::Device, fs_resolver::FsPath, path::PerMountFlags, ramfs::RamFs}, + fs::{fs_resolver::FsPath, path::PerMountFlags, ramfs::RamFs}, prelude::*, }; @@ -42,11 +42,3 @@ pub fn init_in_first_process(ctx: &Context) -> Result<()> { Ok(()) } - -/// Looks up a device according to the device ID. -pub fn get_device(devid: DeviceId) -> Result> { - // TODO: Add support for looking up block devices. - registry::char::lookup(devid).ok_or_else(|| { - Error::with_message(Errno::EINVAL, "the device ID is invalid or unsupported") - }) -} diff --git a/kernel/src/device/registry/block.rs b/kernel/src/device/registry/block.rs index 771ac9f8b..6c61cfa3f 100644 --- a/kernel/src/device/registry/block.rs +++ b/kernel/src/device/registry/block.rs @@ -127,3 +127,18 @@ impl FileIo for OpenBlockFile { true } } + +pub(super) fn lookup(id: DeviceId) -> Option> { + let block_device = aster_block::lookup(id)?; + + let mut registry = DEVICE_REGISTRY.lock(); + let block_device_file = registry + .entry(id.to_raw()) + .or_insert_with(move || Arc::new(BlockFile::new(block_device))) + .clone(); + Some(block_device_file) +} + +// TODO: Merge the two mapping tables, one is here and the other is in the block component. +// Maintaining two mapping tables is undesirable due to duplication and (potential) inconsistency. +static DEVICE_REGISTRY: Mutex>> = Mutex::new(BTreeMap::new()); diff --git a/kernel/src/device/registry/char.rs b/kernel/src/device/registry/char.rs index 0e80f14aa..88e2d8f79 100644 --- a/kernel/src/device/registry/char.rs +++ b/kernel/src/device/registry/char.rs @@ -42,7 +42,7 @@ pub fn collect_all() -> Vec> { } /// Looks up a char device of a given device ID. -pub fn lookup(id: DeviceId) -> Option> { +pub(super) fn lookup(id: DeviceId) -> Option> { DEVICE_REGISTRY.lock().get(&id.to_raw()).cloned() } diff --git a/kernel/src/device/registry/mod.rs b/kernel/src/device/registry/mod.rs index 995d5ae6a..395361f94 100644 --- a/kernel/src/device/registry/mod.rs +++ b/kernel/src/device/registry/mod.rs @@ -1,6 +1,14 @@ // SPDX-License-Identifier: MPL-2.0 -use crate::{fs::fs_resolver::FsResolver, prelude::*}; +use device_id::DeviceId; + +use crate::{ + fs::{ + device::{Device, DeviceType}, + fs_resolver::FsResolver, + }, + prelude::*, +}; mod block; pub(super) mod char; @@ -15,3 +23,10 @@ pub(super) fn init_in_first_process(fs_resolver: &FsResolver) -> Result<()> { Ok(()) } + +pub fn lookup(device_type: DeviceType, device_id: DeviceId) -> Option> { + match device_type { + DeviceType::Char => char::lookup(device_id), + DeviceType::Block => block::lookup(device_id), + } +} diff --git a/kernel/src/fs/ext2/impl_for_vfs/inode.rs b/kernel/src/fs/ext2/impl_for_vfs/inode.rs index 7fbe220b9..3c00195fa 100644 --- a/kernel/src/fs/ext2/impl_for_vfs/inode.rs +++ b/kernel/src/fs/ext2/impl_for_vfs/inode.rs @@ -5,7 +5,7 @@ use core::time::Duration; use device_id::DeviceId; use crate::{ - device::get_device, + device, fs::{ ext2::{FilePerm, Inode as Ext2Inode}, inode_handle::FileIo, @@ -131,12 +131,24 @@ impl Inode for Ext2Inode { status_flags: StatusFlags, ) -> Option>> { match self.inode_type() { - InodeType::BlockDevice | InodeType::CharDevice => { + inode_type @ (InodeType::BlockDevice | InodeType::CharDevice) => { let device_id = self.device_id(); - let device = match get_device(DeviceId::from_encoded_u64(device_id)) { - Ok(device) => device, - Err(e) => return Some(Err(e)), + if device_id == 0 { + return Some(Err(Error::with_message( + Errno::ENODEV, + "the device of ID 0 does not exist", + ))); + } + let device_type = inode_type.as_device_type().unwrap(); + let Some(device) = + device::lookup(device_type, DeviceId::from_encoded_u64(device_id)) + else { + return Some(Err(Error::with_message( + Errno::ENODEV, + "the required device ID does not exist", + ))); }; + Some(device.open()) } InodeType::NamedPipe => Some(self.open_named_pipe(access_mode, status_flags)), diff --git a/kernel/src/fs/utils/inode.rs b/kernel/src/fs/utils/inode.rs index e63b312db..8208a986f 100644 --- a/kernel/src/fs/utils/inode.rs +++ b/kernel/src/fs/utils/inode.rs @@ -68,6 +68,14 @@ impl InodeType { Self::try_from(mode & TYPE_MASK) .map_err(|_| Error::with_message(Errno::EINVAL, "invalid file type")) } + + pub fn as_device_type(&self) -> Option { + match self { + InodeType::BlockDevice => Some(DeviceType::Block), + InodeType::CharDevice => Some(DeviceType::Char), + _ => None, + } + } } impl From for InodeType { diff --git a/kernel/src/syscall/mknod.rs b/kernel/src/syscall/mknod.rs index 16d2d3bef..bb54ccaf4 100644 --- a/kernel/src/syscall/mknod.rs +++ b/kernel/src/syscall/mknod.rs @@ -4,9 +4,9 @@ use device_id::DeviceId; use super::SyscallReturn; use crate::{ - device::get_device, - fs, + device, fs::{ + self, file_table::FileDesc, fs_resolver::{FsPath, AT_FDCWD}, utils::{InodeMode, InodeType, MknodType}, @@ -49,7 +49,9 @@ pub fn sys_mknodat( let _ = dir_path.new_fs_child(&name, InodeType::File, inode_mode)?; } InodeType::CharDevice | InodeType::BlockDevice => { - let device_inode = get_device(DeviceId::from_encoded_u64(dev as u64))?; + let device_type = inode_type.as_device_type().unwrap(); + let device_inode = device::lookup(device_type, DeviceId::from_encoded_u64(dev as u64)) + .ok_or_else(|| Error::new(Errno::ENODEV))?; let _ = dir_path.mknod(&name, inode_mode, device_inode.into())?; } InodeType::NamedPipe => {