feat:Add tracepoint prototype (#1088)

* feat:Add tracepoint prototype

Signed-off-by: Godones <chenlinfeng25@outlook.com>
This commit is contained in:
linfeng
2025-04-22 01:58:44 +08:00
committed by GitHub
parent 2c81a9760e
commit 50bbcae01a
14 changed files with 869 additions and 26 deletions

View File

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

View File

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

View File

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

View File

@ -1,2 +1,3 @@
gen_kallsyms
kallsyms.S
kallsyms.S
kallsyms

View File

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

View File

@ -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<Arc<KSet>> = 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<KSet> {
unsafe { SYS_KERNEL_DEBUG_KSET_INSTANCE.clone().unwrap() }
}

View File

@ -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<KernFSInode>,
subsystems: SpinLock<BTreeMap<String, Arc<EventsSubsystem>>>,
}
impl TracingEventsManager {
pub fn new(root: Arc<KernFSInode>) -> 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<Arc<EventsSubsystem>, 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<Arc<EventsSubsystem>> {
self.subsystems.lock().get(subsystem_name).cloned()
}
}
#[derive(Debug)]
pub struct EventsSubsystem {
root: Arc<KernFSInode>,
events: SpinLock<BTreeMap<String, Arc<EventInfo>>>,
}
impl EventsSubsystem {
pub fn new(root: Arc<KernFSInode>) -> 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<EventInfo>,
) -> 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<Arc<EventInfo>> {
self.events.lock().get(event_name).cloned()
}
/// Get the root inode of the subsystem
pub fn root(&self) -> Arc<KernFSInode> {
self.root.clone()
}
}
#[derive(Debug)]
pub struct EventInfo {
#[allow(unused)]
enable: Arc<KernFSInode>,
// filter: Arc<KernFSInode>,
// trigger: Arc<KernFSInode>,
}
impl EventInfo {
pub fn new(tracepoint: &'static TracePoint, subsystem: Arc<KernFSInode>) -> Arc<Self> {
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<usize, SystemError> {
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<usize, SystemError> {
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<PollStatus, SystemError> {
Err(SystemError::ENOSYS)
}
}
static mut TRACING_EVENTS_MANAGER: Option<TracingEventsManager> = None;
/// Initialize the tracing events
pub fn init_events(events_root: Arc<KernFSInode>) -> 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::<CommonTracePointMeta>();
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();
}

View File

@ -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<Arc<KernFSInode>> = None;
#[allow(unused)]
fn tracing_root_inode() -> Arc<KernFSInode> {
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<usize, SystemError> {
Err(SystemError::EISDIR)
}
fn write(
&self,
_data: KernCallbackData,
_buf: &[u8],
_offset: usize,
) -> Result<usize, SystemError> {
Err(SystemError::EISDIR)
}
fn poll(&self, _data: KernCallbackData) -> Result<PollStatus, SystemError> {
Err(SystemError::EISDIR)
}
}
impl KernInodePrivateData {
pub fn debugfs_tracepoint(&self) -> Option<&'static TracePoint> {
return match self {
KernInodePrivateData::DebugFS(tracepoint) => Some(tracepoint),
_ => None,
};
}
}

View File

@ -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<TracePipe> = 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<TracePipeBuf>,
}
struct TracePipeBuf {
size: usize,
max_record: usize,
buf: Vec<String>,
}
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<usize, SystemError> {
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<usize, SystemError> {
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<usize, SystemError> {
let trace_pipe = trace_pipe();
trace_pipe.read_at(buf, offset)
}
fn write(
&self,
_data: KernCallbackData,
_buf: &[u8],
_offset: usize,
) -> Result<usize, SystemError> {
Err(SystemError::EPERM)
}
fn poll(&self, _data: KernCallbackData) -> Result<PollStatus, SystemError> {
Ok(PollStatus::READ)
}
}

View File

@ -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<fn()>,
unregister: Option<fn()>,
callback: SpinLock<BTreeMap<usize, TracePointFunc>>,
}
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<dyn Any + Send + Sync>,
}
impl TracePoint {
pub const fn new(
key: &'static StaticFalseKey,
name: &'static str,
module_path: &'static str,
register: Option<fn()>,
unregister: Option<fn()>,
) -> 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<dyn Any + Sync + Send>) {
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<BTreeMap<usize, TracePointFunc>> {
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 [<TRACE_ $name>]( $($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::<fn(),fn(&mut (dyn core::any::Any+Send+Sync),$($arg_type),*)>(func)};
func(data $(,$arg)*);
}
}
}
#[allow(unused,non_snake_case)]
pub fn [<register_trace_ $name>](func:fn(&mut (dyn core::any::Any+Send+Sync),$($arg_type),*),data:alloc::boxed::Box<dyn core::any::Any+Send+Sync>){
let func = unsafe{core::mem::transmute::<fn(&mut (dyn core::any::Any+Send+Sync),$($arg_type),*),fn()>(func)};
[<__ $name>].register(func,data);
}
#[allow(unused,non_snake_case)]
pub fn [<unregister_trace_ $name>](func:fn(&mut (dyn core::any::Any+Send+Sync),$($arg_type),*)){
let func = unsafe{core::mem::transmute::<fn(&mut (dyn core::any::Any+Send+Sync),$($arg_type),*),fn()>(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:[<TRACE_PRINT_ $name>],
};
#[allow(non_snake_case)]
pub fn [<TRACE_PRINT_ $name>](_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);
}
}
};
}

View File

@ -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<usize, SystemError> {
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<usize, SystemError> {
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),
};
}
}

View File

@ -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<FATFileSystem> = 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<Arc<dyn IndexNode>, 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())?;