feat: Introduce userspace namespace manager and adapt all schemes.

This commit is contained in:
Ibuki Omatsu
2026-01-21 03:56:58 +00:00
committed by Jeremy Soller
parent 1753859f75
commit 334928f151
90 changed files with 3069 additions and 1125 deletions
+181 -129
View File
@@ -12,7 +12,7 @@ use std::str;
use libredox::flag::CLOCK_MONOTONIC;
use redox_rt::protocol::SocketCall;
use redox_scheme::{
scheme::{Op, SchemeSync},
scheme::{register_scheme_inner, Op, SchemeSync},
CallerCtx, OpenResult, Socket,
};
use syscall::data::TimeSpec;
@@ -239,13 +239,21 @@ where
fn handle_shutdown(&mut self, file: &mut SchemeFile<Self>, how: usize) -> SyscallResult<usize>;
}
pub enum Handle<SocketT>
where
SocketT: SchemeSocket,
{
SchemeRoot,
Null(NullFile),
File(SchemeFile<SocketT>),
}
pub struct SocketScheme<SocketT>
where
SocketT: SchemeSocket + AnySocket<'static>,
{
next_fd: usize,
nulls: BTreeMap<usize, NullFile>,
pub files: BTreeMap<usize, SchemeFile<SocketT>>,
pub handles: BTreeMap<usize, Handle<SocketT>>,
ref_counts: BTreeMap<SocketHandle, usize>,
context: Context,
pub socket_set: Rc<RefCell<SocketSet>>,
@@ -259,33 +267,36 @@ where
SocketT: SchemeSocket + AnySocket<'static>,
{
pub fn new(
name: &str,
iface: Interface,
route_table: Rc<RefCell<RouteTable>>,
socket_set: Rc<RefCell<SocketSet>>,
scheme_file: Socket,
) -> SocketScheme<SocketT> {
SocketScheme {
) -> SyscallResult<SocketScheme<SocketT>> {
let mut scheme = SocketScheme {
next_fd: 1,
nulls: BTreeMap::new(),
files: BTreeMap::new(),
handles: BTreeMap::new(),
ref_counts: BTreeMap::new(),
socket_set,
scheme_data: SocketT::new_scheme_data(),
scheme_file,
_phantom_socket: PhantomData,
context: Context { iface, route_table },
}
};
let cap_id = scheme.scheme_root()?;
register_scheme_inner(&scheme.scheme_file, name, cap_id)?;
Ok(scheme)
}
pub fn handle_block(&mut self, op: &Op) -> SyscallResult<Option<TimeSpec>> {
let fd = op.file_id().expect("op is not fd based request");
let (read_timeout, write_timeout) = {
let file = self
.files
let handle = self
.handles
.get(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
if let SchemeFile::Socket(ref scheme_file) = *file {
if let Handle::File(SchemeFile::Socket(ref scheme_file)) = *handle {
Ok((scheme_file.read_timeout, scheme_file.write_timeout))
} else {
Err(SyscallError::new(syscall::EBADF))
@@ -319,14 +330,13 @@ where
buf: &mut [u8],
) -> SyscallResult<usize> {
let file = self
.files
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let file = match *file {
SchemeFile::Socket(ref mut file) => file,
_ => {
return Err(SyscallError::new(syscall::EBADF));
}
Handle::File(SchemeFile::Socket(ref mut file)) => file,
_ => return Err(SyscallError::new(syscall::EBADF)),
};
match setting {
@@ -369,14 +379,12 @@ where
buf: &[u8],
) -> SyscallResult<usize> {
let file = self
.files
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let file = match *file {
SchemeFile::Socket(ref mut file) => file,
_ => {
return Err(SyscallError::new(syscall::EBADF));
}
Handle::File(SchemeFile::Socket(ref mut file)) => file,
_ => return Err(SyscallError::new(syscall::EBADF)),
};
match setting {
Setting::ReadTimeout | Setting::WriteTimeout => {
@@ -445,9 +453,14 @@ where
// SocketCall::GetToken => self.handle_get_token(id, payload),
SocketCall::GetPeerName => {
let file = self
.files
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let file = match *file {
Handle::File(ref mut f) => f,
_ => return Err(SyscallError::new(syscall::EBADF)),
};
let mut socket_set = self.socket_set.borrow_mut();
let socket = socket_set.get_mut::<SocketT>(file.socket_handle());
@@ -456,28 +469,31 @@ where
SocketCall::Shutdown => {
let how = metadata[1] as usize;
if let Some(null_file) = self.nulls.get_mut(&fd) {
match how {
0 => null_file.read_enabled = false,
1 => null_file.write_enabled = false,
2 => {
null_file.read_enabled = false;
null_file.write_enabled = false;
}
_ => return Err(SyscallError::new(EINVAL)),
}
return Ok(0);
}
let file = self
.files
match self
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
.ok_or_else(|| SyscallError::new(syscall::EBADF))?
{
Handle::File(file) => {
let mut socket_set = self.socket_set.borrow_mut();
let socket = socket_set.get_mut::<SocketT>(file.socket_handle());
let mut socket_set = self.socket_set.borrow_mut();
let socket = socket_set.get_mut::<SocketT>(file.socket_handle());
SocketT::handle_shutdown(socket, file, how)
SocketT::handle_shutdown(socket, file, how)
}
Handle::Null(null_file) => {
match how {
0 => null_file.read_enabled = false,
1 => null_file.write_enabled = false,
2 => {
null_file.read_enabled = false;
null_file.write_enabled = false;
}
_ => return Err(SyscallError::new(EINVAL)),
}
Ok(0)
}
Handle::SchemeRoot => Err(SyscallError::new(syscall::EBADF)),
}
}
_ => Err(SyscallError::new(EOPNOTSUPP)),
}
@@ -504,7 +520,7 @@ where
let id = self.next_fd;
self.next_fd += 1;
self.nulls.insert(id, null);
self.handles.insert(id, Handle::Null(null));
Ok(OpenResult::ThisScheme {
number: id,
@@ -536,7 +552,7 @@ where
self.next_fd += 1;
self.ref_counts.insert(socket_handle, 1);
self.files.insert(id, file);
self.handles.insert(id, Handle::File(file));
Ok(OpenResult::ThisScheme {
number: id,
@@ -550,8 +566,30 @@ impl<SocketT> SchemeSync for SocketScheme<SocketT>
where
SocketT: SchemeSocket + AnySocket<'static>,
{
fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> SyscallResult<OpenResult> {
self.open_inner(path, flags, ctx.uid, ctx.gid, true, true)
fn scheme_root(&mut self) -> SyscallResult<usize> {
let id = self.next_fd;
self.next_fd += 1;
self.handles.insert(id, Handle::SchemeRoot);
Ok(id)
}
fn openat(
&mut self,
fd: usize,
path: &str,
flags: usize,
_fcntl_flags: u32,
ctx: &CallerCtx,
) -> SyscallResult<OpenResult> {
let handle = self
.handles
.get(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
match handle {
Handle::SchemeRoot => self.open_inner(path, flags, ctx.uid, ctx.gid, true, true),
_ => Err(SyscallError::new(syscall::EACCES)),
}
}
fn call(
@@ -565,22 +603,11 @@ where
}
fn on_close(&mut self, fd: usize) {
if let Some(_null) = self.nulls.remove(&fd) {
let handle = if let Some(handle) = self.handles.remove(&fd) {
handle
} else {
return;
}
let socket_handle = {
let Some(file) = self.files.get(&fd) else {
return;
};
file.socket_handle()
};
let scheme_file = self.files.remove(&fd);
let mut socket_set = self.socket_set.borrow_mut();
if let Some(scheme_file) = scheme_file {
let socket = socket_set.get::<SocketT>(socket_handle);
let _ = socket.close_file(&scheme_file, &mut self.scheme_data);
}
// incorrect, and kernel can't send close until all references are gone
/*self.wait_queue.retain(
@@ -590,30 +617,42 @@ where
}| a != fd,
);*/
let remove = match self.ref_counts.entry(socket_handle) {
Entry::Vacant(_) => {
warn!("Closing a socket_handle with no ref");
true
}
Entry::Occupied(mut e) => {
if *e.get() == 0 {
warn!("Closing a socket_handle with no ref");
e.remove();
true
} else {
*e.get_mut() -= 1;
if *e.get() == 0 {
e.remove();
match handle {
Handle::SchemeRoot => return,
Handle::Null(_) => return,
Handle::File(scheme_file) => {
let socket_handle = scheme_file.socket_handle();
let mut socket_set = self.socket_set.borrow_mut();
let socket = socket_set.get::<SocketT>(socket_handle);
let _ = socket.close_file(&scheme_file, &mut self.scheme_data);
let remove = match self.ref_counts.entry(socket_handle) {
Entry::Vacant(_) => {
warn!("Closing a socket_handle with no ref");
true
} else {
false
}
Entry::Occupied(mut e) => {
if *e.get() == 0 {
warn!("Closing a socket_handle with no ref");
e.remove();
true
} else {
*e.get_mut() -= 1;
if *e.get() == 0 {
e.remove();
true
} else {
false
}
}
}
};
if remove {
socket_set.remove(socket_handle);
}
}
};
if remove {
socket_set.remove(socket_handle);
}
}
@@ -627,15 +666,15 @@ where
) -> SyscallResult<usize> {
let (fd, setting) = {
let file = self
.files
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
match *file {
SchemeFile::Setting(ref setting_handle) => {
Handle::File(SchemeFile::Setting(ref setting_handle)) => {
(setting_handle.fd, setting_handle.setting)
}
SchemeFile::Socket(ref mut file) => {
Handle::File(SchemeFile::Socket(ref mut file)) => {
let mut socket_set = self.socket_set.borrow_mut();
let socket = socket_set.get_mut::<SocketT>(file.socket_handle);
let ret = SocketT::write_buf(socket, file, buf);
@@ -646,6 +685,7 @@ where
}
return ret;
}
_ => return Err(SyscallError::new(syscall::EBADF)),
}
};
self.update_setting(fd, setting, buf)
@@ -661,14 +701,14 @@ where
) -> SyscallResult<usize> {
let (fd, setting) = {
let file = self
.files
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
match *file {
SchemeFile::Setting(ref setting_handle) => {
Handle::File(SchemeFile::Setting(ref setting_handle)) => {
(setting_handle.fd, setting_handle.setting)
}
SchemeFile::Socket(ref mut file) => {
Handle::File(SchemeFile::Socket(ref mut file)) => {
let mut socket_set = self.socket_set.borrow_mut();
let socket = socket_set.get_mut::<SocketT>(file.socket_handle);
@@ -681,6 +721,7 @@ where
return ret;
}
_ => return Err(SyscallError::new(syscall::EBADF)),
}
};
self.get_setting(fd, setting, buf)
@@ -689,27 +730,28 @@ where
fn dup(&mut self, fd: usize, buf: &[u8], _ctx: &CallerCtx) -> SyscallResult<OpenResult> {
let path = str::from_utf8(buf).or_else(|_| Err(SyscallError::new(syscall::EINVAL)))?;
if let Some((flags, uid, gid, read_enabled, write_enabled)) =
self.nulls.get(&fd).map(|null| {
(
null.flags,
null.uid,
null.gid,
null.read_enabled,
null.write_enabled,
)
})
{
// dup from empty path to a new path
return self.open_inner(path, flags, uid, gid, read_enabled, write_enabled);
}
let new_file = {
let file = self
.files
let handle = self
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let file = match *handle {
Handle::SchemeRoot => return Err(SyscallError::new(syscall::EBADF)),
Handle::Null(ref null) => {
let (flags, uid, gid, read_enabled, write_enabled) = (
null.flags,
null.uid,
null.gid,
null.read_enabled,
null.write_enabled,
);
// dup from empty path to a new path
return self.open_inner(path, flags, uid, gid, read_enabled, write_enabled);
}
Handle::File(ref mut file) => file,
};
let socket_handle = file.socket_handle();
let (new_handle, update_with) = match path {
@@ -757,7 +799,10 @@ where
.and_modify(|e| *e = e.saturating_sub(1))
.or_insert(0);
*self.ref_counts.entry(socket_handle).or_insert(0) += 1;
*self
.ref_counts
.entry(new_handle.socket_handle())
.or_insert(0) += 1;
file.socket_handle = socket_handle;
file.data = data;
@@ -771,7 +816,7 @@ where
};
let id = self.next_fd;
self.files.insert(id, new_file);
self.handles.insert(id, Handle::File(new_file));
self.next_fd += 1;
Ok(OpenResult::ThisScheme {
@@ -787,9 +832,15 @@ where
_ctx: &CallerCtx,
) -> SyscallResult<SyscallEventFlags> {
let file = self
.files
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let file = match *file {
Handle::File(ref mut f) => f,
_ => return Err(SyscallError::new(syscall::EBADF)),
};
match *file {
SchemeFile::Setting(_) => return Err(SyscallError::new(syscall::EBADF)),
SchemeFile::Socket(ref mut file) => {
@@ -806,7 +857,7 @@ where
fn fsync(&mut self, fd: usize, _ctx: &CallerCtx) -> SyscallResult<()> {
{
let _file = self
.files
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
}
@@ -817,10 +868,15 @@ where
fn fpath(&mut self, fd: usize, buf: &mut [u8], _ctx: &CallerCtx) -> SyscallResult<usize> {
let file = self
.files
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let file = match *file {
Handle::File(ref mut f) => f,
_ => return Err(SyscallError::new(syscall::EBADF)),
};
let socket_set = self.socket_set.borrow();
let socket = socket_set.get::<SocketT>(file.socket_handle());
@@ -834,33 +890,29 @@ where
arg: usize,
_ctx: &CallerCtx,
) -> SyscallResult<usize> {
if let Some(ref mut null) = self.nulls.get_mut(&fd) {
match cmd {
let handle = self
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
match *handle {
Handle::File(SchemeFile::Socket(ref mut socket_file)) => match cmd {
syscall::F_GETFL => Ok(socket_file.flags),
syscall::F_SETFL => {
socket_file.flags = arg & !syscall::O_ACCMODE;
Ok(0)
}
_ => Err(SyscallError::new(syscall::EINVAL)),
},
Handle::Null(ref mut null) => match cmd {
syscall::F_GETFL => Ok(null.flags),
syscall::F_SETFL => {
null.flags = arg & !syscall::O_ACCMODE;
Ok(0)
}
_ => Err(SyscallError::new(syscall::EINVAL)),
}
} else {
let file = self
.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
if let SchemeFile::Socket(ref mut socket_file) = *file {
match cmd {
syscall::F_GETFL => Ok(socket_file.flags),
syscall::F_SETFL => {
socket_file.flags = arg & !syscall::O_ACCMODE;
Ok(0)
}
_ => Err(SyscallError::new(syscall::EINVAL)),
}
} else {
Err(SyscallError::new(syscall::EBADF))
}
},
_ => Err(SyscallError::new(syscall::EBADF)),
}
}
}