Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions kernel/src/fs/procfs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ pub enum ProcEntryType {
TraceCounters,
/// /proc/trace/providers - registered providers
TraceProviders,
/// /proc/slabinfo - slab allocator statistics
SlabInfo,
}

impl ProcEntryType {
Expand All @@ -79,6 +81,7 @@ impl ProcEntryType {
ProcEntryType::TraceBuffer => "buffer",
ProcEntryType::TraceCounters => "counters",
ProcEntryType::TraceProviders => "providers",
ProcEntryType::SlabInfo => "slabinfo",
}
}

Expand All @@ -95,6 +98,7 @@ impl ProcEntryType {
ProcEntryType::TraceBuffer => "/proc/trace/buffer",
ProcEntryType::TraceCounters => "/proc/trace/counters",
ProcEntryType::TraceProviders => "/proc/trace/providers",
ProcEntryType::SlabInfo => "/proc/slabinfo",
}
}

Expand All @@ -111,6 +115,7 @@ impl ProcEntryType {
ProcEntryType::TraceBuffer => 103,
ProcEntryType::TraceCounters => 104,
ProcEntryType::TraceProviders => 105,
ProcEntryType::SlabInfo => 5,
}
}

Expand Down Expand Up @@ -166,6 +171,7 @@ pub fn init() {
procfs.entries.push(ProcEntry::new(ProcEntryType::Version));
procfs.entries.push(ProcEntry::new(ProcEntryType::MemInfo));
procfs.entries.push(ProcEntry::new(ProcEntryType::CpuInfo));
procfs.entries.push(ProcEntry::new(ProcEntryType::SlabInfo));

// Register /proc/trace directory and entries
procfs.entries.push(ProcEntry::new(ProcEntryType::TraceDir));
Expand Down Expand Up @@ -288,6 +294,7 @@ pub fn read_entry(entry_type: ProcEntryType) -> Result<String, i32> {
ProcEntryType::TraceBuffer => Ok(trace::generate_buffer()),
ProcEntryType::TraceCounters => Ok(trace::generate_counters()),
ProcEntryType::TraceProviders => Ok(trace::generate_providers()),
ProcEntryType::SlabInfo => Ok(generate_slabinfo()),
}
}

Expand Down Expand Up @@ -408,3 +415,20 @@ fn generate_cpuinfo() -> String {
)
}
}

/// Generate /proc/slabinfo content
fn generate_slabinfo() -> String {
use alloc::format;
use crate::memory::slab::{FD_TABLE_SLAB, SIGNAL_HANDLERS_SLAB};

let mut out = String::from("# name active free total objsize pct\n");
for slab in &[&FD_TABLE_SLAB, &SIGNAL_HANDLERS_SLAB] {
let s = slab.stats();
let pct = if s.capacity > 0 { (s.allocated * 100) / s.capacity } else { 0 };
out.push_str(&format!(
"{:<16} {:>5} {:>5} {:>5} {:>7} {:>2}%\n",
s.name, s.allocated, s.free, s.capacity, s.obj_size, pct,
));
}
out
}
28 changes: 22 additions & 6 deletions kernel/src/ipc/fd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
//! to underlying file objects (pipes, stdio, sockets, etc.).

use alloc::sync::Arc;
use crate::memory::slab::{SlabBox, FD_TABLE_SLAB};
use spin::Mutex;

/// Maximum number of file descriptors per process
Expand Down Expand Up @@ -128,6 +129,8 @@ pub enum FdKind {
FifoRead(alloc::string::String, Arc<Mutex<super::pipe::PipeBuffer>>),
/// FIFO (named pipe) write end - path is stored for cleanup on close
FifoWrite(alloc::string::String, Arc<Mutex<super::pipe::PipeBuffer>>),
/// Procfs virtual file (content generated at open time)
ProcfsFile { content: alloc::string::String, position: usize },
}

