Support generating the mount infomation

This commit is contained in:
Chen Chengjun 2025-10-24 02:36:32 +00:00 committed by Jianfeng Jiang
parent 79d737c268
commit 7b68571290
19 changed files with 210 additions and 3 deletions

View File

@ -351,6 +351,16 @@ impl From<aster_systree::Error> for Error {
}
}
impl From<aster_util::printer::VmPrinterError> 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) => {

View File

@ -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(())

View File

@ -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(())

View File

@ -88,6 +88,10 @@ impl DevPts {
}
impl FileSystem for DevPts {
fn name(&self) -> &'static str {
"devpts"
}
fn sync(&self) -> Result<()> {
Ok(())
}

View File

@ -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()?;

View File

@ -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()?;

View File

@ -69,6 +69,8 @@ pub fn init() {
ext2::init();
exfat::init();
overlayfs::init();
path::init();
}
pub fn init_on_each_cpu() {

View File

@ -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<dyn Inode> {
let fs = self.fs();
@ -1193,6 +1197,7 @@ mod tests {
fn create_overlay_fs() -> Arc<dyn FileSystem> {
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());

View File

@ -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();
}

View File

@ -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<SpinLock<IdAlloc>> = 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<Dentry>,
/// Mountpoint dentry. A mount node can be mounted on one dentry of another mount node,
@ -84,7 +98,9 @@ impl Mount {
parent_mount: Option<Weak<Mount>>,
mnt_ns: Weak<MountNamespace>,
) -> Arc<Self> {
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<MountNamespace>>,
) -> Arc<Self> {
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<usize> {
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> {
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
)
}
}

View File

@ -77,6 +77,10 @@ impl ProcFs {
}
impl FileSystem for ProcFs {
fn name(&self) -> &'static str {
"proc"
}
fn sync(&self) -> Result<()> {
Ok(())
}

View File

@ -74,6 +74,10 @@ impl RamFs {
}
impl FileSystem for RamFs {
fn name(&self) -> &'static str {
"ramfs"
}
fn sync(&self) -> Result<()> {
// do nothing
Ok(())

View File

@ -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(())

View File

@ -19,6 +19,10 @@ pub struct TmpFs {
}
impl FileSystem for TmpFs {
fn name(&self) -> &'static str {
"tmpfs"
}
fn sync(&self) -> Result<()> {
// do nothing
Ok(())

View File

@ -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<dyn Inode>;
/// Returns the super block of this file system.
fn sb(&self) -> SuperBlock;
/// Returns the flags of this file system.
fn flags(&self) -> FsFlags;
}

View File

@ -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) {

View File

@ -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,

View File

@ -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<Arc<ThreadFsInfo>>,
// Files
/// File table
file_table: Mutex<Option<RoArc<FileTable>>>,
@ -100,6 +103,17 @@ impl PosixThread {
&self.name
}
/// Returns a read guard to the filesystem information of the thread.
pub fn fs(&self) -> RwMutexReadGuard<Arc<ThreadFsInfo>> {
self.fs.read()
}
/// Updates the filesystem information of the thread.
pub fn update_fs(&self, new_fs: Arc<ThreadFsInfo>) {
let mut fs_lock = self.fs.write();
*fs_lock = new_fs;
}
pub fn file_table(&self) -> &Mutex<Option<RoArc<FileTable>>> {
&self.file_table
}

View File

@ -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<Option<Vaddr>> {