From ddd17eefd18758f0e0e2f44ab67d3e51663fa017 Mon Sep 17 00:00:00 2001 From: sparkzky Date: Thu, 18 Dec 2025 15:18:16 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E6=96=B0?= =?UTF-8?q?=E7=89=88procfs=EF=BC=8C=E4=BD=9C=E4=B8=BAtestprocfs=E6=8C=82?= =?UTF-8?q?=E8=BD=BD=E8=BF=9B=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: sparkzky --- kernel/src/filesystem/procfs/cmdline.rs | 51 +++ kernel/src/filesystem/procfs/cpuinfo.rs | 283 ++++++++++++++++ kernel/src/filesystem/procfs/kmsg_file.rs | 46 +++ kernel/src/filesystem/procfs/meminfo.rs | 72 +++++ kernel/src/filesystem/procfs/mod.rs | 75 +++-- kernel/src/filesystem/procfs/mounts.rs | 98 ++++++ kernel/src/filesystem/procfs/pid/exe.rs | 45 +++ kernel/src/filesystem/procfs/pid/fd.rs | 167 ++++++++++ kernel/src/filesystem/procfs/pid/mod.rs | 131 ++++++++ kernel/src/filesystem/procfs/pid/status.rs | 179 +++++++++++ kernel/src/filesystem/procfs/proc_cpuinfo.rs | 1 + kernel/src/filesystem/procfs/root.rs | 301 ++++++++++++++++++ kernel/src/filesystem/procfs/self_.rs | 40 +++ .../src/filesystem/procfs/template/builder.rs | 280 ++++++++++++++++ kernel/src/filesystem/procfs/template/dir.rs | 294 +++++++++++++++++ kernel/src/filesystem/procfs/template/file.rs | 185 +++++++++++ kernel/src/filesystem/procfs/template/mod.rs | 102 ++++++ kernel/src/filesystem/procfs/template/sym.rs | 154 +++++++++ kernel/src/filesystem/procfs/utils.rs | 30 ++ kernel/src/filesystem/procfs/version.rs | 64 ++++ kernel/src/filesystem/vfs/mod.rs | 12 +- kernel/src/filesystem/vfs/vcore.rs | 15 + kernel/src/process/mod.rs | 15 + kernel/src/syscall/mod.rs | 2 +- 24 files changed, 2607 insertions(+), 35 deletions(-) create mode 100644 kernel/src/filesystem/procfs/cmdline.rs create mode 100644 kernel/src/filesystem/procfs/cpuinfo.rs create mode 100644 kernel/src/filesystem/procfs/kmsg_file.rs create mode 100644 kernel/src/filesystem/procfs/meminfo.rs create mode 100644 kernel/src/filesystem/procfs/mounts.rs create mode 100644 kernel/src/filesystem/procfs/pid/exe.rs create mode 100644 kernel/src/filesystem/procfs/pid/fd.rs create mode 100644 kernel/src/filesystem/procfs/pid/mod.rs create mode 100644 kernel/src/filesystem/procfs/pid/status.rs create mode 100644 kernel/src/filesystem/procfs/root.rs create mode 100644 kernel/src/filesystem/procfs/self_.rs create mode 100644 kernel/src/filesystem/procfs/template/builder.rs create mode 100644 kernel/src/filesystem/procfs/template/dir.rs create mode 100644 kernel/src/filesystem/procfs/template/file.rs create mode 100644 kernel/src/filesystem/procfs/template/mod.rs create mode 100644 kernel/src/filesystem/procfs/template/sym.rs create mode 100644 kernel/src/filesystem/procfs/utils.rs create mode 100644 kernel/src/filesystem/procfs/version.rs diff --git a/kernel/src/filesystem/procfs/cmdline.rs b/kernel/src/filesystem/procfs/cmdline.rs new file mode 100644 index 000000000..b48f8fab1 --- /dev/null +++ b/kernel/src/filesystem/procfs/cmdline.rs @@ -0,0 +1,51 @@ +//! /proc/cmdline - 内核启动命令行参数 +//! +//! 这个文件展示了传递给内核的启动参数 + +use crate::filesystem::{ + procfs::{ + template::{Builder, FileOps, ProcFileBuilder}, + utils::proc_read, + }, + vfs::{syscall::ModeType, FilePrivateData, IndexNode}, +}; +use alloc::{ + borrow::ToOwned, + sync::{Arc, Weak}, + vec::Vec, +}; +use system_error::SystemError; + +/// /proc/cmdline 文件的 FileOps 实现 +#[derive(Debug)] +pub struct CmdlineFileOps; + +impl CmdlineFileOps { + pub fn new_inode(parent: Weak) -> Arc { + ProcFileBuilder::new(Self, ModeType::S_IRUGO) // 0444 - 所有用户可读 + .parent(parent) + .build() + .unwrap() + } + + fn generate_cmdline_content() -> Vec { + // TODO: 从 bootloader 获取实际的 cmdline + // 目前返回一个占位符 + let cmdline = "BOOT_IMAGE=/boot/vmlinuz root=/dev/sda1 ro quiet splash\n"; + cmdline.as_bytes().to_owned() + } +} + +impl FileOps for CmdlineFileOps { + fn read_at( + &self, + offset: usize, + len: usize, + buf: &mut [u8], + _data: crate::libs::spinlock::SpinLockGuard, + ) -> Result { + let content = Self::generate_cmdline_content(); + + proc_read(offset, len, buf, &content) + } +} diff --git a/kernel/src/filesystem/procfs/cpuinfo.rs b/kernel/src/filesystem/procfs/cpuinfo.rs new file mode 100644 index 000000000..40dd7da28 --- /dev/null +++ b/kernel/src/filesystem/procfs/cpuinfo.rs @@ -0,0 +1,283 @@ +//! `/proc/cpuinfo` 文件操作 +//! 提供 CPU 信息的只读接口 + +use crate::{ + filesystem::{ + procfs::{ + template::{Builder, FileOps, ProcFileBuilder}, + utils::proc_read, + }, + vfs::{syscall::ModeType, IndexNode}, + }, + smp::cpu::smp_cpu_manager, +}; +use alloc::sync::{Arc, Weak}; +use alloc::{format, string::String, vec::Vec}; +use system_error::SystemError; + +/// `/proc/cpuinfo` 文件 +#[derive(Debug)] +pub struct CpuInfoFileOps; + +impl CpuInfoFileOps { + pub fn new_inode(parent: Weak) -> Arc { + ProcFileBuilder::new(Self, ModeType::S_IRUGO) + .parent(parent) + .build() + .unwrap() + } +} + +impl FileOps for CpuInfoFileOps { + fn read_at( + &self, + offset: usize, + len: usize, + buf: &mut [u8], + _: crate::libs::spinlock::SpinLockGuard, + ) -> Result { + let mut data: Vec = vec![]; + let cpu_manager = smp_cpu_manager(); + + // 遍历所有present的CPU + for cpu_id in cpu_manager.present_cpus().iter_cpu() { + // 生成每个 CPU 的信息 + let cpu_info = generate_cpu_info(cpu_id); + data.extend_from_slice(cpu_info.as_bytes()); + + // 在每个CPU信息之间添加空行分隔 + data.push(b'\n'); + } + + proc_read(offset, len, buf, &data) + } +} + +/// 生成单个 CPU 的信息字符串 +/// 当前使用的 raw_cpuid 库仅支持 x86_64 架构 +/// 当在某个线程或核心上执行 CPUID 指令时,它返回的是 当前核心视角下的 CPU 信息。 +/// 所以需要通过 sched_setaffinity() 把线程绑定到不同核心,然后在该线程执行 CPUID。 +/// 但是目前还没实现sched_setaffinity系统调用 +fn generate_cpu_info(cpu_id: crate::smp::cpu::ProcessorId) -> String { + let mut info = String::new(); + + #[cfg(target_arch = "x86_64")] + { + use raw_cpuid::CpuId; + + info.push_str(&format!("processor\t: {}\n", cpu_id.data())); + + let cpuid = CpuId::new(); + + // 获取厂商信息 + if let Some(vendor_info) = cpuid.get_vendor_info() { + let vendor_string = vendor_info.as_str(); + if vendor_string != "GenuineIntel" && vendor_string != "AuthenticAMD" { + info.push_str("vendor_id\t: Unknown\n"); + return info; + } + info.push_str(&format!("vendor_id\t: {}\n", vendor_string)); + } else { + info.push_str("vendor_id\t: Unknown\n"); + return info; + } + + // 获取 CPU 特性信息 + if let Some(feature_info) = cpuid.get_feature_info() { + info.push_str(&format!("cpu family\t: {}\n", feature_info.family_id())); + info.push_str(&format!("model\t\t: {}\n", feature_info.model_id())); + info.push_str(&format!("stepping\t: {}\n", feature_info.stepping_id())); + } + + // 获取处理器品牌字符串 + if let Some(brand_string) = cpuid.get_processor_brand_string() { + info.push_str(&format!("model name\t: {}\n", brand_string.as_str())); + } else { + info.push_str("model name\t: Unknown\n"); + } + + // 微代码版本(在虚拟化环境中通常无法获取真实值 && raw_cpuid 库只支持amd cpu获取microcode) + // info.push_str("microcode\t: 0xffffffff\n"); + + // CPU 频率 + if let Some(cpu_fre) = cpuid.get_processor_frequency_info() { + let cpu_mhz = cpu_fre.processor_base_frequency() as f64; + info.push_str(&format!("cpu MHz\t\t: {}\n", cpu_mhz)); + } else { + let tsc_khz = crate::arch::driver::tsc::TSCManager::cpu_khz(); + if tsc_khz > 0 { + let cpu_mhz = tsc_khz as f64 / 1000.0; + info.push_str(&format!("cpu MHz\t\t: {:.3}\n", cpu_mhz)); + } else { + info.push_str("cpu MHz\t\t: unknown\n"); + } + } + + // L3缓存大小 + if let Some(cache_params) = cpuid.get_cache_parameters() { + for cache in cache_params { + if cache.level() == 3 { + let cache_size = + cache.sets() * cache.associativity() * cache.coherency_line_size(); + info.push_str(&format!("cache size\t: {} KB\n", cache_size / 1024)); + break; + } + } + } else { + info.push_str("cache size\t: unknown\n"); + } + + let boot_data = &crate::arch::x86_64::smp::SMP_BOOT_DATA; + + // // 物理 CPU 封装 ID + + // siblings - 同一个物理cpu中的逻辑处理器数量 + let siblings = smp_cpu_manager().present_cpus_count(); + info.push_str(&format!("siblings\t: {}\n", siblings)); + + // // core id - 在同一个物理cpu内的核心ID + + // // cpu cores - 每个物理cpu中的核心数 + + // APIC ID // 不确定是哪个 + let apic_id = boot_data.phys_id(cpu_id.data() as usize); + info.push_str(&format!("apicid\t\t: {}\n", apic_id)); + info.push_str(&format!("initial apicid\t: {}\n", apic_id)); + + // FPU 和其他特性 + if let Some(feature_info) = cpuid.get_feature_info() { + info.push_str(&format!( + "fpu\t\t: {}\n", + if feature_info.has_fpu() { "yes" } else { "no" } + )); + // info.push_str("fpu_exception\t: yes\n"); + + // CPUID level + // if let Some(vendor_info) = cpuid.get_extended_feature_info() { + // info.push_str(&format!("cpuid level\t: {}\n", vendor_info.)); + // } + + // wp 标志 + let cr0: u64; + unsafe { + core::arch::asm!("mov {}, cr0", out(reg) cr0); + } + let wp_enabled = (cr0 >> 16) & 1 != 0; + info.push_str(&format!( + "wp\t\t: {}\n", + if wp_enabled { "yes" } else { "no" } + )); + + // CPU 特性标志 - 只包含真实检测到的特性 + info.push_str("flags\t\t: "); + let mut flags = Vec::new(); + + if feature_info.has_fpu() { + flags.push("fpu"); + } + if feature_info.has_vme() { + flags.push("vme"); + } + if feature_info.has_de() { + flags.push("de"); + } + if feature_info.has_pse() { + flags.push("pse"); + } + if feature_info.has_tsc() { + flags.push("tsc"); + } + if feature_info.has_msr() { + flags.push("msr"); + } + if feature_info.has_pae() { + flags.push("pae"); + } + if feature_info.has_mce() { + flags.push("mce"); + } + if feature_info.has_cmpxchg8b() { + flags.push("cx8"); + } + if feature_info.has_apic() { + flags.push("apic"); + } + if feature_info.has_sysenter_sysexit() { + flags.push("sep"); + } + if feature_info.has_mtrr() { + flags.push("mtrr"); + } + if feature_info.has_pge() { + flags.push("pge"); + } + if feature_info.has_mca() { + flags.push("mca"); + } + if feature_info.has_cmov() { + flags.push("cmov"); + } + if feature_info.has_pat() { + flags.push("pat"); + } + if feature_info.has_pse36() { + flags.push("pse36"); + } + if feature_info.has_clflush() { + flags.push("clflush"); + } + if feature_info.has_mmx() { + flags.push("mmx"); + } + if feature_info.has_fxsave_fxstor() { + flags.push("fxsr"); + } + if feature_info.has_sse() { + flags.push("sse"); + } + if feature_info.has_sse2() { + flags.push("sse2"); + } + if feature_info.has_ss() { + flags.push("ss"); + } + if feature_info.has_htt() { + flags.push("ht"); + } + + info.push_str(&flags.join(" ")); + info.push('\n'); + + // bugs 内核根据 CPUID、微码版本以及已知漏洞列表汇总出来 + // 这里暂时不实现 + + info.push_str(&format!( + "clflush size\t: {}\n", + feature_info.cflush_cache_line_size() + )); + info.push_str(&format!( + "cache_alignment\t: {}\n", + feature_info.cflush_cache_line_size() + )); + } + + // BogoMIPS(基于TSC频率的简化计算)在虚拟机中无意义 暂时不实现 + // let tsc_khz = crate::arch::driver::tsc::TSCManager::cpu_khz(); + // if tsc_khz > 0 { + // let bogomips = (tsc_khz as f64 / 1000.0) * 2.0; + // info.push_str(&format!("bogomips\t: {:.2}\n", bogomips)); + // } + + // info.push_str("cache_alignment\t: 64\n"); + if let Some(processor_capacity_feature_info) = cpuid.get_processor_capacity_feature_info() { + info.push_str(&format!( + "address sizes\t: {} bits physical, {} bits virtual\n", + processor_capacity_feature_info.physical_address_bits(), + processor_capacity_feature_info.linear_address_bits() + )); + } + // info.push_str("power management:\n"); + } + + info +} diff --git a/kernel/src/filesystem/procfs/kmsg_file.rs b/kernel/src/filesystem/procfs/kmsg_file.rs new file mode 100644 index 000000000..cd6a3905e --- /dev/null +++ b/kernel/src/filesystem/procfs/kmsg_file.rs @@ -0,0 +1,46 @@ +//! /proc/kmsg - 内核消息缓冲区 +//! +//! 这个文件提供对内核日志消息的访问 + +use crate::{ + filesystem::{ + procfs::{ + kmsg::KMSG, + template::{Builder, FileOps, ProcFileBuilder}, + }, + vfs::{syscall::ModeType, FilePrivateData, IndexNode}, + }, + libs::spinlock::SpinLockGuard, +}; +use alloc::sync::{Arc, Weak}; +use system_error::SystemError; + +/// /proc/kmsg 文件的 FileOps 实现 +#[derive(Debug)] +pub struct KmsgFileOps; + +impl KmsgFileOps { + pub fn new_inode(parent: Weak) -> Arc { + ProcFileBuilder::new(Self, ModeType::S_IRUGO) // 0444 - 所有用户可读 + .parent(parent) + .build() + .unwrap() + } +} + +impl FileOps for KmsgFileOps { + fn read_at( + &self, + _offset: usize, + _len: usize, + buf: &mut [u8], + _data: SpinLockGuard, + ) -> Result { + // 访问全局 KMSG 缓冲区 + let kmsg = unsafe { KMSG.as_ref().ok_or(SystemError::ENODEV)? }; + let mut kmsg_guard = kmsg.lock(); + + // 读取 kmsg 内容 + kmsg_guard.read(buf) + } +} diff --git a/kernel/src/filesystem/procfs/meminfo.rs b/kernel/src/filesystem/procfs/meminfo.rs new file mode 100644 index 000000000..77324cda8 --- /dev/null +++ b/kernel/src/filesystem/procfs/meminfo.rs @@ -0,0 +1,72 @@ +//! /proc/meminfo - 系统内存信息 +//! +//! 这个文件展示了系统的内存使用情况 + +use crate::{ + filesystem::{ + procfs::{ + template::{Builder, FileOps, ProcFileBuilder}, + utils::{proc_read, trim_string}, + }, + vfs::{syscall::ModeType, FilePrivateData, IndexNode}, + }, + mm::allocator::page_frame::FrameAllocator, +}; +use alloc::{ + borrow::ToOwned, + format, + sync::{Arc, Weak}, + vec::Vec, +}; +use system_error::SystemError; + +/// /proc/meminfo 文件的 FileOps 实现 +#[derive(Debug)] +pub struct MeminfoFileOps; + +impl MeminfoFileOps { + pub fn new_inode(parent: Weak) -> Arc { + ProcFileBuilder::new(Self, ModeType::S_IRUGO) // 0444 - 所有用户可读 + .parent(parent) + .build() + .unwrap() + } + + fn generate_meminfo_content() -> Vec { + use crate::arch::mm::LockedFrameAllocator; + + let usage = unsafe { LockedFrameAllocator.usage() }; + + let mut data: Vec = vec![]; + + data.append( + &mut format!("MemTotal:\t{} kB\n", usage.total().bytes() >> 10) + .as_bytes() + .to_owned(), + ); + + data.append( + &mut format!("MemFree:\t{} kB\n", usage.free().bytes() >> 10) + .as_bytes() + .to_owned(), + ); + + // 去除多余的 \0 并在结尾添加 \0 + trim_string(&mut data); + + data + } +} + +impl FileOps for MeminfoFileOps { + fn read_at( + &self, + offset: usize, + len: usize, + buf: &mut [u8], + _data: crate::libs::spinlock::SpinLockGuard, + ) -> Result { + let content = Self::generate_meminfo_content(); + proc_read(offset, len, buf, &content) + } +} diff --git a/kernel/src/filesystem/procfs/mod.rs b/kernel/src/filesystem/procfs/mod.rs index 652c9e449..18b0e9efa 100644 --- a/kernel/src/filesystem/procfs/mod.rs +++ b/kernel/src/filesystem/procfs/mod.rs @@ -1,5 +1,3 @@ -use core::intrinsics::size_of; - use ::log::{error, info}; use alloc::{ borrow::ToOwned, @@ -9,16 +7,20 @@ use alloc::{ sync::{Arc, Weak}, vec::Vec, }; +use core::intrinsics::size_of; use system_error::SystemError; use crate::{ arch::mm::LockedFrameAllocator, driver::base::device::device_number::DeviceNumber, - filesystem::vfs::{ - mount::{MountFlags, MountPath}, - syscall::RenameFlags, - vcore::generate_inode_id, - FileType, + filesystem::{ + procfs::template::Builder, + vfs::{ + mount::{MountFlags, MountPath}, + syscall::RenameFlags, + vcore::generate_inode_id, + FileType, + }, }, libs::{ once::Once, @@ -37,12 +39,23 @@ use super::vfs::{ FileSystem, FsInfo, IndexNode, InodeId, Magic, Metadata, SuperBlock, }; +mod cmdline; +mod cpuinfo; pub mod kmsg; +mod kmsg_file; pub mod log; +mod meminfo; +mod mounts; +mod pid; mod proc_cpuinfo; mod proc_mounts; mod proc_version; +pub mod root; +mod self_; mod syscall; +pub(super) mod template; +mod utils; +mod version; /// @brief 进程文件类型 /// @usage 用于定义进程文件夹下的各类文件类型 @@ -181,9 +194,19 @@ pub struct InodeInfo { // 其他需要传入的信息在此定义 } +impl Default for InodeInfo { + fn default() -> Self { + InodeInfo { + pid: None, + ftype: ProcFileType::Default, + fd: -1, + } + } +} + /// @brief procfs的inode名称的最大长度 -const PROCFS_MAX_NAMELEN: usize = 64; -const PROCFS_BLOCK_SIZE: u64 = 512; +pub(super) const PROCFS_MAX_NAMELEN: usize = 64; +pub(super) const PROCFS_BLOCK_SIZE: u64 = 512; /// @brief procfs文件系统的Inode结构体 #[derive(Debug)] pub struct LockedProcFSInode(SpinLock); @@ -592,7 +615,7 @@ impl ProcFS { .parent(result.root_inode()) .name("meminfo") .file_type(FileType::File) - .mode(ModeType::from_bits_truncate(0o444)) + .mode(ModeType::S_IRUGO) .ftype(ProcFileType::ProcMeminfo) .build() .unwrap(); @@ -605,7 +628,7 @@ impl ProcFS { .parent(result.root_inode()) .name("kmsg") .file_type(FileType::File) - .mode(ModeType::from_bits_truncate(0o444)) + .mode(ModeType::S_IRUGO) .ftype(ProcFileType::ProcKmsg) .build() .unwrap(); @@ -651,7 +674,7 @@ impl ProcFS { .parent(result.root_inode()) .name("version") .file_type(FileType::File) - .mode(ModeType::from_bits_truncate(0o444)) + .mode(ModeType::S_IRUGO) .ftype(ProcFileType::ProcVersion) .build() .unwrap(); @@ -664,7 +687,7 @@ impl ProcFS { .parent(result.root_inode()) .name("cpuinfo") .file_type(FileType::File) - .mode(ModeType::from_bits_truncate(0o444)) + .mode(ModeType::S_IRUGO) .ftype(ProcFileType::ProcCpuinfo) .build() .unwrap(); @@ -700,11 +723,7 @@ impl ProcFS { )?; // 创建相关文件 // status文件 - let status_binding = pid_dir.create( - "status", - FileType::File, - ModeType::from_bits_truncate(0o444), - )?; + let status_binding = pid_dir.create("status", FileType::File, ModeType::S_IRUGO)?; let status_file: &LockedProcFSInode = status_binding .as_any_ref() .downcast_ref::() @@ -713,12 +732,8 @@ impl ProcFS { status_file.0.lock().fdata.ftype = ProcFileType::ProcStatus; // exe文件 - let exe_binding = pid_dir.create_with_data( - "exe", - FileType::SymLink, - ModeType::from_bits_truncate(0o444), - 0, - )?; + let exe_binding = + pid_dir.create_with_data("exe", FileType::SymLink, ModeType::S_IRUGO, 0)?; let exe_file = exe_binding .as_any_ref() .downcast_ref::() @@ -767,11 +782,7 @@ impl LockedProcFSInode { let file = fd_table.get_file_by_fd(fd); if file.is_some() { let _ = self.unlink(&fd.to_string()); - let fd_file = self.create( - &fd.to_string(), - FileType::SymLink, - ModeType::from_bits_truncate(0o444), - )?; + let fd_file = self.create(&fd.to_string(), FileType::SymLink, ModeType::S_IRUGO)?; let fd_file_proc = fd_file .as_any_ref() .downcast_ref::() @@ -862,6 +873,7 @@ impl IndexNode for LockedProcFSInode { buf: &mut [u8], data: SpinLockGuard, ) -> Result { + info!("ProcFS: read_at called with offset {}, len {}", offset, len); if buf.len() < len { return Err(SystemError::EINVAL); } @@ -878,8 +890,7 @@ impl IndexNode for LockedProcFSInode { ProcFileType::ProcStatus | ProcFileType::ProcMeminfo | ProcFileType::ProcMounts - | ProcFileType::ProcVersion - | ProcFileType::ProcCpuinfo => { + | ProcFileType::ProcVersion => { // 获取数据信息 let mut private_data = match &*data { FilePrivateData::Procfs(p) => p.clone(), @@ -892,7 +903,7 @@ impl IndexNode for LockedProcFSInode { ProcFileType::ProcExe => return inode.read_exe_link(buf, offset), ProcFileType::ProcSelf => return inode.read_self_link(buf), ProcFileType::ProcFdFile => return inode.read_fd_link(buf), - + ProcFileType::ProcCpuinfo => {} _ => (), }; diff --git a/kernel/src/filesystem/procfs/mounts.rs b/kernel/src/filesystem/procfs/mounts.rs new file mode 100644 index 000000000..8862daf98 --- /dev/null +++ b/kernel/src/filesystem/procfs/mounts.rs @@ -0,0 +1,98 @@ +//! /proc/mounts - 系统挂载点信息 +//! +//! 这个文件展示了系统当前的所有挂载点 + +use crate::{ + filesystem::{ + procfs::{ + template::{Builder, FileOps, ProcFileBuilder}, + utils::proc_read, + }, + vfs::{syscall::ModeType, FilePrivateData, IndexNode}, + }, + process::ProcessManager, +}; +use alloc::{ + string::{String, ToString}, + sync::{Arc, Weak}, + vec::Vec, +}; +use system_error::SystemError; + +/// /proc/mounts 文件的 FileOps 实现 +#[derive(Debug)] +pub struct MountsFileOps; + +impl MountsFileOps { + pub fn new_inode(parent: Weak) -> Arc { + ProcFileBuilder::new(Self, ModeType::S_IRUGO) // 0444 - 所有用户可读 + .parent(parent) + .build() + .unwrap() + } + + /// 生成 mounts 内容 + #[inline(never)] + fn generate_mounts_content() -> String { + let mntns = ProcessManager::current_mntns(); + let mounts = mntns.mount_list().clone_inner(); + + let mut lines = Vec::with_capacity(mounts.len()); + let mut cap = 0; + for (mp, mfs) in mounts { + let mut line = String::new(); + let fs_type = mfs.fs_type(); + let source = match fs_type { + // 特殊文件系统,直接显示文件系统名称 + "devfs" | "devpts" | "sysfs" | "procfs" | "tmpfs" | "ramfs" | "rootfs" + | "debugfs" | "configfs" => fs_type.to_string(), + // 其他文件系统,尝试显示挂载设备名称 + _ => { + if let Some(s) = mfs.self_mountpoint() { + // 尝试从挂载点获取设备名称 + if let Some(device_name) = s.dname().ok().map(|d| d.to_string()) { + device_name + } else { + // 如果获取不到设备名称,使用绝对路径 + s.absolute_path().unwrap_or("unknown".to_string()) + } + } else { + // 没有挂载点信息,使用文件系统类型 + fs_type.to_string() + } + } + }; + + line.push_str(&format!("{source} {m} {fs_type}", m = mp.as_str())); + + line.push(' '); + line.push_str(&mfs.mount_flags().options_string()); + + line.push_str(" 0 0\n"); + cap += line.len(); + lines.push(line); + } + + let mut content = String::with_capacity(cap); + for line in lines { + content.push_str(&line); + } + + content + } +} + +impl FileOps for MountsFileOps { + fn read_at( + &self, + offset: usize, + len: usize, + buf: &mut [u8], + _data: crate::libs::spinlock::SpinLockGuard, + ) -> Result { + let mounts_content = Self::generate_mounts_content(); + let bytes = mounts_content.as_bytes(); + + proc_read(offset, len, buf, bytes) + } +} diff --git a/kernel/src/filesystem/procfs/pid/exe.rs b/kernel/src/filesystem/procfs/pid/exe.rs new file mode 100644 index 000000000..04fbec620 --- /dev/null +++ b/kernel/src/filesystem/procfs/pid/exe.rs @@ -0,0 +1,45 @@ +//! /proc/[pid]/exe - 进程可执行文件的符号链接 +//! +//! 这个符号链接指向进程的可执行文件路径 + +use crate::{ + filesystem::{ + procfs::template::{Builder, ProcSymBuilder, SymOps}, + vfs::{syscall::ModeType, IndexNode}, + }, + process::{ProcessManager, RawPid}, +}; +use alloc::sync::{Arc, Weak}; +use system_error::SystemError; + +/// /proc/[pid]/exe 符号链接的 SymOps 实现 +#[derive(Debug)] +pub struct ExeSymOps { + /// 存储 PID,在读取时动态查找进程 + pid: RawPid, +} + +impl ExeSymOps { + pub fn new(pid: RawPid) -> Self { + Self { pid } + } + + pub fn new_inode(pid: RawPid, parent: Weak) -> Arc { + ProcSymBuilder::new(Self::new(pid), ModeType::S_IRWXUGO) // 0777 - 符号链接权限 + .parent(parent) + .build() + .unwrap() + } +} + +impl SymOps for ExeSymOps { + fn read_link(&self, buf: &mut [u8]) -> Result { + // 动态查找进程,获取目标进程的可执行文件路径 + let pcb = ProcessManager::find(self.pid).ok_or(SystemError::ESRCH)?; + let exe = pcb.execute_path(); + let exe_bytes = exe.as_bytes(); + let len = exe_bytes.len().min(buf.len()); + buf[..len].copy_from_slice(&exe_bytes[..len]); + Ok(len) + } +} diff --git a/kernel/src/filesystem/procfs/pid/fd.rs b/kernel/src/filesystem/procfs/pid/fd.rs new file mode 100644 index 000000000..19bf36e93 --- /dev/null +++ b/kernel/src/filesystem/procfs/pid/fd.rs @@ -0,0 +1,167 @@ +//! /proc/[pid]/fd - 进程文件描述符目录 +//! +//! 这个目录包含了进程打开的所有文件描述符的符号链接 + +use crate::{ + filesystem::{ + procfs::template::{Builder, DirOps, ProcDir, ProcDirBuilder, ProcSymBuilder, SymOps}, + vfs::{syscall::ModeType, IndexNode}, + }, + libs::rwlock::RwLockReadGuard, + process::{ProcessControlBlock, ProcessManager, RawPid}, +}; +use alloc::{ + collections::BTreeMap, + format, + string::{String, ToString}, + sync::{Arc, Weak}, + vec::Vec, +}; +use system_error::SystemError; + +/// /proc/[pid]/fd 目录的 DirOps 实现 +#[derive(Debug)] +pub struct FdDirOps { + /// 存储 PID,在需要时动态查找进程 + pid: RawPid, +} + +impl FdDirOps { + pub fn new_inode( + process_ref: Arc, + parent: Weak, + ) -> Arc { + let pid = process_ref.raw_pid(); + ProcDirBuilder::new(Self { pid }, ModeType::from_bits_truncate(0o500)) // dr-x------ + .parent(parent) + .volatile() // fd 是易失的,因为它们与特定进程关联 + .build() + .unwrap() + } + + /// 获取进程引用 + fn get_process(&self) -> Option> { + ProcessManager::find(self.pid) + } +} + +impl DirOps for FdDirOps { + fn lookup_child( + &self, + dir: &ProcDir, + name: &str, + ) -> Result, SystemError> { + // 解析文件描述符编号 + let fd = name.parse::().map_err(|_| SystemError::ENOENT)?; + + // 获取进程引用 + let process = self.get_process().ok_or(SystemError::ESRCH)?; + + // 检查文件描述符是否存在,并立即释放fd_table锁 + { + let fd_table = process.fd_table(); + let fd_table_guard = fd_table.read(); + + if fd_table_guard.get_file_by_fd(fd).is_none() { + return Err(SystemError::ENOENT); + } + } // fd_table_guard在这里被释放 + + // 创建或获取缓存的符号链接 + let mut cached_children = dir.cached_children().write(); + + if let Some(child) = cached_children.get(name) { + return Ok(child.clone()); + } + + // 创建新的符号链接(传递 PID 和 fd) + let inode = FdSymOps::new_inode(self.pid, fd, dir.self_ref_weak().clone()); + cached_children.insert(name.to_string(), inode.clone()); + + Ok(inode) + } + + fn populate_children<'a>( + &self, + dir: &'a ProcDir, + ) -> RwLockReadGuard<'a, BTreeMap>> { + let mut cached_children = dir.cached_children().write(); + + // 清空现有缓存 + cached_children.clear(); + + // 获取进程的所有文件描述符 + if let Some(process) = self.get_process() { + // 先收集所有的fd,避免在持有锁时做复杂操作 + let fds: Vec = { + let fd_table = process.fd_table(); + let fd_table_guard = fd_table.read(); + fd_table_guard.iter().map(|(fd, _)| fd).collect() + }; + + // 现在fd_table锁已经释放,我们可以安全地创建inodes + for fd in fds { + let fd_str = fd.to_string(); + + // 创建或获取缓存的符号链接(传递 PID 和 fd) + cached_children.entry(fd_str.clone()).or_insert_with(|| { + FdSymOps::new_inode(self.pid, fd, dir.self_ref_weak().clone()) + }); + } + } + + cached_children.downgrade() + } +} + +/// /proc/[pid]/fd/[fd] 符号链接的 SymOps 实现 +#[derive(Debug)] +pub struct FdSymOps { + /// 存储 PID,在需要时动态查找进程 + pid: RawPid, + fd: i32, +} + +impl FdSymOps { + pub fn new_inode(pid: RawPid, fd: i32, parent: Weak) -> Arc { + ProcSymBuilder::new(Self { pid, fd }, ModeType::from_bits_truncate(0o700)) // lrwx------ + .parent(parent) + .volatile() + .build() + .unwrap() + } +} + +impl SymOps for FdSymOps { + fn read_link(&self, buf: &mut [u8]) -> Result { + // 动态查找进程 + let process = ProcessManager::find(self.pid).ok_or(SystemError::ESRCH)?; + + // 先获取文件对象的 clone,然后立即释放 fd_table 锁 + // 避免在持有锁时调用可能获取其他锁的方法(如 absolute_path) + let file = { + let fd_table = process.fd_table(); + let fd_table_guard = fd_table.read(); + + fd_table_guard + .get_file_by_fd(self.fd) + .ok_or(SystemError::EBADF)? + }; // fd_table 锁在这里被释放 + + // 现在安全地获取文件的路径 + let path = if let Ok(path) = file.inode().absolute_path() { + path + } else { + // 匿名文件或无法获取路径 + let inode_id = file.inode().metadata()?.inode_id; + format!("anon_inode:[{}]", inode_id) + }; + + // 复制路径到缓冲区 + let path_bytes = path.as_bytes(); + let copy_len = path_bytes.len().min(buf.len()); + buf[..copy_len].copy_from_slice(&path_bytes[..copy_len]); + + Ok(copy_len) + } +} diff --git a/kernel/src/filesystem/procfs/pid/mod.rs b/kernel/src/filesystem/procfs/pid/mod.rs new file mode 100644 index 000000000..bf812a250 --- /dev/null +++ b/kernel/src/filesystem/procfs/pid/mod.rs @@ -0,0 +1,131 @@ +use crate::{ + filesystem::{ + procfs::{ + template::{ + lookup_child_from_table, populate_children_from_table, DirOps, ProcDir, + ProcDirBuilder, + }, + Builder, + }, + vfs::{syscall::ModeType, IndexNode}, + }, + libs::rwlock::RwLockReadGuard, + process::{ProcessControlBlock, ProcessManager, RawPid}, +}; +use alloc::{ + collections::BTreeMap, + string::{String,ToString}, + sync::{Arc, Weak}, +}; +use system_error::SystemError; + +mod exe; +mod fd; +mod status; + +use exe::ExeSymOps; +use fd::FdDirOps; +use status::StatusFileOps; + +/// /proc/[pid] 目录的 DirOps 实现 +#[derive(Debug)] +pub struct PidDirOps { + // 存储 PID,用于在需要时查找进程 + pid: RawPid, +} + +impl PidDirOps { + pub fn new_inode(pid: RawPid, parent: Weak) -> Arc { + ProcDirBuilder::new(Self { pid }, ModeType::from_bits_truncate(0o555)) + .parent(parent) + .volatile() // PID 目录是易失的,因为它们与特定进程关联 + .build() + .unwrap() + } + + /// 获取进程引用 + fn get_process(&self) -> Option> { + ProcessManager::find(self.pid) + } + + /// 静态条目表 + /// 包含 /proc/[pid] 目录下的所有静态文件和目录 + #[expect(clippy::type_complexity)] + const STATIC_ENTRIES: &'static [( + &'static str, + fn(&PidDirOps, Weak) -> Arc, + )] = &[ + ("status", |ops, parent| { + StatusFileOps::new_inode(ops.pid, parent) + }), + ("exe", |ops, parent| ExeSymOps::new_inode(ops.pid, parent)), + ("fd", |ops, parent| { + // fd 目录仍然需要进程引用来列出文件描述符 + if let Some(process) = ops.get_process() { + FdDirOps::new_inode(process, parent) + } else { + // 进程已退出,创建空目录 + use crate::filesystem::procfs::template::ProcDirBuilder; + + #[derive(Debug)] + struct EmptyDirOps; + impl DirOps for EmptyDirOps { + fn lookup_child( + &self, + _dir: &ProcDir, + _name: &str, + ) -> Result, SystemError> { + Err(SystemError::ENOENT) + } + + fn populate_children<'a>( + &self, + dir: &'a ProcDir, + ) -> RwLockReadGuard<'a, BTreeMap>> { + dir.cached_children().write().downgrade() + } + } + + ProcDirBuilder::new(EmptyDirOps, ModeType::from_bits_truncate(0o500)) + .parent(parent) + .build() + .unwrap() + } + }), + ]; +} + +impl DirOps for PidDirOps { + fn lookup_child( + &self, + dir: &ProcDir, + name: &str, + ) -> Result, SystemError> { + let mut cached_children = dir.cached_children().write(); + + // 处理静态条目(包括 fd) + if let Some(child) = + lookup_child_from_table(name, &mut cached_children, Self::STATIC_ENTRIES, |f| { + (f)(self, dir.self_ref_weak().clone()) + }) + { + return Ok(child); + } + + Err(SystemError::ENOENT) + } + + fn populate_children<'a>( + &self, + dir: &'a ProcDir, + ) -> RwLockReadGuard<'a, BTreeMap>> { + let mut cached_children = dir.cached_children().write(); + + // 填充静态条目(包括 fd) + populate_children_from_table(&mut cached_children, Self::STATIC_ENTRIES, |f| { + (f)(self, dir.self_ref_weak().clone()) + }); + + cached_children.downgrade() + } +} diff --git a/kernel/src/filesystem/procfs/pid/status.rs b/kernel/src/filesystem/procfs/pid/status.rs new file mode 100644 index 000000000..bf59f3c02 --- /dev/null +++ b/kernel/src/filesystem/procfs/pid/status.rs @@ -0,0 +1,179 @@ +//! /proc/[pid]/status - 进程状态信息 +//! +//! 显示进程的详细状态信息 + +use crate::{ + filesystem::{ + procfs::{ + template::{Builder, FileOps, ProcFileBuilder}, + utils::{proc_read, trim_string}, + }, + vfs::{syscall::ModeType, FilePrivateData, IndexNode}, + }, + libs::spinlock::SpinLockGuard, + process::{ProcessManager, RawPid}, +}; +use alloc::{ + borrow::ToOwned, + format, + string::ToString, + sync::{Arc, Weak}, + vec::Vec, +}; +use system_error::SystemError; + +/// /proc/[pid]/status 文件的 FileOps 实现 +#[derive(Debug)] +pub struct StatusFileOps { + /// 存储 PID,在读取时动态查找进程 + pid: RawPid, +} + +impl StatusFileOps { + pub fn new(pid: RawPid) -> Self { + Self { pid } + } + + pub fn new_inode(pid: RawPid, parent: Weak) -> Arc { + ProcFileBuilder::new(Self::new(pid), ModeType::S_IRUGO) + .parent(parent) + .build() + .unwrap() + } + + /// 生成 status 文件内容 + fn generate_status_content(&self) -> Result, SystemError> { + // 动态查找进程,确保获取最新状态 + let pcb = ProcessManager::find(self.pid).ok_or(SystemError::ESRCH)?; + let mut pdata = Vec::new(); + + // Name + pdata.append( + &mut format!("Name:\t{}", pcb.basic().name()) + .as_bytes() + .to_owned(), + ); + + let sched_info_guard = pcb.sched_info(); + let state = sched_info_guard.inner_lock_read_irqsave().state(); + let cpu_id = sched_info_guard + .on_cpu() + .map(|cpu| cpu.data() as i32) + .unwrap_or(-1); + + let priority = sched_info_guard.policy(); + let vrtime = sched_info_guard.sched_entity.vruntime; + let time = sched_info_guard.sched_entity.sum_exec_runtime; + let start_time = sched_info_guard.sched_entity.exec_start; + + // State + pdata.append(&mut format!("\nState:\t{:?}", state).as_bytes().to_owned()); + + // Tgid + pdata.append( + &mut format!( + "\nTgid:\t{}", + pcb.task_tgid_vnr() + .unwrap_or(crate::process::RawPid::new(0)) + .into() + ) + .into(), + ); + + // Pid + pdata.append( + &mut format!("\nPid:\t{}", pcb.task_pid_vnr().data()) + .as_bytes() + .to_owned(), + ); + + // Ppid + pdata.append( + &mut format!( + "\nPpid:\t{}", + pcb.parent_pcb() + .map(|p| p.task_pid_vnr().data() as isize) + .unwrap_or(-1) + ) + .as_bytes() + .to_owned(), + ); + + // FDSize + if matches!(state, crate::process::ProcessState::Exited(_)) { + pdata.append(&mut format!("\nFDSize:\t{}", 0).into()); + } else { + pdata.append( + &mut format!("\nFDSize:\t{}", pcb.fd_table().read().fd_open_count()).into(), + ); + } + + // Tty + let name = if let Some(tty) = pcb.sig_info_irqsave().tty() { + tty.core().name().clone() + } else { + "none".to_string() + }; + pdata.append(&mut format!("\nTty:\t{}", name).as_bytes().to_owned()); + + // 进程在 CPU 上的运行时间 + pdata.append(&mut format!("\nTime:\t{}", time).as_bytes().to_owned()); + // 进程开始运行的时间 + pdata.append(&mut format!("\nStime:\t{}", start_time).as_bytes().to_owned()); + // Kthread + pdata.append(&mut format!("\nKthread:\t{}", pcb.is_kthread() as usize).into()); + pdata.append(&mut format!("\ncpu_id:\t{}", cpu_id).as_bytes().to_owned()); + pdata.append(&mut format!("\npriority:\t{:?}", priority).as_bytes().to_owned()); + pdata.append( + &mut format!("\npreempt:\t{}", pcb.preempt_count()) + .as_bytes() + .to_owned(), + ); + + pdata.append(&mut format!("\nvrtime:\t{}", vrtime).as_bytes().to_owned()); + + if let Some(user_vm) = pcb.basic().user_vm() { + let address_space_guard = user_vm.read(); + // todo: 当前进程运行过程中占用内存的峰值 + let hiwater_vm: u64 = 0; + // 进程代码段的大小 + let text = (address_space_guard.end_code - address_space_guard.start_code) / 1024; + // 进程数据段的大小 + let data = (address_space_guard.end_data - address_space_guard.start_data) / 1024; + drop(address_space_guard); + pdata.append( + &mut format!("\nVmPeak:\t{} kB", hiwater_vm) + .as_bytes() + .to_owned(), + ); + pdata.append(&mut format!("\nVmData:\t{} kB", data).as_bytes().to_owned()); + pdata.append(&mut format!("\nVmExe:\t{} kB", text).as_bytes().to_owned()); + } + + pdata.append( + &mut format!("\nflags: {:?}\n", pcb.flags().clone()) + .as_bytes() + .to_owned(), + ); + + // 去除多余的 \0 并在结尾添加 \0 + trim_string(&mut pdata); + + Ok(pdata) + } +} + +impl FileOps for StatusFileOps { + fn read_at( + &self, + offset: usize, + len: usize, + buf: &mut [u8], + _data: SpinLockGuard, + ) -> Result { + let content = self.generate_status_content()?; + log::info!("Generated /proc/[pid]/status content"); + + proc_read(offset, len, buf, &content) + } +} diff --git a/kernel/src/filesystem/procfs/proc_cpuinfo.rs b/kernel/src/filesystem/procfs/proc_cpuinfo.rs index cb8bf4d07..897d49c38 100644 --- a/kernel/src/filesystem/procfs/proc_cpuinfo.rs +++ b/kernel/src/filesystem/procfs/proc_cpuinfo.rs @@ -10,6 +10,7 @@ impl ProcFSInode { &self, pdata: &mut ProcfsFilePrivateData, ) -> Result { + log::info!("Opening /proc/cpuinfo"); let cpu_manager = smp_cpu_manager(); // 遍历所有present的CPU diff --git a/kernel/src/filesystem/procfs/root.rs b/kernel/src/filesystem/procfs/root.rs new file mode 100644 index 000000000..df55ff231 --- /dev/null +++ b/kernel/src/filesystem/procfs/root.rs @@ -0,0 +1,301 @@ +//! /proc 根目录实现 +//! +//! 这个文件实现了 /proc 的根目录,包含静态条目和动态的进程目录 + +use crate::{ + filesystem::{ + procfs::{ + cmdline::CmdlineFileOps, + cpuinfo::CpuInfoFileOps, + kmsg_file::KmsgFileOps, + meminfo::MeminfoFileOps, + mounts::MountsFileOps, + pid::PidDirOps, + self_::SelfSymOps, + template::{ + lookup_child_from_table, populate_children_from_table, DirOps, ProcDir, + ProcDirBuilder, + }, + version::VersionFileOps, + Builder, PROCFS_BLOCK_SIZE, PROCFS_MAX_NAMELEN, + }, + vfs::{ + mount::{MountFlags, MountPath}, + syscall::ModeType, + IndexNode, + }, + }, + libs::{once::Once, rwlock::RwLockReadGuard}, + process::{ProcessManager, RawPid}, +}; +use alloc::{ + collections::BTreeMap, + string::{String, ToString}, + sync::{Arc, Weak}, + vec::Vec, +}; +use system_error::SystemError; + +/// /proc 根目录的 DirOps 实现 +#[derive(Debug)] +pub struct RootDirOps; + +// drop 的时候把对应pid的文件夹删除 +impl RootDirOps { + pub fn new_inode(fs: Weak) -> Arc { + //todo 这里要注册一个observer,用于动态创建进程目录 + + ProcDirBuilder::new(Self, ModeType::from_bits_truncate(0o555)) + .fs(fs) + .build() + .unwrap() + } + + /// 静态条目表 + /// 包含所有非进程目录的 /proc 条目 + #[expect(clippy::type_complexity)] + const STATIC_ENTRIES: &'static [( + &'static str, + fn(Weak) -> Arc, + )] = &[ + ("cmdline", CmdlineFileOps::new_inode), + ("cpuinfo", CpuInfoFileOps::new_inode), + ("kmsg", KmsgFileOps::new_inode), + ("meminfo", MeminfoFileOps::new_inode), + ("mounts", MountsFileOps::new_inode), + ("self", SelfSymOps::new_inode), + ("version", VersionFileOps::new_inode), + ]; +} + +impl DirOps for RootDirOps { + fn lookup_child( + &self, + dir: &ProcDir, + name: &str, + ) -> Result, SystemError> { + // 首先检查是否是 PID 目录 + if let Ok(pid) = name.parse::() { + // 检查进程是否存在 + if ProcessManager::find(pid).is_some() { + let mut cached_children = dir.cached_children().write(); + + // 检查缓存中是否已存在 + if let Some(child) = cached_children.get(name) { + return Ok(child.clone()); + } + + // 创建新的 PID 目录(只传递 PID,不传递进程引用) + let inode = PidDirOps::new_inode(pid, dir.self_ref_weak().clone()); + cached_children.insert(name.to_string(), inode.clone()); + return Ok(inode); + } else { + return Err(SystemError::ENOENT); + } + } + + // 查找静态条目 + let mut cached_children = dir.cached_children().write(); + + if let Some(child) = + lookup_child_from_table(name, &mut cached_children, Self::STATIC_ENTRIES, |f| { + (f)(dir.self_ref_weak().clone()) + }) + { + return Ok(child); + } + + Err(SystemError::ENOENT) + } + + fn populate_children<'a>( + &self, + dir: &'a ProcDir, + ) -> RwLockReadGuard<'a, BTreeMap>> { + // 先收集进程 PID,然后立即释放进程表锁 + let pid_list = { + let all_processes = crate::process::all_process().lock_irqsave(); + if let Some(process_map) = all_processes.as_ref() { + process_map.keys().cloned().collect::>() + } else { + Vec::new() + } + }; + // 进程表锁已经释放 + + // 获取缓存写锁并填充 + let mut cached_children = dir.cached_children().write(); + + // 填充进程目录(只传递 PID) + for pid in pid_list { + cached_children + .entry(pid.to_string()) + .or_insert_with(|| PidDirOps::new_inode(pid, dir.self_ref_weak().clone())); + } + + // 填充静态条目 + populate_children_from_table(&mut cached_children, Self::STATIC_ENTRIES, |f| { + (f)(dir.self_ref_weak().clone()) + }); + + cached_children.downgrade() + } +} + +use crate::filesystem::vfs::{FileSystem, FsInfo, Magic, SuperBlock}; +use crate::libs::rwlock::RwLock; + +/// procfs 文件系统 +#[derive(Debug)] +pub struct TestProcFS { + /// procfs 的 root inode + root_inode: Arc, + super_block: RwLock, +} + +impl TestProcFS { + pub fn new() -> Arc { + let super_block = SuperBlock::new( + Magic::PROC_MAGIC, + PROCFS_BLOCK_SIZE, + PROCFS_MAX_NAMELEN as u64, + ); + + let fs: Arc = Arc::new_cyclic(|weak_fs| TestProcFS { + super_block: RwLock::new(super_block), + root_inode: RootDirOps::new_inode(weak_fs.clone()), + }); + + fs + } +} + +impl FileSystem for TestProcFS { + fn root_inode(&self) -> Arc { + self.root_inode.clone() + } + + fn info(&self) -> FsInfo { + FsInfo { + blk_dev_id: 0, + max_name_len: PROCFS_MAX_NAMELEN, + } + } + + fn as_any_ref(&self) -> &dyn core::any::Any { + self + } + + fn name(&self) -> &str { + "testprocfs" + } + + fn super_block(&self) -> SuperBlock { + self.super_block.read().clone() + } +} + +pub(crate) fn test_procfs_init() -> Result<(), SystemError> { + static INIT: Once = Once::new(); + let mut result = None; + INIT.call_once(|| { + ::log::info!("Initializing TestProcFS..."); + // 创建 procfs 实例 + let procfs: Arc = TestProcFS::new(); + let root_inode = ProcessManager::current_mntns().root_inode(); + // procfs 挂载 + let mntfs = root_inode + .mkdir("testproc", ModeType::from_bits_truncate(0o755)) + .expect("Unabled to find /testproc") + .mount(procfs, MountFlags::empty()) + .expect("Failed to mount at /testproc"); + let ino = root_inode.metadata().unwrap().inode_id; + let mount_path = Arc::new(MountPath::from("/testproc")); + ProcessManager::current_mntns() + .add_mount(Some(ino), mount_path, mntfs) + .expect("Failed to add mount for /testproc"); + ::log::info!("TestProcFS mounted."); + result = Some(Ok(())); + }); + + return result.unwrap(); +} + +// #[derive(Debug)] +// struct ProcRootDirOps; + +// impl ProcRootDirOps { +// pub fn new_inode(fs: Weak) -> Arc { +// //todo 这里要注册一个observer,用于动态创建进程目录 + +// ProcDirBuilder::new(Self, ModeType::from_bits_truncate(0o555)) +// .fs(fs) +// .build() +// .unwrap() +// } + +// #[expect(clippy::type_complexity)] +// const STATIC_ENTRIES: &'static [( +// &'static str, +// fn(Weak) -> Arc, +// )] = &[("cpuinfo", CpuInfoFileOps::new_inode)]; +// } + +// impl DirOps for ProcRootDirOps { +// fn lookup_child( +// &self, +// dir: &template::ProcDir, +// name: &str, +// ) -> Result, SystemError> { +// if let Ok(pid) = name.parse::() { +// let all_processes = all_process().lock_irqsave(); +// if let Some(process_ref) = all_processes.as_ref().unwrap().get(&pid) { +// let mut cached_children = dir.cached_children().write(); + +// // put the child into cache if not exists +// if let Some(child) = cached_children.get(name) { +// return Ok(child.clone()); +// } else { +// let inode = +// PidDirOps::new_inode(process_ref.clone(), dir.self_ref_weak().clone()); +// cached_children.insert(name.to_string(), inode.clone()); +// return Ok(inode); +// } +// } +// } + +// let mut cached_children = dir.cached_children().write(); + +// if let Some(child) = +// lookup_child_from_table(name, &mut cached_children, Self::STATIC_ENTRIES, |f| { +// (f)(dir.self_ref_weak().clone()) +// }) +// { +// return Ok(child); +// } + +// Err(SystemError::ENOENT) +// } + +// fn populate_children<'a>( +// &self, +// dir: &'a template::ProcDir, +// ) -> crate::libs::rwlock::RwLockReadGuard<'a, BTreeMap>> { +// let all_processes = all_process().lock_irqsave(); +// let mut cached_children = dir.cached_children().write(); + +// for (pid, process_ref) in all_processes.as_ref().unwrap().iter() { +// cached_children.entry(pid.to_string()).or_insert_with(|| { +// PidDirOps::new_inode(process_ref.clone(), dir.self_ref_weak().clone()) +// }); +// } + +// drop(all_processes); + +// populate_children_from_table(&mut cached_children, Self::STATIC_ENTRIES, |f| { +// (f)(dir.self_ref_weak().clone()) +// }); + +// cached_children.downgrade() +// } +// } diff --git a/kernel/src/filesystem/procfs/self_.rs b/kernel/src/filesystem/procfs/self_.rs new file mode 100644 index 000000000..7f3adf924 --- /dev/null +++ b/kernel/src/filesystem/procfs/self_.rs @@ -0,0 +1,40 @@ +//! /proc/self - 指向当前进程目录的符号链接 +//! +//! /proc/self 是一个指向 /proc/[pid] 的符号链接,其中 pid 是当前进程的 PID + +use crate::{ + filesystem::{ + procfs::template::{Builder, ProcSymBuilder, SymOps}, + vfs::{syscall::ModeType, IndexNode}, + }, + process::ProcessManager, +}; +use alloc::{ + string::ToString, + sync::{Arc, Weak}, +}; +use system_error::SystemError; + +/// /proc/self 符号链接的 SymOps 实现 +#[derive(Debug)] +pub struct SelfSymOps; + +impl SelfSymOps { + pub fn new_inode(parent: Weak) -> Arc { + ProcSymBuilder::new(Self, ModeType::S_IRWXUGO) // 0777 - 符号链接权限 + .parent(parent) + .build() + .unwrap() + } +} + +impl SymOps for SelfSymOps { + fn read_link(&self, buf: &mut [u8]) -> Result { + // 返回当前进程的 PID + let current_pid = ProcessManager::current_pid().data(); + let pid_bytes = current_pid.to_string(); + let len = pid_bytes.len().min(buf.len()); + buf[..len].copy_from_slice(&pid_bytes.as_bytes()[..len]); + Ok(len) + } +} diff --git a/kernel/src/filesystem/procfs/template/builder.rs b/kernel/src/filesystem/procfs/template/builder.rs new file mode 100644 index 000000000..9bb322ab9 --- /dev/null +++ b/kernel/src/filesystem/procfs/template/builder.rs @@ -0,0 +1,280 @@ +use crate::filesystem::{ + procfs::template::{DirOps, FileOps, ProcDir, ProcFile, ProcSym, SymOps}, + vfs::{syscall::ModeType, FileSystem, IndexNode}, +}; +use alloc::sync::{Arc, Weak}; +use system_error::SystemError; + +struct BuilderCommon { + mode: ModeType, + parent: Option>, + fs: Option>, + is_volatile: bool, + data: usize, + ino: Option, +} + +impl BuilderCommon { + fn new(mode: ModeType) -> Self { + Self { + mode, + parent: None, + fs: None, + is_volatile: false, + data: 0, + ino: None, + } + } + + fn set_parent(&mut self, parent: Weak) { + self.parent = Some(parent); + } + + fn set_fs(&mut self, fs: Weak) { + self.fs = Some(fs); + } + + fn set_volatile(&mut self) { + self.is_volatile = true; + } + + fn set_data(&mut self, data: usize) { + self.data = data; + } + + fn set_ino(&mut self, ino: u64) { + self.ino = Some(ino); + } +} + +pub trait Builder { + type Output; + + fn new(ops: Ops, mode: ModeType) -> Self; + fn build(self) -> Result, SystemError>; +} + +pub struct ProcFileBuilder { + file: F, + common: BuilderCommon, +} + +impl ProcFileBuilder { + pub fn parent(mut self, parent: Weak) -> Self { + self.common.set_parent(parent); + self + } + + pub fn fs(mut self, fs: Weak) -> Self { + self.common.set_fs(fs); + self + } + + pub fn volatile(mut self) -> Self { + self.common.set_volatile(); + self + } + + pub fn data(mut self, data: usize) -> Self { + self.common.set_data(data); + self + } + + pub fn ino(mut self, ino: u64) -> Self { + self.common.set_ino(ino); + self + } +} + +impl Builder for ProcFileBuilder +where + F: FileOps, +{ + type Output = ProcFile; + + /// 创建一个新的 ProcFileBuilder + /// + /// # 参数 + /// - `file`: 实现了 FileOps trait 的文件操作对象 + /// - `mode`: 文件权限模式 + fn new(file: F, mode: ModeType) -> Self { + Self { + file, + common: BuilderCommon::new(mode), + } + } + + fn build(self) -> Result, SystemError> { + // 从父节点获取文件系统(如果未显式设置) + let fs = if let Some(fs) = self.common.fs { + fs + } else if let Some(parent) = &self.common.parent { + if let Some(parent_node) = parent.upgrade() { + Arc::downgrade(&parent_node.fs()) + } else { + return Err(SystemError::EINVAL); + } + } else { + return Err(SystemError::EINVAL); + }; + + Ok(ProcFile::new_with_data( + self.file, + fs, + self.common.parent, + self.common.is_volatile, + self.common.mode, + self.common.data, + )) + } +} + +pub struct ProcDirBuilder { + dir: D, + common: BuilderCommon, +} + +impl ProcDirBuilder { + pub fn parent(mut self, parent: Weak) -> Self { + self.common.set_parent(parent); + self + } + + pub fn fs(mut self, fs: Weak) -> Self { + self.common.set_fs(fs); + self + } + + pub fn volatile(mut self) -> Self { + self.common.set_volatile(); + self + } + + pub fn data(mut self, data: usize) -> Self { + self.common.set_data(data); + self + } + + pub fn ino(mut self, ino: u64) -> Self { + self.common.set_ino(ino); + self + } +} + +impl Builder for ProcDirBuilder +where + D: DirOps, +{ + type Output = ProcDir; + + /// 创建一个新的 ProcDirBuilder + /// + /// # 参数 + /// - `dir`: 实现了 DirOps trait 的目录操作对象 + /// - `mode`: 目录权限模式 + fn new(dir: D, mode: ModeType) -> Self { + Self { + dir, + common: BuilderCommon::new(mode), + } + } + + fn build(self) -> Result, SystemError> { + // 从父节点获取文件系统(如果未显式设置) + let fs = if let Some(fs) = self.common.fs { + fs + } else if let Some(parent) = &self.common.parent { + if let Some(parent_node) = parent.upgrade() { + Arc::downgrade(&parent_node.fs()) + } else { + return Err(SystemError::EINVAL); + } + } else { + return Err(SystemError::EINVAL); + }; + + Ok(ProcDir::new_with_data( + self.dir, + fs, + self.common.parent, + self.common.is_volatile, + self.common.mode, + self.common.data, + )) + } +} + +pub struct ProcSymBuilder { + sym: S, + common: BuilderCommon, +} + +impl ProcSymBuilder { + pub fn parent(mut self, parent: Weak) -> Self { + self.common.set_parent(parent); + self + } + + pub fn fs(mut self, fs: Weak) -> Self { + self.common.set_fs(fs); + self + } + + pub fn volatile(mut self) -> Self { + self.common.set_volatile(); + self + } + + pub fn data(mut self, data: usize) -> Self { + self.common.set_data(data); + self + } + + pub fn ino(mut self, ino: u64) -> Self { + self.common.set_ino(ino); + self + } +} + +impl Builder for ProcSymBuilder +where + S: SymOps, +{ + type Output = ProcSym; + + /// 创建一个新的 ProcSymBuilder + /// + /// # 参数 + /// - `sym`: 实现了 SymOps trait 的符号链接操作对象 + /// - `mode`: 符号链接权限模式 + fn new(sym: S, mode: ModeType) -> Self { + Self { + sym, + common: BuilderCommon::new(mode), + } + } + + fn build(self) -> Result>, SystemError> { + // 从父节点获取文件系统(如果未显式设置) + let fs = if let Some(fs) = self.common.fs { + fs + } else if let Some(parent) = &self.common.parent { + if let Some(parent_node) = parent.upgrade() { + Arc::downgrade(&parent_node.fs()) + } else { + return Err(SystemError::EINVAL); + } + } else { + return Err(SystemError::EINVAL); + }; + + Ok(ProcSym::new_with_data( + self.sym, + fs, + self.common.parent, + self.common.is_volatile, + self.common.mode, + self.common.data, + )) + } +} diff --git a/kernel/src/filesystem/procfs/template/dir.rs b/kernel/src/filesystem/procfs/template/dir.rs new file mode 100644 index 000000000..5d5373c73 --- /dev/null +++ b/kernel/src/filesystem/procfs/template/dir.rs @@ -0,0 +1,294 @@ +use crate::{ + driver::base::device::device_number::DeviceNumber, + filesystem::{ + procfs::template::Common, + vfs::{ + file::FileMode, syscall::ModeType, utils::DName, vcore::generate_inode_id, + FilePrivateData, FileSystem, FileType, IndexNode, InodeId, Metadata, + }, + }, + libs::{ + rwlock::{RwLock, RwLockReadGuard}, + spinlock::SpinLockGuard, + }, + time::PosixTimeSpec, +}; +use alloc::collections::BTreeMap; +use alloc::fmt::Debug; +use alloc::string::String; +use alloc::string::ToString; +use alloc::sync::{Arc, Weak}; +use alloc::vec::Vec; +use inherit_methods_macro::inherit_methods; +use system_error::SystemError; + +#[derive(Debug)] +pub struct ProcDir { + inner: Ops, + self_ref: Weak>, + parent: Option>, + cached_children: RwLock>>, + common: Common, + // 没用到? + // fdata: InodeInfo, +} + +impl ProcDir { + pub(super) fn new( + dir: Ops, + fs: Weak, + parent: Option>, + is_volatile: bool, + mode: ModeType, + ) -> Arc { + Self::new_with_data(dir, fs, parent, is_volatile, mode, 0) + } + + pub(super) fn new_with_data( + dir: Ops, + fs: Weak, + parent: Option>, + is_volatile: bool, + mode: ModeType, + data: usize, + ) -> Arc { + let common = { + // let ino = generate_inode_id(); + // let metadata = Metadata::new_dir(ino, mode, super::BLOCK_SIZE); + let metadata = Metadata { + dev_id: 0, + inode_id: generate_inode_id(), + size: 0, + blk_size: 0, + blocks: 0, + atime: PosixTimeSpec::default(), + mtime: PosixTimeSpec::default(), + ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), + file_type: FileType::Dir, + mode, + nlinks: 1, + uid: 0, + gid: 0, + raw_dev: DeviceNumber::from(data as u32), + }; + Common::new(metadata, fs, is_volatile) + }; + + Arc::new_cyclic(|weak_self| Self { + inner: dir, + self_ref: weak_self.clone(), + parent, + cached_children: RwLock::new(BTreeMap::new()), + common, + }) + } + + pub fn self_ref(&self) -> Option>> { + self.self_ref.upgrade() + } + + pub fn self_ref_weak(&self) -> &Weak> { + &self.self_ref + } + + pub fn parent(&self) -> Option> { + self.parent.as_ref().and_then(|p| p.upgrade()) + } + + pub fn cached_children(&self) -> &RwLock>> { + &self.cached_children + } +} + +#[inherit_methods(from = "self.common")] +impl IndexNode for ProcDir { + fn fs(&self) -> Arc; + fn as_any_ref(&self) -> &dyn core::any::Any; + fn metadata(&self) -> Result; + fn set_metadata(&self, metadata: &Metadata) -> Result<(), SystemError>; + + fn read_at( + &self, + _offset: usize, + _len: usize, + _buf: &mut [u8], + _data: SpinLockGuard, + ) -> Result { + Err(SystemError::EISDIR) + } + + fn write_at( + &self, + _offset: usize, + _len: usize, + _buf: &[u8], + _data: SpinLockGuard, + ) -> Result { + Err(SystemError::EISDIR) + } + + fn list(&self) -> Result, SystemError> { + let mut keys = Vec::new(); + keys.push(String::from(".")); + keys.push(String::from("..")); + + // 填充所有子节点并立即复制键,然后释放锁 + { + let cached_children = self.inner.populate_children(self); + keys.extend(cached_children.keys().cloned()); + } + + return Ok(keys); + } + + fn find(&self, name: &str) -> Result, SystemError> { + match name { + "" | "." => { + return Ok(self.self_ref().ok_or(SystemError::ENOENT)?); + } + + ".." => { + // 如果有父节点,返回父节点;否则返回自身(根目录的 .. 指向自己) + return Ok(self + .parent() + .unwrap_or_else(|| self.self_ref().expect("self_ref should be valid"))); + } + + name => { + //todo 先忽略fd目录的处理 + // 先查缓存(使用作用域来确保锁及时释放) + { + let cached_children = self.cached_children.read(); + if let Some(inode) = cached_children.get(name) { + if self.inner.validate_child(inode.as_ref()) { + return Ok(inode.clone()); + } + } + } // 读锁在这里释放 + + // 缓存未命中,调用 DirOps::lookup_child 创建 + self.inner.lookup_child(self, name) + } + } + } + + fn get_entry_name(&self, ino: InodeId) -> Result { + match ino.into() { + 0 => { + return Ok(String::from(".")); + } + 1 => { + return Ok(String::from("..")); + } + ino => { + // 暴力遍历所有的children,判断inode id是否相同 + // TODO: 优化这里,这个地方性能很差! + let mut key: Vec = self + .cached_children + .read() + .iter() + .filter_map(|(k, v)| { + if v.metadata().unwrap().inode_id.into() == ino { + Some(k.to_string()) + } else { + None + } + }) + .collect(); + + match key.len() { + 0 => { + return Err(SystemError::ENOENT); + } + 1 => { + return Ok(key.remove(0)); + } + _ => panic!( + "Procfs get_entry_name: key.len()={key_len}>1, current inode_id={inode_id:?}, to find={to_find:?}", + key_len = key.len(), + inode_id = self.metadata().unwrap().inode_id, + to_find = ino + ), + } + } + } + } + + fn dname(&self) -> Result { + Ok(self.common.dname.clone()) + } + + fn open( + &self, + _data: SpinLockGuard, + _mode: &FileMode, + ) -> Result<(), SystemError> { + return Ok(()); + } + + fn close(&self, _data: SpinLockGuard) -> Result<(), SystemError> { + return Ok(()); + } + + fn link(&self, _name: &str, _other: &Arc) -> Result<(), SystemError> { + todo!("procfs dir link not implemented"); + } +} + +pub trait DirOps: Sync + Send + Sized + Debug { + fn lookup_child( + &self, + dir: &ProcDir, + name: &str, + ) -> Result, SystemError>; + + fn populate_children<'a>( + &self, + dir: &'a ProcDir, + ) -> RwLockReadGuard<'a, BTreeMap>>; + + #[must_use] + fn validate_child(&self, _child: &dyn IndexNode) -> bool { + true + } +} + +pub fn lookup_child_from_table( + name: &str, + cached_children: &mut BTreeMap>, + table: &[(&str, Fp)], + constructor_adaptor: F, +) -> Option> +where + Fp: Copy, + F: FnOnce(Fp) -> Arc, +{ + for (child_name, child_constructor) in table.iter() { + if *child_name == name { + return Some( + cached_children + .entry(String::from(name)) + .or_insert_with(|| (constructor_adaptor)(*child_constructor)) + .clone(), + ); + } + } + + None +} + +pub fn populate_children_from_table( + cached_children: &mut BTreeMap>, + table: &[(&str, Fp)], + constructor_adaptor: F, +) where + Fp: Copy, + F: Fn(Fp) -> Arc, +{ + for (child_name, child_constructor) in table.iter() { + cached_children + .entry(String::from(*child_name)) + .or_insert_with(|| (constructor_adaptor)(*child_constructor)); + } +} diff --git a/kernel/src/filesystem/procfs/template/file.rs b/kernel/src/filesystem/procfs/template/file.rs new file mode 100644 index 000000000..a4a2e9bc0 --- /dev/null +++ b/kernel/src/filesystem/procfs/template/file.rs @@ -0,0 +1,185 @@ +use crate::{ + driver::base::device::device_number::DeviceNumber, + filesystem::{ + procfs::template::Common, + vfs::{ + file::FileMode, syscall::ModeType, vcore::generate_inode_id, FilePrivateData, + FileSystem, FileType, IndexNode, Metadata, + }, + }, + libs::spinlock::SpinLockGuard, + time::PosixTimeSpec, +}; +use alloc::fmt::Debug; +use alloc::string::String; +use alloc::sync::{Arc, Weak}; +use alloc::vec::Vec; +use inherit_methods_macro::inherit_methods; +use system_error::SystemError; + +/// ProcFile 是 procfs 文件的泛型包装器 +/// F 是实现了 FileOps trait 的具体文件操作类型 +#[derive(Debug)] +pub struct ProcFile { + inner: F, + self_ref: Weak>, + parent: Option>, + common: Common, +} + +impl ProcFile { + /// 创建一个新的 ProcFile + pub(super) fn new( + file: F, + fs: Weak, + parent: Option>, + is_volatile: bool, + mode: ModeType, + ) -> Arc { + Self::new_with_data(file, fs, parent, is_volatile, mode, 0) + } + + /// 创建一个新的 ProcFile(带额外数据) + pub(super) fn new_with_data( + file: F, + fs: Weak, + parent: Option>, + is_volatile: bool, + mode: ModeType, + data: usize, + ) -> Arc { + let common = { + let metadata = Metadata { + dev_id: 0, + inode_id: generate_inode_id(), + size: 0, + blk_size: 0, + blocks: 0, + atime: PosixTimeSpec::default(), + mtime: PosixTimeSpec::default(), + ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), + file_type: FileType::File, + mode, + nlinks: 1, + uid: 0, + gid: 0, + raw_dev: DeviceNumber::from(data as u32), + }; + Common::new(metadata, fs, is_volatile) + }; + + Arc::new_cyclic(|weak_self| Self { + inner: file, + self_ref: weak_self.clone(), + parent, + common, + }) + } + + pub fn self_ref(&self) -> Option>> { + self.self_ref.upgrade() + } + + pub fn self_ref_weak(&self) -> &Weak> { + &self.self_ref + } + + pub fn parent(&self) -> Option> { + self.parent.as_ref().and_then(|p| p.upgrade()) + } +} + +/// FileOps trait 定义了 procfs 文件需要实现的操作 +pub trait FileOps: Sync + Send + Sized + Debug { + /// 从文件的指定偏移量读取数据 + /// + /// # 参数 + /// - `offset`: 读取的起始偏移量 + /// - `len`: 要读取的字节数 + /// - `buf`: 存放读取数据的缓冲区 + /// - `data`: 文件私有数据 + /// + /// # 返回值 + /// - `Ok(usize)`: 实际读取的字节数 + /// - `Err(SystemError)`: 错误码 + fn read_at( + &self, + offset: usize, + len: usize, + buf: &mut [u8], + data: SpinLockGuard, + ) -> Result; + + /// 向文件的指定偏移量写入数据(可选,默认返回 EPERM) + /// + /// # 参数 + /// - `offset`: 写入的起始偏移量 + /// - `len`: 要写入的字节数 + /// - `buf`: 包含要写入数据的缓冲区 + /// - `data`: 文件私有数据 + /// + /// # 返回值 + /// - `Ok(usize)`: 实际写入的字节数 + /// - `Err(SystemError)`: 错误码 + fn write_at( + &self, + _offset: usize, + _len: usize, + _buf: &[u8], + _data: SpinLockGuard, + ) -> Result { + Err(SystemError::EPERM) + } +} + +/// 为 ProcFile 实现 IndexNode trait +/// 使用 inherit_methods 宏从 common 继承通用方法 +#[inherit_methods(from = "self.common")] +impl IndexNode for ProcFile { + fn fs(&self) -> Arc; + fn as_any_ref(&self) -> &dyn core::any::Any; + fn metadata(&self) -> Result; + fn set_metadata(&self, metadata: &Metadata) -> Result<(), SystemError>; + + fn read_at( + &self, + offset: usize, + len: usize, + buf: &mut [u8], + data: SpinLockGuard, + ) -> Result { + // log::info!("ProcFile read_at called"); + self.inner.read_at(offset, len, buf, data) + } + + fn write_at( + &self, + offset: usize, + len: usize, + buf: &[u8], + data: SpinLockGuard, + ) -> Result { + self.inner.write_at(offset, len, buf, data) + } + + fn list(&self) -> Result, SystemError> { + Err(SystemError::ENOTDIR) + } + + fn find(&self, _name: &str) -> Result, SystemError> { + Err(SystemError::ENOTDIR) + } + + fn open( + &self, + _data: SpinLockGuard, + _mode: &FileMode, + ) -> Result<(), SystemError> { + return Ok(()); + } + + fn close(&self, _data: SpinLockGuard) -> Result<(), SystemError> { + return Ok(()); + } +} diff --git a/kernel/src/filesystem/procfs/template/mod.rs b/kernel/src/filesystem/procfs/template/mod.rs new file mode 100644 index 000000000..19d5506af --- /dev/null +++ b/kernel/src/filesystem/procfs/template/mod.rs @@ -0,0 +1,102 @@ +//! ProcFS Template 系统 +//! +//! 这个模块提供了一套基于 trait 和泛型的 template 系统,用于简化 procfs 的实现。 +//! 设计参考了 Asterinas 的 procfs template 系统。 +//! +//! # 核心组件 +//! +//! - `Common`: 共享的元数据和行为 +//! - `ProcFile`: 文件的泛型包装器 +//! - `ProcDir`: 目录的泛型包装器 +//! - `ProcSym`: 符号链接的泛型包装器 +//! - `FileOps`, `DirOps`, `SymOps`: 定义定制点的 trait +//! - Builder 模式:用于灵活构造 inode + +use crate::{ + filesystem::{ + procfs::InodeInfo, + vfs::{utils::DName, FileSystem, Metadata}, + }, + libs::rwlock::RwLock, +}; + +use alloc::sync::{Arc, Weak}; +use system_error::SystemError; + +mod builder; +mod dir; +mod file; +mod sym; + +// 公开导出 +pub use self::{ + builder::{Builder, ProcDirBuilder, ProcFileBuilder, ProcSymBuilder}, + dir::{lookup_child_from_table, populate_children_from_table, DirOps, ProcDir}, + file::{FileOps, ProcFile}, + sym::{ProcSym, SymOps}, +}; + +/// Common - 所有 procfs inode 共享的基础设施 +/// +/// 包含: +/// - 元数据(inode 号、权限、所有者、时间戳等) +/// - 文件系统引用 +/// - volatile 标志 +#[derive(Debug)] +pub(super) struct Common { + fs: Weak, + metadata: RwLock, + is_volatile: bool, + fdata: RwLock, + dname: DName, +} + +impl Common { + /// 创建一个新的 Common 实例 + pub fn new(metadata: Metadata, fs: Weak, is_volatile: bool) -> Self { + Self { + metadata: RwLock::new(metadata), + fs, + is_volatile, + fdata: RwLock::new(InodeInfo::default()), + dname: DName::default(), + } + } + + /// 获取文件系统引用 + pub(super) fn fs(&self) -> Arc { + self.fs.upgrade().unwrap() + } + + /// 获取 Any 引用(用于类型转换) + pub(super) fn as_any_ref(&self) -> &dyn core::any::Any { + self + } + + /// 获取元数据 + pub(super) fn metadata(&self) -> Result { + let metadata = self.metadata.read().clone(); + Ok(metadata) + } + + /// 设置元数据 + pub(super) fn set_metadata(&self, metadata: &Metadata) -> Result<(), SystemError> { + let mut meta = self.metadata.write(); + meta.atime = metadata.atime; + meta.mtime = metadata.mtime; + meta.ctime = metadata.ctime; + meta.btime = metadata.btime; + meta.mode = metadata.mode; + meta.uid = metadata.uid; + meta.gid = metadata.gid; + + Ok(()) + } + + /// 检查是否为 volatile + /// + /// Volatile inode 不会被 VFS 的 dentry cache 缓存 + pub fn is_volatile(&self) -> bool { + self.is_volatile + } +} diff --git a/kernel/src/filesystem/procfs/template/sym.rs b/kernel/src/filesystem/procfs/template/sym.rs new file mode 100644 index 000000000..608bacfec --- /dev/null +++ b/kernel/src/filesystem/procfs/template/sym.rs @@ -0,0 +1,154 @@ +use crate::{ + driver::base::device::device_number::DeviceNumber, + filesystem::{ + procfs::template::Common, + vfs::{ + FilePrivateData, FileSystem, FileType, IndexNode, Metadata, file::FileMode, syscall::ModeType, vcore::generate_inode_id + }, + }, + libs::spinlock::SpinLockGuard, + time::PosixTimeSpec, +}; +use alloc::fmt::Debug; +use alloc::sync::{Arc, Weak}; +use alloc::vec::Vec; +use alloc::string::String; +use inherit_methods_macro::inherit_methods; +use system_error::SystemError; + +/// ProcSym 是 procfs 符号链接的泛型包装器 +/// S 是实现了 SymOps trait 的具体符号链接操作类型 +#[derive(Debug)] +pub struct ProcSym { + inner: S, + self_ref: Weak>, + parent: Option>, + common: Common, +} + +impl ProcSym { + /// 创建一个新的 ProcSym + pub(super) fn new( + sym: S, + fs: Weak, + parent: Option>, + is_volatile: bool, + mode: ModeType, + ) -> Arc { + Self::new_with_data(sym, fs, parent, is_volatile, mode, 0) + } + + /// 创建一个新的 ProcSym(带额外数据) + pub(super) fn new_with_data( + sym: S, + fs: Weak, + parent: Option>, + is_volatile: bool, + mode: ModeType, + data: usize, + ) -> Arc { + let common = { + let metadata = Metadata { + dev_id: 0, + inode_id: generate_inode_id(), + size: 0, + blk_size: 0, + blocks: 0, + atime: PosixTimeSpec::default(), + mtime: PosixTimeSpec::default(), + ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), + file_type: FileType::SymLink, + mode, + nlinks: 1, + uid: 0, + gid: 0, + raw_dev: DeviceNumber::from(data as u32), + }; + Common::new(metadata, fs, is_volatile) + }; + + Arc::new_cyclic(|weak_self| Self { + inner: sym, + self_ref: weak_self.clone(), + parent, + common, + }) + } + + pub fn self_ref(&self) -> Option>> { + self.self_ref.upgrade() + } + + pub fn self_ref_weak(&self) -> &Weak> { + &self.self_ref + } + + pub fn parent(&self) -> Option> { + self.parent.as_ref().and_then(|p| p.upgrade()) + } +} + +/// SymOps trait 定义了 procfs 符号链接需要实现的操作 +pub trait SymOps: Sync + Send + Sized + Debug { + /// 读取符号链接的目标路径 + /// + /// # 返回值 + /// - `Ok(String)`: 符号链接指向的目标路径 + /// - `Err(SystemError)`: 错误码 + fn read_link(&self, buf: &mut [u8]) -> Result; +} + +/// 为 ProcSym 实现 IndexNode trait +/// 使用 inherit_methods 宏从 common 继承通用方法 +#[inherit_methods(from = "self.common")] +impl IndexNode for ProcSym { + fn fs(&self) -> Arc; + fn as_any_ref(&self) -> &dyn core::any::Any; + fn metadata(&self) -> Result; + fn set_metadata(&self, metadata: &Metadata) -> Result<(), SystemError>; + + fn read_at( + &self, + _offset: usize, + _len: usize, + buf: &mut [u8], + _data: SpinLockGuard, + ) -> Result { + //todo 符号链接不能直接读取,但是由于目前系统中对于 readlink 的支持有限 + //暂时通过 read_at 来模拟 readlink 的行为 + // log::info!("ProcSym read_at called, redirecting to read_link"); + self.inner.read_link(buf) + } + + fn write_at( + &self, + _offset: usize, + _len: usize, + _buf: &[u8], + _data: SpinLockGuard, + ) -> Result { + // 符号链接不能写入 + Err(SystemError::EINVAL) + } + + fn list(&self) -> Result, SystemError> { + Err(SystemError::ENOTDIR) + } + + fn find(&self, _name: &str) -> Result, SystemError> { + Err(SystemError::ENOTDIR) + } + + fn open( + &self, + _data: SpinLockGuard, + _mode: &FileMode, + ) -> Result<(), SystemError> { + return Ok(()); + } + + fn close(&self, _data: SpinLockGuard) -> Result<(), SystemError> { + return Ok(()); + } +} diff --git a/kernel/src/filesystem/procfs/utils.rs b/kernel/src/filesystem/procfs/utils.rs new file mode 100644 index 000000000..d3e908866 --- /dev/null +++ b/kernel/src/filesystem/procfs/utils.rs @@ -0,0 +1,30 @@ +use alloc::vec::Vec; +use system_error::SystemError; + +/// 去除Vec中所有的\0,并在结尾添加\0 +#[inline] +pub(super) fn trim_string(data: &mut Vec) { + data.retain(|x| *x != 0); + data.push(0); +} + +/// proc文件系统读取函数 +pub(super) fn proc_read( + offset: usize, + len: usize, + buf: &mut [u8], + data: &[u8], +) -> Result { + let start = data.len().min(offset); + let end = data.len().min(offset + len); + + // buffer空间不足 + if buf.len() < (end - start) { + return Err(SystemError::ENOBUFS); + } + + // 拷贝数据 + let src = &data[start..end]; + buf[0..src.len()].copy_from_slice(src); + return Ok(src.len()); +} diff --git a/kernel/src/filesystem/procfs/version.rs b/kernel/src/filesystem/procfs/version.rs new file mode 100644 index 000000000..6b6ab1263 --- /dev/null +++ b/kernel/src/filesystem/procfs/version.rs @@ -0,0 +1,64 @@ +//! /proc/version - 内核版本信息 +//! +//! 这个文件展示了内核版本、编译信息等 + +use crate::{ + filesystem::{ + procfs::{ + template::{Builder, FileOps, ProcFileBuilder}, + utils::proc_read, + }, + vfs::{syscall::ModeType, FilePrivateData, IndexNode}, + }, + init::version_info, +}; +use alloc::{ + borrow::ToOwned, + format, + sync::{Arc, Weak}, + vec::Vec, +}; +use system_error::SystemError; + +/// /proc/version 文件的 FileOps 实现 +#[derive(Debug)] +pub struct VersionFileOps; + +impl VersionFileOps { + pub fn new_inode(parent: Weak) -> Arc { + ProcFileBuilder::new(Self, ModeType::S_IRUGO) // 0444 - 所有用户可读 + .parent(parent) + .build() + .unwrap() + } + + fn generate_version_content() -> Vec { + let info = version_info::get_kernel_build_info(); + + // Linux version 5.15.0-152-generic (buildd@lcy02-amd64-094) (gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, GNU ld (GNU Binutils for Ubuntu) 2.38) #162-Ubuntu SMP Wed Jul 23 09:48:42 UTC 2025 + let version_content = format!( + "Linux version {} ({}@{}) ({}, {}) {}\n", + info.release, + info.build_user, + info.build_host, + info.compiler_info, + info.linker_info, + info.version + ); + + version_content.into_bytes().to_owned() + } +} + +impl FileOps for VersionFileOps { + fn read_at( + &self, + offset: usize, + len: usize, + buf: &mut [u8], + _data: crate::libs::spinlock::SpinLockGuard, + ) -> Result { + let content = Self::generate_version_content(); + proc_read(offset, len, buf, &content) + } +} diff --git a/kernel/src/filesystem/vfs/mod.rs b/kernel/src/filesystem/vfs/mod.rs index d0552a7ea..e8a020dd1 100644 --- a/kernel/src/filesystem/vfs/mod.rs +++ b/kernel/src/filesystem/vfs/mod.rs @@ -9,7 +9,7 @@ pub mod syscall; pub mod utils; pub mod vcore; -use ::core::{any::Any, fmt::Debug, sync::atomic::AtomicUsize}; +use ::core::{any::Any, fmt::Debug, fmt::Display, sync::atomic::AtomicUsize}; use alloc::{string::String, sync::Arc, vec::Vec}; use derive_builder::Builder; use intertrait::CastFromSync; @@ -47,6 +47,12 @@ pub const MAX_PATHLEN: usize = 1024; // 定义inode号 int_like!(InodeId, AtomicInodeId, usize, AtomicUsize); +impl Display for InodeId { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.0) + } +} + /// 文件的类型 #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum FileType { @@ -476,7 +482,9 @@ pub trait IndexNode: Any + Sync + Send + Debug + CastFromSync { fn as_any_ref(&self) -> &dyn Any; /// @brief 列出当前inode下的所有目录项的名字 - fn list(&self) -> Result, SystemError>; + fn list(&self) -> Result, SystemError> { + Err(SystemError::ENOTDIR) + } /// # mount - 挂载文件系统 /// diff --git a/kernel/src/filesystem/vfs/vcore.rs b/kernel/src/filesystem/vfs/vcore.rs index 7fbd13b2c..7f4ef7775 100644 --- a/kernel/src/filesystem/vfs/vcore.rs +++ b/kernel/src/filesystem/vfs/vcore.rs @@ -4,6 +4,7 @@ use alloc::sync::Arc; use log::{error, info}; use system_error::SystemError; +use crate::filesystem::procfs::root::test_procfs_init; use crate::libs::casting::DowncastArc; use crate::{ define_event_trace, @@ -58,6 +59,9 @@ pub fn vfs_init() -> Result<(), SystemError> { sysfs_init().expect("Failed to initialize sysfs"); + // TestProcFS 应该在文件系统迁移之后初始化 + // test_procfs_init().expect("Failed to initialize test procfs"); + let root_entries = ProcessManager::current_mntns() .root_inode() .list() @@ -105,6 +109,9 @@ fn migrate_virtual_filesystem(new_fs: Arc) -> Result<(), SystemE .mount_from(old_root_inode.find("sys").expect("sys not mounted!")) .expect("Failed to migrate filesystem of sys"); + // TestProcFS 不需要迁移,因为它是在新文件系统上直接挂载的 + // 如果需要 testproc,应该在迁移完成后重新挂载 + unsafe { current_mntns.force_change_root_mountfs(new_fs); } @@ -159,6 +166,10 @@ pub fn mount_root_fs() -> Result<(), SystemError> { } info!("Successfully migrate rootfs to FAT32!"); + // 在文件系统迁移完成后初始化 TestProcFS + test_procfs_init().expect("Failed to initialize test procfs"); + info!("TestProcFS initialized after rootfs migration."); + return Ok(()); } @@ -176,6 +187,10 @@ pub fn change_root_fs() -> Result<(), SystemError> { } info!("Successfully migrate rootfs to initramfs!"); + // 在文件系统迁移完成后初始化 TestProcFS + test_procfs_init().expect("Failed to initialize test procfs"); + info!("TestProcFS initialized after rootfs migration."); + return Ok(()); } diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 9588a05ec..915ae0e7a 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -4,6 +4,7 @@ use core::{ hint::spin_loop, intrinsics::unlikely, mem::ManuallyDrop, + str::FromStr, sync::atomic::{compiler_fence, fence, AtomicBool, AtomicU64, AtomicUsize, Ordering}, }; @@ -98,6 +99,11 @@ pub mod utils; static ALL_PROCESS: SpinLock>>> = SpinLock::new(None); +pub(crate) fn all_process() -> &'static SpinLock>>> +{ + &ALL_PROCESS +} + pub static mut PROCESS_SWITCH_RESULT: Option> = None; /// 一个只改变1次的全局变量,标志进程管理器是否已经初始化完成 @@ -686,6 +692,15 @@ impl fmt::Display for RawPid { } } +impl FromStr for RawPid { + type Err = core::num::ParseIntError; + + fn from_str(s: &str) -> Result { + let pid = usize::from_str(s)?; + Ok(RawPid(pid)) + } +} + impl RawPid { /// 该RawPid暂未分配,待会会初始化它。 /// 这个状态只应当出现在进程/线程创建的过程中 diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index e6d2b3096..83237cfc9 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -90,7 +90,7 @@ impl Syscall { if let Some(handler) = syscall_table().get(syscall_num) { // 使用以下代码可以打印系统调用号和参数,方便调试 - // let show = ProcessManager::current_pid().data() >= 8; + // let show = ProcessManager::current_pid().data() >= 12; let show = false; if show { log::debug!( From 5a0a0a159382d20fbbca5ae903145f9c90e97074 Mon Sep 17 00:00:00 2001 From: sparkzky Date: Thu, 18 Dec 2025 15:43:42 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E5=88=A0=E9=99=A4=E5=8E=9F?= =?UTF-8?q?=E6=9C=89=E7=9A=84procfs=EF=BC=8C=E6=94=B9=E7=94=A8=E6=96=B0?= =?UTF-8?q?=E7=9A=84procfs=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: sparkzky --- kernel/src/filesystem/procfs/mod.rs | 1248 +----------------- kernel/src/filesystem/procfs/pid/mod.rs | 5 +- kernel/src/filesystem/procfs/root.rs | 127 +- kernel/src/filesystem/procfs/template/sym.rs | 5 +- kernel/src/filesystem/vfs/vcore.rs | 17 +- kernel/src/process/fork.rs | 10 - kernel/src/process/mod.rs | 6 +- kernel/src/process/syscall/clone_utils.rs | 11 +- 8 files changed, 60 insertions(+), 1369 deletions(-) diff --git a/kernel/src/filesystem/procfs/mod.rs b/kernel/src/filesystem/procfs/mod.rs index 18b0e9efa..1d5063bcd 100644 --- a/kernel/src/filesystem/procfs/mod.rs +++ b/kernel/src/filesystem/procfs/mod.rs @@ -1,43 +1,14 @@ -use ::log::{error, info}; -use alloc::{ - borrow::ToOwned, - collections::BTreeMap, - format, - string::{String, ToString}, - sync::{Arc, Weak}, - vec::Vec, -}; -use core::intrinsics::size_of; +//! ProcFS - 进程文件系统 +//! +//! 实现 Linux 兼容的 /proc 文件系统 + +use alloc::{sync::Arc, vec::Vec}; use system_error::SystemError; -use crate::{ - arch::mm::LockedFrameAllocator, - driver::base::device::device_number::DeviceNumber, - filesystem::{ - procfs::template::Builder, - vfs::{ - mount::{MountFlags, MountPath}, - syscall::RenameFlags, - vcore::generate_inode_id, - FileType, - }, - }, - libs::{ - once::Once, - rwlock::RwLock, - spinlock::{SpinLock, SpinLockGuard}, - }, - mm::allocator::page_frame::FrameAllocator, - process::{ProcessManager, ProcessState, RawPid}, - time::PosixTimeSpec, -}; +use crate::{libs::once::Once, process::ProcessManager, process::RawPid}; -use super::vfs::{ - file::{FileMode, FilePrivateData}, - syscall::ModeType, - utils::DName, - FileSystem, FsInfo, IndexNode, InodeId, Magic, Metadata, SuperBlock, -}; +use super::vfs::mount::{MountFlags, MountPath}; +use super::vfs::syscall::ModeType; mod cmdline; mod cpuinfo; @@ -47,9 +18,6 @@ pub mod log; mod meminfo; mod mounts; mod pid; -mod proc_cpuinfo; -mod proc_mounts; -mod proc_version; pub mod root; mod self_; mod syscall; @@ -57,176 +25,49 @@ pub(super) mod template; mod utils; mod version; -/// @brief 进程文件类型 -/// @usage 用于定义进程文件夹下的各类文件类型 -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -#[repr(u8)] -pub enum ProcFileType { - ///展示进程状态信息 - ProcStatus = 0, - /// meminfo - ProcMeminfo = 1, - /// kmsg - ProcKmsg = 2, - /// 可执行路径 - ProcExe = 3, - /// /proc/mounts - ProcSelf = 4, - ProcFdDir = 5, - ProcFdFile = 6, - ProcMounts = 7, - /// /proc/version - ProcVersion = 8, - /// /proc/cpuinfo - ProcCpuinfo = 9, - //todo: 其他文件类型 - ///默认文件类型 - Default, -} - -impl From for ProcFileType { - fn from(value: u8) -> Self { - match value { - 0 => ProcFileType::ProcStatus, - 1 => ProcFileType::ProcMeminfo, - 2 => ProcFileType::ProcKmsg, - 3 => ProcFileType::ProcExe, - 4 => ProcFileType::ProcSelf, - 5 => ProcFileType::ProcFdDir, - 6 => ProcFileType::ProcFdFile, - 7 => ProcFileType::ProcMounts, - 8 => ProcFileType::ProcVersion, - 9 => ProcFileType::ProcCpuinfo, - _ => ProcFileType::Default, - } - } -} -/// @brief 创建 ProcFS 文件的参数结构体 -#[derive(Debug, Clone)] -pub struct ProcFileCreationParams<'a> { - pub parent: Arc, - pub name: &'a str, - pub file_type: FileType, - pub mode: ModeType, - pub pid: Option, - pub ftype: ProcFileType, - pub data: Option<&'a str>, -} - -impl<'a> ProcFileCreationParams<'a> { - pub fn builder() -> ProcFileCreationParamsBuilder<'a> { - ProcFileCreationParamsBuilder::default() - } -} - -/// @brief ProcFileCreationParams 的 Builder 模式实现 -#[derive(Debug, Clone, Default)] -pub struct ProcFileCreationParamsBuilder<'a> { - parent: Option>, - name: Option<&'a str>, - file_type: Option, - mode: Option, - pid: Option, - ftype: Option, - data: Option<&'a str>, -} - -#[allow(dead_code)] -impl<'a> ProcFileCreationParamsBuilder<'a> { - pub fn parent(mut self, parent: Arc) -> Self { - self.parent = Some(parent); - self - } +// 重新导出 ProcFS +pub use root::ProcFS; - pub fn name(mut self, name: &'a str) -> Self { - self.name = Some(name); - self - } - - pub fn file_type(mut self, file_type: FileType) -> Self { - self.file_type = Some(file_type); - self - } - - pub fn mode(mut self, mode: ModeType) -> Self { - self.mode = Some(mode); - self - } - - pub fn pid(mut self, pid: RawPid) -> Self { - self.pid = Some(pid); - self - } - - pub fn ftype(mut self, ftype: ProcFileType) -> Self { - self.ftype = Some(ftype); - self - } +/// procfs 的 inode 名称的最大长度 +pub(super) const PROCFS_MAX_NAMELEN: usize = 64; +/// procfs 的块大小 +pub(super) const PROCFS_BLOCK_SIZE: u64 = 512; - pub fn data(mut self, data: &'a str) -> Self { - self.data = Some(data); - self - } +/// 供 template 使用的 Builder trait +pub(super) use template::Builder; - pub fn build(self) -> Result, SystemError> { - Ok(ProcFileCreationParams { - parent: self.parent.ok_or(SystemError::EINVAL)?, - name: self.name.ok_or(SystemError::EINVAL)?, - file_type: self.file_type.ok_or(SystemError::EINVAL)?, - mode: self.mode.unwrap_or(ModeType::S_IRUGO), - pid: self.pid, - ftype: self.ftype.ok_or(SystemError::EINVAL)?, - data: self.data, - }) - } +/// procfs 文件类型 +#[derive(Debug, Clone, Copy, Default)] +pub(super) enum ProcFileType { + /// 默认类型 + #[default] + Default, + /// 进程状态文件 + ProcStatus, + /// 进程内存映射文件 + ProcMaps, } -/// @brief 节点私有信息结构体 -/// @usage 用于传入各类文件所需的信息 -#[derive(Debug)] +/// procfs inode 信息 +#[derive(Debug, Default)] pub struct InodeInfo { - ///进程的pid - pid: Option, - ///文件类型 - ftype: ProcFileType, + /// 进程的 pid + pub pid: Option, + /// 文件类型 + pub ftype: ProcFileType, /// 文件描述符 - fd: i32, - // 其他需要传入的信息在此定义 -} - -impl Default for InodeInfo { - fn default() -> Self { - InodeInfo { - pid: None, - ftype: ProcFileType::Default, - fd: -1, - } - } -} - -/// @brief procfs的inode名称的最大长度 -pub(super) const PROCFS_MAX_NAMELEN: usize = 64; -pub(super) const PROCFS_BLOCK_SIZE: u64 = 512; -/// @brief procfs文件系统的Inode结构体 -#[derive(Debug)] -pub struct LockedProcFSInode(SpinLock); - -/// @brief procfs文件系统结构体 -#[derive(Debug)] -pub struct ProcFS { - /// procfs的root inode - root_inode: Arc, - super_block: RwLock, + pub fd: i32, } +/// procfs 文件私有数据 #[derive(Debug, Clone)] pub struct ProcfsFilePrivateData { - data: Vec, + pub data: Vec, } impl ProcfsFilePrivateData { pub fn new() -> Self { - return ProcfsFilePrivateData { data: Vec::new() }; + ProcfsFilePrivateData { data: Vec::new() } } } @@ -236,1028 +77,19 @@ impl Default for ProcfsFilePrivateData { } } -/// @brief procfs文件系统的Inode结构体(不包含锁) -#[derive(Debug)] -pub struct ProcFSInode { - /// 指向父Inode的弱引用 - parent: Weak, - /// 指向自身的弱引用 - self_ref: Weak, - /// 子Inode的B树 - children: BTreeMap>, - /// 当前inode的数据部分 - data: Vec, - /// 当前inode的元数据 - metadata: Metadata, - /// 指向inode所在的文件系统对象的指针 - fs: Weak, - /// 储存私有信息 - fdata: InodeInfo, - /// 目录项 - dname: DName, -} - -/// 对ProcFSInode实现获取各类文件信息的函数 -impl ProcFSInode { - /// @brief 去除Vec中所有的\0,并在结尾添加\0 - #[inline] - fn trim_string(&self, data: &mut Vec) { - data.retain(|x| *x != 0); - - data.push(0); - } - // todo:其他数据获取函数实现 - - /// @brief 打开status文件 - /// - fn open_status(&self, pdata: &mut ProcfsFilePrivateData) -> Result { - // 获取该pid对应的pcb结构体 - let pid = self - .fdata - .pid - .expect("ProcFS: pid is None when opening 'status' file."); - let pcb = ProcessManager::find_task_by_vpid(pid); - let pcb = if let Some(pcb) = pcb { - pcb - } else { - error!( - "ProcFS: Cannot find pcb for pid {:?} when opening its 'status' file.", - pid - ); - return Err(SystemError::ESRCH); - }; - - // ::log::debug!( - // "ProcFS: Opening 'status' file for pid {:?} (cnt: {})", - // pcb.raw_pid(), - // Arc::strong_count(&pcb) - // ); - // 传入数据 - let pdata: &mut Vec = &mut pdata.data; - // name - pdata.append( - &mut format!("Name:\t{}", pcb.basic().name()) - .as_bytes() - .to_owned(), - ); - - let sched_info_guard = pcb.sched_info(); - let state = sched_info_guard.inner_lock_read_irqsave().state(); - let cpu_id = sched_info_guard - .on_cpu() - .map(|cpu| cpu.data() as i32) - .unwrap_or(-1); - - let priority = sched_info_guard.policy(); - let vrtime = sched_info_guard.sched_entity.vruntime; - let time = sched_info_guard.sched_entity.sum_exec_runtime; - let start_time = sched_info_guard.sched_entity.exec_start; - // State - pdata.append(&mut format!("\nState:\t{:?}", state).as_bytes().to_owned()); - - // Tgid - pdata.append( - &mut format!( - "\nTgid:\t{}", - pcb.task_tgid_vnr().unwrap_or(RawPid::new(0)).into() - ) - .into(), - ); - - // pid - pdata.append( - &mut format!("\nPid:\t{}", pcb.task_pid_vnr().data()) - .as_bytes() - .to_owned(), - ); - - // ppid - pdata.append( - &mut format!( - "\nPpid:\t{}", - pcb.parent_pcb() - .map(|p| p.task_pid_vnr().data() as isize) - .unwrap_or(-1) - ) - .as_bytes() - .to_owned(), - ); - - // fdsize - if matches!(state, ProcessState::Exited(_)) { - // 进程已经退出,fdsize为0 - pdata.append(&mut format!("\nFDSize:\t{}", 0).into()); - } else { - pdata.append( - &mut format!("\nFDSize:\t{}", pcb.fd_table().read().fd_open_count()).into(), - ); - } - - // tty - let name = if let Some(tty) = pcb.sig_info_irqsave().tty() { - tty.core().name().clone() - } else { - "none".to_string() - }; - pdata.append(&mut format!("\nTty:\t{}", name).as_bytes().to_owned()); - - // 进程在cpu上的运行时间 - pdata.append(&mut format!("\nTime:\t{}", time).as_bytes().to_owned()); - // 进程开始运行的时间 - pdata.append(&mut format!("\nStime:\t{}", start_time).as_bytes().to_owned()); - // kthread - pdata.append(&mut format!("\nKthread:\t{}", pcb.is_kthread() as usize).into()); - pdata.append(&mut format!("\ncpu_id:\t{}", cpu_id).as_bytes().to_owned()); - pdata.append(&mut format!("\npriority:\t{:?}", priority).as_bytes().to_owned()); - pdata.append( - &mut format!("\npreempt:\t{}", pcb.preempt_count()) - .as_bytes() - .to_owned(), - ); - - pdata.append(&mut format!("\nvrtime:\t{}", vrtime).as_bytes().to_owned()); - - if let Some(user_vm) = pcb.basic().user_vm() { - let address_space_guard = user_vm.read(); - // todo: 当前进程运行过程中占用内存的峰值 - let hiwater_vm: u64 = 0; - // 进程代码段的大小 - let text = (address_space_guard.end_code - address_space_guard.start_code) / 1024; - // 进程数据段的大小 - let data = (address_space_guard.end_data - address_space_guard.start_data) / 1024; - drop(address_space_guard); - pdata.append( - &mut format!("\nVmPeak:\t{} kB", hiwater_vm) - .as_bytes() - .to_owned(), - ); - pdata.append(&mut format!("\nVmData:\t{} kB", data).as_bytes().to_owned()); - pdata.append(&mut format!("\nVmExe:\t{} kB", text).as_bytes().to_owned()); - } - - pdata.append( - &mut format!("\nflags: {:?}\n", pcb.flags().clone()) - .as_bytes() - .to_owned(), - ); - - // 去除多余的\0 - self.trim_string(pdata); - - return Ok((pdata.len() * size_of::()) as i64); - } - - /// 打开 meminfo 文件 - fn open_meminfo(&self, pdata: &mut ProcfsFilePrivateData) -> Result { - // 获取内存信息 - let usage = unsafe { LockedFrameAllocator.usage() }; - - // 传入数据 - let data: &mut Vec = &mut pdata.data; - - data.append( - &mut format!("MemTotal:\t{} kB\n", usage.total().bytes() >> 10) - .as_bytes() - .to_owned(), - ); - - data.append( - &mut format!("MemFree:\t{} kB\n", usage.free().bytes() >> 10) - .as_bytes() - .to_owned(), - ); - - // 去除多余的\0 - self.trim_string(data); - - return Ok((data.len() * size_of::()) as i64); - } - - // 打开 exe 文件 - fn open_exe(&self, _pdata: &mut ProcfsFilePrivateData) -> Result { - // 这个文件是一个软链接,直接返回0即可 - let pcb = ProcessManager::current_pcb(); - let exe = pcb.execute_path(); - return Ok(exe.len() as _); - } - - fn open_self(&self, _pdata: &mut ProcfsFilePrivateData) -> Result { - let pid = ProcessManager::current_pid().data(); - return Ok(pid.to_string().len() as _); - } - - // 读取exe文件 - fn read_exe_link(&self, buf: &mut [u8], offset: usize) -> Result { - // 判断是否有记录pid信息,有的话就是当前进程的exe文件,没有则是当前进程的exe文件 - let pcb = if let Some(pid) = self.fdata.pid { - ProcessManager::find_task_by_vpid(pid).ok_or(SystemError::ESRCH)? - } else { - // 如果没有pid信息,则读取当前进程的exe文件 - ProcessManager::current_pcb() - }; - let exe = pcb.execute_path(); - let exe_bytes = exe.as_bytes(); - if offset >= exe_bytes.len() { - return Ok(0); - } - let len = buf.len().min(exe_bytes.len() - offset); - buf[..len].copy_from_slice(&exe_bytes[offset..offset + len]); - Ok(len) - } - - /// read current task pid dynamically - fn read_self_link(&self, buf: &mut [u8]) -> Result { - let pid = ProcessManager::current_pid().data(); - let pid_bytes = pid.to_string(); - let len = pid_bytes.len().min(buf.len()); - buf[..len].copy_from_slice(&pid_bytes.as_bytes()[..len]); - Ok(len) - } - - fn read_fd_link(&self, buf: &mut [u8]) -> Result { - let fd = self.fdata.fd; - let fd_table = ProcessManager::current_pcb().fd_table(); - let fd_table = fd_table.read(); - let file = fd_table.get_file_by_fd(fd); - if let Some(file) = file { - let inode = file.inode(); - let path = inode.absolute_path().unwrap(); - let len = path.len().min(buf.len()); - buf[..len].copy_from_slice(&path.as_bytes()[..len]); - Ok(len) - } else { - return Err(SystemError::EBADF); - } - } - - /// proc文件系统读取函数 - fn proc_read( - &self, - offset: usize, - len: usize, - buf: &mut [u8], - pdata: &mut ProcfsFilePrivateData, - ) -> Result { - let start = pdata.data.len().min(offset); - let end = pdata.data.len().min(offset + len); - - // buffer空间不足 - if buf.len() < (end - start) { - return Err(SystemError::ENOBUFS); - } - - // 拷贝数据 - let src = &pdata.data[start..end]; - buf[0..src.len()].copy_from_slice(src); - return Ok(src.len()); - } -} - -impl FileSystem for ProcFS { - fn root_inode(&self) -> Arc { - return self.root_inode.clone(); - } - - fn info(&self) -> FsInfo { - return FsInfo { - blk_dev_id: 0, - max_name_len: PROCFS_MAX_NAMELEN, - }; - } - - fn as_any_ref(&self) -> &dyn core::any::Any { - self - } - fn name(&self) -> &str { - "procfs" - } - - fn super_block(&self) -> SuperBlock { - self.super_block.read().clone() - } -} - -impl ProcFS { - #[inline(never)] - fn create_proc_file(&self, params: ProcFileCreationParams) -> Result<(), SystemError> { - let binding = params - .parent - .create(params.name, params.file_type, params.mode)?; - let proc_file = binding - .as_any_ref() - .downcast_ref::() - .unwrap(); - let mut proc_file_guard = proc_file.0.lock(); - proc_file_guard.fdata.pid = params.pid; - proc_file_guard.fdata.ftype = params.ftype; - if let Some(data_content) = params.data { - proc_file_guard.data = data_content.to_string().as_bytes().to_vec(); - } - drop(proc_file_guard); - Ok(()) - } - - #[inline(never)] - pub fn new() -> Arc { - let super_block = SuperBlock::new( - Magic::PROC_MAGIC, - PROCFS_BLOCK_SIZE, - PROCFS_MAX_NAMELEN as u64, - ); - // 初始化root inode - let root: Arc = - Arc::new(LockedProcFSInode(SpinLock::new(ProcFSInode { - parent: Weak::default(), - self_ref: Weak::default(), - children: BTreeMap::new(), - data: Vec::new(), - metadata: Metadata { - dev_id: 0, - inode_id: generate_inode_id(), - size: 0, - blk_size: 0, - blocks: 0, - atime: PosixTimeSpec::default(), - mtime: PosixTimeSpec::default(), - ctime: PosixTimeSpec::default(), - btime: PosixTimeSpec::default(), - file_type: FileType::Dir, - mode: ModeType::from_bits_truncate(0o555), - nlinks: 1, - uid: 0, - gid: 0, - raw_dev: DeviceNumber::default(), - }, - fs: Weak::default(), - fdata: InodeInfo { - pid: None, - ftype: ProcFileType::Default, - fd: -1, - }, - dname: DName::default(), - }))); - - let result: Arc = Arc::new(ProcFS { - root_inode: root, - super_block: RwLock::new(super_block), - }); - - // 对root inode加锁,并继续完成初始化工作 - let mut root_guard: SpinLockGuard = result.root_inode.0.lock(); - root_guard.parent = Arc::downgrade(&result.root_inode); - root_guard.self_ref = Arc::downgrade(&result.root_inode); - root_guard.fs = Arc::downgrade(&result); - // 释放锁 - drop(root_guard); - - // 创建meminfo文件 - let meminfo_params = ProcFileCreationParams::builder() - .parent(result.root_inode()) - .name("meminfo") - .file_type(FileType::File) - .mode(ModeType::S_IRUGO) - .ftype(ProcFileType::ProcMeminfo) - .build() - .unwrap(); - result - .create_proc_file(meminfo_params) - .unwrap_or_else(|_| panic!("create meminfo error")); - - // 创建kmsg文件 - let kmsg_params = ProcFileCreationParams::builder() - .parent(result.root_inode()) - .name("kmsg") - .file_type(FileType::File) - .mode(ModeType::S_IRUGO) - .ftype(ProcFileType::ProcKmsg) - .build() - .unwrap(); - result - .create_proc_file(kmsg_params) - .unwrap_or_else(|_| panic!("create kmsg error")); - // 这个文件是用来欺骗Aya框架识别内核版本 - /* On Ubuntu LINUX_VERSION_CODE doesn't correspond to info.release, - * but Ubuntu provides /proc/version_signature file, as described at - * https://ubuntu.com/kernel, with an example contents below, which we - * can use to get a proper LINUX_VERSION_CODE. - * - * Ubuntu 5.4.0-12.15-generic 5.4.8 - * - * In the above, 5.4.8 is what kernel is actually expecting, while - * uname() call will return 5.4.0 in info.release. - */ - let version_signature_params = ProcFileCreationParams::builder() - .parent(result.root_inode()) - .name("version_signature") - .file_type(FileType::File) - .ftype(ProcFileType::Default) - .data("DragonOS 6.0.0-generic 6.0.0\n") - .build() - .unwrap(); - result - .create_proc_file(version_signature_params) - .unwrap_or_else(|_| panic!("create version_signature error")); - - let mounts_params = ProcFileCreationParams::builder() - .parent(result.root_inode()) - .name("mounts") - .file_type(FileType::File) - .ftype(ProcFileType::ProcMounts) - .build() - .unwrap(); - result - .create_proc_file(mounts_params) - .unwrap_or_else(|_| panic!("create mounts error")); - - // 创建 version 文件 - let version_params = ProcFileCreationParams::builder() - .parent(result.root_inode()) - .name("version") - .file_type(FileType::File) - .mode(ModeType::S_IRUGO) - .ftype(ProcFileType::ProcVersion) - .build() - .unwrap(); - result - .create_proc_file(version_params) - .unwrap_or_else(|_| panic!("create version error")); - - // 创建 cpuinfo 文件 - let cpuinfo_params = ProcFileCreationParams::builder() - .parent(result.root_inode()) - .name("cpuinfo") - .file_type(FileType::File) - .mode(ModeType::S_IRUGO) - .ftype(ProcFileType::ProcCpuinfo) - .build() - .unwrap(); - result - .create_proc_file(cpuinfo_params) - .unwrap_or_else(|_| panic!("create cpuinfo error")); - - let self_params = ProcFileCreationParams::builder() - .parent(result.root_inode()) - .name("self") - .file_type(FileType::SymLink) - .mode(ModeType::from_bits_truncate(0o555)) - .ftype(ProcFileType::ProcSelf) - .build() - .unwrap(); - result - .create_proc_file(self_params) - .unwrap_or_else(|_| panic!("create self error")); - - return result; - } - - /// @brief 进程注册函数 - /// @usage 在进程中调用并创建进程对应文件 - pub fn register_pid(&self, pid: RawPid) -> Result<(), SystemError> { - // 获取当前inode - let inode = self.root_inode(); - // 创建对应进程文件夹 - let pid_dir = inode.create( - &pid.to_string(), - FileType::Dir, - ModeType::from_bits_truncate(0o555), - )?; - // 创建相关文件 - // status文件 - let status_binding = pid_dir.create("status", FileType::File, ModeType::S_IRUGO)?; - let status_file: &LockedProcFSInode = status_binding - .as_any_ref() - .downcast_ref::() - .unwrap(); - status_file.0.lock().fdata.pid = Some(pid); - status_file.0.lock().fdata.ftype = ProcFileType::ProcStatus; - - // exe文件 - let exe_binding = - pid_dir.create_with_data("exe", FileType::SymLink, ModeType::S_IRUGO, 0)?; - let exe_file = exe_binding - .as_any_ref() - .downcast_ref::() - .unwrap(); - exe_file.0.lock().fdata.pid = Some(pid); - exe_file.0.lock().fdata.ftype = ProcFileType::ProcExe; - - // fd dir - let fd = pid_dir.create("fd", FileType::Dir, ModeType::from_bits_truncate(0o555))?; - let fd = fd.as_any_ref().downcast_ref::().unwrap(); - fd.0.lock().fdata.ftype = ProcFileType::ProcFdDir; - //todo: 创建其他文件 - - return Ok(()); - } - - /// @brief 解除进程注册 - /// - pub fn unregister_pid(&self, pid: RawPid) -> Result<(), SystemError> { - // 获取当前inode - let proc: Arc = self.root_inode(); - // 获取进程文件夹 - let pid_dir: Arc = proc.find(&pid.to_string())?; - // 删除进程文件夹下文件 - pid_dir.unlink("status")?; - pid_dir.unlink("exe")?; - pid_dir.rmdir("fd")?; - - // 查看进程文件是否还存在 - // let pf= pid_dir.find("status").expect("Cannot find status"); - - // 删除进程文件夹 - proc.unlink(&pid.to_string())?; - - return Ok(()); - } -} - -impl LockedProcFSInode { - fn dynamical_find_fd(&self, fd: &str) -> Result, SystemError> { - // ::log::info!("ProcFS: Dynamically opening fd files for current process."); - let fd = fd.parse::().map_err(|_| SystemError::EINVAL)?; - let pcb = ProcessManager::current_pcb(); - let fd_table = pcb.fd_table(); - let fd_table = fd_table.read(); - let file = fd_table.get_file_by_fd(fd); - if file.is_some() { - let _ = self.unlink(&fd.to_string()); - let fd_file = self.create(&fd.to_string(), FileType::SymLink, ModeType::S_IRUGO)?; - let fd_file_proc = fd_file - .as_any_ref() - .downcast_ref::() - .unwrap(); - fd_file_proc.0.lock().fdata.fd = fd; - fd_file_proc.0.lock().fdata.ftype = ProcFileType::ProcFdFile; - return Ok(fd_file); - } else { - return Err(SystemError::ENOENT); - } - } - - fn dynamical_list_fd(&self) -> Result, SystemError> { - // ::log::info!("ProcFS: Dynamically listing fd files for current process"); - let pcb = ProcessManager::current_pcb(); - let fd_table = pcb.fd_table(); - let fd_table = fd_table.read(); - let res = fd_table.iter().map(|(fd, _)| fd.to_string()).collect(); - return Ok(res); - } -} - -impl IndexNode for LockedProcFSInode { - fn open( - &self, - mut data: SpinLockGuard, - _mode: &FileMode, - ) -> Result<(), SystemError> { - // 加锁 - let mut inode: SpinLockGuard = self.0.lock(); - let proc_ty = inode.fdata.ftype; - - // 如果inode类型为文件夹,则直接返回成功 - if let FileType::Dir = inode.metadata.file_type { - return Ok(()); - } - let mut private_data = ProcfsFilePrivateData::new(); - // 根据文件类型获取相应数据 - let file_size = match proc_ty { - ProcFileType::ProcStatus => inode.open_status(&mut private_data)?, - ProcFileType::ProcMeminfo => inode.open_meminfo(&mut private_data)?, - ProcFileType::ProcExe => inode.open_exe(&mut private_data)?, - ProcFileType::ProcMounts => inode.open_mounts(&mut private_data)?, - ProcFileType::ProcVersion => inode.open_version(&mut private_data)?, - ProcFileType::ProcCpuinfo => inode.open_cpuinfo(&mut private_data)?, - ProcFileType::Default => inode.data.len() as i64, - ProcFileType::ProcSelf => inode.open_self(&mut private_data)?, - _ => 0, - }; - *data = FilePrivateData::Procfs(private_data); - // 更新metadata里面的文件大小数值 - inode.metadata.size = file_size; - drop(inode); - return Ok(()); - } - - fn rmdir(&self, name: &str) -> Result<(), SystemError> { - let mut guard = self.0.lock(); - if guard.metadata.file_type != FileType::Dir { - return Err(SystemError::ENOTDIR); - } - let name = DName::from(name); - guard.children.remove(&name); - return Ok(()); - } - - fn parent(&self) -> Result, SystemError> { - let parent = self.0.lock().parent.upgrade().ok_or(SystemError::ENOENT)?; - return Ok(parent as Arc); - } - - fn close(&self, mut data: SpinLockGuard) -> Result<(), SystemError> { - let guard: SpinLockGuard = self.0.lock(); - // 如果inode类型为文件夹,则直接返回成功 - if let FileType::Dir = guard.metadata.file_type { - return Ok(()); - } - // 释放data - *data = FilePrivateData::Procfs(ProcfsFilePrivateData::new()); - - return Ok(()); - } - - fn read_at( - &self, - offset: usize, - len: usize, - buf: &mut [u8], - data: SpinLockGuard, - ) -> Result { - info!("ProcFS: read_at called with offset {}, len {}", offset, len); - if buf.len() < len { - return Err(SystemError::EINVAL); - } - // 加锁 - let inode = self.0.lock(); - - // 检查当前inode是否为一个文件夹,如果是的话,就返回错误 - if inode.metadata.file_type == FileType::Dir { - return Err(SystemError::EISDIR); - } - - // 根据文件类型读取相应数据 - match inode.fdata.ftype { - ProcFileType::ProcStatus - | ProcFileType::ProcMeminfo - | ProcFileType::ProcMounts - | ProcFileType::ProcVersion => { - // 获取数据信息 - let mut private_data = match &*data { - FilePrivateData::Procfs(p) => p.clone(), - _ => { - panic!("ProcFS: FilePrivateData mismatch!"); - } - }; - return inode.proc_read(offset, len, buf, &mut private_data); - } - ProcFileType::ProcExe => return inode.read_exe_link(buf, offset), - ProcFileType::ProcSelf => return inode.read_self_link(buf), - ProcFileType::ProcFdFile => return inode.read_fd_link(buf), - ProcFileType::ProcCpuinfo => {} - _ => (), - }; - - // 默认读取 - let start = inode.data.len().min(offset); - let end = inode.data.len().min(offset + len); - - // buffer空间不足 - if buf.len() < (end - start) { - return Err(SystemError::ENOBUFS); - } - - // 拷贝数据 - let src = &inode.data[start..end]; - buf[0..src.len()].copy_from_slice(src); - return Ok(src.len()); - } - - fn write_at( - &self, - _offset: usize, - _len: usize, - _buf: &[u8], - _data: SpinLockGuard, - ) -> Result { - return Err(SystemError::ENOSYS); - } - - fn fs(&self) -> Arc { - return self.0.lock().fs.upgrade().unwrap(); - } - - fn as_any_ref(&self) -> &dyn core::any::Any { - self - } - - fn metadata(&self) -> Result { - let inode = self.0.lock(); - let metadata = inode.metadata.clone(); - return Ok(metadata); - } - - fn set_metadata(&self, metadata: &Metadata) -> Result<(), SystemError> { - let mut inode = self.0.lock(); - inode.metadata.atime = metadata.atime; - inode.metadata.mtime = metadata.mtime; - inode.metadata.ctime = metadata.ctime; - inode.metadata.btime = metadata.btime; - inode.metadata.mode = metadata.mode; - inode.metadata.uid = metadata.uid; - inode.metadata.gid = metadata.gid; - - return Ok(()); - } - - fn resize(&self, len: usize) -> Result<(), SystemError> { - let mut inode = self.0.lock(); - if inode.metadata.file_type == FileType::File { - inode.data.resize(len, 0); - return Ok(()); - } else { - return Err(SystemError::EINVAL); - } - } - - fn create_with_data( - &self, - name: &str, - file_type: FileType, - mode: ModeType, - data: usize, - ) -> Result, SystemError> { - // 获取当前inode - let mut inode = self.0.lock(); - // 如果当前inode不是文件夹,则返回 - if inode.metadata.file_type != FileType::Dir { - return Err(SystemError::ENOTDIR); - } - let name = DName::from(name); - // 如果有重名的,则返回 - if inode.children.contains_key(&name) { - return Err(SystemError::EEXIST); - } - - // 创建inode - let result: Arc = - Arc::new(LockedProcFSInode(SpinLock::new(ProcFSInode { - parent: inode.self_ref.clone(), - self_ref: Weak::default(), - children: BTreeMap::new(), - data: Vec::new(), - metadata: Metadata { - dev_id: 0, - inode_id: generate_inode_id(), - size: 0, - blk_size: 0, - blocks: 0, - atime: PosixTimeSpec::default(), - mtime: PosixTimeSpec::default(), - ctime: PosixTimeSpec::default(), - btime: PosixTimeSpec::default(), - file_type, - mode, - nlinks: 1, - uid: 0, - gid: 0, - raw_dev: DeviceNumber::from(data as u32), - }, - fs: inode.fs.clone(), - fdata: InodeInfo { - pid: None, - ftype: ProcFileType::Default, - fd: -1, - }, - dname: name.clone(), - }))); - - // 初始化inode的自引用的weak指针 - result.0.lock().self_ref = Arc::downgrade(&result); - - // 将子inode插入父inode的B树中 - inode.children.insert(name, result.clone()); - - return Ok(result); - } - - fn link(&self, name: &str, other: &Arc) -> Result<(), SystemError> { - let other: &LockedProcFSInode = other - .downcast_ref::() - .ok_or(SystemError::EPERM)?; - let mut inode: SpinLockGuard = self.0.lock(); - let mut other_locked: SpinLockGuard = other.0.lock(); - - // 如果当前inode不是文件夹,那么报错 - if inode.metadata.file_type != FileType::Dir { - return Err(SystemError::ENOTDIR); - } - - // 如果另一个inode是文件夹,那么也报错 - if other_locked.metadata.file_type == FileType::Dir { - return Err(SystemError::EISDIR); - } - let name = DName::from(name); - // 如果当前文件夹下已经有同名文件,也报错。 - if inode.children.contains_key(&name) { - return Err(SystemError::EEXIST); - } - - inode - .children - .insert(name, other_locked.self_ref.upgrade().unwrap()); - - // 增加硬链接计数 - other_locked.metadata.nlinks += 1; - return Ok(()); - } - - fn unlink(&self, name: &str) -> Result<(), SystemError> { - let mut inode: SpinLockGuard = self.0.lock(); - // 如果当前inode不是目录,那么也没有子目录/文件的概念了,因此要求当前inode的类型是目录 - if inode.metadata.file_type != FileType::Dir { - return Err(SystemError::ENOTDIR); - } - - // 不允许删除当前文件夹,也不允许删除上一个目录 - if name == "." || name == ".." { - return Err(SystemError::ENOTEMPTY); - } - let name = DName::from(name); - // 获得要删除的文件的inode - let to_delete = inode.children.get(&name).ok_or(SystemError::ENOENT)?; - - // 减少硬链接计数 - to_delete.0.lock().metadata.nlinks -= 1; - - // 在当前目录中删除这个子目录项 - inode.children.remove(&name); - - return Ok(()); - } - - fn move_to( - &self, - _old_name: &str, - _target: &Arc, - _new_name: &str, - _flag: RenameFlags, - ) -> Result<(), SystemError> { - return Err(SystemError::ENOSYS); - } - - fn find(&self, name: &str) -> Result, SystemError> { - if self.0.lock().metadata.file_type != FileType::Dir { - return Err(SystemError::ENOTDIR); - } - - match name { - "" | "." => { - return Ok(self - .0 - .lock() - .self_ref - .upgrade() - .ok_or(SystemError::ENOENT)?); - } - - ".." => { - return Ok(self.0.lock().parent.upgrade().ok_or(SystemError::ENOENT)?); - } - - name => { - if self.0.lock().fdata.ftype == ProcFileType::ProcFdDir { - return self.dynamical_find_fd(name); - } - // 在子目录项中查找 - return Ok(self - .0 - .lock() - .children - .get(&DName::from(name)) - .ok_or(SystemError::ENOENT)? - .clone()); - } - } - } - - fn get_entry_name(&self, ino: InodeId) -> Result { - let inode: SpinLockGuard = self.0.lock(); - if inode.metadata.file_type != FileType::Dir { - return Err(SystemError::ENOTDIR); - } - - match ino.into() { - 0 => { - return Ok(String::from(".")); - } - 1 => { - return Ok(String::from("..")); - } - ino => { - // 暴力遍历所有的children,判断inode id是否相同 - // TODO: 优化这里,这个地方性能很差! - let mut key: Vec = inode - .children - .iter() - .filter_map(|(k, v)| { - if v.0.lock().metadata.inode_id.into() == ino { - Some(k.to_string()) - } else { - None - } - }) - .collect(); - - match key.len() { - 0 => { - return Err(SystemError::ENOENT); - } - 1 => { - return Ok(key.remove(0)); - } - _ => panic!( - "Procfs get_entry_name: key.len()={key_len}>1, current inode_id={inode_id:?}, to find={to_find:?}", - key_len = key.len(), - inode_id = inode.metadata.inode_id, - to_find = ino - ), - } - } - } - } - - fn list(&self) -> Result, SystemError> { - let info = self.metadata()?; - if info.file_type != FileType::Dir { - return Err(SystemError::ENOTDIR); - } - - let mut keys = Vec::new(); - keys.push(String::from(".")); - keys.push(String::from("..")); - - if self.0.lock().fdata.ftype == ProcFileType::ProcFdDir { - // 对于 /proc/self/fd 目录,需要包含 "." 和 "..",然后添加所有fd - let mut fd_list = self.dynamical_list_fd()?; - keys.append(&mut fd_list); - return Ok(keys); - } - - keys.append( - &mut self - .0 - .lock() - .children - .keys() - .map(ToString::to_string) - .collect(), - ); - - return Ok(keys); - } - - fn dname(&self) -> Result { - Ok(self.0.lock().dname.clone()) - } -} - -/// @brief 向procfs注册进程 -#[inline(never)] -pub fn procfs_register_pid(pid: RawPid) -> Result<(), SystemError> { - let root_inode = ProcessManager::current_mntns().root_inode(); - let procfs_inode = root_inode.find("proc")?; - - let procfs_inode = procfs_inode - .downcast_ref::() - .expect("Failed to find procfs' root inode"); - let fs = procfs_inode.fs(); - let procfs: &ProcFS = fs.as_any_ref().downcast_ref::().unwrap(); - - // 调用注册函数 - procfs.register_pid(pid)?; - - Ok(()) -} - -/// @brief 在ProcFS中,解除进程的注册 -#[inline(never)] -pub fn procfs_unregister_pid(pid: RawPid) -> Result<(), SystemError> { - let root_inode = ProcessManager::current_mntns().root_inode(); - // 获取procfs实例 - let procfs_inode: Arc = root_inode.find("proc")?; - - let procfs_inode: &LockedProcFSInode = procfs_inode - .downcast_ref::() - .expect("Failed to find procfs' root inode"); - let fs: Arc = procfs_inode.fs(); - let procfs: &ProcFS = fs.as_any_ref().downcast_ref::().unwrap(); - - // 调用解除注册函数 - return procfs.unregister_pid(pid); -} - +/// 初始化 ProcFS pub fn procfs_init() -> Result<(), SystemError> { static INIT: Once = Once::new(); let mut result = None; INIT.call_once(|| { - info!("Initializing ProcFS..."); + ::log::info!("Initializing ProcFS..."); // 创建 procfs 实例 let procfs: Arc = ProcFS::new(); let root_inode = ProcessManager::current_mntns().root_inode(); // procfs 挂载 let mntfs = root_inode .mkdir("proc", ModeType::from_bits_truncate(0o755)) - .expect("Unabled to find /proc") + .expect("Unable to create /proc") .mount(procfs, MountFlags::empty()) .expect("Failed to mount at /proc"); let ino = root_inode.metadata().unwrap().inode_id; @@ -1265,7 +97,7 @@ pub fn procfs_init() -> Result<(), SystemError> { ProcessManager::current_mntns() .add_mount(Some(ino), mount_path, mntfs) .expect("Failed to add mount for /proc"); - info!("ProcFS mounted."); + ::log::info!("ProcFS mounted at /proc"); result = Some(Ok(())); }); diff --git a/kernel/src/filesystem/procfs/pid/mod.rs b/kernel/src/filesystem/procfs/pid/mod.rs index bf812a250..0dfeaff83 100644 --- a/kernel/src/filesystem/procfs/pid/mod.rs +++ b/kernel/src/filesystem/procfs/pid/mod.rs @@ -14,7 +14,7 @@ use crate::{ }; use alloc::{ collections::BTreeMap, - string::{String,ToString}, + string::{String, ToString}, sync::{Arc, Weak}, }; use system_error::SystemError; @@ -81,7 +81,8 @@ impl PidDirOps { fn populate_children<'a>( &self, dir: &'a ProcDir, - ) -> RwLockReadGuard<'a, BTreeMap>> { + ) -> RwLockReadGuard<'a, BTreeMap>> + { dir.cached_children().write().downgrade() } } diff --git a/kernel/src/filesystem/procfs/root.rs b/kernel/src/filesystem/procfs/root.rs index df55ff231..8e15cfacf 100644 --- a/kernel/src/filesystem/procfs/root.rs +++ b/kernel/src/filesystem/procfs/root.rs @@ -19,13 +19,9 @@ use crate::{ version::VersionFileOps, Builder, PROCFS_BLOCK_SIZE, PROCFS_MAX_NAMELEN, }, - vfs::{ - mount::{MountFlags, MountPath}, - syscall::ModeType, - IndexNode, - }, + vfs::{syscall::ModeType, IndexNode}, }, - libs::{once::Once, rwlock::RwLockReadGuard}, + libs::rwlock::RwLockReadGuard, process::{ProcessManager, RawPid}, }; use alloc::{ @@ -42,7 +38,7 @@ pub struct RootDirOps; // drop 的时候把对应pid的文件夹删除 impl RootDirOps { - pub fn new_inode(fs: Weak) -> Arc { + pub fn new_inode(fs: Weak) -> Arc { //todo 这里要注册一个observer,用于动态创建进程目录 ProcDirBuilder::new(Self, ModeType::from_bits_truncate(0o555)) @@ -145,15 +141,15 @@ impl DirOps for RootDirOps { use crate::filesystem::vfs::{FileSystem, FsInfo, Magic, SuperBlock}; use crate::libs::rwlock::RwLock; -/// procfs 文件系统 +/// ProcFS 文件系统 #[derive(Debug)] -pub struct TestProcFS { +pub struct ProcFS { /// procfs 的 root inode root_inode: Arc, super_block: RwLock, } -impl TestProcFS { +impl ProcFS { pub fn new() -> Arc { let super_block = SuperBlock::new( Magic::PROC_MAGIC, @@ -161,7 +157,7 @@ impl TestProcFS { PROCFS_MAX_NAMELEN as u64, ); - let fs: Arc = Arc::new_cyclic(|weak_fs| TestProcFS { + let fs: Arc = Arc::new_cyclic(|weak_fs| ProcFS { super_block: RwLock::new(super_block), root_inode: RootDirOps::new_inode(weak_fs.clone()), }); @@ -170,7 +166,7 @@ impl TestProcFS { } } -impl FileSystem for TestProcFS { +impl FileSystem for ProcFS { fn root_inode(&self) -> Arc { self.root_inode.clone() } @@ -187,115 +183,10 @@ impl FileSystem for TestProcFS { } fn name(&self) -> &str { - "testprocfs" + "procfs" } fn super_block(&self) -> SuperBlock { self.super_block.read().clone() } } - -pub(crate) fn test_procfs_init() -> Result<(), SystemError> { - static INIT: Once = Once::new(); - let mut result = None; - INIT.call_once(|| { - ::log::info!("Initializing TestProcFS..."); - // 创建 procfs 实例 - let procfs: Arc = TestProcFS::new(); - let root_inode = ProcessManager::current_mntns().root_inode(); - // procfs 挂载 - let mntfs = root_inode - .mkdir("testproc", ModeType::from_bits_truncate(0o755)) - .expect("Unabled to find /testproc") - .mount(procfs, MountFlags::empty()) - .expect("Failed to mount at /testproc"); - let ino = root_inode.metadata().unwrap().inode_id; - let mount_path = Arc::new(MountPath::from("/testproc")); - ProcessManager::current_mntns() - .add_mount(Some(ino), mount_path, mntfs) - .expect("Failed to add mount for /testproc"); - ::log::info!("TestProcFS mounted."); - result = Some(Ok(())); - }); - - return result.unwrap(); -} - -// #[derive(Debug)] -// struct ProcRootDirOps; - -// impl ProcRootDirOps { -// pub fn new_inode(fs: Weak) -> Arc { -// //todo 这里要注册一个observer,用于动态创建进程目录 - -// ProcDirBuilder::new(Self, ModeType::from_bits_truncate(0o555)) -// .fs(fs) -// .build() -// .unwrap() -// } - -// #[expect(clippy::type_complexity)] -// const STATIC_ENTRIES: &'static [( -// &'static str, -// fn(Weak) -> Arc, -// )] = &[("cpuinfo", CpuInfoFileOps::new_inode)]; -// } - -// impl DirOps for ProcRootDirOps { -// fn lookup_child( -// &self, -// dir: &template::ProcDir, -// name: &str, -// ) -> Result, SystemError> { -// if let Ok(pid) = name.parse::() { -// let all_processes = all_process().lock_irqsave(); -// if let Some(process_ref) = all_processes.as_ref().unwrap().get(&pid) { -// let mut cached_children = dir.cached_children().write(); - -// // put the child into cache if not exists -// if let Some(child) = cached_children.get(name) { -// return Ok(child.clone()); -// } else { -// let inode = -// PidDirOps::new_inode(process_ref.clone(), dir.self_ref_weak().clone()); -// cached_children.insert(name.to_string(), inode.clone()); -// return Ok(inode); -// } -// } -// } - -// let mut cached_children = dir.cached_children().write(); - -// if let Some(child) = -// lookup_child_from_table(name, &mut cached_children, Self::STATIC_ENTRIES, |f| { -// (f)(dir.self_ref_weak().clone()) -// }) -// { -// return Ok(child); -// } - -// Err(SystemError::ENOENT) -// } - -// fn populate_children<'a>( -// &self, -// dir: &'a template::ProcDir, -// ) -> crate::libs::rwlock::RwLockReadGuard<'a, BTreeMap>> { -// let all_processes = all_process().lock_irqsave(); -// let mut cached_children = dir.cached_children().write(); - -// for (pid, process_ref) in all_processes.as_ref().unwrap().iter() { -// cached_children.entry(pid.to_string()).or_insert_with(|| { -// PidDirOps::new_inode(process_ref.clone(), dir.self_ref_weak().clone()) -// }); -// } - -// drop(all_processes); - -// populate_children_from_table(&mut cached_children, Self::STATIC_ENTRIES, |f| { -// (f)(dir.self_ref_weak().clone()) -// }); - -// cached_children.downgrade() -// } -// } diff --git a/kernel/src/filesystem/procfs/template/sym.rs b/kernel/src/filesystem/procfs/template/sym.rs index 608bacfec..c67e9809e 100644 --- a/kernel/src/filesystem/procfs/template/sym.rs +++ b/kernel/src/filesystem/procfs/template/sym.rs @@ -3,16 +3,17 @@ use crate::{ filesystem::{ procfs::template::Common, vfs::{ - FilePrivateData, FileSystem, FileType, IndexNode, Metadata, file::FileMode, syscall::ModeType, vcore::generate_inode_id + file::FileMode, syscall::ModeType, vcore::generate_inode_id, FilePrivateData, + FileSystem, FileType, IndexNode, Metadata, }, }, libs::spinlock::SpinLockGuard, time::PosixTimeSpec, }; use alloc::fmt::Debug; +use alloc::string::String; use alloc::sync::{Arc, Weak}; use alloc::vec::Vec; -use alloc::string::String; use inherit_methods_macro::inherit_methods; use system_error::SystemError; diff --git a/kernel/src/filesystem/vfs/vcore.rs b/kernel/src/filesystem/vfs/vcore.rs index 7f4ef7775..c885aa8f9 100644 --- a/kernel/src/filesystem/vfs/vcore.rs +++ b/kernel/src/filesystem/vfs/vcore.rs @@ -4,7 +4,6 @@ use alloc::sync::Arc; use log::{error, info}; use system_error::SystemError; -use crate::filesystem::procfs::root::test_procfs_init; use crate::libs::casting::DowncastArc; use crate::{ define_event_trace, @@ -59,9 +58,6 @@ pub fn vfs_init() -> Result<(), SystemError> { sysfs_init().expect("Failed to initialize sysfs"); - // TestProcFS 应该在文件系统迁移之后初始化 - // test_procfs_init().expect("Failed to initialize test procfs"); - let root_entries = ProcessManager::current_mntns() .root_inode() .list() @@ -109,9 +105,6 @@ fn migrate_virtual_filesystem(new_fs: Arc) -> Result<(), SystemE .mount_from(old_root_inode.find("sys").expect("sys not mounted!")) .expect("Failed to migrate filesystem of sys"); - // TestProcFS 不需要迁移,因为它是在新文件系统上直接挂载的 - // 如果需要 testproc,应该在迁移完成后重新挂载 - unsafe { current_mntns.force_change_root_mountfs(new_fs); } @@ -159,17 +152,13 @@ pub fn mount_root_fs() -> Result<(), SystemError> { let r = migrate_virtual_filesystem(fatfs); if r.is_err() { - error!("Failed to migrate virtual filesyst em to FAT32!"); + error!("Failed to migrate virtual filesystem to FAT32!"); loop { spin_loop(); } } info!("Successfully migrate rootfs to FAT32!"); - // 在文件系统迁移完成后初始化 TestProcFS - test_procfs_init().expect("Failed to initialize test procfs"); - info!("TestProcFS initialized after rootfs migration."); - return Ok(()); } @@ -187,10 +176,6 @@ pub fn change_root_fs() -> Result<(), SystemError> { } info!("Successfully migrate rootfs to initramfs!"); - // 在文件系统迁移完成后初始化 TestProcFS - test_procfs_init().expect("Failed to initialize test procfs"); - info!("TestProcFS initialized after rootfs migration."); - return Ok(()); } diff --git a/kernel/src/process/fork.rs b/kernel/src/process/fork.rs index 5953a1136..da80e4a03 100644 --- a/kernel/src/process/fork.rs +++ b/kernel/src/process/fork.rs @@ -16,7 +16,6 @@ use system_error::SystemError; use crate::{ arch::{interrupt::TrapFrame, ipc::signal::Signal}, - filesystem::procfs::procfs_register_pid, ipc::signal_types::SignalFlags, libs::rwlock::RwLock, mm::VirtAddr, @@ -225,15 +224,6 @@ impl ProcessManager { // ); // } - // 向procfs注册进程 - procfs_register_pid(pcb.raw_pid()).unwrap_or_else(|e| { - panic!( - "fork: Failed to register pid to procfs, pid: [{:?}]. Error: {:?}", - pcb.raw_pid(), - e - ) - }); - pcb.sched_info().set_on_cpu(Some(smp_get_processor_id())); ProcessManager::wakeup(&pcb).unwrap_or_else(|e| { diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 915ae0e7a..f70e84dc4 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -31,7 +31,6 @@ use crate::{ exception::InterruptArch, filesystem::{ fs::FsStruct, - procfs::procfs_unregister_pid, vfs::{file::FileDescriptorVec, FileType, IndexNode}, }, ipc::{ @@ -1703,9 +1702,8 @@ impl Drop for ProcessControlBlock { let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; // log::debug!("Drop ProcessControlBlock: pid: {}", self.raw_pid(),); self.__exit_signal(); - // 在ProcFS中,解除进程的注册 - // 这里忽略错误,因为进程可能未注册到procfs - procfs_unregister_pid(self.raw_pid()).ok(); + // 新的 ProcFS 是动态的,进程目录会在访问时按需创建 + // 不再需要显式注册/注销进程 if let Some(ppcb) = self.parent_pcb.read_irqsave().upgrade() { ppcb.children .write_irqsave() diff --git a/kernel/src/process/syscall/clone_utils.rs b/kernel/src/process/syscall/clone_utils.rs index a8851808f..d4e02639b 100644 --- a/kernel/src/process/syscall/clone_utils.rs +++ b/kernel/src/process/syscall/clone_utils.rs @@ -4,7 +4,6 @@ use crate::arch::interrupt::TrapFrame; use crate::arch::ipc::signal::Signal; use crate::arch::ipc::signal::MAX_SIG_NUM; use crate::arch::MMArch; -use crate::filesystem::procfs::procfs_register_pid; use crate::mm::{MemoryManagementArch, VirtAddr}; use crate::process::fork::{CloneFlags, KernelCloneArgs, MAX_PID_NS_LEVEL}; use crate::process::{KernelStack, ProcessControlBlock, ProcessManager}; @@ -78,14 +77,8 @@ pub fn do_clone( // 克隆pcb ProcessManager::copy_process(¤t_pcb, &pcb, clone_args, frame)?; - // 向procfs注册进程 - procfs_register_pid(pcb.raw_pid()).unwrap_or_else(|e| { - panic!( - "fork: Failed to register pid to procfs, pid: [{:?}]. Error: {:?}", - pcb.raw_pid(), - e - ) - }); + // 新的 ProcFS 是动态的,进程目录会在访问时按需创建 + // 不再需要显式注册进程 if flags.contains(CloneFlags::CLONE_VFORK) { pcb.thread.write_irqsave().vfork_done = Some(vfork.clone());