mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-25 10:23:23 +00:00
Add /proc/meminfo support
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
ff525112d0
commit
12ed40578d
48
kernel/aster-nix/src/fs/procfs/meminfo.rs
Normal file
48
kernel/aster-nix/src/fs/procfs/meminfo.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! This module offers `/proc/meminfo` file support, which tells the user space
|
||||||
|
//! about the memory statistics in the entire system. The definition of the
|
||||||
|
//! fields are similar to that of Linux's but there exist differences.
|
||||||
|
//!
|
||||||
|
//! Reference: <https://man7.org/linux/man-pages/man5/proc_meminfo.5.html>
|
||||||
|
|
||||||
|
use alloc::format;
|
||||||
|
|
||||||
|
use ostd::mm::stat;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
fs::{
|
||||||
|
procfs::template::{FileOps, ProcFileBuilder},
|
||||||
|
utils::Inode,
|
||||||
|
},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Represents the inode at `/proc/meminfo`.
|
||||||
|
pub struct MemInfoFileOps;
|
||||||
|
|
||||||
|
impl MemInfoFileOps {
|
||||||
|
pub fn new_inode(parent: Weak<dyn Inode>) -> Arc<dyn Inode> {
|
||||||
|
ProcFileBuilder::new(Self).parent(parent).build().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Total memory in the entire system in bytes.
|
||||||
|
fn mem_total() -> usize {
|
||||||
|
stat::mem_total()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An estimation of how much memory is available for starting new
|
||||||
|
/// applications, without disk operations.
|
||||||
|
fn mem_available() -> usize {
|
||||||
|
stat::mem_available()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileOps for MemInfoFileOps {
|
||||||
|
fn data(&self) -> Result<Vec<u8>> {
|
||||||
|
let total = mem_total();
|
||||||
|
let available = mem_available();
|
||||||
|
let output = format!("MemTotal:\t{}\nMemAvailable:\t{}\n", total, available);
|
||||||
|
Ok(output.into_bytes())
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ use core::sync::atomic::{AtomicU64, Ordering};
|
|||||||
use sys::SysDirOps;
|
use sys::SysDirOps;
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
|
meminfo::MemInfoFileOps,
|
||||||
pid::PidDirOps,
|
pid::PidDirOps,
|
||||||
self_::SelfSymOps,
|
self_::SelfSymOps,
|
||||||
template::{DirOps, ProcDir, ProcDirBuilder, ProcSymBuilder, SymOps},
|
template::{DirOps, ProcDir, ProcDirBuilder, ProcSymBuilder, SymOps},
|
||||||
@ -20,6 +21,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
mod filesystems;
|
mod filesystems;
|
||||||
|
mod meminfo;
|
||||||
mod pid;
|
mod pid;
|
||||||
mod self_;
|
mod self_;
|
||||||
mod sys;
|
mod sys;
|
||||||
@ -102,6 +104,8 @@ impl DirOps for RootDirOps {
|
|||||||
SysDirOps::new_inode(this_ptr.clone())
|
SysDirOps::new_inode(this_ptr.clone())
|
||||||
} else if name == "filesystems" {
|
} else if name == "filesystems" {
|
||||||
FileSystemsFileOps::new_inode(this_ptr.clone())
|
FileSystemsFileOps::new_inode(this_ptr.clone())
|
||||||
|
} else if name == "meminfo" {
|
||||||
|
MemInfoFileOps::new_inode(this_ptr.clone())
|
||||||
} else if let Ok(pid) = name.parse::<Pid>() {
|
} else if let Ok(pid) = name.parse::<Pid>() {
|
||||||
let process_ref =
|
let process_ref =
|
||||||
process_table::get_process(pid).ok_or_else(|| Error::new(Errno::ENOENT))?;
|
process_table::get_process(pid).ok_or_else(|| Error::new(Errno::ENOENT))?;
|
||||||
@ -123,6 +127,8 @@ impl DirOps for RootDirOps {
|
|||||||
cached_children.put_entry_if_not_found("filesystems", || {
|
cached_children.put_entry_if_not_found("filesystems", || {
|
||||||
FileSystemsFileOps::new_inode(this_ptr.clone())
|
FileSystemsFileOps::new_inode(this_ptr.clone())
|
||||||
});
|
});
|
||||||
|
cached_children
|
||||||
|
.put_entry_if_not_found("meminfo", || MemInfoFileOps::new_inode(this_ptr.clone()));
|
||||||
|
|
||||||
for process in process_table::process_table().iter() {
|
for process in process_table::process_table().iter() {
|
||||||
let pid = process.pid().to_string();
|
let pid = process.pid().to_string();
|
||||||
|
@ -17,6 +17,7 @@ mod offset;
|
|||||||
pub(crate) mod page;
|
pub(crate) mod page;
|
||||||
pub(crate) mod page_prop;
|
pub(crate) mod page_prop;
|
||||||
pub(crate) mod page_table;
|
pub(crate) mod page_table;
|
||||||
|
pub mod stat;
|
||||||
pub mod vm_space;
|
pub mod vm_space;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
@ -15,7 +15,47 @@ use spin::Once;
|
|||||||
use super::{cont_pages::ContPages, meta::PageMeta, Page};
|
use super::{cont_pages::ContPages, meta::PageMeta, Page};
|
||||||
use crate::{boot::memory_region::MemoryRegionType, mm::PAGE_SIZE, sync::SpinLock};
|
use crate::{boot::memory_region::MemoryRegionType, mm::PAGE_SIZE, sync::SpinLock};
|
||||||
|
|
||||||
pub(in crate::mm) static PAGE_ALLOCATOR: Once<SpinLock<FrameAllocator>> = Once::new();
|
/// FrameAllocator with a counter for allocated memory
|
||||||
|
pub(in crate::mm) struct CountingFrameAllocator {
|
||||||
|
allocator: FrameAllocator,
|
||||||
|
total: usize,
|
||||||
|
allocated: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CountingFrameAllocator {
|
||||||
|
pub fn new(allocator: FrameAllocator, total: usize) -> Self {
|
||||||
|
CountingFrameAllocator {
|
||||||
|
allocator,
|
||||||
|
total,
|
||||||
|
allocated: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alloc(&mut self, count: usize) -> Option<usize> {
|
||||||
|
match self.allocator.alloc(count) {
|
||||||
|
Some(value) => {
|
||||||
|
self.allocated += count * PAGE_SIZE;
|
||||||
|
Some(value)
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dealloc(&mut self, start_frame: usize, count: usize) {
|
||||||
|
self.allocator.dealloc(start_frame, count);
|
||||||
|
self.allocated -= count * PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mem_total(&self) -> usize {
|
||||||
|
self.total
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mem_available(&self) -> usize {
|
||||||
|
self.total - self.allocated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in crate::mm) static PAGE_ALLOCATOR: Once<SpinLock<CountingFrameAllocator>> = Once::new();
|
||||||
|
|
||||||
/// Allocate a single page.
|
/// Allocate a single page.
|
||||||
pub(crate) fn alloc_single<M: PageMeta>() -> Option<Page<M>> {
|
pub(crate) fn alloc_single<M: PageMeta>() -> Option<Page<M>> {
|
||||||
@ -63,6 +103,7 @@ pub(crate) fn alloc<M: PageMeta>(len: usize) -> Option<Vec<Page<M>>> {
|
|||||||
|
|
||||||
pub(crate) fn init() {
|
pub(crate) fn init() {
|
||||||
let regions = crate::boot::memory_regions();
|
let regions = crate::boot::memory_regions();
|
||||||
|
let mut total: usize = 0;
|
||||||
let mut allocator = FrameAllocator::<32>::new();
|
let mut allocator = FrameAllocator::<32>::new();
|
||||||
for region in regions.iter() {
|
for region in regions.iter() {
|
||||||
if region.typ() == MemoryRegionType::Usable {
|
if region.typ() == MemoryRegionType::Usable {
|
||||||
@ -75,6 +116,7 @@ pub(crate) fn init() {
|
|||||||
}
|
}
|
||||||
// Add global free pages to the frame allocator.
|
// Add global free pages to the frame allocator.
|
||||||
allocator.add_frame(start, end);
|
allocator.add_frame(start, end);
|
||||||
|
total += (end - start) * PAGE_SIZE;
|
||||||
info!(
|
info!(
|
||||||
"Found usable region, start:{:x}, end:{:x}",
|
"Found usable region, start:{:x}, end:{:x}",
|
||||||
region.base(),
|
region.base(),
|
||||||
@ -82,5 +124,6 @@ pub(crate) fn init() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PAGE_ALLOCATOR.call_once(|| SpinLock::new(allocator));
|
let counting_allocator = CountingFrameAllocator::new(allocator, total);
|
||||||
|
PAGE_ALLOCATOR.call_once(|| SpinLock::new(counting_allocator));
|
||||||
}
|
}
|
||||||
|
21
ostd/src/mm/stat/mod.rs
Normal file
21
ostd/src/mm/stat/mod.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! APIs for memory statistics.
|
||||||
|
|
||||||
|
use crate::mm::page::allocator::PAGE_ALLOCATOR;
|
||||||
|
|
||||||
|
/// Total memory available for any usages in the system (in bytes).
|
||||||
|
///
|
||||||
|
/// It would be only a slightly less than total physical memory of the system
|
||||||
|
/// in most occasions. For example, bad memory, kernel statically-allocated
|
||||||
|
/// memory or firmware reserved memories do not count.
|
||||||
|
pub fn mem_total() -> usize {
|
||||||
|
PAGE_ALLOCATOR.get().unwrap().lock().mem_total()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Current readily available memory (in bytes).
|
||||||
|
///
|
||||||
|
/// Such memory can be directly used for allocation without reclaiming.
|
||||||
|
pub fn mem_available() -> usize {
|
||||||
|
PAGE_ALLOCATOR.get().unwrap().lock().mem_available()
|
||||||
|
}
|
Reference in New Issue
Block a user