Add lock token to FdTbl without borrow check

This commit is contained in:
Wildan M
2026-03-09 13:12:19 +07:00
parent 206f82709a
commit 8412321568
11 changed files with 147 additions and 76 deletions
+70 -27
View File
@@ -16,12 +16,12 @@ use crate::{
},
cpu_set::{LogicalCpuId, LogicalCpuSet},
cpu_stats,
ipi::{IpiKind, IpiTarget, ipi},
memory::{Enomem, Frame, RaiiFrame, allocate_p2frame, deallocate_p2frame},
ipi::{ipi, IpiKind, IpiTarget},
memory::{allocate_p2frame, deallocate_p2frame, Enomem, Frame, RaiiFrame},
paging::{RmmA, RmmArch},
percpu::PercpuBlock,
scheme::{CallerCtx, FileHandle, SchemeId},
sync::{CleanLockToken, L1, L4, LockToken, RwLock},
sync::{CleanLockToken, LockToken, RwLock, L1, L4, L5},
syscall::usercopy::UserSliceRw,
};
@@ -131,7 +131,7 @@ pub struct Context {
/// The name of the context
pub name: ArrayString<CONTEXT_NAME_CAPAC>,
/// The open files in the scheme
pub files: Arc<spin::RwLock<FdTbl>>,
pub files: Arc<LockedFdTbl>,
/// All contexts except kmain will primarily live in userspace, and enter the kernel only when
/// interrupts or syscalls occur. This flag is set for all contexts but kmain.
pub userspace: bool,
@@ -191,7 +191,7 @@ impl Context {
kstack: None,
addr_space: None,
name: ArrayString::new(),
files: Arc::new(spin::RwLock::new(FdTbl::new())),
files: Arc::new(RwLock::new(FdTbl::new())),
userspace: false,
fmap_ret: None,
being_sigkilled: false,
@@ -266,30 +266,45 @@ impl Context {
/// Add a file to the lowest available slot.
/// Return the file descriptor number or None if no slot was found
pub fn add_file(&self, file: FileDescriptor) -> Option<FileHandle> {
self.add_file_min(file, 0)
pub fn add_file(
&self,
file: FileDescriptor,
lock_token: &mut LockToken<L4>,
) -> Option<FileHandle> {
self.add_file_min(file, 0, lock_token)
}
/// Add a file to the lowest available slot greater than or equal to min.
/// Return the file descriptor number or None if no slot was found
pub fn add_file_min(&self, file: FileDescriptor, min: usize) -> Option<FileHandle> {
self.files.write().add_file_min(file, min)
pub fn add_file_min(
&self,
file: FileDescriptor,
min: usize,
lock_token: &mut LockToken<L4>,
) -> Option<FileHandle> {
self.files.write(lock_token.token()).add_file_min(file, min)
}
/// Bulk-add multiple files to the POSIX file table
pub fn bulk_add_files_posix(
&self,
files_to_add: Vec<FileDescriptor>,
lock_token: &mut LockToken<L4>,
) -> Option<Vec<FileHandle>> {
self.files.write().bulk_add_files_posix(files_to_add)
self.files
.write(lock_token.token())
.bulk_add_files_posix(files_to_add)
}
/// Bulk-insert multiple files into to the upper file table contiguously
pub fn bulk_insert_files_upper(
&self,
files_to_insert: Vec<FileDescriptor>,
lock_token: &mut LockToken<L4>,
) -> Option<Vec<FileHandle>> {
self.files.write().bulk_insert_files_upper(files_to_insert)
self.files
.write(lock_token.token())
.bulk_insert_files_upper(files_to_insert)
}
/// Bulk-insert multiple files into to the upper file table manually
@@ -297,37 +312,61 @@ impl Context {
&self,
files_to_insert: Vec<FileDescriptor>,
handles: &[FileHandle],
lock_token: &mut LockToken<L4>,
) -> Result<()> {
self.files
.write()
.write(lock_token.token())
.bulk_insert_files_upper_manual(files_to_insert, handles)
}
/// Get a file
pub fn get_file(&self, i: FileHandle) -> Option<FileDescriptor> {
self.files.read().get_file(i)
pub fn get_file(
&self,
i: FileHandle,
lock_token: &mut LockToken<L4>,
) -> Option<FileDescriptor> {
self.files.read(lock_token.token()).get_file(i)
}
/// Bulk get files
pub fn bulk_get_files(&self, handles: &[FileHandle]) -> Result<Vec<FileDescriptor>> {
self.files.read().bulk_get_files(handles)
pub fn bulk_get_files(
&self,
handles: &[FileHandle],
lock_token: &mut LockToken<L4>,
) -> Result<Vec<FileDescriptor>> {
self.files.read(lock_token.token()).bulk_get_files(handles)
}
/// Insert a file with a specific handle number. This is used by dup2
/// Return the file descriptor number or None if the slot was not empty, or i was invalid
pub fn insert_file(&self, i: FileHandle, file: FileDescriptor) -> Option<FileHandle> {
self.files.write().insert_file(i, file)
pub fn insert_file(
&self,
i: FileHandle,
file: FileDescriptor,
lock_token: &mut LockToken<L4>,
) -> Option<FileHandle> {
self.files.write(lock_token.token()).insert_file(i, file)
}
/// Remove a file
// TODO: adjust files vector to smaller size if possible
pub fn remove_file(&self, i: FileHandle) -> Option<FileDescriptor> {
self.files.write().remove_file(i)
pub fn remove_file(
&self,
i: FileHandle,
lock_token: &mut LockToken<L4>,
) -> Option<FileDescriptor> {
self.files.write(lock_token.token()).remove_file(i)
}
/// Bulk remove files
pub fn bulk_remove_files(&self, handles: &[FileHandle]) -> Result<Vec<FileDescriptor>> {
self.files.write().bulk_remove_files(handles)
pub fn bulk_remove_files(
&self,
handles: &[FileHandle],
lock_token: &mut LockToken<L4>,
) -> Result<Vec<FileDescriptor>> {
self.files
.write(lock_token.token())
.bulk_remove_files(handles)
}
pub fn is_current_context(&self) -> bool {
@@ -582,6 +621,8 @@ pub struct FdTbl {
active_count: usize,
}
pub type LockedFdTbl = RwLock<L5, FdTbl>;
impl FdTbl {
pub fn new() -> Self {
Self {
@@ -955,7 +996,8 @@ pub fn bulk_add_fds(
return Ok(0);
}
let current_lock = context::current();
let current = current_lock.write(token.token());
let mut current = current_lock.write(token.token());
let (current, mut token) = current.token_split();
let files: Vec<FileDescriptor> = descriptions
.into_iter()
@@ -965,7 +1007,7 @@ pub fn bulk_add_fds(
})
.collect();
let handles = current
.bulk_add_files_posix(files)
.bulk_add_files_posix(files, &mut token)
.ok_or(Error::new(EMFILE))?;
let payload_chunks = payload.in_exact_chunks(size_of::<usize>());
for (handle, chunk) in handles.iter().zip(payload_chunks) {
@@ -998,12 +1040,13 @@ pub fn bulk_insert_fds(
.read_usize()?;
let current_lock = context::current();
let current = current_lock.write(token.token());
let mut current = current_lock.write(token.token());
let (current, mut token) = current.token_split();
if first_fd == usize::MAX {
let files = files_iter.collect::<Vec<_>>();
let handles = current
.bulk_insert_files_upper(files)
.bulk_insert_files_upper(files, &mut token)
.ok_or(Error::new(EMFILE))?;
let payload_chunks = payload.in_exact_chunks(size_of::<usize>());
for (handle, chunk) in handles.iter().zip(payload_chunks) {
@@ -1016,7 +1059,7 @@ pub fn bulk_insert_fds(
.map(|res| res.map(|i| FileHandle::from(i | syscall::UPPER_FDTBL_TAG)))
.collect::<Result<_, _>>()?;
let files = files_iter.collect::<Vec<_>>();
current.bulk_insert_files_upper_manual(files, &handles)?;
current.bulk_insert_files_upper_manual(files, &handles, &mut token)?;
Ok(handles.len())
}
}
+2 -1
View File
@@ -17,7 +17,8 @@ use crate::{
context::{arch::setup_new_utable, file::LockedFileDescription},
cpu_set::LogicalCpuSet,
memory::{
AddRefError, Enomem, Frame, PageInfo, RaiiFrame, RefCount, RefKind, deallocate_frame, get_page_info, init_frame, the_zeroed_frame
deallocate_frame, get_page_info, init_frame, the_zeroed_frame, AddRefError, Enomem, Frame,
PageInfo, RaiiFrame, RefCount, RefKind,
},
paging::{Page, PageFlags, PageMapper, RmmA, TableKind, VirtualAddress},
percpu::PercpuBlock,
+1 -1
View File
@@ -49,7 +49,7 @@ impl EventQueue {
let context_ref = context::current();
let context = context_ref.read(token.token());
let files = context.files.read();
let files = context.files.read(token.token());
match files.get(event.id).ok_or(Error::new(EBADF))? {
Some(file) => file.clone(),
None => return Err(Error::new(EBADF)),
+5 -2
View File
@@ -26,9 +26,12 @@ use syscall::{
use crate::{
context::{
self, ContextLock, file::{FileDescription, InternalFlags, LockedFileDescription}, memory::AddrSpaceWrapper
self,
file::{FileDescription, InternalFlags, LockedFileDescription},
memory::AddrSpaceWrapper,
ContextLock,
},
sync::{CleanLockToken, L0, L1, LockToken, RwLock},
sync::{CleanLockToken, LockToken, RwLock, L0, L1},
syscall::usercopy::{UserSliceRo, UserSliceRw, UserSliceWo},
};
+3 -3
View File
@@ -12,11 +12,11 @@ use crate::{
file::{FileDescription, InternalFlags, LockedFileDescription},
},
event,
sync::{CleanLockToken, L1, RwLock, WaitCondition},
sync::{CleanLockToken, RwLock, WaitCondition, L1},
syscall::{
data::Stat,
error::{EAGAIN, EBADF, EINTR, EINVAL, ENOENT, EPIPE, Error, Result},
flag::{EVENT_READ, EVENT_WRITE, EventFlags, MODE_FIFO, O_NONBLOCK},
error::{Error, Result, EAGAIN, EBADF, EINTR, EINVAL, ENOENT, EPIPE},
flag::{EventFlags, EVENT_READ, EVENT_WRITE, MODE_FIFO, O_NONBLOCK},
usercopy::{UserSliceRo, UserSliceRw, UserSliceWo},
},
};
+9 -8
View File
@@ -2,7 +2,7 @@ use crate::{
arch::paging::{Page, VirtualAddress},
context::{
self,
context::{HardBlockedReason, SignalState},
context::{HardBlockedReason, LockedFdTbl, SignalState},
file::InternalFlags,
memory::{handle_notify_files, AddrSpace, AddrSpaceWrapper, Grant, PageSpan},
Context, ContextLock, Status,
@@ -114,12 +114,12 @@ enum ContextHandle {
Sighandler,
Start,
NewFiletable {
filetable: Arc<spin::RwLock<FdTbl>>,
filetable: Arc<LockedFdTbl>,
binary_format: bool,
data: Box<[u8]>,
},
Filetable {
filetable: Weak<spin::RwLock<FdTbl>>,
filetable: Weak<LockedFdTbl>,
binary_format: bool,
data: Box<[u8]>,
},
@@ -138,7 +138,7 @@ enum ContextHandle {
CurrentFiletable,
AwaitingFiletableChange {
new_ft: Arc<spin::RwLock<FdTbl>>,
new_ft: Arc<LockedFdTbl>,
},
// TODO: Remove this once openat is implemented, or allow openat-via-dup via e.g. the top-level
@@ -354,7 +354,7 @@ impl ProcScheme {
*data = if binary_format {
let mut data = Vec::new();
for index in filetable
.read()
.read(token.token())
.enumerate()
.filter_map(|(idx, val)| val.as_ref().map(|_| idx))
{
@@ -366,7 +366,7 @@ impl ProcScheme {
let mut data = String::new();
for index in filetable
.read()
.read(token.token())
.enumerate()
.filter_map(|(idx, val)| val.as_ref().map(|_| idx))
{
@@ -767,7 +767,8 @@ impl KernelScheme for ProcScheme {
}
let filetable = filetable.upgrade().ok_or(Error::new(EOWNERDEAD))?;
let new_filetable = Arc::new(spin::RwLock::new(filetable.read().clone()));
let new_filetable =
Arc::new(RwLock::new(filetable.read(token.token()).clone()));
handle(
Handle {
@@ -835,7 +836,7 @@ impl KernelScheme for ProcScheme {
fn extract_scheme_number(fd: usize, token: &mut CleanLockToken) -> Result<(KernelSchemes, usize)> {
let file_descriptor = context::current()
.read(token.token())
.get_file(FileHandle::from(fd))
.get_file(FileHandle::from(fd), token)
.ok_or(Error::new(EBADF))?;
let (scheme_id, number) = {
let desc = file_descriptor.description.read(token.token());
+5 -1
View File
@@ -26,7 +26,11 @@ fn inner(fpath_user: UserSliceRw, token: &mut CleanLockToken) -> Result<Vec<u8>>
let (contexts, mut token) = contexts.token_split();
for context_ref in contexts.iter().filter_map(|r| r.upgrade()) {
let context = context_ref.read(token.token());
rows.push((context.pid, context.name, context.files.read().clone()));
rows.push((
context.pid,
context.name,
context.files.read(token.token()).clone(),
));
}
}
rows.sort_by_key(|row| row.0);
+14 -10
View File
@@ -754,7 +754,7 @@ impl UserInner {
Response::Fd({
context::current()
.read(token.token())
.remove_file(FileHandle::from(fd))
.remove_file(FileHandle::from(fd), token)
.ok_or(Error::new(EINVAL))?
.description
}),
@@ -793,14 +793,18 @@ impl UserInner {
description,
cloexec: true,
},
token,
);
} else {
let fd = context::current()
.read(token.token())
.add_file(FileDescriptor {
description,
cloexec: true,
})
.add_file(
FileDescriptor {
description,
cloexec: true,
},
token,
)
.ok_or(Error::new(EMFILE))?;
UserSlice::wo(dst_fd_or_ptr, size_of::<usize>())?.write_usize(fd.get())?;
}
@@ -1012,11 +1016,11 @@ impl UserInner {
let context_lock = context::current();
let mut context = context_lock.read(token.token());
let (context, mut lock_token) = context.token_split();
let desc =
context
.files
.read()
.find_by_scheme(self.scheme_id, file, &mut lock_token)?;
let desc = context.files.read(token.token()).find_by_scheme(
self.scheme_id,
file,
&mut lock_token,
)?;
(context.pid, desc.description)
};
+11
View File
@@ -89,32 +89,43 @@ pub struct L4 {}
#[derive(Debug)]
pub struct L5 {}
#[derive(Debug)]
pub struct L6 {}
impl Level for L0 {}
impl Level for L1 {}
impl Level for L2 {}
impl Level for L3 {}
impl Level for L4 {}
impl Level for L5 {}
impl Level for L6 {}
impl Lower<L1> for L0 {}
impl Lower<L2> for L0 {}
impl Lower<L3> for L0 {}
impl Lower<L4> for L0 {}
impl Lower<L5> for L0 {}
impl Lower<L6> for L0 {}
impl Lower<L2> for L1 {}
impl Lower<L3> for L1 {}
impl Lower<L4> for L1 {}
impl Lower<L5> for L1 {}
impl Lower<L6> for L1 {}
impl Lower<L3> for L2 {}
impl Lower<L4> for L2 {}
impl Lower<L5> for L2 {}
impl Lower<L6> for L2 {}
impl Lower<L4> for L3 {}
impl Lower<L5> for L3 {}
impl Lower<L6> for L3 {}
impl Lower<L5> for L4 {}
impl Lower<L6> for L4 {}
impl Lower<L6> for L5 {}
/// Indicate that the implementor is higher that the level O
pub trait Higher<O: Level>: Level {}
+25 -22
View File
@@ -39,7 +39,7 @@ pub fn file_op_generic_ext<T>(
let (file, desc) = {
let file = context::current()
.read(token.token())
.get_file(fd)
.get_file(fd, token)
.ok_or(Error::new(EBADF))?;
let desc = *file.description.read(token.token());
(file, desc)
@@ -75,7 +75,7 @@ pub fn openat(
let pipe = context::current()
.read(token.token())
.get_file(fh)
.get_file(fh, token)
.ok_or(Error::new(EBADF))?;
let (scheme_id, number) = {
@@ -116,10 +116,13 @@ pub fn openat(
context::current()
.read(token.token())
.add_file(FileDescriptor {
description: new_description,
cloexec: flags as usize & O_CLOEXEC == O_CLOEXEC,
})
.add_file(
FileDescriptor {
description: new_description,
cloexec: flags as usize & O_CLOEXEC == O_CLOEXEC,
},
token,
)
.ok_or(Error::new(EMFILE))
}
/// Unlinkat syscall
@@ -134,7 +137,7 @@ pub fn unlinkat(
let path_buf = copy_path_to_buf(raw_path, PATH_MAX)?;
let pipe = context::current()
.read(token.token())
.get_file(fh)
.get_file(fh, token)
.ok_or(Error::new(EBADF))?;
let (number, scheme_id) = {
@@ -161,7 +164,7 @@ pub fn close(fd: FileHandle, token: &mut CleanLockToken) -> Result<()> {
let file = {
let context_lock = context::current();
let context = context_lock.read(token.token());
context.remove_file(fd).ok_or(Error::new(EBADF))?
context.remove_file(fd, token).ok_or(Error::new(EBADF))?
};
file.close(token)
@@ -178,7 +181,7 @@ fn duplicate_file(
let context = context_lock.read(token.token());
(
context.caller_ctx(),
context.get_file(fd).ok_or(Error::new(EBADF))?,
context.get_file(fd, token).ok_or(Error::new(EBADF))?,
)
};
@@ -220,7 +223,7 @@ pub fn dup(fd: FileHandle, buf: UserSliceRo, token: &mut CleanLockToken) -> Resu
context::current()
.read(token.token())
.add_file(new_file)
.add_file(new_file, token)
.ok_or(Error::new(EMFILE))
}
@@ -241,7 +244,7 @@ pub fn dup2(
let context = context_ref.read(token.token());
context
.insert_file(new_fd, new_file)
.insert_file(new_fd, new_file, token)
.ok_or(Error::new(EMFILE))
}
}
@@ -281,8 +284,8 @@ fn call_normal(
context::current().read(token.token()),
flags.contains(CallFlags::CONSUME),
) {
(ctxt, true) => ctxt.remove_file(fd),
(ctxt, false) => ctxt.get_file(fd),
(ctxt, true) => ctxt.remove_file(fd, token),
(ctxt, false) => ctxt.get_file(fd, token),
})
.ok_or(Error::new(EBADF))?;
@@ -335,7 +338,7 @@ fn fdwrite_inner(
let current_lock = context::current();
let mut current = current_lock.read(token.token());
let (current, mut lock_token) = current.token_split();
let file_descriptor = current.get_file(socket).ok_or(Error::new(EBADF))?;
let file_descriptor = current.get_file(socket, token).ok_or(Error::new(EBADF))?;
let desc = &file_descriptor.description.read(lock_token.token());
(desc.scheme, desc.number)
};
@@ -347,9 +350,9 @@ fn fdwrite_inner(
scheme,
number,
if flags.contains(CallFlags::FD_CLONE) {
current.bulk_get_files(&target_fds)
current.bulk_get_files(&target_fds, token)
} else {
current.bulk_remove_files(&target_fds)
current.bulk_remove_files(&target_fds, token)
}?
.into_iter()
.map(|f| f.description)
@@ -387,7 +390,7 @@ fn call_fdread(
let current_lock = context::current();
let mut current = current_lock.read(token.token());
let (current, mut lock_token) = current.token_split();
let file_descriptor = current.get_file(fd).ok_or(Error::new(EBADF))?;
let file_descriptor = current.get_file(fd, token).ok_or(Error::new(EBADF))?;
let desc = file_descriptor.description.read(lock_token.token());
(desc.scheme, desc.number)
};
@@ -421,7 +424,7 @@ pub fn sendfd(
pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize, token: &mut CleanLockToken) -> Result<usize> {
let file = context::current()
.read(token.token())
.get_file(fd)
.get_file(fd, token)
.ok_or(Error::new(EBADF))?;
let (scheme_id, number, flags) = {
@@ -437,7 +440,7 @@ pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize, token: &mut CleanLockToken)
let context = context_lock.read(token.token());
return context
.add_file_min(new_file, arg)
.add_file_min(new_file, arg, token)
.ok_or(Error::new(EMFILE))
.map(FileHandle::into);
}
@@ -455,7 +458,7 @@ pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize, token: &mut CleanLockToken)
let mut context = context_lock.read(token.token());
let (context, mut lock_token) = context.token_split();
let mut files = context.files.write();
let mut files = context.files.write(token.token());
match *files.get_mut(fd.get()).ok_or(Error::new(EBADF))? {
Some(ref mut file) => match cmd {
F_GETFD => {
@@ -486,7 +489,7 @@ pub fn flink(fd: FileHandle, raw_path: UserSliceRo, token: &mut CleanLockToken)
let caller_ctx = context::current().read(token.token()).caller_ctx();
let file = context::current()
.read(token.token())
.get_file(fd)
.get_file(fd, token)
.ok_or(Error::new(EBADF))?;
/*
@@ -518,7 +521,7 @@ pub fn frename(fd: FileHandle, raw_path: UserSliceRo, token: &mut CleanLockToken
let caller_ctx = context::current().read(token.token()).caller_ctx();
let file = context::current()
.read(token.token())
.get_file(fd)
.get_file(fd, token)
.ok_or(Error::new(EBADF))?;
/*
+2 -1
View File
@@ -37,7 +37,7 @@ pub fn exit_this_context(excp: Option<syscall::Exception>, token: &mut CleanLock
{
let mut context = context_lock.write(token.token());
close_files = Arc::try_unwrap(mem::take(&mut context.files))
.map_or_else(|_| FdTbl::new(), spin::RwLock::into_inner);
.map_or_else(|_| FdTbl::new(), RwLock::into_inner);
addrspace_opt = context
.set_addr_space(None)
.and_then(|a| Arc::try_unwrap(a).ok());
@@ -267,6 +267,7 @@ fn insert_fd(scheme: SchemeId, number: usize, cloexec: bool, token: &mut CleanLo
cloexec,
},
syscall::flag::UPPER_FDTBL_TAG + scheme.get(),
token,
)
.expect("failed to insert fd to current context")
.get()