kernel: add openat_into + dup_into for upstream 0.9.0 syscall API
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
use alloc::format;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::{
|
||||
percpu::get_all_stats,
|
||||
sync::CleanLockToken,
|
||||
syscall::error::{Error, Result, ENOENT},
|
||||
};
|
||||
|
||||
/// Format one per-CPU stat line compatible with Linux `/proc/stat`:
|
||||
/// `user nice system idle iowait irq softirq steal`.
|
||||
///
|
||||
/// Redox's scheduler tracks user, nice, kernel, idle, and irq. The
|
||||
/// remaining Linux fields (iowait, softirq, steal) are not tracked
|
||||
/// separately and are reported as 0.
|
||||
pub fn resource_for(cpu: u32, _token: &mut CleanLockToken) -> Result<Vec<u8>> {
|
||||
let stats = get_all_stats();
|
||||
for (id, stat) in stats {
|
||||
if id.get() == cpu {
|
||||
let line = format!(
|
||||
"{} {} {} {} {} 0 0 0\n",
|
||||
stat.user, stat.nice, stat.kernel, stat.idle, stat.irq
|
||||
);
|
||||
return Ok(line.into_bytes());
|
||||
}
|
||||
}
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
@@ -28,6 +28,7 @@ use super::{CallerCtx, HandleMap, KernelScheme, OpenResult, StrOrBytes};
|
||||
mod block;
|
||||
mod context;
|
||||
mod cpu;
|
||||
mod cpu_stat;
|
||||
mod exe;
|
||||
mod fdstat;
|
||||
mod iostat;
|
||||
@@ -213,6 +214,24 @@ impl KernelScheme for SysScheme {
|
||||
if path.is_empty() {
|
||||
let id = HANDLES.write(token.token()).insert(Handle::TopLevel);
|
||||
|
||||
Ok(OpenResult::SchemeLocal(id, InternalFlags::POSITIONED))
|
||||
} else if let Some(rest) = path.strip_prefix("cpu/") {
|
||||
// /scheme/sys/cpu/{cpu}/stat — per-CPU load counters compatible
|
||||
// with Linux /proc/stat. Only the `stat` file is exposed for
|
||||
// now; cpufreqd and redbear-power open it directly.
|
||||
let mut parts = rest.split('/').filter(|p| !p.is_empty());
|
||||
let cpu_str = parts.next().ok_or(Error::new(EINVAL))?;
|
||||
let file = parts.next().ok_or(Error::new(EINVAL))?;
|
||||
if parts.next().is_some() || file != "stat" {
|
||||
return Err(Error::new(ENOENT));
|
||||
}
|
||||
let cpu: u32 = cpu_str.parse().map_err(|_| Error::new(EINVAL))?;
|
||||
let data = cpu_stat::resource_for(cpu, token)?;
|
||||
let id = HANDLES.write(token.token()).insert(Handle::Resource {
|
||||
path: "cpu_stat",
|
||||
kind: Kind::Rd(|_| Ok(Vec::new())),
|
||||
data: Arc::new(RwLock::new(Some(data))),
|
||||
});
|
||||
Ok(OpenResult::SchemeLocal(id, InternalFlags::POSITIONED))
|
||||
} else if path == "msr" || path.starts_with("msr/") {
|
||||
// /scheme/sys/msr/{cpu}/0x{msr} — Phase G.1: MSR R/W scheme
|
||||
|
||||
@@ -126,6 +126,35 @@ pub fn openat(
|
||||
)
|
||||
.ok_or(Error::new(EMFILE))
|
||||
}
|
||||
/// Open a file at a specific path, placing the result into a reserved fd slot (upstream 0.9.0).
|
||||
pub fn openat_into(
|
||||
fh: FileHandle,
|
||||
raw_path: UserSliceRo,
|
||||
flags: usize,
|
||||
fcntl_flags: u32,
|
||||
new_fd: FileHandle,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<FileHandle> {
|
||||
let path_buf = copy_path_to_buf(raw_path, PATH_MAX)?;
|
||||
let (scheme_id, number) = {
|
||||
let current_lock = context::current();
|
||||
let mut current = current_lock.read(token.token());
|
||||
let (context, mut token) = current.token_split();
|
||||
let pipe = context.get_file(fh, &mut token).ok_or(Error::new(EBADF))?;
|
||||
let desc = pipe.description.read(token.token());
|
||||
(desc.scheme, desc.number)
|
||||
};
|
||||
let caller_ctx = context::current().read(token.token()).caller_ctx();
|
||||
let new_description = {
|
||||
let scheme = scheme::get_scheme(token.token(), scheme_id)?;
|
||||
let res = scheme.kopenat(number, StrOrBytes::from_str(&path_buf), flags, fcntl_flags, caller_ctx, token)?;
|
||||
res?
|
||||
};
|
||||
let current_lock = context::current();
|
||||
let mut current = current_lock.read(token.token());
|
||||
let (context, mut token) = current.token_split();
|
||||
context.insert_file(new_fd, new_description, &mut token).ok_or(Error::new(EEXIST))
|
||||
}
|
||||
/// Unlinkat syscall
|
||||
pub fn unlinkat(
|
||||
fh: FileHandle,
|
||||
@@ -233,6 +262,20 @@ pub fn dup(fd: FileHandle, buf: UserSliceRo, token: &mut CleanLockToken) -> Resu
|
||||
.ok_or(Error::new(EMFILE))
|
||||
}
|
||||
|
||||
/// Duplicate a file descriptor, placing into a specific fd slot (upstream 0.9.0).
|
||||
pub fn dup_into(
|
||||
fd: FileHandle,
|
||||
new_fd: FileHandle,
|
||||
buf: UserSliceRo,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<FileHandle> {
|
||||
let new_file = duplicate_file(fd, buf, token)?;
|
||||
let current_lock = context::current();
|
||||
let mut current = current_lock.read(token.token());
|
||||
let (context, mut token) = current.token_split();
|
||||
context.insert_file(new_fd, new_file, &mut token).ok_or(Error::new(EEXIST))
|
||||
}
|
||||
|
||||
/// Duplicate file descriptor, replacing another
|
||||
pub fn dup2(
|
||||
fd: FileHandle,
|
||||
|
||||
@@ -153,6 +153,12 @@ pub fn syscall(
|
||||
}),
|
||||
|
||||
SYS_DUP => dup(fd, UserSlice::ro(c, d)?, token).map(FileHandle::into),
|
||||
SYS_DUP_INTO => dup_into(
|
||||
fd,
|
||||
FileHandle::from(e),
|
||||
UserSlice::ro(c, d)?,
|
||||
token,
|
||||
).map(FileHandle::into),
|
||||
SYS_DUP2 => {
|
||||
dup2(fd, FileHandle::from(c), UserSlice::ro(d, e)?, token).map(FileHandle::into)
|
||||
}
|
||||
@@ -205,6 +211,14 @@ pub fn syscall(
|
||||
SYS_OPENAT => {
|
||||
openat(fd, UserSlice::ro(c, d)?, e, f as _, 0, 0, token).map(FileHandle::into)
|
||||
}
|
||||
SYS_OPENAT_INTO => openat_into(
|
||||
fd,
|
||||
UserSlice::ro(c, d)?,
|
||||
e,
|
||||
f as u32,
|
||||
FileHandle::from(g as usize),
|
||||
token,
|
||||
),
|
||||
SYS_OPENAT_WITH_FILTER => openat(
|
||||
fd,
|
||||
UserSlice::ro(c, d)?,
|
||||
|
||||
Reference in New Issue
Block a user