From 84123215680775f41fb739ffa06cf95e698804d6 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Mon, 9 Mar 2026 13:12:19 +0700 Subject: [PATCH] Add lock token to FdTbl without borrow check --- src/context/context.rs | 97 +++++++++++++++++++++++++++++----------- src/context/memory.rs | 3 +- src/event.rs | 2 +- src/scheme/mod.rs | 7 ++- src/scheme/pipe.rs | 6 +-- src/scheme/proc.rs | 17 +++---- src/scheme/sys/iostat.rs | 6 ++- src/scheme/user.rs | 24 +++++----- src/sync/ordered.rs | 11 +++++ src/syscall/fs.rs | 47 ++++++++++--------- src/syscall/process.rs | 3 +- 11 files changed, 147 insertions(+), 76 deletions(-) diff --git a/src/context/context.rs b/src/context/context.rs index 56bdcfe227..8146d977bf 100644 --- a/src/context/context.rs +++ b/src/context/context.rs @@ -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, /// The open files in the scheme - pub files: Arc>, + pub files: Arc, /// 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 { - self.add_file_min(file, 0) + pub fn add_file( + &self, + file: FileDescriptor, + lock_token: &mut LockToken, + ) -> Option { + 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 { - self.files.write().add_file_min(file, min) + pub fn add_file_min( + &self, + file: FileDescriptor, + min: usize, + lock_token: &mut LockToken, + ) -> Option { + 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, + lock_token: &mut LockToken, ) -> Option> { - 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, + lock_token: &mut LockToken, ) -> Option> { - 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, handles: &[FileHandle], + lock_token: &mut LockToken, ) -> 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 { - self.files.read().get_file(i) + pub fn get_file( + &self, + i: FileHandle, + lock_token: &mut LockToken, + ) -> Option { + self.files.read(lock_token.token()).get_file(i) } /// Bulk get files - pub fn bulk_get_files(&self, handles: &[FileHandle]) -> Result> { - self.files.read().bulk_get_files(handles) + pub fn bulk_get_files( + &self, + handles: &[FileHandle], + lock_token: &mut LockToken, + ) -> Result> { + 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 { - self.files.write().insert_file(i, file) + pub fn insert_file( + &self, + i: FileHandle, + file: FileDescriptor, + lock_token: &mut LockToken, + ) -> Option { + 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 { - self.files.write().remove_file(i) + pub fn remove_file( + &self, + i: FileHandle, + lock_token: &mut LockToken, + ) -> Option { + self.files.write(lock_token.token()).remove_file(i) } /// Bulk remove files - pub fn bulk_remove_files(&self, handles: &[FileHandle]) -> Result> { - self.files.write().bulk_remove_files(handles) + pub fn bulk_remove_files( + &self, + handles: &[FileHandle], + lock_token: &mut LockToken, + ) -> Result> { + 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; + 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 = 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::()); 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::>(); 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::()); 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::>()?; let files = files_iter.collect::>(); - current.bulk_insert_files_upper_manual(files, &handles)?; + current.bulk_insert_files_upper_manual(files, &handles, &mut token)?; Ok(handles.len()) } } diff --git a/src/context/memory.rs b/src/context/memory.rs index 532cb153a8..0c2b3c86aa 100644 --- a/src/context/memory.rs +++ b/src/context/memory.rs @@ -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, diff --git a/src/event.rs b/src/event.rs index 80767abdeb..14e71d68ae 100644 --- a/src/event.rs +++ b/src/event.rs @@ -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)), diff --git a/src/scheme/mod.rs b/src/scheme/mod.rs index 110d95c396..75f9c0bfca 100644 --- a/src/scheme/mod.rs +++ b/src/scheme/mod.rs @@ -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}, }; diff --git a/src/scheme/pipe.rs b/src/scheme/pipe.rs index 91b75f1dca..1c0bd4df47 100644 --- a/src/scheme/pipe.rs +++ b/src/scheme/pipe.rs @@ -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}, }, }; diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs index 44febe3be0..b6030c072d 100644 --- a/src/scheme/proc.rs +++ b/src/scheme/proc.rs @@ -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>, + filetable: Arc, binary_format: bool, data: Box<[u8]>, }, Filetable { - filetable: Weak>, + filetable: Weak, binary_format: bool, data: Box<[u8]>, }, @@ -138,7 +138,7 @@ enum ContextHandle { CurrentFiletable, AwaitingFiletableChange { - new_ft: Arc>, + new_ft: Arc, }, // 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()); diff --git a/src/scheme/sys/iostat.rs b/src/scheme/sys/iostat.rs index b7b5ea145e..455f280cc1 100644 --- a/src/scheme/sys/iostat.rs +++ b/src/scheme/sys/iostat.rs @@ -26,7 +26,11 @@ fn inner(fpath_user: UserSliceRw, token: &mut CleanLockToken) -> Result> 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); diff --git a/src/scheme/user.rs b/src/scheme/user.rs index 889633b417..4edac5a4f6 100644 --- a/src/scheme/user.rs +++ b/src/scheme/user.rs @@ -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::())?.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) }; diff --git a/src/sync/ordered.rs b/src/sync/ordered.rs index 57cb67ee98..5734d8997a 100644 --- a/src/sync/ordered.rs +++ b/src/sync/ordered.rs @@ -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 for L0 {} impl Lower for L0 {} impl Lower for L0 {} impl Lower for L0 {} impl Lower for L0 {} +impl Lower for L0 {} impl Lower for L1 {} impl Lower for L1 {} impl Lower for L1 {} impl Lower for L1 {} +impl Lower for L1 {} impl Lower for L2 {} impl Lower for L2 {} impl Lower for L2 {} +impl Lower for L2 {} impl Lower for L3 {} impl Lower for L3 {} +impl Lower for L3 {} impl Lower for L4 {} +impl Lower for L4 {} + +impl Lower for L5 {} /// Indicate that the implementor is higher that the level O pub trait Higher: Level {} diff --git a/src/syscall/fs.rs b/src/syscall/fs.rs index 2f5bd23a3f..79a5352128 100644 --- a/src/syscall/fs.rs +++ b/src/syscall/fs.rs @@ -39,7 +39,7 @@ pub fn file_op_generic_ext( 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 { 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))?; /* diff --git a/src/syscall/process.rs b/src/syscall/process.rs index f57e4a20c6..4ce1ee0984 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -37,7 +37,7 @@ pub fn exit_this_context(excp: Option, 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()