From 7b6857129013b08eb66d7cc030d36d577aa2cf0a Mon Sep 17 00:00:00 2001 From: Chen Chengjun Date: Fri, 24 Oct 2025 02:36:32 +0000 Subject: [PATCH] Support generating the mount infomation --- kernel/src/error.rs | 10 ++ kernel/src/fs/cgroupfs/fs.rs | 4 + kernel/src/fs/configfs/fs.rs | 4 + kernel/src/fs/devpts/mod.rs | 4 + kernel/src/fs/exfat/fs.rs | 4 + kernel/src/fs/ext2/impl_for_vfs/fs.rs | 4 + kernel/src/fs/mod.rs | 2 + kernel/src/fs/overlayfs/fs.rs | 8 ++ kernel/src/fs/path/mod.rs | 4 + kernel/src/fs/path/mount.rs | 124 ++++++++++++++++++ kernel/src/fs/procfs/mod.rs | 4 + kernel/src/fs/ramfs/fs.rs | 4 + kernel/src/fs/sysfs/fs.rs | 4 + kernel/src/fs/tmpfs/fs.rs | 4 + kernel/src/fs/utils/fs.rs | 7 + kernel/src/process/namespace/unshare.rs | 1 + kernel/src/process/posix_thread/builder.rs | 1 + kernel/src/process/posix_thread/mod.rs | 18 ++- .../src/process/posix_thread/thread_local.rs | 2 +- 19 files changed, 210 insertions(+), 3 deletions(-) diff --git a/kernel/src/error.rs b/kernel/src/error.rs index 0bb60aa23..ce1a44f64 100644 --- a/kernel/src/error.rs +++ b/kernel/src/error.rs @@ -351,6 +351,16 @@ impl From for Error { } } +impl From for Error { + fn from(value: aster_util::printer::VmPrinterError) -> Self { + match value { + aster_util::printer::VmPrinterError::PageFault => { + Error::with_message(Errno::EFAULT, "Page fault occurred during VmPrinter write") + } + } + } +} + #[macro_export] macro_rules! return_errno { ($errno: expr) => { diff --git a/kernel/src/fs/cgroupfs/fs.rs b/kernel/src/fs/cgroupfs/fs.rs index 5c353aa5a..bad43df8e 100644 --- a/kernel/src/fs/cgroupfs/fs.rs +++ b/kernel/src/fs/cgroupfs/fs.rs @@ -48,6 +48,10 @@ impl CgroupFs { } impl FileSystem for CgroupFs { + fn name(&self) -> &'static str { + "cgroup2" + } + fn sync(&self) -> Result<()> { // CgroupFs is volatile, sync is a no-op Ok(()) diff --git a/kernel/src/fs/configfs/fs.rs b/kernel/src/fs/configfs/fs.rs index 26f3dfff2..08423a19f 100644 --- a/kernel/src/fs/configfs/fs.rs +++ b/kernel/src/fs/configfs/fs.rs @@ -53,6 +53,10 @@ impl ConfigFs { } impl FileSystem for ConfigFs { + fn name(&self) -> &'static str { + "configfs" + } + fn sync(&self) -> Result<()> { // `ConfigFs` is volatile, sync is a no-op Ok(()) diff --git a/kernel/src/fs/devpts/mod.rs b/kernel/src/fs/devpts/mod.rs index b2f77058b..62afad298 100644 --- a/kernel/src/fs/devpts/mod.rs +++ b/kernel/src/fs/devpts/mod.rs @@ -88,6 +88,10 @@ impl DevPts { } impl FileSystem for DevPts { + fn name(&self) -> &'static str { + "devpts" + } + fn sync(&self) -> Result<()> { Ok(()) } diff --git a/kernel/src/fs/exfat/fs.rs b/kernel/src/fs/exfat/fs.rs index ac1a70a3c..e37f76a92 100644 --- a/kernel/src/fs/exfat/fs.rs +++ b/kernel/src/fs/exfat/fs.rs @@ -403,6 +403,10 @@ impl PageCacheBackend for ExfatFs { } impl FileSystem for ExfatFs { + fn name(&self) -> &'static str { + "exfat" + } + fn sync(&self) -> Result<()> { for inode in self.inodes.read().values() { inode.sync_all()?; diff --git a/kernel/src/fs/ext2/impl_for_vfs/fs.rs b/kernel/src/fs/ext2/impl_for_vfs/fs.rs index 02c60f8e7..bec555bc8 100644 --- a/kernel/src/fs/ext2/impl_for_vfs/fs.rs +++ b/kernel/src/fs/ext2/impl_for_vfs/fs.rs @@ -11,6 +11,10 @@ use crate::{ }; impl FileSystem for Ext2 { + fn name(&self) -> &'static str { + "ext2" + } + fn sync(&self) -> Result<()> { self.sync_all_inodes()?; self.sync_metadata()?; diff --git a/kernel/src/fs/mod.rs b/kernel/src/fs/mod.rs index d6a988f1d..5d83d239f 100644 --- a/kernel/src/fs/mod.rs +++ b/kernel/src/fs/mod.rs @@ -69,6 +69,8 @@ pub fn init() { ext2::init(); exfat::init(); overlayfs::init(); + + path::init(); } pub fn init_on_each_cpu() { diff --git a/kernel/src/fs/overlayfs/fs.rs b/kernel/src/fs/overlayfs/fs.rs index 84891c42a..14557de21 100644 --- a/kernel/src/fs/overlayfs/fs.rs +++ b/kernel/src/fs/overlayfs/fs.rs @@ -154,6 +154,10 @@ impl OverlayFs { } impl FileSystem for OverlayFs { + fn name(&self) -> &'static str { + "overlay" + } + /// Utilizes the layered directory entries to build the root inode. fn root_inode(&self) -> Arc { let fs = self.fs(); @@ -1193,6 +1197,7 @@ mod tests { fn create_overlay_fs() -> Arc { crate::time::clocks::init_for_ktest(); + crate::fs::path::init(); let mode = InodeMode::all(); let upper = { @@ -1238,6 +1243,7 @@ mod tests { #[ktest] fn work_and_upper_should_be_in_same_mount() { crate::time::clocks::init_for_ktest(); + crate::fs::path::init(); let upper = Path::new_fs_root(new_dummy_mount()); let lower = vec![Path::new_fs_root(new_dummy_mount())]; @@ -1252,6 +1258,7 @@ mod tests { #[ktest] fn work_should_be_empty() { crate::time::clocks::init_for_ktest(); + crate::fs::path::init(); let mode = InodeMode::all(); let upper = { @@ -1271,6 +1278,7 @@ mod tests { #[ktest] fn obscured_multi_layers() { crate::time::clocks::init_for_ktest(); + crate::fs::path::init(); let mode = InodeMode::all(); let root = Path::new_fs_root(new_dummy_mount()); diff --git a/kernel/src/fs/path/mod.rs b/kernel/src/fs/path/mod.rs index 7907a759f..f44ae0c3d 100644 --- a/kernel/src/fs/path/mod.rs +++ b/kernel/src/fs/path/mod.rs @@ -477,3 +477,7 @@ pub const fn is_dot_or_dotdot(filename: &str) -> bool { } const DOT_BYTE: u8 = b'.'; + +pub(super) fn init() { + mount::init(); +} diff --git a/kernel/src/fs/path/mount.rs b/kernel/src/fs/path/mount.rs index 7575752ce..1a0881c02 100644 --- a/kernel/src/fs/path/mount.rs +++ b/kernel/src/fs/path/mount.rs @@ -1,6 +1,9 @@ // SPDX-License-Identifier: MPL-2.0 +use aster_util::printer::VmPrinter; use hashbrown::HashMap; +use id_alloc::IdAlloc; +use spin::Once; use crate::{ fs::{ @@ -32,11 +35,22 @@ impl Default for MountPropType { } } +static ID_ALLOCATOR: Once> = Once::new(); + +pub(super) fn init() { + // TODO: Make it configurable. + const MAX_MOUNT_NUM: usize = 10000; + + ID_ALLOCATOR.call_once(|| SpinLock::new(IdAlloc::with_capacity(MAX_MOUNT_NUM))); +} + /// A `Mount` represents a mounted filesystem instance in the VFS. /// /// Each `Mount` can be viewed as a node in the mount tree, maintaining /// mount-related information and the structure of the mount tree. pub struct Mount { + /// Global unique identifier for the mount node. + id: usize, /// Root dentry. root_dentry: Arc, /// Mountpoint dentry. A mount node can be mounted on one dentry of another mount node, @@ -84,7 +98,9 @@ impl Mount { parent_mount: Option>, mnt_ns: Weak, ) -> Arc { + let id = ID_ALLOCATOR.get().unwrap().lock().alloc().unwrap(); Arc::new_cyclic(|weak_self| Self { + id, root_dentry: Dentry::new_root(fs.root_inode()), mountpoint: RwLock::new(None), parent: RwLock::new(parent_mount), @@ -96,6 +112,11 @@ impl Mount { }) } + /// Gets the mount ID. + pub fn id(&self) -> usize { + self.id + } + /// Mounts a fs on the mountpoint, it will create a new child mount node. /// /// If the given mountpoint has already been mounted, then its mounted child mount @@ -152,6 +173,7 @@ impl Mount { new_ns: Option<&Weak>, ) -> Arc { Arc::new_cyclic(|weak_self| Self { + id: ID_ALLOCATOR.get().unwrap().lock().alloc().unwrap(), root_dentry: root_dentry.clone(), mountpoint: RwLock::new(None), parent: RwLock::new(None), @@ -362,6 +384,59 @@ impl Mount { Some(target_mount) } + /// Reads the mount information starting from this mount as the root, + pub fn read_mount_info(&self, offset: usize, writer: &mut VmWriter) -> Result { + let mut printer = VmPrinter::new_skip(writer, offset); + + let mut stack = vec![self.this()]; + while let Some(mount) = stack.pop() { + let mount_id = mount.id(); + let parent = mount.parent().and_then(|parent| parent.upgrade()); + let parent_id = parent.as_ref().map_or(mount_id, |p| p.id()); + let root = Path::new_fs_root(mount.clone()).abs_path(); + let mount_point = if let Some(parent) = parent { + if let Some(mount_point_dentry) = mount.mountpoint() { + Path::new(parent, mount_point_dentry).abs_path() + } else { + "".to_string() + } + } else { + // No parent means it's the root of the namespace. + "/".to_string() + }; + let fs_type = mount.fs().name(); + + // The following fields are dummy for now. + let major = 0; + let minor = 0; + let mount_options = "rw,relatime"; + let source = "none"; + let super_options = "rw"; + + let entry = MountInfoEntry { + mount_id, + parent_id, + major, + minor, + root: &root, + mount_point: &mount_point, + mount_options, + fs_type, + source, + super_options, + }; + + writeln!(printer, "{}", entry)?; + + let children = mount.children.read(); + for child_mount in children.values() { + stack.push(child_mount.clone()); + } + } + + Ok(printer.bytes_written()) + } + fn this(&self) -> Arc { self.this.upgrade().unwrap() } @@ -376,3 +451,52 @@ impl Debug for Mount { .finish() } } + +impl Drop for Mount { + fn drop(&mut self) { + ID_ALLOCATOR.get().unwrap().lock().free(self.id); + } +} + +/// A single entry in the mountinfo file. +struct MountInfoEntry<'a> { + /// A unique ID for the mount (but not guaranteed to be unique across reboots). + mount_id: usize, + /// The ID of the parent mount (or self if it has no parent). + parent_id: usize, + /// The major device ID of the filesystem. + major: u32, + /// The minor device ID of the filesystem. + minor: u32, + /// The root of the mount within the filesystem. + root: &'a str, + /// The mount point relative to the process's root directory. + mount_point: &'a str, + /// Per-mount options. + mount_options: &'a str, + /// The type of the filesystem in the form "type[.subtype]". + fs_type: &'a str, + /// Filesystem-specific information or "none". + source: &'a str, + /// Per-superblock options. + super_options: &'a str, +} + +impl core::fmt::Display for MountInfoEntry<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "{} {} {}:{} {} {} {} - {} {} {}", + self.mount_id, + self.parent_id, + self.major, + self.minor, + &self.root, + &self.mount_point, + &self.mount_options, + &self.fs_type, + &self.source, + &self.super_options + ) + } +} diff --git a/kernel/src/fs/procfs/mod.rs b/kernel/src/fs/procfs/mod.rs index 5076e647a..270213420 100644 --- a/kernel/src/fs/procfs/mod.rs +++ b/kernel/src/fs/procfs/mod.rs @@ -77,6 +77,10 @@ impl ProcFs { } impl FileSystem for ProcFs { + fn name(&self) -> &'static str { + "proc" + } + fn sync(&self) -> Result<()> { Ok(()) } diff --git a/kernel/src/fs/ramfs/fs.rs b/kernel/src/fs/ramfs/fs.rs index f5c3aa6e3..79fcf727b 100644 --- a/kernel/src/fs/ramfs/fs.rs +++ b/kernel/src/fs/ramfs/fs.rs @@ -74,6 +74,10 @@ impl RamFs { } impl FileSystem for RamFs { + fn name(&self) -> &'static str { + "ramfs" + } + fn sync(&self) -> Result<()> { // do nothing Ok(()) diff --git a/kernel/src/fs/sysfs/fs.rs b/kernel/src/fs/sysfs/fs.rs index 33497be65..b2544d2e7 100644 --- a/kernel/src/fs/sysfs/fs.rs +++ b/kernel/src/fs/sysfs/fs.rs @@ -49,6 +49,10 @@ impl SysFs { } impl FileSystem for SysFs { + fn name(&self) -> &'static str { + "sysfs" + } + fn sync(&self) -> Result<()> { // Sysfs is volatile, sync is a no-op Ok(()) diff --git a/kernel/src/fs/tmpfs/fs.rs b/kernel/src/fs/tmpfs/fs.rs index 60938e3a7..7fb7c5700 100644 --- a/kernel/src/fs/tmpfs/fs.rs +++ b/kernel/src/fs/tmpfs/fs.rs @@ -19,6 +19,10 @@ pub struct TmpFs { } impl FileSystem for TmpFs { + fn name(&self) -> &'static str { + "tmpfs" + } + fn sync(&self) -> Result<()> { // do nothing Ok(()) diff --git a/kernel/src/fs/utils/fs.rs b/kernel/src/fs/utils/fs.rs index 033d52dab..50b1f71f6 100644 --- a/kernel/src/fs/utils/fs.rs +++ b/kernel/src/fs/utils/fs.rs @@ -44,12 +44,19 @@ bitflags! { } pub trait FileSystem: Any + Sync + Send { + /// Gets the name of this FS type such as `"ext4"` or `"sysfs"`. + fn name(&self) -> &'static str; + + /// Syncs the file system. fn sync(&self) -> Result<()>; + /// Returns the root inode of this file system. fn root_inode(&self) -> Arc; + /// Returns the super block of this file system. fn sb(&self) -> SuperBlock; + /// Returns the flags of this file system. fn flags(&self) -> FsFlags; } diff --git a/kernel/src/process/namespace/unshare.rs b/kernel/src/process/namespace/unshare.rs index 366013fa0..fddb5cd97 100644 --- a/kernel/src/process/namespace/unshare.rs +++ b/kernel/src/process/namespace/unshare.rs @@ -33,6 +33,7 @@ impl ContextUnshareAdminApi for Context<'_> { let mut fs_ref = self.thread_local.borrow_fs_mut(); let new_fs = fs_ref.as_ref().clone(); *fs_ref = Arc::new(new_fs); + self.posix_thread.update_fs(fs_ref.clone()); } fn unshare_sysvsem(&self) { diff --git a/kernel/src/process/posix_thread/builder.rs b/kernel/src/process/posix_thread/builder.rs index 615959fd8..ee8213240 100644 --- a/kernel/src/process/posix_thread/builder.rs +++ b/kernel/src/process/posix_thread/builder.rs @@ -172,6 +172,7 @@ impl PosixThreadBuilder { tid, name: Mutex::new(thread_name), credentials, + fs: RwMutex::new(fs.clone()), file_table: Mutex::new(Some(file_table.clone_ro())), sig_mask, sig_queues, diff --git a/kernel/src/process/posix_thread/mod.rs b/kernel/src/process/posix_thread/mod.rs index c95baf1c3..f9e8d9fa1 100644 --- a/kernel/src/process/posix_thread/mod.rs +++ b/kernel/src/process/posix_thread/mod.rs @@ -3,7 +3,7 @@ use core::sync::atomic::{AtomicU32, Ordering}; use aster_rights::{ReadDupOp, ReadOp, WriteOp}; -use ostd::sync::{RoArc, Waker}; +use ostd::sync::{RoArc, RwMutexReadGuard, Waker}; use super::{ kill::SignalSenderIds, @@ -19,7 +19,7 @@ use super::{ }; use crate::{ events::Observer, - fs::file_table::FileTable, + fs::{file_table::FileTable, thread_info::ThreadFsInfo}, prelude::*, process::{namespace::nsproxy::NsProxy, signal::constants::SIGCONT}, thread::{Thread, Tid}, @@ -53,6 +53,9 @@ pub struct PosixThread { /// Process credentials. At the kernel level, credentials are a per-thread attribute. credentials: Credentials, + /// The file system information of the thread. + fs: RwMutex>, + // Files /// File table file_table: Mutex>>, @@ -100,6 +103,17 @@ impl PosixThread { &self.name } + /// Returns a read guard to the filesystem information of the thread. + pub fn fs(&self) -> RwMutexReadGuard> { + self.fs.read() + } + + /// Updates the filesystem information of the thread. + pub fn update_fs(&self, new_fs: Arc) { + let mut fs_lock = self.fs.write(); + *fs_lock = new_fs; + } + pub fn file_table(&self) -> &Mutex>> { &self.file_table } diff --git a/kernel/src/process/posix_thread/thread_local.rs b/kernel/src/process/posix_thread/thread_local.rs index 7072eba5d..2c93fc805 100644 --- a/kernel/src/process/posix_thread/thread_local.rs +++ b/kernel/src/process/posix_thread/thread_local.rs @@ -152,7 +152,7 @@ impl ThreadLocal { } pub fn is_fs_shared(&self) -> bool { - Arc::strong_count(&self.fs.borrow()) > 1 + Arc::strong_count(&self.fs.borrow()) > 2 } pub fn sig_context(&self) -> &Cell> {