Move the executable `PathOrInode` to `ProcessVm`

This commit is contained in:
Wang Siyuan 2025-11-07 06:41:12 +00:00 committed by Tate, Hongliang Tian
parent 423053f2e6
commit 449939a32b
9 changed files with 50 additions and 45 deletions

View File

@ -26,7 +26,14 @@ impl CommFileOps {
impl FileOps for CommFileOps {
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
let exe_path = self.0.executable_file().display_name();
let vmar_guard = self.0.lock_vmar();
let Some(vmar) = vmar_guard.as_ref() else {
// According to Linux behavior, return an empty string
// if the process is a zombie process.
return Ok(0);
};
let exe_path = vmar.process_vm().executable_file().display_name();
let last_component = exe_path.rsplit('/').next().unwrap_or(&exe_path);
let mut comm = last_component.as_bytes().to_vec();
comm.truncate(TASK_COMM_LEN - 1);

View File

@ -29,7 +29,12 @@ impl ExeSymOps {
impl SymOps for ExeSymOps {
fn read_link(&self) -> Result<SymbolicLink> {
let res = match self.0.executable_file() {
let vmar_guard = self.0.lock_vmar();
let Some(vmar) = vmar_guard.as_ref() else {
return_errno_with_message!(Errno::ENOENT, "the process has exited");
};
let res = match vmar.process_vm().executable_file().clone() {
PathOrInode::Path(path) => SymbolicLink::Path(path),
PathOrInode::Inode(inode) => SymbolicLink::Inode(inode),
};

View File

@ -20,7 +20,6 @@ use crate::{
fs::{
cgroupfs::CgroupMembership,
file_table::{FdFlags, FileTable},
fs_resolver::PathOrInode,
thread_info::ThreadFsInfo,
},
prelude::*,
@ -489,10 +488,10 @@ fn clone_child_process(
let child_tid = allocate_posix_tid();
let child = {
let child_elf_file = process.executable_file();
let mut child_thread_builder = {
let child_thread_name =
ThreadName::new_from_executable_path(&child_elf_file.display_name());
let child_thread_name = ThreadName::new_from_executable_path(
&child_vmar.process_vm().executable_file().display_name(),
);
let credentials = {
let credentials = ctx.posix_thread.credentials();
@ -517,7 +516,6 @@ fn clone_child_process(
create_child_process(
child_tid,
child_elf_file,
child_vmar,
child_resource_limits,
child_nice,
@ -714,7 +712,6 @@ fn clone_ns_proxy(
#[expect(clippy::too_many_arguments)]
fn create_child_process(
pid: Pid,
child_elf_file: PathOrInode,
vmar: Arc<Vmar>,
resource_limits: ResourceLimits,
nice: Nice,
@ -725,7 +722,6 @@ fn create_child_process(
) -> Arc<Process> {
let child_proc = Process::new(
pid,
child_elf_file,
vmar,
resource_limits,
nice,

View File

@ -142,7 +142,7 @@ fn do_execve_no_return(
let elf_load_info = {
let mut vmar = ctx.process.lock_vmar();
// Reset the virtual memory state.
unshare_and_renew_vmar(ctx, &mut vmar);
unshare_and_renew_vmar(ctx, &mut vmar, elf_file.clone());
// Load the binary into the process's address space
program_to_load.load_to_vmar(vmar.unwrap(), fs_resolver)?
};
@ -166,7 +166,6 @@ fn do_execve_no_return(
// Update the process's executable path and set the thread name
let executable_path = elf_file.display_name();
*posix_thread.thread_name().lock() = ThreadName::new_from_executable_path(&executable_path);
process.set_executable_file(elf_file);
// Unshare and reset signal dispositions to their default actions.
unshare_and_reset_sigdispositions(process);

View File

@ -47,14 +47,6 @@ fn create_init_process(
argv: Vec<CString>,
envp: Vec<CString>,
) -> Result<Arc<Process>> {
let pid = allocate_posix_tid();
let process_vm = new_vmar_and_map();
let resource_limits = ResourceLimits::default();
let nice = Nice::default();
let oom_score_adj = 0;
let sig_dispositions = Arc::new(Mutex::new(SigDispositions::default()));
let user_ns = UserNamespace::get_init_singleton().clone();
let fs = {
let fs_resolver = MountNamespace::get_init_singleton().new_fs_resolver();
ThreadFsInfo::new(fs_resolver)
@ -62,9 +54,16 @@ fn create_init_process(
let fs_path = FsPath::try_from(executable_path)?;
let elf_path = fs.resolver().read().lookup(&fs_path)?;
let pid = allocate_posix_tid();
let process_vm = new_vmar_and_map(PathOrInode::Path(elf_path.clone()));
let resource_limits = ResourceLimits::default();
let nice = Nice::default();
let oom_score_adj = 0;
let sig_dispositions = Arc::new(Mutex::new(SigDispositions::default()));
let user_ns = UserNamespace::get_init_singleton().clone();
let init_proc = Process::new(
pid,
PathOrInode::Path(elf_path.clone()),
process_vm,
resource_limits,
nice,
@ -114,11 +113,12 @@ fn create_init_task(
let vmar = process.lock_vmar();
program_to_load.load_to_vmar(vmar.unwrap(), &fs_resolver)?
};
let mut user_ctx = UserContext::default();
user_ctx.set_instruction_pointer(elf_load_info.entry_point as _);
user_ctx.set_stack_pointer(elf_load_info.user_stack_top as _);
let thread_name = ThreadName::new_from_executable_path(&elf_path.abs_path());
let thread_builder = PosixThreadBuilder::new(tid, thread_name, Box::new(user_ctx), credentials)
.process(Arc::downgrade(process))
.fs(Arc::new(fs))

View File

@ -21,7 +21,6 @@ use super::{
};
use crate::{
fs::cgroupfs::CgroupNode,
fs::fs_resolver::PathOrInode,
prelude::*,
process::{
signal::{sig_queues::SigQueues, Pollee},
@ -87,8 +86,6 @@ pub struct Process {
pub(super) pidfile_pollee: Pollee,
// Mutable Part
/// The executable `PathOrInode`.
executable_file: RwLock<PathOrInode>,
/// The threads
tasks: Mutex<TaskSet>,
/// Process status
@ -215,10 +212,8 @@ impl Process {
Some(Task::current()?.as_posix_thread()?.process())
}
#[expect(clippy::too_many_arguments)]
pub(super) fn new(
pid: Pid,
executable_file: PathOrInode,
vmar: Arc<Vmar>,
resource_limits: ResourceLimits,
@ -236,7 +231,6 @@ impl Process {
Arc::new_cyclic(|process_ref: &Weak<Process>| Self {
pid,
tasks: Mutex::new(TaskSet::new()),
executable_file: RwLock::new(executable_file),
vmar: Mutex::new(Some(vmar)),
children_wait_queue,
pidfile_pollee: Pollee::new(),
@ -294,14 +288,6 @@ impl Process {
&self.tasks
}
pub fn executable_file(&self) -> PathOrInode {
self.executable_file.read().clone()
}
pub fn set_executable_file(&self, executable_file: PathOrInode) {
*self.executable_file.write() = executable_file;
}
pub fn resource_limits(&self) -> &ResourceLimits {
&self.resource_limits
}

View File

@ -24,7 +24,7 @@ pub use self::{
InitStack, InitStackReader, INIT_STACK_SIZE, MAX_LEN_STRING_ARG, MAX_NR_STRING_ARGS,
},
};
use crate::{prelude::*, vm::vmar::Vmar};
use crate::{fs::fs_resolver::PathOrInode, prelude::*, vm::vmar::Vmar};
/*
* The user's virtual memory space layout looks like below.
@ -68,6 +68,8 @@ pub struct ProcessVm {
init_stack: InitStack,
/// The user heap
heap: Heap,
/// The executable `PathOrInode`.
executable_file: PathOrInode,
/// The base address for vDSO segment
#[cfg(target_arch = "riscv64")]
vdso_base: AtomicUsize,
@ -75,10 +77,11 @@ pub struct ProcessVm {
impl ProcessVm {
/// Creates a new `ProcessVm` without mapping anything.
pub fn new() -> Self {
fn new(executable_file: PathOrInode) -> Self {
Self {
init_stack: InitStack::new(),
heap: Heap::new(),
executable_file,
#[cfg(target_arch = "riscv64")]
vdso_base: AtomicUsize::new(0),
}
@ -89,6 +92,7 @@ impl ProcessVm {
Self {
init_stack: process_vm.init_stack.clone(),
heap: process_vm.heap.clone(),
executable_file: process_vm.executable_file.clone(),
#[cfg(target_arch = "riscv64")]
vdso_base: AtomicUsize::new(process_vm.vdso_base.load(Ordering::Relaxed)),
}
@ -104,6 +108,11 @@ impl ProcessVm {
&self.heap
}
/// Returns a reference to the executable `PathOrInode`.
pub fn executable_file(&self) -> &PathOrInode {
&self.executable_file
}
/// Maps and writes the initial portion of the main stack of a process.
pub(super) fn map_and_write_init_stack(
&self,
@ -194,8 +203,8 @@ impl<'a> ProcessVmarGuard<'a> {
/// Creates a new VMAR and map the heap.
///
/// This method should only be used to create a VMAR for the init process.
pub(super) fn new_vmar_and_map() -> Arc<Vmar> {
let new_vmar = Vmar::new();
pub(super) fn new_vmar_and_map(executable_file: PathOrInode) -> Arc<Vmar> {
let new_vmar = Vmar::new(ProcessVm::new(executable_file));
new_vmar
.process_vm()
.heap()
@ -205,8 +214,12 @@ pub(super) fn new_vmar_and_map() -> Arc<Vmar> {
}
/// Unshares and renews the [`Vmar`] of the current process.
pub(super) fn unshare_and_renew_vmar(ctx: &Context, vmar: &mut ProcessVmarGuard) {
let new_vmar = Vmar::new();
pub(super) fn unshare_and_renew_vmar(
ctx: &Context,
vmar: &mut ProcessVmarGuard,
executable_file: PathOrInode,
) {
let new_vmar = Vmar::new(ProcessVm::new(executable_file));
let guard = disable_preempt();
*ctx.thread_local.vmar().borrow_mut() = Some(new_vmar.clone());
new_vmar.vm_space().activate();

View File

@ -117,8 +117,8 @@ pub fn handle_pending_signal(
match sig_default_action {
SigDefaultAction::Core | SigDefaultAction::Term => {
warn!(
"{:?}: terminating on signal {}",
ctx.process.executable_file().display_name(),
"PID {}: terminating on signal {}",
ctx.process.pid(),
sig_num.sig_name()
);
// We should exit current here, since we cannot restore a valid status from trap now.

View File

@ -49,11 +49,10 @@ pub struct Vmar {
impl Vmar {
/// Creates a new VMAR.
pub fn new() -> Arc<Self> {
pub fn new(process_vm: ProcessVm) -> Arc<Self> {
let inner = VmarInner::new();
let vm_space = VmSpace::new();
let rss_counters = array::from_fn(|_| PerCpuCounter::new());
let process_vm = ProcessVm::new();
Arc::new(Vmar {
inner: RwMutex::new(inner),
vm_space: Arc::new(vm_space),