impl core::fmt::Debug for FdKind {
Expand Down Expand Up @@ -161,6 +164,7 @@ impl core::fmt::Debug for FdKind {
}
FdKind::FifoRead(path, _) => write!(f, "FifoRead({})", path),
FdKind::FifoWrite(path, _) => write!(f, "FifoWrite({})", path),
FdKind::ProcfsFile { content, position } => write!(f, "ProcfsFile(len={}, pos={})", content.len(), position),
}
}
}
Expand Down Expand Up @@ -208,11 +212,11 @@ impl FileDescriptor {

/// Per-process file descriptor table
///
/// Note: Uses Box to heap-allocate the fd array to avoid stack overflow
/// during process creation (the array is ~6KB which is too large for stack).
/// Note: Uses SlabBox to allocate the fd array from a slab cache (O(1) alloc/free)
/// with fallback to the global heap. The array is ~6KB which is too large for stack.
pub struct FdTable {
/// The file descriptors (None = unused slot)
fds: alloc::boxed::Box<[Option<FileDescriptor>; MAX_FDS]>,
fds: SlabBox<[Option<FileDescriptor>; MAX_FDS]>,
}

impl Default for FdTable {
Expand All @@ -225,7 +229,7 @@ impl Clone for FdTable {
fn clone(&self) -> Self {
// CRITICAL: No logging here - this runs during fork() with potential timer interrupts
// Logging can cause deadlock if timer fires while holding logger lock
let cloned_fds = alloc::boxed::Box::new((*self.fds).clone());
let cloned_fds = self.fds.clone();

// Increment reference counts for all cloned fds that need it
for fd_opt in cloned_fds.iter() {
Expand Down Expand Up @@ -274,8 +278,17 @@ impl Clone for FdTable {
impl FdTable {
/// Create a new file descriptor table with standard I/O pre-allocated
pub fn new() -> Self {
// Use Box::new to allocate directly on heap, avoiding stack overflow
let mut fds = alloc::boxed::Box::new(core::array::from_fn(|_| None));
// Try slab allocation first (O(1)), fall back to global heap
let mut fds = if let Some(raw) = FD_TABLE_SLAB.alloc() {
// Slab returns zeroed memory; write None into each slot
let arr = raw as *mut [Option<FileDescriptor>; MAX_FDS];
for i in 0..MAX_FDS {
unsafe { core::ptr::write(&mut (*arr)[i], None); }
}
unsafe { SlabBox::from_slab(arr, &FD_TABLE_SLAB) }
} else {
SlabBox::from_box(alloc::boxed::Box::new(core::array::from_fn(|_| None)))
};

// Pre-allocate stdin, stdout, stderr
fds[STDIN as usize] = Some(FileDescriptor::new(FdKind::StdIo(STDIN)));
Expand Down Expand Up @@ -609,6 +622,9 @@ impl Drop for FdTable {
buffer.lock().close_write();
log::debug!("FdTable::drop() - closed FIFO write fd {} ({})", i, path);
}
FdKind::ProcfsFile { .. } => {
// Procfs files are purely in-memory, nothing to clean up
}
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions kernel/src/ipc/poll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,12 @@ pub fn poll_fd(fd_entry: &FileDescriptor, events: i16) -> i16 {
}
}
}
FdKind::ProcfsFile { content, position } => {
// Procfs file is readable if there's remaining content
if (events & events::POLLIN) != 0 && *position < content.len() {
revents |= events::POLLIN;
}
}
}

revents
Expand Down
4 changes: 4 additions & 0 deletions kernel/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,10 @@ fn kernel_main(boot_info: &'static mut bootloader_api::BootInfo) -> ! {
crate::fs::devptsfs::init();
log::info!("devptsfs initialized at /dev/pts");

// Initialize procfs (/proc virtual filesystem)
crate::fs::procfs::init();
log::info!("procfs initialized at /proc");

// Update IST stacks with per-CPU emergency stacks
gdt::update_ist_stacks();
log::info!("Updated IST stacks with per-CPU emergency and page fault stacks");
Expand Down
4 changes: 4 additions & 0 deletions kernel/src/main_aarch64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,10 @@ pub extern "C" fn kernel_main() -> ! {
kernel::fs::devptsfs::init();
serial_println!("[boot] devptsfs initialized at /dev/pts");

// Initialize procfs (/proc virtual filesystem)
kernel::fs::procfs::init();
serial_println!("[boot] procfs initialized at /proc");

// Initialize TTY subsystem (console + PTY infrastructure)
kernel::tty::init();
serial_println!("[boot] TTY subsystem initialized");
Expand Down
5 changes: 5 additions & 0 deletions kernel/src/memory/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod per_cpu_stack;
pub mod process_memory;
pub mod stack;
pub mod tlb;
pub mod slab;
pub mod vma;
#[cfg(not(target_arch = "x86_64"))]
pub mod arch_stub;
Expand Down Expand Up @@ -44,6 +45,7 @@ pub fn init_aarch64_heap() {
let phys_offset = physical_memory_offset();
let mapper = unsafe { paging::init(phys_offset) };
heap::init(&mapper).expect("ARM64 heap initialization failed");
slab::init();
}

/// Next available MMIO virtual address
Expand Down Expand Up @@ -125,6 +127,9 @@ pub fn init(physical_memory_offset: VirtAddr, memory_regions: &'static MemoryReg
heap::init(&mapper).expect("heap initialization failed");
}

// Initialize slab caches (must be after heap)
slab::init();

// Initialize stack allocation system
log::info!("Initializing stack allocation system...");
stack::init();
Expand Down
Loading
Loading