From 50bbcae01a986b23dc9fe49ec0d4bde35c23173d Mon Sep 17 00:00:00 2001 From: linfeng Date: Tue, 22 Apr 2025 01:58:44 +0800 Subject: [PATCH] feat:Add tracepoint prototype (#1088) * feat:Add tracepoint prototype Signed-off-by: Godones --- kernel/Cargo.lock | 155 +++++++++++++-- kernel/Cargo.toml | 2 +- kernel/src/arch/loongarch64/link.ld | 10 + kernel/src/arch/riscv64/link.ld | 10 + kernel/src/arch/x86_64/link.lds | 10 + kernel/src/debug/.gitignore | 3 +- kernel/src/debug/mod.rs | 2 + kernel/src/debug/sysfs/mod.rs | 28 +++ kernel/src/debug/tracing/events.rs | 239 +++++++++++++++++++++++ kernel/src/debug/tracing/mod.rs | 97 +++++++++ kernel/src/debug/tracing/trace_pipe.rs | 123 ++++++++++++ kernel/src/debug/tracing/tracepoint.rs | 187 ++++++++++++++++++ kernel/src/filesystem/kernfs/callback.rs | 23 ++- kernel/src/filesystem/vfs/core.rs | 6 +- 14 files changed, 869 insertions(+), 26 deletions(-) create mode 100644 kernel/src/debug/sysfs/mod.rs create mode 100644 kernel/src/debug/tracing/events.rs create mode 100644 kernel/src/debug/tracing/mod.rs create mode 100644 kernel/src/debug/tracing/trace_pipe.rs create mode 100644 kernel/src/debug/tracing/tracepoint.rs diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 0588552d0..0abe04081 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -212,7 +212,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe05a1a3c09033e9e87f7ba13af35cf2508148d3a97fb6b16475df84207993fa" dependencies = [ "libc", - "windows", + "windows 0.58.0", ] [[package]] @@ -1498,14 +1498,14 @@ dependencies = [ [[package]] name = "static-keys" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ae6eb9d5e3c88a62145a3f2edd2e45c296bad8ef3e31b06d654acff70272744" +checksum = "aa784228d57f9f47a0f5837289ba92296239c2273f146d97b35bbd8538806777" dependencies = [ "clear-cache", "libc", "mach2", - "windows", + "windows 0.59.0", ] [[package]] @@ -1972,23 +1972,46 @@ version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ - "windows-core", + "windows-core 0.58.0", "windows-targets 0.52.6", ] +[[package]] +name = "windows" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1" +dependencies = [ + "windows-core 0.59.0", + "windows-targets 0.53.0", +] + [[package]] name = "windows-core" version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" dependencies = [ - "windows-implement", - "windows-interface", - "windows-result", - "windows-strings", + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", + "windows-strings 0.1.0", "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce" +dependencies = [ + "windows-implement 0.59.0", + "windows-interface 0.59.1", + "windows-result 0.3.2", + "windows-strings 0.3.1", + "windows-targets 0.53.0", +] + [[package]] name = "windows-implement" version = "0.58.0" @@ -2000,6 +2023,17 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "windows-implement" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "windows-interface" version = "0.58.0" @@ -2011,6 +2045,23 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + [[package]] name = "windows-result" version = "0.2.0" @@ -2020,16 +2071,34 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-result" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-strings" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows-result", + "windows-result 0.2.0", "windows-targets 0.52.6", ] +[[package]] +name = "windows-strings" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -2072,13 +2141,29 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -2091,6 +2176,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -2103,6 +2194,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -2115,12 +2212,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -2133,6 +2242,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -2145,6 +2260,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -2157,6 +2278,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -2169,6 +2296,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" version = "0.7.4" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 822aaba29..ca69ba04b 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -75,7 +75,7 @@ lru = "0.12.3" rbpf = { path = "crates/rbpf" } printf-compat = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/printf-compat", rev = "5f5c9cc363", default-features = false } -static-keys = "=0.6.1" +static-keys = { version = "=0.7" } defer = "0.2.1" cfg-if = { version = "1.0.0" } diff --git a/kernel/src/arch/loongarch64/link.ld b/kernel/src/arch/loongarch64/link.ld index f710ad62b..a567adba2 100644 --- a/kernel/src/arch/loongarch64/link.ld +++ b/kernel/src/arch/loongarch64/link.ld @@ -66,6 +66,16 @@ SECTIONS } . = ALIGN(32768); + + trace_point_start_pa = .; + .tracepoint (trace_point_start_pa): AT(trace_point_start_pa - KERNEL_VMA) + { + _tracepoint = .; + *(.tracepoint) + *(.tracepoint.*) + _etracepoint = .; + } + . = ALIGN(32768); init_proc_union_start_pa = .; .data.init_proc_union (init_proc_union_start_pa): diff --git a/kernel/src/arch/riscv64/link.ld b/kernel/src/arch/riscv64/link.ld index 0f88eaefe..1a726a658 100644 --- a/kernel/src/arch/riscv64/link.ld +++ b/kernel/src/arch/riscv64/link.ld @@ -68,6 +68,16 @@ SECTIONS . = ALIGN(32768); + trace_point_start_pa = .; + .tracepoint (trace_point_start_pa): AT(trace_point_start_pa - KERNEL_VMA) + { + _tracepoint = .; + *(.tracepoint) + *(.tracepoint.*) + _etracepoint = .; + } + . = ALIGN(32768); + init_proc_union_start_pa = .; .data.init_proc_union (init_proc_union_start_pa): AT(init_proc_union_start_pa - KERNEL_VMA) { *(.data.init_proc_union) } diff --git a/kernel/src/arch/x86_64/link.lds b/kernel/src/arch/x86_64/link.lds index 8c9ef16be..04e058805 100644 --- a/kernel/src/arch/x86_64/link.lds +++ b/kernel/src/arch/x86_64/link.lds @@ -67,6 +67,16 @@ SECTIONS . = ALIGN(32768); + trace_point_start_pa = .; + .tracepoint (trace_point_start_pa): AT(trace_point_start_pa - KERNEL_VMA) + { + _tracepoint = .; + *(.tracepoint) + *(.tracepoint.*) + _etracepoint = .; + } + . = ALIGN(32768); + init_proc_union_start_pa = .; .data.init_proc_union (init_proc_union_start_pa): AT(init_proc_union_start_pa - KERNEL_VMA) { *(.data.init_proc_union) } diff --git a/kernel/src/debug/.gitignore b/kernel/src/debug/.gitignore index 3a71f44dd..4b1e76761 100644 --- a/kernel/src/debug/.gitignore +++ b/kernel/src/debug/.gitignore @@ -1,2 +1,3 @@ gen_kallsyms -kallsyms.S \ No newline at end of file +kallsyms.S +kallsyms diff --git a/kernel/src/debug/mod.rs b/kernel/src/debug/mod.rs index 16d0a1a43..23bc112cf 100644 --- a/kernel/src/debug/mod.rs +++ b/kernel/src/debug/mod.rs @@ -2,4 +2,6 @@ pub mod jump_label; pub mod klog; pub mod kprobe; pub mod panic; +pub mod sysfs; pub mod traceback; +pub mod tracing; diff --git a/kernel/src/debug/sysfs/mod.rs b/kernel/src/debug/sysfs/mod.rs new file mode 100644 index 000000000..0557b04b7 --- /dev/null +++ b/kernel/src/debug/sysfs/mod.rs @@ -0,0 +1,28 @@ +use crate::driver::base::kset::KSet; +use crate::init::initcall::INITCALL_POSTCORE; +use crate::misc::ksysfs::sys_kernel_kset; +use alloc::string::ToString; +use alloc::sync::Arc; +use system_error::SystemError; +use unified_init::macros::unified_init; + +/// `/sys/kernel/debug`的kset +static mut SYS_KERNEL_DEBUG_KSET_INSTANCE: Option> = None; + +/// 初始化debug模块在sysfs中的目录 +#[unified_init(INITCALL_POSTCORE)] +fn debugfs_init() -> Result<(), SystemError> { + let debug_kset = KSet::new("debug".to_string()); + debug_kset + .register(Some(sys_kernel_kset())) + .expect("register debug kset failed"); + unsafe { + SYS_KERNEL_DEBUG_KSET_INSTANCE = Some(debug_kset); + } + super::tracing::init_debugfs_tracing()?; + return Ok(()); +} + +pub fn debugfs_kset() -> Arc { + unsafe { SYS_KERNEL_DEBUG_KSET_INSTANCE.clone().unwrap() } +} diff --git a/kernel/src/debug/tracing/events.rs b/kernel/src/debug/tracing/events.rs new file mode 100644 index 000000000..3b3223d90 --- /dev/null +++ b/kernel/src/debug/tracing/events.rs @@ -0,0 +1,239 @@ +use crate::debug::tracing::tracepoint::{CommonTracePointMeta, TracePoint}; +use crate::debug::tracing::TracingDirCallBack; +use crate::filesystem::kernfs::callback::{KernCallbackData, KernFSCallback, KernInodePrivateData}; +use crate::filesystem::kernfs::KernFSInode; +use crate::filesystem::vfs::syscall::ModeType; +use crate::filesystem::vfs::PollStatus; +use crate::libs::spinlock::SpinLock; +use alloc::boxed::Box; +use alloc::collections::BTreeMap; +use alloc::string::{String, ToString}; +use alloc::sync::Arc; +use system_error::SystemError; + +#[derive(Debug)] +pub struct TracingEventsManager { + root: Arc, + subsystems: SpinLock>>, +} + +impl TracingEventsManager { + pub fn new(root: Arc) -> Self { + Self { + root, + subsystems: SpinLock::new(BTreeMap::new()), + } + } + + /// Create a subsystem by name + /// + /// If the subsystem already exists, return the existing subsystem. + pub fn create_subsystem( + &self, + subsystem_name: &str, + ) -> Result, SystemError> { + if self.subsystems.lock().contains_key(subsystem_name) { + return Ok(self.get_subsystem(subsystem_name).unwrap()); + } + let dir = self.root.add_dir( + subsystem_name.to_string(), + ModeType::from_bits_truncate(0o755), + None, + Some(&TracingDirCallBack), + )?; + let subsystem = Arc::new(EventsSubsystem::new(dir)); + self.subsystems + .lock() + .insert(subsystem_name.to_string(), subsystem.clone()); + Ok(subsystem) + } + + /// Get the subsystem by name + pub fn get_subsystem(&self, subsystem_name: &str) -> Option> { + self.subsystems.lock().get(subsystem_name).cloned() + } +} + +#[derive(Debug)] +pub struct EventsSubsystem { + root: Arc, + events: SpinLock>>, +} + +impl EventsSubsystem { + pub fn new(root: Arc) -> Self { + Self { + root, + events: SpinLock::new(BTreeMap::new()), + } + } + + /// Insert a new event into the subsystem + pub fn insert_event( + &self, + event_name: &str, + event_info: Arc, + ) -> Result<(), SystemError> { + self.events + .lock() + .insert(event_name.to_string(), event_info); + Ok(()) + } + + /// Get the event by name + #[allow(unused)] + pub fn get_event(&self, event_name: &str) -> Option> { + self.events.lock().get(event_name).cloned() + } + + /// Get the root inode of the subsystem + pub fn root(&self) -> Arc { + self.root.clone() + } +} + +#[derive(Debug)] +pub struct EventInfo { + #[allow(unused)] + enable: Arc, + // filter: Arc, + // trigger: Arc, +} + +impl EventInfo { + pub fn new(tracepoint: &'static TracePoint, subsystem: Arc) -> Arc { + let trace_dir = subsystem + .add_dir( + tracepoint.name().to_string(), + ModeType::from_bits_truncate(0o755), + None, + Some(&TracingDirCallBack), + ) + .expect("add tracepoint dir failed"); + let enable_inode = trace_dir + .add_file( + "enable".to_string(), + ModeType::from_bits_truncate(0o644), + None, + Some(KernInodePrivateData::DebugFS(tracepoint)), + Some(&EnableCallBack), + ) + .expect("add enable file failed"); + + Arc::new(Self { + enable: enable_inode, + }) + } +} + +impl Drop for EventInfo { + fn drop(&mut self) {} +} + +#[derive(Debug)] +struct EnableCallBack; + +impl KernFSCallback for EnableCallBack { + fn open(&self, _data: KernCallbackData) -> Result<(), SystemError> { + Ok(()) + } + + fn read( + &self, + data: KernCallbackData, + buf: &mut [u8], + offset: usize, + ) -> Result { + if offset > 0 { + return Ok(0); + } + let pri_data = data.private_data(); + match pri_data { + Some(pri_data) => { + let tracepoint = pri_data.debugfs_tracepoint().ok_or(SystemError::EINVAL)?; + let buf_value = if tracepoint.is_enabled() { b"1" } else { b"0" }; + let len = buf.len().min(buf_value.len()); + buf[..len].copy_from_slice(&buf_value[..len]); + Ok(len) + } + None => { + return Err(SystemError::EINVAL); + } + } + } + + fn write( + &self, + data: KernCallbackData, + buf: &[u8], + _offset: usize, + ) -> Result { + let pri_data = data.private_data(); + match pri_data { + Some(pri_data) => { + let tracepoint = pri_data.debugfs_tracepoint().ok_or(SystemError::EINVAL)?; + let value = core::str::from_utf8(buf) + .map_err(|_| SystemError::EINVAL)? + .trim(); + match value { + "0" => { + tracepoint.disable(); + } + "1" => { + tracepoint.enable(); + } + _ => { + log::info!("EnableCallBack invalid value: {}", value); + return Err(SystemError::EINVAL); + } + } + Ok(buf.len()) + } + None => { + return Err(SystemError::EINVAL); + } + } + } + + fn poll(&self, _data: KernCallbackData) -> Result { + Err(SystemError::ENOSYS) + } +} + +static mut TRACING_EVENTS_MANAGER: Option = None; + +/// Initialize the tracing events +pub fn init_events(events_root: Arc) -> Result<(), SystemError> { + let events_manager = TracingEventsManager::new(events_root); + let tracepoint_data_start = _tracepoint as usize as *const CommonTracePointMeta; + let tracepoint_data_end = _etracepoint as usize as *const CommonTracePointMeta; + let tracepoint_data_len = (tracepoint_data_end as usize - tracepoint_data_start as usize) + / size_of::(); + let tracepoint_data = + unsafe { core::slice::from_raw_parts(tracepoint_data_start, tracepoint_data_len) }; + for tracepoint_meta in tracepoint_data { + let tracepoint = tracepoint_meta.trace_point; + tracepoint.register(tracepoint_meta.print_func, Box::new(())); + log::info!( + "tracepoint name: {}, module path: {}", + tracepoint.name(), + tracepoint.module_path() + ); + // kernel::{subsystem}:: + let mut subsys_name = tracepoint.module_path().split("::"); + let subsys_name = subsys_name.nth(1).ok_or(SystemError::EINVAL)?; + let subsys = events_manager.create_subsystem(subsys_name)?; + let event_info = EventInfo::new(tracepoint, subsys.root()); + subsys.insert_event(tracepoint.name(), event_info)?; + } + + unsafe { + TRACING_EVENTS_MANAGER = Some(events_manager); + } + + Ok(()) +} +extern "C" { + fn _tracepoint(); + fn _etracepoint(); +} diff --git a/kernel/src/debug/tracing/mod.rs b/kernel/src/debug/tracing/mod.rs new file mode 100644 index 000000000..d2235a29e --- /dev/null +++ b/kernel/src/debug/tracing/mod.rs @@ -0,0 +1,97 @@ +mod events; +pub mod trace_pipe; +pub mod tracepoint; + +use crate::debug::sysfs::debugfs_kset; +use crate::debug::tracing::trace_pipe::TRACE_PIPE_MAX_RECORD; +use crate::driver::base::kobject::KObject; +use crate::filesystem::kernfs::callback::{KernCallbackData, KernFSCallback, KernInodePrivateData}; +use crate::filesystem::kernfs::KernFSInode; +use crate::filesystem::vfs::syscall::ModeType; +use crate::filesystem::vfs::PollStatus; +use alloc::string::ToString; +use alloc::sync::Arc; +use system_error::SystemError; +use tracepoint::TracePoint; + +static mut TRACING_ROOT_INODE: Option> = None; + +#[allow(unused)] +fn tracing_root_inode() -> Arc { + unsafe { TRACING_ROOT_INODE.clone().unwrap() } +} + +/// Initialize the debugfs tracing directory +pub fn init_debugfs_tracing() -> Result<(), SystemError> { + let debugfs = debugfs_kset(); + let root_dir = debugfs.inode().ok_or(SystemError::ENOENT)?; + let tracing_root = root_dir.add_dir( + "tracing".to_string(), + ModeType::from_bits_truncate(0o555), + None, + Some(&TracingDirCallBack), + )?; + let events_root = tracing_root.add_dir( + "events".to_string(), + ModeType::from_bits_truncate(0o755), + None, + Some(&TracingDirCallBack), + )?; + + tracing_root.add_file( + "trace_pipe".to_string(), + ModeType::from_bits_truncate(0o444), + Some(TRACE_PIPE_MAX_RECORD), + None, + Some(&trace_pipe::TracePipeCallBack), + )?; + + trace_pipe::init_trace_pipe(); + + events::init_events(events_root)?; + + unsafe { + TRACING_ROOT_INODE = Some(tracing_root); + } + Ok(()) +} + +#[derive(Debug)] +pub struct TracingDirCallBack; + +impl KernFSCallback for TracingDirCallBack { + fn open(&self, _data: KernCallbackData) -> Result<(), SystemError> { + Ok(()) + } + + fn read( + &self, + _data: KernCallbackData, + _buf: &mut [u8], + _offset: usize, + ) -> Result { + Err(SystemError::EISDIR) + } + + fn write( + &self, + _data: KernCallbackData, + _buf: &[u8], + _offset: usize, + ) -> Result { + Err(SystemError::EISDIR) + } + + fn poll(&self, _data: KernCallbackData) -> Result { + Err(SystemError::EISDIR) + } +} + +impl KernInodePrivateData { + pub fn debugfs_tracepoint(&self) -> Option<&'static TracePoint> { + return match self { + KernInodePrivateData::DebugFS(tracepoint) => Some(tracepoint), + _ => None, + }; + } +} diff --git a/kernel/src/debug/tracing/trace_pipe.rs b/kernel/src/debug/tracing/trace_pipe.rs new file mode 100644 index 000000000..7c5c8a4ee --- /dev/null +++ b/kernel/src/debug/tracing/trace_pipe.rs @@ -0,0 +1,123 @@ +use crate::filesystem::kernfs::callback::{KernCallbackData, KernFSCallback}; +use crate::filesystem::vfs::PollStatus; +use crate::libs::spinlock::SpinLock; +use alloc::string::String; +use alloc::vec::Vec; +use core::fmt::Debug; +use system_error::SystemError; + +static mut TRACE_PIPE: Option = None; + +pub const TRACE_PIPE_MAX_RECORD: usize = 4096; + +pub fn init_trace_pipe() { + unsafe { + TRACE_PIPE = Some(TracePipe::new(TRACE_PIPE_MAX_RECORD)); + } +} + +pub fn trace_pipe() -> &'static TracePipe { + unsafe { TRACE_PIPE.as_ref().unwrap() } +} + +/// Push a record to trace pipe +pub fn trace_pipe_push_record(record: String) { + trace_pipe().push_record(record); +} + +pub struct TracePipe { + buf: SpinLock, +} + +struct TracePipeBuf { + size: usize, + max_record: usize, + buf: Vec, +} + +impl TracePipeBuf { + pub const fn new(max_record: usize) -> Self { + Self { + max_record, + size: 0, + buf: Vec::new(), + } + } + + pub fn push_str(&mut self, record: String) { + let record_size = record.len(); + if self.size + record_size > self.max_record { + let mut i = 0; + while i < record_size { + let t = self.buf.pop().unwrap(); + self.size -= t.len(); + i += t.len(); + } + } + self.buf.push(record); + self.size += record_size; + } + + pub fn read_at(&self, buf: &mut [u8], offset: usize) -> Result { + if offset == self.size { + return Ok(0); + } + if buf.len() < self.size { + return Err(SystemError::EINVAL); + } + let mut count = 0; + for line in self.buf.iter() { + let line = line.as_bytes(); + buf[count..count + line.len()].copy_from_slice(line); + count += line.len(); + } + Ok(count) + } +} + +impl TracePipe { + pub const fn new(max_record: usize) -> Self { + Self { + buf: SpinLock::new(TracePipeBuf::new(max_record)), + } + } + pub fn push_record(&self, record: String) { + self.buf.lock().push_str(record); + } + + pub fn read_at(&self, buf: &mut [u8], offset: usize) -> Result { + self.buf.lock().read_at(buf, offset) + } +} + +#[derive(Debug)] +pub struct TracePipeCallBack; + +impl KernFSCallback for TracePipeCallBack { + fn open(&self, _data: KernCallbackData) -> Result<(), SystemError> { + Ok(()) + } + + fn read( + &self, + _data: KernCallbackData, + buf: &mut [u8], + offset: usize, + ) -> Result { + let trace_pipe = trace_pipe(); + trace_pipe.read_at(buf, offset) + } + + fn write( + &self, + _data: KernCallbackData, + _buf: &[u8], + _offset: usize, + ) -> Result { + Err(SystemError::EPERM) + } + + fn poll(&self, _data: KernCallbackData) -> Result { + Ok(PollStatus::READ) + } +} diff --git a/kernel/src/debug/tracing/tracepoint.rs b/kernel/src/debug/tracing/tracepoint.rs new file mode 100644 index 000000000..fada434b3 --- /dev/null +++ b/kernel/src/debug/tracing/tracepoint.rs @@ -0,0 +1,187 @@ +use crate::libs::spinlock::{SpinLock, SpinLockGuard}; +use alloc::boxed::Box; +use alloc::collections::BTreeMap; +use core::any::Any; +use core::fmt::Debug; +use static_keys::StaticFalseKey; + +pub struct TracePoint { + name: &'static str, + module_path: &'static str, + key: &'static StaticFalseKey, + register: Option, + unregister: Option, + callback: SpinLock>, +} + +impl Debug for TracePoint { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("TracePoint") + .field("name", &self.name) + .finish() + } +} + +#[derive(Debug)] +#[repr(C)] +pub struct CommonTracePointMeta { + pub trace_point: &'static TracePoint, + pub print_func: fn(), +} + +#[derive(Debug)] +pub struct TracePointFunc { + pub func: fn(), + pub data: Box, +} + +impl TracePoint { + pub const fn new( + key: &'static StaticFalseKey, + name: &'static str, + module_path: &'static str, + register: Option, + unregister: Option, + ) -> Self { + Self { + name, + module_path, + key, + register, + unregister, + callback: SpinLock::new(BTreeMap::new()), + } + } + + pub fn name(&self) -> &'static str { + self.name + } + + pub fn module_path(&self) -> &'static str { + self.module_path + } + + /// Register a callback function to the tracepoint + pub fn register(&self, func: fn(), data: Box) { + let trace_point_func = TracePointFunc { func, data }; + let mut funcs = self.callback.lock(); + if let Some(register) = self.register { + register(); + } + let ptr = func as usize; + funcs.entry(ptr).or_insert(trace_point_func); + } + + /// Unregister a callback function from the tracepoint + pub fn unregister(&self, func: fn()) { + let mut funcs = self.callback.lock(); + if let Some(unregister) = self.unregister { + unregister(); + } + let func_ptr = func as usize; + funcs.remove(&func_ptr); + } + + /// Get the callback list + pub fn callback_list(&self) -> SpinLockGuard> { + self.callback.lock() + } + + /// Enable the tracepoint + pub fn enable(&self) { + unsafe { + self.key.enable(); + } + } + + /// Disable the tracepoint + pub fn disable(&self) { + unsafe { + self.key.disable(); + } + } + + /// Check if the tracepoint is enabled + pub fn is_enabled(&self) -> bool { + self.key.is_enabled() + } +} + +/// Define a tracepoint +/// +/// User should call register_trace_\$name to register a callback function to the tracepoint and +/// call trace_\$name to trigger the callback function +#[macro_export] +macro_rules! define_trace_point { + ($name:ident $(,$arg:ident:$arg_type:ty),*) => { + paste::paste!{ + static_keys::define_static_key_false!([<__ $name _KEY>]); + #[allow(non_upper_case_globals)] + #[used] + static [<__ $name>]: $crate::debug::tracing::tracepoint::TracePoint = $crate::debug::tracing::tracepoint::TracePoint::new(&[<__ $name _KEY>],stringify!($name), module_path!(),None,None); + + #[inline(always)] + #[allow(non_snake_case)] + pub fn []( $($arg:$arg_type),* ){ + + if static_keys::static_branch_unlikely!([<__ $name _KEY>]){ + let mut funcs = [<__ $name>].callback_list(); + for trace_func in funcs.values_mut(){ + let func = trace_func.func; + let data = trace_func.data.as_mut(); + let func = unsafe{core::mem::transmute::(func)}; + func(data $(,$arg)*); + } + } + + } + + #[allow(unused,non_snake_case)] + pub fn [](func:fn(&mut (dyn core::any::Any+Send+Sync),$($arg_type),*),data:alloc::boxed::Box){ + let func = unsafe{core::mem::transmute::(func)}; + [<__ $name>].register(func,data); + } + + #[allow(unused,non_snake_case)] + pub fn [](func:fn(&mut (dyn core::any::Any+Send+Sync),$($arg_type),*)){ + let func = unsafe{core::mem::transmute::(func)}; + [<__ $name>].unregister(func); + } + + } + }; +} + +#[macro_export] +macro_rules! define_event_trace{ + ($name:ident, + ($($arg:ident:$arg_type:ty),*), + $fmt:expr) =>{ + define_trace_point!($name $(,$arg:$arg_type),*); + paste::paste!{ + #[derive(Debug)] + #[repr(C)] + #[allow(non_snake_case)] + + struct [<__ $name _TracePointMeta>]{ + trace_point: &'static $crate::debug::tracing::tracepoint::TracePoint, + print_func: fn(&mut (dyn core::any::Any+Send+Sync),$($arg_type),*), + } + #[allow(non_upper_case_globals)] + #[link_section = ".tracepoint"] + #[used] + static [<__ $name _meta>]: [<__ $name _TracePointMeta>] = [<__ $name _TracePointMeta>]{ + trace_point:&[<__ $name>], + print_func:[], + }; + #[allow(non_snake_case)] + pub fn [](_data:&mut (dyn core::any::Any+Send+Sync),$($arg:$arg_type),* ){ + let time = $crate::time::Instant::now(); + let cpu_id = $crate::arch::cpu::current_cpu_id().data(); + let current_pid = $crate::process::ProcessManager::current_pcb().pid().data(); + let format = format!("[{}][{}][{}] {}\n",time,cpu_id,current_pid,$fmt); + $crate::debug::tracing::trace_pipe::trace_pipe_push_record(format); + } + } + }; +} diff --git a/kernel/src/filesystem/kernfs/callback.rs b/kernel/src/filesystem/kernfs/callback.rs index 563893c60..a6ed1443c 100644 --- a/kernel/src/filesystem/kernfs/callback.rs +++ b/kernel/src/filesystem/kernfs/callback.rs @@ -1,3 +1,5 @@ +use super::KernFSInode; +use crate::debug::tracing::tracepoint::TracePoint; use crate::{ filesystem::{sysfs::SysFSKernPrivateData, vfs::PollStatus}, libs::spinlock::SpinLockGuard, @@ -6,8 +8,6 @@ use alloc::sync::Arc; use core::fmt::Debug; use system_error::SystemError; -use super::KernFSInode; - /// KernFS文件的回调接口 /// /// 当用户态程序打开、读取、写入、关闭文件时,kernfs会调用相应的回调函数。 @@ -86,24 +86,23 @@ impl<'a> KernCallbackData<'a> { #[derive(Debug)] pub enum KernInodePrivateData { SysFS(SysFSKernPrivateData), + DebugFS(&'static TracePoint), } impl KernInodePrivateData { #[inline(always)] pub fn callback_read(&self, buf: &mut [u8], offset: usize) -> Result { - match self { - KernInodePrivateData::SysFS(private_data) => { - return private_data.callback_read(buf, offset); - } - } + return match self { + KernInodePrivateData::SysFS(private_data) => private_data.callback_read(buf, offset), + _ => Err(SystemError::ENOSYS), + }; } #[inline(always)] pub fn callback_write(&self, buf: &[u8], offset: usize) -> Result { - match self { - KernInodePrivateData::SysFS(private_data) => { - return private_data.callback_write(buf, offset); - } - } + return match self { + KernInodePrivateData::SysFS(private_data) => private_data.callback_write(buf, offset), + _ => Err(SystemError::ENOSYS), + }; } } diff --git a/kernel/src/filesystem/vfs/core.rs b/kernel/src/filesystem/vfs/core.rs index 85ea2c4f2..2642adf8c 100644 --- a/kernel/src/filesystem/vfs/core.rs +++ b/kernel/src/filesystem/vfs/core.rs @@ -5,6 +5,7 @@ use log::{error, info}; use system_error::SystemError; use crate::{ + define_event_trace, define_trace_point, driver::base::block::{gendisk::GenDisk, manager::block_dev_manager}, filesystem::{ devfs::devfs_init, @@ -155,7 +156,7 @@ pub fn mount_root_fs() -> Result<(), SystemError> { let fatfs: Arc = fatfs.unwrap(); let r = migrate_virtual_filesystem(fatfs); if r.is_err() { - error!("Failed to migrate virtual filesystem to FAT32!"); + error!("Failed to migrate virtual filesyst em to FAT32!"); loop { spin_loop(); } @@ -165,12 +166,15 @@ pub fn mount_root_fs() -> Result<(), SystemError> { return Ok(()); } +define_event_trace!(DO_MKDIR_AT,(path:&str,mode:FileMode), + format_args!("mkdir at {} with mode {:?}",path, mode)); /// @brief 创建文件/文件夹 pub fn do_mkdir_at( dirfd: i32, path: &str, mode: FileMode, ) -> Result, SystemError> { + TRACE_DO_MKDIR_AT(path, mode); // debug!("Call do mkdir at"); let (mut current_inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path.trim())?;