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:
+2
-1
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user