mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-28 20:03:22 +00:00
Remove the shim kernel crate
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
d76c7a5b1e
commit
dafd16075f
60
kernel/src/fs/procfs/filesystems.rs
Normal file
60
kernel/src/fs/procfs/filesystems.rs
Normal file
@ -0,0 +1,60 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use alloc::format;
|
||||
|
||||
use crate::{
|
||||
fs::{
|
||||
procfs::template::{FileOps, ProcFileBuilder},
|
||||
utils::Inode,
|
||||
},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
/// Represents the inode at /proc/filesystems.
|
||||
pub struct FileSystemsFileOps;
|
||||
|
||||
impl FileSystemsFileOps {
|
||||
pub fn new_inode(parent: Weak<dyn Inode>) -> Arc<dyn Inode> {
|
||||
ProcFileBuilder::new(Self).parent(parent).build().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl FileOps for FileSystemsFileOps {
|
||||
fn data(&self) -> Result<Vec<u8>> {
|
||||
let mut result = String::new();
|
||||
for fs in FILESYSTEM_TYPES.iter() {
|
||||
if fs.is_nodev {
|
||||
result.push_str(&format!("nodev\t{}\n", fs.name));
|
||||
} else {
|
||||
result.push_str(&format!("\t{}\n", fs.name));
|
||||
}
|
||||
}
|
||||
Ok(result.into_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref FILESYSTEM_TYPES: Vec<FileSystemType> = {
|
||||
vec![
|
||||
FileSystemType::new("proc", true),
|
||||
FileSystemType::new("ramfs", true),
|
||||
FileSystemType::new("devpts", true),
|
||||
FileSystemType::new("ext2", false),
|
||||
FileSystemType::new("exfat", false),
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
struct FileSystemType {
|
||||
name: String,
|
||||
is_nodev: bool,
|
||||
}
|
||||
|
||||
impl FileSystemType {
|
||||
fn new(name: &str, is_nodev: bool) -> Self {
|
||||
FileSystemType {
|
||||
name: name.to_string(),
|
||||
is_nodev,
|
||||
}
|
||||
}
|
||||
}
|
48
kernel/src/fs/procfs/meminfo.rs
Normal file
48
kernel/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())
|
||||
}
|
||||
}
|
140
kernel/src/fs/procfs/mod.rs
Normal file
140
kernel/src/fs/procfs/mod.rs
Normal file
@ -0,0 +1,140 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use core::sync::atomic::{AtomicU64, Ordering};
|
||||
|
||||
use sys::SysDirOps;
|
||||
|
||||
use self::{
|
||||
meminfo::MemInfoFileOps,
|
||||
pid::PidDirOps,
|
||||
self_::SelfSymOps,
|
||||
template::{DirOps, ProcDir, ProcDirBuilder, ProcSymBuilder, SymOps},
|
||||
};
|
||||
use crate::{
|
||||
events::Observer,
|
||||
fs::{
|
||||
procfs::filesystems::FileSystemsFileOps,
|
||||
utils::{DirEntryVecExt, FileSystem, FsFlags, Inode, SuperBlock, NAME_MAX},
|
||||
},
|
||||
prelude::*,
|
||||
process::{process_table, process_table::PidEvent, Pid},
|
||||
};
|
||||
|
||||
mod filesystems;
|
||||
mod meminfo;
|
||||
mod pid;
|
||||
mod self_;
|
||||
mod sys;
|
||||
mod template;
|
||||
|
||||
/// Magic number.
|
||||
const PROC_MAGIC: u64 = 0x9fa0;
|
||||
/// Root Inode ID.
|
||||
const PROC_ROOT_INO: u64 = 1;
|
||||
/// Block size.
|
||||
const BLOCK_SIZE: usize = 1024;
|
||||
|
||||
pub struct ProcFS {
|
||||
sb: SuperBlock,
|
||||
root: Arc<dyn Inode>,
|
||||
inode_allocator: AtomicU64,
|
||||
}
|
||||
|
||||
impl ProcFS {
|
||||
pub fn new() -> Arc<Self> {
|
||||
Arc::new_cyclic(|weak_fs| Self {
|
||||
sb: SuperBlock::new(PROC_MAGIC, BLOCK_SIZE, NAME_MAX),
|
||||
root: RootDirOps::new_inode(weak_fs.clone()),
|
||||
inode_allocator: AtomicU64::new(PROC_ROOT_INO + 1),
|
||||
})
|
||||
}
|
||||
|
||||
pub(in crate::fs::procfs) fn alloc_id(&self) -> u64 {
|
||||
self.inode_allocator.fetch_add(1, Ordering::SeqCst)
|
||||
}
|
||||
}
|
||||
|
||||
impl FileSystem for ProcFS {
|
||||
fn sync(&self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn root_inode(&self) -> Arc<dyn Inode> {
|
||||
self.root.clone()
|
||||
}
|
||||
|
||||
fn sb(&self) -> SuperBlock {
|
||||
self.sb.clone()
|
||||
}
|
||||
|
||||
fn flags(&self) -> FsFlags {
|
||||
FsFlags::empty()
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the inode at `/proc`.
|
||||
struct RootDirOps;
|
||||
|
||||
impl RootDirOps {
|
||||
pub fn new_inode(fs: Weak<ProcFS>) -> Arc<dyn Inode> {
|
||||
let root_inode = ProcDirBuilder::new(Self)
|
||||
.fs(fs)
|
||||
.ino(PROC_ROOT_INO)
|
||||
.build()
|
||||
.unwrap();
|
||||
let weak_ptr = Arc::downgrade(&root_inode);
|
||||
process_table::register_observer(weak_ptr);
|
||||
root_inode
|
||||
}
|
||||
}
|
||||
|
||||
impl Observer<PidEvent> for ProcDir<RootDirOps> {
|
||||
fn on_events(&self, events: &PidEvent) {
|
||||
let PidEvent::Exit(pid) = events;
|
||||
let mut cached_children = self.cached_children().write();
|
||||
cached_children.remove_entry_by_name(&pid.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
impl DirOps for RootDirOps {
|
||||
fn lookup_child(&self, this_ptr: Weak<dyn Inode>, name: &str) -> Result<Arc<dyn Inode>> {
|
||||
let child = if name == "self" {
|
||||
SelfSymOps::new_inode(this_ptr.clone())
|
||||
} else if name == "sys" {
|
||||
SysDirOps::new_inode(this_ptr.clone())
|
||||
} else if name == "filesystems" {
|
||||
FileSystemsFileOps::new_inode(this_ptr.clone())
|
||||
} else if name == "meminfo" {
|
||||
MemInfoFileOps::new_inode(this_ptr.clone())
|
||||
} else if let Ok(pid) = name.parse::<Pid>() {
|
||||
let process_ref =
|
||||
process_table::get_process(pid).ok_or_else(|| Error::new(Errno::ENOENT))?;
|
||||
PidDirOps::new_inode(process_ref, this_ptr.clone())
|
||||
} else {
|
||||
return_errno!(Errno::ENOENT);
|
||||
};
|
||||
Ok(child)
|
||||
}
|
||||
|
||||
fn populate_children(&self, this_ptr: Weak<dyn Inode>) {
|
||||
let this = {
|
||||
let this = this_ptr.upgrade().unwrap();
|
||||
this.downcast_ref::<ProcDir<RootDirOps>>().unwrap().this()
|
||||
};
|
||||
let mut cached_children = this.cached_children().write();
|
||||
cached_children.put_entry_if_not_found("self", || SelfSymOps::new_inode(this_ptr.clone()));
|
||||
cached_children.put_entry_if_not_found("sys", || SysDirOps::new_inode(this_ptr.clone()));
|
||||
cached_children.put_entry_if_not_found("filesystems", || {
|
||||
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() {
|
||||
let pid = process.pid().to_string();
|
||||
cached_children.put_entry_if_not_found(&pid, || {
|
||||
PidDirOps::new_inode(process.clone(), this_ptr.clone())
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
40
kernel/src/fs/procfs/pid/cmdline.rs
Normal file
40
kernel/src/fs/procfs/pid/cmdline.rs
Normal file
@ -0,0 +1,40 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use crate::{
|
||||
fs::{
|
||||
procfs::template::{FileOps, ProcFileBuilder},
|
||||
utils::Inode,
|
||||
},
|
||||
prelude::*,
|
||||
Process,
|
||||
};
|
||||
|
||||
/// Represents the inode at `/proc/[pid]/cmdline`.
|
||||
pub struct CmdlineFileOps(Arc<Process>);
|
||||
|
||||
impl CmdlineFileOps {
|
||||
pub fn new_inode(process_ref: Arc<Process>, parent: Weak<dyn Inode>) -> Arc<dyn Inode> {
|
||||
ProcFileBuilder::new(Self(process_ref))
|
||||
.parent(parent)
|
||||
.build()
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl FileOps for CmdlineFileOps {
|
||||
fn data(&self) -> Result<Vec<u8>> {
|
||||
let cmdline_output = if self.0.is_zombie() {
|
||||
// Returns 0 characters for zombie process.
|
||||
Vec::new()
|
||||
} else {
|
||||
let Ok(argv_cstrs) = self.0.vm().init_stack_reader().argv() else {
|
||||
return Ok(Vec::new());
|
||||
};
|
||||
argv_cstrs
|
||||
.into_iter()
|
||||
.flat_map(|c_str| c_str.into_bytes_with_nul().into_iter())
|
||||
.collect()
|
||||
};
|
||||
Ok(cmdline_output)
|
||||
}
|
||||
}
|
39
kernel/src/fs/procfs/pid/comm.rs
Normal file
39
kernel/src/fs/procfs/pid/comm.rs
Normal file
@ -0,0 +1,39 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use crate::{
|
||||
fs::{
|
||||
procfs::template::{FileOps, ProcFileBuilder},
|
||||
utils::Inode,
|
||||
},
|
||||
prelude::*,
|
||||
Process,
|
||||
};
|
||||
|
||||
/// Represents the inode at `/proc/[pid]/comm`.
|
||||
pub struct CommFileOps(Arc<Process>);
|
||||
|
||||
impl CommFileOps {
|
||||
pub fn new_inode(process_ref: Arc<Process>, parent: Weak<dyn Inode>) -> Arc<dyn Inode> {
|
||||
ProcFileBuilder::new(Self(process_ref))
|
||||
.parent(parent)
|
||||
.build()
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl FileOps for CommFileOps {
|
||||
fn data(&self) -> Result<Vec<u8>> {
|
||||
let mut comm_output = {
|
||||
let exe_path = self.0.executable_path();
|
||||
let last_component = exe_path.rsplit('/').next().unwrap_or(&exe_path);
|
||||
let mut comm = last_component.as_bytes().to_vec();
|
||||
comm.push(b'\0');
|
||||
comm.truncate(TASK_COMM_LEN);
|
||||
comm
|
||||
};
|
||||
comm_output.push(b'\n');
|
||||
Ok(comm_output)
|
||||
}
|
||||
}
|
||||
|
||||
const TASK_COMM_LEN: usize = 16;
|
28
kernel/src/fs/procfs/pid/exe.rs
Normal file
28
kernel/src/fs/procfs/pid/exe.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use crate::{
|
||||
fs::{
|
||||
procfs::{ProcSymBuilder, SymOps},
|
||||
utils::Inode,
|
||||
},
|
||||
prelude::*,
|
||||
Process,
|
||||
};
|
||||
|
||||
/// Represents the inode at `/proc/[pid]/exe`.
|
||||
pub struct ExeSymOps(Arc<Process>);
|
||||
|
||||
impl ExeSymOps {
|
||||
pub fn new_inode(process_ref: Arc<Process>, parent: Weak<dyn Inode>) -> Arc<dyn Inode> {
|
||||
ProcSymBuilder::new(Self(process_ref))
|
||||
.parent(parent)
|
||||
.build()
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl SymOps for ExeSymOps {
|
||||
fn read_link(&self) -> Result<String> {
|
||||
Ok(self.0.executable_path())
|
||||
}
|
||||
}
|
98
kernel/src/fs/procfs/pid/fd.rs
Normal file
98
kernel/src/fs/procfs/pid/fd.rs
Normal file
@ -0,0 +1,98 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use crate::{
|
||||
fs::{
|
||||
file_handle::FileLike,
|
||||
file_table::FileDesc,
|
||||
inode_handle::InodeHandle,
|
||||
procfs::{
|
||||
pid::FdEvents, DirOps, Observer, ProcDir, ProcDirBuilder, ProcSymBuilder, SymOps,
|
||||
},
|
||||
utils::{DirEntryVecExt, Inode},
|
||||
},
|
||||
prelude::*,
|
||||
Process,
|
||||
};
|
||||
|
||||
/// Represents the inode at `/proc/[pid]/fd`.
|
||||
pub struct FdDirOps(Arc<Process>);
|
||||
|
||||
impl FdDirOps {
|
||||
pub fn new_inode(process_ref: Arc<Process>, parent: Weak<dyn Inode>) -> Arc<dyn Inode> {
|
||||
let fd_inode = ProcDirBuilder::new(Self(process_ref.clone()))
|
||||
.parent(parent)
|
||||
.build()
|
||||
.unwrap();
|
||||
let file_table = process_ref.file_table().lock();
|
||||
let weak_ptr = Arc::downgrade(&fd_inode);
|
||||
file_table.register_observer(weak_ptr);
|
||||
fd_inode
|
||||
}
|
||||
}
|
||||
|
||||
impl Observer<FdEvents> for ProcDir<FdDirOps> {
|
||||
fn on_events(&self, events: &FdEvents) {
|
||||
let fd_string = if let FdEvents::Close(fd) = events {
|
||||
fd.to_string()
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
let mut cached_children = self.cached_children().write();
|
||||
cached_children.remove_entry_by_name(&fd_string);
|
||||
}
|
||||
}
|
||||
|
||||
impl DirOps for FdDirOps {
|
||||
fn lookup_child(&self, this_ptr: Weak<dyn Inode>, name: &str) -> Result<Arc<dyn Inode>> {
|
||||
let file = {
|
||||
let fd = name
|
||||
.parse::<FileDesc>()
|
||||
.map_err(|_| Error::new(Errno::ENOENT))?;
|
||||
let file_table = self.0.file_table().lock();
|
||||
file_table
|
||||
.get_file(fd)
|
||||
.map_err(|_| Error::new(Errno::ENOENT))?
|
||||
.clone()
|
||||
};
|
||||
Ok(FileSymOps::new_inode(file, this_ptr.clone()))
|
||||
}
|
||||
|
||||
fn populate_children(&self, this_ptr: Weak<dyn Inode>) {
|
||||
let this = {
|
||||
let this = this_ptr.upgrade().unwrap();
|
||||
this.downcast_ref::<ProcDir<FdDirOps>>().unwrap().this()
|
||||
};
|
||||
let file_table = self.0.file_table().lock();
|
||||
let mut cached_children = this.cached_children().write();
|
||||
for (fd, file) in file_table.fds_and_files() {
|
||||
cached_children.put_entry_if_not_found(&fd.to_string(), || {
|
||||
FileSymOps::new_inode(file.clone(), this_ptr.clone())
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the inode at `/proc/[pid]/fd/N`.
|
||||
struct FileSymOps(Arc<dyn FileLike>);
|
||||
|
||||
impl FileSymOps {
|
||||
pub fn new_inode(file: Arc<dyn FileLike>, parent: Weak<dyn Inode>) -> Arc<dyn Inode> {
|
||||
ProcSymBuilder::new(Self(file))
|
||||
.parent(parent)
|
||||
.build()
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl SymOps for FileSymOps {
|
||||
fn read_link(&self) -> Result<String> {
|
||||
let path = if let Some(inode_handle) = self.0.downcast_ref::<InodeHandle>() {
|
||||
inode_handle.dentry().abs_path()
|
||||
} else {
|
||||
// TODO: get the real path for other FileLike object
|
||||
String::from("/dev/tty")
|
||||
};
|
||||
Ok(path)
|
||||
}
|
||||
}
|
78
kernel/src/fs/procfs/pid/mod.rs
Normal file
78
kernel/src/fs/procfs/pid/mod.rs
Normal file
@ -0,0 +1,78 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use self::{cmdline::CmdlineFileOps, comm::CommFileOps, exe::ExeSymOps, fd::FdDirOps};
|
||||
use super::template::{DirOps, ProcDir, ProcDirBuilder};
|
||||
use crate::{
|
||||
events::Observer,
|
||||
fs::{
|
||||
file_table::FdEvents,
|
||||
utils::{DirEntryVecExt, Inode},
|
||||
},
|
||||
prelude::*,
|
||||
process::Process,
|
||||
};
|
||||
|
||||
mod cmdline;
|
||||
mod comm;
|
||||
mod exe;
|
||||
mod fd;
|
||||
|
||||
/// Represents the inode at `/proc/[pid]`.
|
||||
pub struct PidDirOps(Arc<Process>);
|
||||
|
||||
impl PidDirOps {
|
||||
pub fn new_inode(process_ref: Arc<Process>, parent: Weak<dyn Inode>) -> Arc<dyn Inode> {
|
||||
let pid_inode = ProcDirBuilder::new(Self(process_ref.clone()))
|
||||
.parent(parent)
|
||||
// The pid directories must be volatile, because it is just associated with one process.
|
||||
.volatile()
|
||||
.build()
|
||||
.unwrap();
|
||||
let file_table = process_ref.file_table().lock();
|
||||
let weak_ptr = Arc::downgrade(&pid_inode);
|
||||
file_table.register_observer(weak_ptr);
|
||||
pid_inode
|
||||
}
|
||||
}
|
||||
|
||||
impl Observer<FdEvents> for ProcDir<PidDirOps> {
|
||||
fn on_events(&self, events: &FdEvents) {
|
||||
if let FdEvents::DropFileTable = events {
|
||||
let mut cached_children = self.cached_children().write();
|
||||
cached_children.remove_entry_by_name("fd");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DirOps for PidDirOps {
|
||||
fn lookup_child(&self, this_ptr: Weak<dyn Inode>, name: &str) -> Result<Arc<dyn Inode>> {
|
||||
let inode = match name {
|
||||
"exe" => ExeSymOps::new_inode(self.0.clone(), this_ptr.clone()),
|
||||
"comm" => CommFileOps::new_inode(self.0.clone(), this_ptr.clone()),
|
||||
"fd" => FdDirOps::new_inode(self.0.clone(), this_ptr.clone()),
|
||||
"cmdline" => CmdlineFileOps::new_inode(self.0.clone(), this_ptr.clone()),
|
||||
_ => return_errno!(Errno::ENOENT),
|
||||
};
|
||||
Ok(inode)
|
||||
}
|
||||
|
||||
fn populate_children(&self, this_ptr: Weak<dyn Inode>) {
|
||||
let this = {
|
||||
let this = this_ptr.upgrade().unwrap();
|
||||
this.downcast_ref::<ProcDir<PidDirOps>>().unwrap().this()
|
||||
};
|
||||
let mut cached_children = this.cached_children().write();
|
||||
cached_children.put_entry_if_not_found("exe", || {
|
||||
ExeSymOps::new_inode(self.0.clone(), this_ptr.clone())
|
||||
});
|
||||
cached_children.put_entry_if_not_found("comm", || {
|
||||
CommFileOps::new_inode(self.0.clone(), this_ptr.clone())
|
||||
});
|
||||
cached_children.put_entry_if_not_found("fd", || {
|
||||
FdDirOps::new_inode(self.0.clone(), this_ptr.clone())
|
||||
});
|
||||
cached_children.put_entry_if_not_found("cmdline", || {
|
||||
CmdlineFileOps::new_inode(self.0.clone(), this_ptr.clone())
|
||||
});
|
||||
}
|
||||
}
|
24
kernel/src/fs/procfs/self_.rs
Normal file
24
kernel/src/fs/procfs/self_.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use crate::{
|
||||
fs::{
|
||||
procfs::{ProcSymBuilder, SymOps},
|
||||
utils::Inode,
|
||||
},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
/// Represents the inode at `/proc/self`.
|
||||
pub struct SelfSymOps;
|
||||
|
||||
impl SelfSymOps {
|
||||
pub fn new_inode(parent: Weak<dyn Inode>) -> Arc<dyn Inode> {
|
||||
ProcSymBuilder::new(Self).parent(parent).build().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl SymOps for SelfSymOps {
|
||||
fn read_link(&self) -> Result<String> {
|
||||
Ok(current!().pid().to_string())
|
||||
}
|
||||
}
|
29
kernel/src/fs/procfs/sys/kernel/cap_last_cap.rs
Normal file
29
kernel/src/fs/procfs/sys/kernel/cap_last_cap.rs
Normal file
@ -0,0 +1,29 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use alloc::format;
|
||||
|
||||
use crate::{
|
||||
fs::{
|
||||
procfs::template::{FileOps, ProcFileBuilder},
|
||||
utils::Inode,
|
||||
},
|
||||
prelude::*,
|
||||
process::credentials::capabilities::CapSet,
|
||||
};
|
||||
|
||||
/// Represents the inode at `/proc/sys/kernel/cap_last_cap`.
|
||||
pub struct CapLastCapFileOps;
|
||||
|
||||
impl CapLastCapFileOps {
|
||||
pub fn new_inode(parent: Weak<dyn Inode>) -> Arc<dyn Inode> {
|
||||
ProcFileBuilder::new(Self).parent(parent).build().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl FileOps for CapLastCapFileOps {
|
||||
fn data(&self) -> Result<Vec<u8>> {
|
||||
let cap_last_cap_value = CapSet::most_significant_bit();
|
||||
let output = format!("{}\n", cap_last_cap_value);
|
||||
Ok(output.into_bytes())
|
||||
}
|
||||
}
|
46
kernel/src/fs/procfs/sys/kernel/mod.rs
Normal file
46
kernel/src/fs/procfs/sys/kernel/mod.rs
Normal file
@ -0,0 +1,46 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use crate::{
|
||||
fs::{
|
||||
procfs::{
|
||||
sys::kernel::cap_last_cap::CapLastCapFileOps,
|
||||
template::{DirOps, ProcDirBuilder},
|
||||
ProcDir,
|
||||
},
|
||||
utils::{DirEntryVecExt, Inode},
|
||||
},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
mod cap_last_cap;
|
||||
|
||||
/// Represents the inode at `/proc/sys/kernel`.
|
||||
|
||||
pub struct KernelDirOps;
|
||||
|
||||
impl KernelDirOps {
|
||||
pub fn new_inode(parent: Weak<dyn Inode>) -> Arc<dyn Inode> {
|
||||
ProcDirBuilder::new(Self).parent(parent).build().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl DirOps for KernelDirOps {
|
||||
fn lookup_child(&self, this_ptr: Weak<dyn Inode>, name: &str) -> Result<Arc<dyn Inode>> {
|
||||
let inode = match name {
|
||||
"cap_last_cap" => CapLastCapFileOps::new_inode(this_ptr.clone()),
|
||||
_ => return_errno!(Errno::ENOENT),
|
||||
};
|
||||
Ok(inode)
|
||||
}
|
||||
|
||||
fn populate_children(&self, this_ptr: Weak<dyn Inode>) {
|
||||
let this = {
|
||||
let this = this_ptr.upgrade().unwrap();
|
||||
this.downcast_ref::<ProcDir<KernelDirOps>>().unwrap().this()
|
||||
};
|
||||
let mut cached_children = this.cached_children().write();
|
||||
cached_children.put_entry_if_not_found("cap_last_cap", || {
|
||||
CapLastCapFileOps::new_inode(this_ptr.clone())
|
||||
});
|
||||
}
|
||||
}
|
41
kernel/src/fs/procfs/sys/mod.rs
Normal file
41
kernel/src/fs/procfs/sys/mod.rs
Normal file
@ -0,0 +1,41 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use self::kernel::KernelDirOps;
|
||||
use crate::{
|
||||
fs::{
|
||||
procfs::template::{DirOps, ProcDir, ProcDirBuilder},
|
||||
utils::{DirEntryVecExt, Inode},
|
||||
},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
mod kernel;
|
||||
|
||||
/// Represents the inode at `/proc/sys`.
|
||||
pub struct SysDirOps;
|
||||
|
||||
impl SysDirOps {
|
||||
pub fn new_inode(parent: Weak<dyn Inode>) -> Arc<dyn Inode> {
|
||||
ProcDirBuilder::new(Self).parent(parent).build().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl DirOps for SysDirOps {
|
||||
fn lookup_child(&self, this_ptr: Weak<dyn Inode>, name: &str) -> Result<Arc<dyn Inode>> {
|
||||
let inode = match name {
|
||||
"kernel" => KernelDirOps::new_inode(this_ptr.clone()),
|
||||
_ => return_errno!(Errno::ENOENT),
|
||||
};
|
||||
Ok(inode)
|
||||
}
|
||||
|
||||
fn populate_children(&self, this_ptr: Weak<dyn Inode>) {
|
||||
let this = {
|
||||
let this = this_ptr.upgrade().unwrap();
|
||||
this.downcast_ref::<ProcDir<SysDirOps>>().unwrap().this()
|
||||
};
|
||||
let mut cached_children = this.cached_children().write();
|
||||
cached_children
|
||||
.put_entry_if_not_found("kernel", || KernelDirOps::new_inode(this_ptr.clone()))
|
||||
}
|
||||
}
|
198
kernel/src/fs/procfs/template/builder.rs
Normal file
198
kernel/src/fs/procfs/template/builder.rs
Normal file
@ -0,0 +1,198 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use super::{
|
||||
dir::{DirOps, ProcDir},
|
||||
file::{FileOps, ProcFile},
|
||||
sym::{ProcSym, SymOps},
|
||||
};
|
||||
use crate::{
|
||||
fs::utils::{FileSystem, Inode},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
pub struct ProcDirBuilder<O: DirOps> {
|
||||
// Mandatory field
|
||||
dir: O,
|
||||
// Optional fields
|
||||
optional_builder: Option<OptionalBuilder>,
|
||||
}
|
||||
|
||||
impl<O: DirOps> ProcDirBuilder<O> {
|
||||
pub fn new(dir: O) -> Self {
|
||||
let optional_builder: OptionalBuilder = Default::default();
|
||||
Self {
|
||||
dir,
|
||||
optional_builder: Some(optional_builder),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parent(self, parent: Weak<dyn Inode>) -> Self {
|
||||
self.optional_builder(|ob| ob.parent(parent))
|
||||
}
|
||||
|
||||
pub fn fs(self, fs: Weak<dyn FileSystem>) -> Self {
|
||||
self.optional_builder(|ob| ob.fs(fs))
|
||||
}
|
||||
|
||||
pub fn volatile(self) -> Self {
|
||||
self.optional_builder(|ob| ob.volatile())
|
||||
}
|
||||
|
||||
pub fn ino(self, ino: u64) -> Self {
|
||||
self.optional_builder(|ob| ob.ino(ino))
|
||||
}
|
||||
|
||||
pub fn build(mut self) -> Result<Arc<ProcDir<O>>> {
|
||||
let (fs, parent, ino, is_volatile) = self.optional_builder.take().unwrap().build()?;
|
||||
Ok(ProcDir::new(self.dir, fs, parent, ino, is_volatile))
|
||||
}
|
||||
|
||||
fn optional_builder<F>(mut self, f: F) -> Self
|
||||
where
|
||||
F: FnOnce(OptionalBuilder) -> OptionalBuilder,
|
||||
{
|
||||
let optional_builder = self.optional_builder.take().unwrap();
|
||||
self.optional_builder = Some(f(optional_builder));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ProcFileBuilder<O: FileOps> {
|
||||
// Mandatory field
|
||||
file: O,
|
||||
// Optional fields
|
||||
optional_builder: Option<OptionalBuilder>,
|
||||
}
|
||||
|
||||
impl<O: FileOps> ProcFileBuilder<O> {
|
||||
pub fn new(file: O) -> Self {
|
||||
let optional_builder: OptionalBuilder = Default::default();
|
||||
Self {
|
||||
file,
|
||||
optional_builder: Some(optional_builder),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parent(self, parent: Weak<dyn Inode>) -> Self {
|
||||
self.optional_builder(|ob| ob.parent(parent))
|
||||
}
|
||||
|
||||
pub fn volatile(self) -> Self {
|
||||
self.optional_builder(|ob| ob.volatile())
|
||||
}
|
||||
|
||||
pub fn build(mut self) -> Result<Arc<ProcFile<O>>> {
|
||||
let (fs, _, _, is_volatile) = self.optional_builder.take().unwrap().build()?;
|
||||
Ok(ProcFile::new(self.file, fs, is_volatile))
|
||||
}
|
||||
|
||||
fn optional_builder<F>(mut self, f: F) -> Self
|
||||
where
|
||||
F: FnOnce(OptionalBuilder) -> OptionalBuilder,
|
||||
{
|
||||
let optional_builder = self.optional_builder.take().unwrap();
|
||||
self.optional_builder = Some(f(optional_builder));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ProcSymBuilder<O: SymOps> {
|
||||
// Mandatory field
|
||||
sym: O,
|
||||
// Optional fields
|
||||
optional_builder: Option<OptionalBuilder>,
|
||||
}
|
||||
|
||||
impl<O: SymOps> ProcSymBuilder<O> {
|
||||
pub fn new(sym: O) -> Self {
|
||||
let optional_builder: OptionalBuilder = Default::default();
|
||||
Self {
|
||||
sym,
|
||||
optional_builder: Some(optional_builder),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parent(self, parent: Weak<dyn Inode>) -> Self {
|
||||
self.optional_builder(|ob| ob.parent(parent))
|
||||
}
|
||||
|
||||
pub fn volatile(self) -> Self {
|
||||
self.optional_builder(|ob| ob.volatile())
|
||||
}
|
||||
|
||||
pub fn build(mut self) -> Result<Arc<ProcSym<O>>> {
|
||||
let (fs, _, _, is_volatile) = self.optional_builder.take().unwrap().build()?;
|
||||
Ok(ProcSym::new(self.sym, fs, is_volatile))
|
||||
}
|
||||
|
||||
fn optional_builder<F>(mut self, f: F) -> Self
|
||||
where
|
||||
F: FnOnce(OptionalBuilder) -> OptionalBuilder,
|
||||
{
|
||||
let optional_builder = self.optional_builder.take().unwrap();
|
||||
self.optional_builder = Some(f(optional_builder));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct OptionalBuilder {
|
||||
parent: Option<Weak<dyn Inode>>,
|
||||
fs: Option<Weak<dyn FileSystem>>,
|
||||
ino: Option<u64>,
|
||||
is_volatile: bool,
|
||||
}
|
||||
|
||||
impl OptionalBuilder {
|
||||
pub fn parent(mut self, parent: Weak<dyn Inode>) -> Self {
|
||||
self.parent = Some(parent);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn fs(mut self, fs: Weak<dyn FileSystem>) -> Self {
|
||||
self.fs = Some(fs);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn ino(mut self, ino: u64) -> Self {
|
||||
self.ino = Some(ino);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn volatile(mut self) -> Self {
|
||||
self.is_volatile = true;
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn build(
|
||||
self,
|
||||
) -> Result<(
|
||||
Weak<dyn FileSystem>,
|
||||
Option<Weak<dyn Inode>>,
|
||||
Option<u64>,
|
||||
bool,
|
||||
)> {
|
||||
if self.parent.is_none() && self.fs.is_none() {
|
||||
return_errno_with_message!(Errno::EINVAL, "must have parent or fs");
|
||||
}
|
||||
let fs = self.fs.unwrap_or_else(|| {
|
||||
Arc::downgrade(&self.parent.as_ref().unwrap().upgrade().unwrap().fs())
|
||||
});
|
||||
|
||||
// The volatile property is inherited from parent.
|
||||
let is_volatile = {
|
||||
let mut is_volatile = self.is_volatile;
|
||||
if let Some(parent) = self.parent.as_ref() {
|
||||
if !parent.upgrade().unwrap().is_dentry_cacheable() {
|
||||
is_volatile = true;
|
||||
}
|
||||
}
|
||||
is_volatile
|
||||
};
|
||||
|
||||
Ok((fs, self.parent, self.ino, is_volatile))
|
||||
}
|
||||
}
|
189
kernel/src/fs/procfs/template/dir.rs
Normal file
189
kernel/src/fs/procfs/template/dir.rs
Normal file
@ -0,0 +1,189 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use core::time::Duration;
|
||||
|
||||
use aster_util::slot_vec::SlotVec;
|
||||
use inherit_methods_macro::inherit_methods;
|
||||
|
||||
use super::{Common, ProcFS};
|
||||
use crate::{
|
||||
fs::utils::{DirentVisitor, FileSystem, Inode, InodeMode, InodeType, Metadata, MknodType},
|
||||
prelude::*,
|
||||
process::{Gid, Uid},
|
||||
};
|
||||
|
||||
pub struct ProcDir<D: DirOps> {
|
||||
inner: D,
|
||||
this: Weak<ProcDir<D>>,
|
||||
parent: Option<Weak<dyn Inode>>,
|
||||
cached_children: RwMutex<SlotVec<(String, Arc<dyn Inode>)>>,
|
||||
common: Common,
|
||||
}
|
||||
|
||||
impl<D: DirOps> ProcDir<D> {
|
||||
pub fn new(
|
||||
dir: D,
|
||||
fs: Weak<dyn FileSystem>,
|
||||
parent: Option<Weak<dyn Inode>>,
|
||||
ino: Option<u64>,
|
||||
is_volatile: bool,
|
||||
) -> Arc<Self> {
|
||||
let common = {
|
||||
let ino = ino.unwrap_or_else(|| {
|
||||
let arc_fs = fs.upgrade().unwrap();
|
||||
let procfs = arc_fs.downcast_ref::<ProcFS>().unwrap();
|
||||
procfs.alloc_id()
|
||||
});
|
||||
|
||||
let metadata =
|
||||
Metadata::new_dir(ino, InodeMode::from_bits_truncate(0o555), super::BLOCK_SIZE);
|
||||
Common::new(metadata, fs, is_volatile)
|
||||
};
|
||||
Arc::new_cyclic(|weak_self| Self {
|
||||
inner: dir,
|
||||
this: weak_self.clone(),
|
||||
parent,
|
||||
cached_children: RwMutex::new(SlotVec::new()),
|
||||
common,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn this(&self) -> Arc<ProcDir<D>> {
|
||||
self.this.upgrade().unwrap()
|
||||
}
|
||||
|
||||
pub fn parent(&self) -> Option<Arc<dyn Inode>> {
|
||||
self.parent.as_ref().and_then(|p| p.upgrade())
|
||||
}
|
||||
|
||||
pub fn cached_children(&self) -> &RwMutex<SlotVec<(String, Arc<dyn Inode>)>> {
|
||||
&self.cached_children
|
||||
}
|
||||
}
|
||||
|
||||
#[inherit_methods(from = "self.common")]
|
||||
impl<D: DirOps + 'static> Inode for ProcDir<D> {
|
||||
fn size(&self) -> usize;
|
||||
fn metadata(&self) -> Metadata;
|
||||
fn ino(&self) -> u64;
|
||||
fn mode(&self) -> Result<InodeMode>;
|
||||
fn set_mode(&self, mode: InodeMode) -> Result<()>;
|
||||
fn owner(&self) -> Result<Uid>;
|
||||
fn set_owner(&self, uid: Uid) -> Result<()>;
|
||||
fn group(&self) -> Result<Gid>;
|
||||
fn set_group(&self, gid: Gid) -> Result<()>;
|
||||
fn atime(&self) -> Duration;
|
||||
fn set_atime(&self, time: Duration);
|
||||
fn mtime(&self) -> Duration;
|
||||
fn set_mtime(&self, time: Duration);
|
||||
fn ctime(&self) -> Duration;
|
||||
fn set_ctime(&self, time: Duration);
|
||||
fn fs(&self) -> Arc<dyn FileSystem>;
|
||||
|
||||
fn resize(&self, _new_size: usize) -> Result<()> {
|
||||
Err(Error::new(Errno::EISDIR))
|
||||
}
|
||||
|
||||
fn type_(&self) -> InodeType {
|
||||
InodeType::Dir
|
||||
}
|
||||
|
||||
fn create(&self, _name: &str, _type_: InodeType, _mode: InodeMode) -> Result<Arc<dyn Inode>> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn mknod(&self, _name: &str, _mode: InodeMode, type_: MknodType) -> Result<Arc<dyn Inode>> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn readdir_at(&self, offset: usize, visitor: &mut dyn DirentVisitor) -> Result<usize> {
|
||||
let try_readdir = |offset: &mut usize, visitor: &mut dyn DirentVisitor| -> Result<()> {
|
||||
// Read the two special entries.
|
||||
if *offset == 0 {
|
||||
let this_inode = self.this();
|
||||
visitor.visit(
|
||||
".",
|
||||
this_inode.common.ino(),
|
||||
this_inode.common.type_(),
|
||||
*offset,
|
||||
)?;
|
||||
*offset += 1;
|
||||
}
|
||||
if *offset == 1 {
|
||||
let parent_inode = self.parent().unwrap_or(self.this());
|
||||
visitor.visit("..", parent_inode.ino(), parent_inode.type_(), *offset)?;
|
||||
*offset += 1;
|
||||
}
|
||||
|
||||
// Read the normal child entries.
|
||||
self.inner.populate_children(self.this.clone());
|
||||
let cached_children = self.cached_children.read();
|
||||
let start_offset = *offset;
|
||||
for (idx, (name, child)) in cached_children
|
||||
.idxes_and_items()
|
||||
.map(|(idx, (name, child))| (idx + 2, (name, child)))
|
||||
.skip_while(|(idx, _)| idx < &start_offset)
|
||||
{
|
||||
visitor.visit(name.as_ref(), child.ino(), child.type_(), idx)?;
|
||||
*offset = idx + 1;
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
|
||||
let mut iterate_offset = offset;
|
||||
match try_readdir(&mut iterate_offset, visitor) {
|
||||
Err(e) if iterate_offset == offset => Err(e),
|
||||
_ => Ok(iterate_offset - offset),
|
||||
}
|
||||
}
|
||||
|
||||
fn link(&self, _old: &Arc<dyn Inode>, _name: &str) -> Result<()> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn unlink(&self, _name: &str) -> Result<()> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn rmdir(&self, _name: &str) -> Result<()> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn lookup(&self, name: &str) -> Result<Arc<dyn Inode>> {
|
||||
let inode = match name {
|
||||
"." => self.this(),
|
||||
".." => self.parent().unwrap_or(self.this()),
|
||||
name => {
|
||||
let mut cached_children = self.cached_children.write();
|
||||
if let Some((_, inode)) = cached_children
|
||||
.iter()
|
||||
.find(|(child_name, inode)| child_name.as_str() == name)
|
||||
{
|
||||
return Ok(inode.clone());
|
||||
}
|
||||
let inode = self.inner.lookup_child(self.this.clone(), name)?;
|
||||
cached_children.put((String::from(name), inode.clone()));
|
||||
inode
|
||||
}
|
||||
};
|
||||
Ok(inode)
|
||||
}
|
||||
|
||||
fn rename(&self, _old_name: &str, _target: &Arc<dyn Inode>, _new_name: &str) -> Result<()> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn is_dentry_cacheable(&self) -> bool {
|
||||
!self.common.is_volatile()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait DirOps: Sync + Send {
|
||||
fn lookup_child(&self, this_ptr: Weak<dyn Inode>, name: &str) -> Result<Arc<dyn Inode>> {
|
||||
Err(Error::new(Errno::ENOENT))
|
||||
}
|
||||
|
||||
fn populate_children(&self, this_ptr: Weak<dyn Inode>) {}
|
||||
}
|
105
kernel/src/fs/procfs/template/file.rs
Normal file
105
kernel/src/fs/procfs/template/file.rs
Normal file
@ -0,0 +1,105 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use core::time::Duration;
|
||||
|
||||
use inherit_methods_macro::inherit_methods;
|
||||
|
||||
use super::{Common, ProcFS};
|
||||
use crate::{
|
||||
fs::utils::{FileSystem, Inode, InodeMode, InodeType, IoctlCmd, Metadata},
|
||||
prelude::*,
|
||||
process::{Gid, Uid},
|
||||
};
|
||||
|
||||
pub struct ProcFile<F: FileOps> {
|
||||
inner: F,
|
||||
common: Common,
|
||||
}
|
||||
|
||||
impl<F: FileOps> ProcFile<F> {
|
||||
pub fn new(file: F, fs: Weak<dyn FileSystem>, is_volatile: bool) -> Arc<Self> {
|
||||
let common = {
|
||||
let arc_fs = fs.upgrade().unwrap();
|
||||
let procfs = arc_fs.downcast_ref::<ProcFS>().unwrap();
|
||||
let metadata = Metadata::new_file(
|
||||
procfs.alloc_id(),
|
||||
InodeMode::from_bits_truncate(0o444),
|
||||
super::BLOCK_SIZE,
|
||||
);
|
||||
Common::new(metadata, fs, is_volatile)
|
||||
};
|
||||
Arc::new(Self {
|
||||
inner: file,
|
||||
common,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[inherit_methods(from = "self.common")]
|
||||
impl<F: FileOps + 'static> Inode for ProcFile<F> {
|
||||
fn size(&self) -> usize;
|
||||
fn metadata(&self) -> Metadata;
|
||||
fn ino(&self) -> u64;
|
||||
fn mode(&self) -> Result<InodeMode>;
|
||||
fn set_mode(&self, mode: InodeMode) -> Result<()>;
|
||||
fn owner(&self) -> Result<Uid>;
|
||||
fn set_owner(&self, uid: Uid) -> Result<()>;
|
||||
fn group(&self) -> Result<Gid>;
|
||||
fn set_group(&self, gid: Gid) -> Result<()>;
|
||||
fn atime(&self) -> Duration;
|
||||
fn set_atime(&self, time: Duration);
|
||||
fn mtime(&self) -> Duration;
|
||||
fn set_mtime(&self, time: Duration);
|
||||
fn ctime(&self) -> Duration;
|
||||
fn set_ctime(&self, time: Duration);
|
||||
fn fs(&self) -> Arc<dyn FileSystem>;
|
||||
|
||||
fn resize(&self, _new_size: usize) -> Result<()> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn type_(&self) -> InodeType {
|
||||
InodeType::File
|
||||
}
|
||||
|
||||
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
let data = self.inner.data()?;
|
||||
let start = data.len().min(offset);
|
||||
let end = data.len().min(offset + writer.avail());
|
||||
let len = end - start;
|
||||
writer.write_fallible(&mut (&data[start..end]).into())?;
|
||||
Ok(len)
|
||||
}
|
||||
|
||||
fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
self.read_at(offset, writer)
|
||||
}
|
||||
|
||||
fn write_at(&self, _offset: usize, _reader: &mut VmReader) -> Result<usize> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn write_direct_at(&self, _offset: usize, _reader: &mut VmReader) -> Result<usize> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn read_link(&self) -> Result<String> {
|
||||
Err(Error::new(Errno::EINVAL))
|
||||
}
|
||||
|
||||
fn write_link(&self, _target: &str) -> Result<()> {
|
||||
Err(Error::new(Errno::EINVAL))
|
||||
}
|
||||
|
||||
fn ioctl(&self, _cmd: IoctlCmd, _arg: usize) -> Result<i32> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn is_dentry_cacheable(&self) -> bool {
|
||||
!self.common.is_volatile()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait FileOps: Sync + Send {
|
||||
fn data(&self) -> Result<Vec<u8>>;
|
||||
}
|
112
kernel/src/fs/procfs/template/mod.rs
Normal file
112
kernel/src/fs/procfs/template/mod.rs
Normal file
@ -0,0 +1,112 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use core::time::Duration;
|
||||
|
||||
pub use self::{
|
||||
builder::{ProcDirBuilder, ProcFileBuilder, ProcSymBuilder},
|
||||
dir::{DirOps, ProcDir},
|
||||
file::FileOps,
|
||||
sym::SymOps,
|
||||
};
|
||||
use super::{ProcFS, BLOCK_SIZE};
|
||||
use crate::{
|
||||
fs::utils::{FileSystem, InodeMode, InodeType, Metadata},
|
||||
prelude::*,
|
||||
process::{Gid, Uid},
|
||||
};
|
||||
|
||||
mod builder;
|
||||
mod dir;
|
||||
mod file;
|
||||
mod sym;
|
||||
|
||||
struct Common {
|
||||
metadata: RwLock<Metadata>,
|
||||
fs: Weak<dyn FileSystem>,
|
||||
is_volatile: bool,
|
||||
}
|
||||
|
||||
impl Common {
|
||||
pub fn new(metadata: Metadata, fs: Weak<dyn FileSystem>, is_volatile: bool) -> Self {
|
||||
Self {
|
||||
metadata: RwLock::new(metadata),
|
||||
fs,
|
||||
is_volatile,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fs(&self) -> Arc<dyn FileSystem> {
|
||||
self.fs.upgrade().unwrap()
|
||||
}
|
||||
|
||||
pub fn metadata(&self) -> Metadata {
|
||||
*self.metadata.read()
|
||||
}
|
||||
|
||||
pub fn ino(&self) -> u64 {
|
||||
self.metadata.read().ino
|
||||
}
|
||||
|
||||
pub fn type_(&self) -> InodeType {
|
||||
self.metadata.read().type_
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
self.metadata.read().size
|
||||
}
|
||||
|
||||
pub fn atime(&self) -> Duration {
|
||||
self.metadata.read().atime
|
||||
}
|
||||
|
||||
pub fn set_atime(&self, time: Duration) {
|
||||
self.metadata.write().atime = time;
|
||||
}
|
||||
|
||||
pub fn mtime(&self) -> Duration {
|
||||
self.metadata.read().mtime
|
||||
}
|
||||
|
||||
pub fn set_mtime(&self, time: Duration) {
|
||||
self.metadata.write().mtime = time;
|
||||
}
|
||||
|
||||
pub fn ctime(&self) -> Duration {
|
||||
self.metadata.read().ctime
|
||||
}
|
||||
|
||||
pub fn set_ctime(&self, time: Duration) {
|
||||
self.metadata.write().ctime = time;
|
||||
}
|
||||
|
||||
pub fn mode(&self) -> Result<InodeMode> {
|
||||
Ok(self.metadata.read().mode)
|
||||
}
|
||||
|
||||
pub fn set_mode(&self, mode: InodeMode) -> Result<()> {
|
||||
self.metadata.write().mode = mode;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn owner(&self) -> Result<Uid> {
|
||||
Ok(self.metadata.read().uid)
|
||||
}
|
||||
|
||||
pub fn set_owner(&self, uid: Uid) -> Result<()> {
|
||||
self.metadata.write().uid = uid;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn group(&self) -> Result<Gid> {
|
||||
Ok(self.metadata.read().gid)
|
||||
}
|
||||
|
||||
pub fn set_group(&self, gid: Gid) -> Result<()> {
|
||||
self.metadata.write().gid = gid;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_volatile(&self) -> bool {
|
||||
self.is_volatile
|
||||
}
|
||||
}
|
97
kernel/src/fs/procfs/template/sym.rs
Normal file
97
kernel/src/fs/procfs/template/sym.rs
Normal file
@ -0,0 +1,97 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use core::time::Duration;
|
||||
|
||||
use inherit_methods_macro::inherit_methods;
|
||||
|
||||
use super::{Common, ProcFS};
|
||||
use crate::{
|
||||
fs::utils::{FileSystem, Inode, InodeMode, InodeType, IoctlCmd, Metadata},
|
||||
prelude::*,
|
||||
process::{Gid, Uid},
|
||||
};
|
||||
|
||||
pub struct ProcSym<S: SymOps> {
|
||||
inner: S,
|
||||
common: Common,
|
||||
}
|
||||
|
||||
impl<S: SymOps> ProcSym<S> {
|
||||
pub fn new(sym: S, fs: Weak<dyn FileSystem>, is_volatile: bool) -> Arc<Self> {
|
||||
let common = {
|
||||
let arc_fs = fs.upgrade().unwrap();
|
||||
let procfs = arc_fs.downcast_ref::<ProcFS>().unwrap();
|
||||
let metadata = Metadata::new_symlink(
|
||||
procfs.alloc_id(),
|
||||
InodeMode::from_bits_truncate(0o777),
|
||||
super::BLOCK_SIZE,
|
||||
);
|
||||
Common::new(metadata, fs, is_volatile)
|
||||
};
|
||||
Arc::new(Self { inner: sym, common })
|
||||
}
|
||||
}
|
||||
|
||||
#[inherit_methods(from = "self.common")]
|
||||
impl<S: SymOps + 'static> Inode for ProcSym<S> {
|
||||
fn size(&self) -> usize;
|
||||
fn metadata(&self) -> Metadata;
|
||||
fn ino(&self) -> u64;
|
||||
fn mode(&self) -> Result<InodeMode>;
|
||||
fn set_mode(&self, mode: InodeMode) -> Result<()>;
|
||||
fn owner(&self) -> Result<Uid>;
|
||||
fn set_owner(&self, uid: Uid) -> Result<()>;
|
||||
fn group(&self) -> Result<Gid>;
|
||||
fn set_group(&self, gid: Gid) -> Result<()>;
|
||||
fn atime(&self) -> Duration;
|
||||
fn set_atime(&self, time: Duration);
|
||||
fn mtime(&self) -> Duration;
|
||||
fn set_mtime(&self, time: Duration);
|
||||
fn ctime(&self) -> Duration;
|
||||
fn set_ctime(&self, time: Duration);
|
||||
fn fs(&self) -> Arc<dyn FileSystem>;
|
||||
|
||||
fn resize(&self, _new_size: usize) -> Result<()> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn type_(&self) -> InodeType {
|
||||
InodeType::SymLink
|
||||
}
|
||||
|
||||
fn read_at(&self, _offset: usize, _writer: &mut VmWriter) -> Result<usize> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn read_direct_at(&self, _offset: usize, _writer: &mut VmWriter) -> Result<usize> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn write_at(&self, _offset: usize, _reader: &mut VmReader) -> Result<usize> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn write_direct_at(&self, _offset: usize, _reader: &mut VmReader) -> Result<usize> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn read_link(&self) -> Result<String> {
|
||||
self.inner.read_link()
|
||||
}
|
||||
|
||||
fn write_link(&self, _target: &str) -> Result<()> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn ioctl(&self, _cmd: IoctlCmd, _arg: usize) -> Result<i32> {
|
||||
Err(Error::new(Errno::EPERM))
|
||||
}
|
||||
|
||||
fn is_dentry_cacheable(&self) -> bool {
|
||||
!self.common.is_volatile()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait SymOps: Sync + Send {
|
||||
fn read_link(&self) -> Result<String>;
|
||||
}
|
Reference in New Issue
Block a user