Merge branch 'ldso-cache' into 'master'

Implement ld_so cache backed by shm

See merge request redox-os/relibc!1134
This commit is contained in:
Jeremy Soller
2026-03-28 18:28:03 -06:00
2 changed files with 117 additions and 9 deletions
+2 -1
View File
@@ -130,8 +130,9 @@ redox_protocols.workspace = true
[features]
# to enable trace level, take out this `no_trace`
default = ["check_against_libc_crate", "no_trace"]
default = ["check_against_libc_crate", "ld_so_cache", "no_trace"]
check_against_libc_crate = ["__libc_only_for_layout_checks"]
ld_so_cache = []
no_trace = ["log/release_max_level_debug"]
# for very verbose activity beyond trace level
trace_tls = []
+115 -8
View File
@@ -34,6 +34,10 @@ use crate::{
},
sync::rwlock::RwLock,
};
#[cfg(feature = "ld_so_cache")]
use crate::header::sys_stat::stat;
#[cfg(not(target_arch = "x86"))]
use crate::{ld_so::dso::resolve_sym, platform::types::c_uint};
@@ -97,7 +101,10 @@ impl MmapFile {
let mut stat = crate::header::sys_stat::stat::default();
Sys::fstat(fd, Out::from_mut(&mut stat))?;
let size = stat.st_size as usize;
Self::from_fd(fd, stat.st_size as usize)
}
fn from_fd(fd: i32, size: usize) -> core::result::Result<Self, Errno> {
let ptr = unsafe {
Sys::mmap(
ptr::null_mut(),
@@ -112,16 +119,37 @@ impl MmapFile {
Ok(Self { fd, ptr, size })
}
fn anonymous(size: usize) -> core::result::Result<Self, Errno> {
let ptr = unsafe {
Sys::mmap(
ptr::null_mut(),
size,
sys_mman::PROT_READ | sys_mman::PROT_WRITE,
sys_mman::MAP_PRIVATE | sys_mman::MAP_ANONYMOUS,
-1,
0,
)
}?;
Ok(Self { fd: -1, ptr, size })
}
fn data(&self) -> &[u8] {
unsafe { core::slice::from_raw_parts(self.ptr.cast::<u8>(), self.size) }
}
fn as_mut_slice(&self) -> &mut [u8] {
unsafe { core::slice::from_raw_parts_mut(self.ptr.cast::<u8>(), self.size) }
}
}
impl Drop for MmapFile {
fn drop(&mut self) {
unsafe {
Sys::munmap(self.ptr, self.size).unwrap();
Sys::close(self.fd).unwrap();
if self.fd != -1 {
Sys::close(self.fd).unwrap();
}
}
}
}
@@ -932,14 +960,93 @@ impl Linker {
DlError::NotFound
})?;
let flags = fcntl::O_RDONLY | fcntl::O_CLOEXEC;
let file = MmapFile::open(CStr::borrow(&path_c), flags).map_err(|err| {
if debug {
eprintln!("[ld.so]: failed to open '{}': {}", path, err)
// TODO: Caches may silently fail within multiple users (try to leverage capabilities?)
// TODO: No way to specify weak cache or pruning the cache manually
#[cfg(feature = "ld_so_cache")]
let file = {
let mut mtime_sec = 0;
let mut mtime_nsec = 0;
let mut source_size = 0;
let src_fd = Sys::open(CStr::borrow(&path_c), fcntl::O_RDONLY | fcntl::O_CLOEXEC, 0)
.map_err(|err| {
if debug {
eprintln!("[ld.so]: failed to open '{}': {}", path, err)
}
DlError::NotFound
})?;
let mut st = stat::default();
if Sys::fstat(src_fd, Out::from_mut(&mut st)).is_ok() {
mtime_sec = st.st_mtim.tv_sec;
mtime_nsec = st.st_mtim.tv_nsec;
source_size = st.st_size as usize;
}
DlError::NotFound
})?;
let shm_path_str = format!(
"/scheme/shm/ld.so.cache.{}.{}.{}\0",
path.replace('/', "_"),
mtime_sec,
mtime_nsec
);
let shm_path = unsafe { CStr::from_bytes_with_nul_unchecked(shm_path_str.as_bytes()) };
let mut shm_exists = false;
if let Ok(shm_fd) = Sys::open(shm_path, fcntl::O_RDONLY, 0) {
let mut shm_stat = stat::default();
if Sys::fstat(shm_fd, Out::from_mut(&mut shm_stat)).is_ok() {
shm_exists = true;
if shm_stat.st_size > 0 {
if let Ok(mmap_file) = MmapFile::anonymous(source_size) {
let mut offset = 0;
let buf = mmap_file.as_mut_slice();
while offset < source_size {
match Sys::read(shm_fd, &mut buf[offset..]) {
Ok(0) | Err(_) => break,
Ok(n) => offset += n,
}
}
let _ = Sys::close(shm_fd);
return Ok(mmap_file);
}
let _ = Sys::close(shm_fd);
}
}
let _ = Sys::close(shm_fd);
}
let file = MmapFile::from_fd(src_fd, source_size).map_err(|err| {
if debug {
eprintln!("[ld.so]: failed to map '{}': {}", path, err)
}
DlError::NotFound
})?;
if !shm_exists {
let _ = Sys::open(shm_path, fcntl::O_CREAT | fcntl::O_RDWR, 0o600)
.map(|fd| Sys::close(fd));
} else {
if let Ok(shm_fd) = Sys::open(shm_path, fcntl::O_RDWR, 0o600) {
let _ = Sys::ftruncate(shm_fd, source_size as i64);
let _ = Sys::write(shm_fd, file.data());
let _ = Sys::close(shm_fd);
}
}
file
};
#[cfg(not(feature = "ld_so_cache"))]
let file = {
let flags = fcntl::O_RDONLY | fcntl::O_CLOEXEC;
MmapFile::open(CStr::borrow(&path_c), flags).map_err(|err| {
if debug {
eprintln!("[ld.so]: failed to open '{}': {}", path, err)
}
DlError::NotFound
})?
};
Ok(file)
}