From b9ce3e64ad57f336b22ae39daaae618ad12c343c Mon Sep 17 00:00:00 2001 From: Ruihan Li Date: Thu, 26 Dec 2024 21:35:56 +0800 Subject: [PATCH] Make the file lookup faster --- kernel/src/device/pty/pty.rs | 16 ++-- kernel/src/fs/epoll/file.rs | 15 ++-- kernel/src/fs/file_handle.rs | 7 ++ kernel/src/fs/file_table.rs | 62 ++++++++++++++ kernel/src/fs/fs_resolver.rs | 31 ++++--- kernel/src/fs/procfs/pid/fd.rs | 6 +- kernel/src/fs/procfs/pid/mod.rs | 2 +- kernel/src/fs/procfs/pid/status.rs | 2 +- kernel/src/process/clone.rs | 14 ++-- kernel/src/process/exit.rs | 6 +- kernel/src/process/posix_thread/builder.rs | 13 ++- kernel/src/process/posix_thread/exit.rs | 2 +- kernel/src/process/posix_thread/mod.rs | 6 +- .../src/process/posix_thread/thread_local.rs | 18 +++- kernel/src/process/program_loader/mod.rs | 6 +- kernel/src/syscall/accept.rs | 12 ++- kernel/src/syscall/bind.rs | 12 +-- kernel/src/syscall/chdir.rs | 15 ++-- kernel/src/syscall/chmod.rs | 8 +- kernel/src/syscall/chown.rs | 8 +- kernel/src/syscall/close.rs | 7 +- kernel/src/syscall/connect.rs | 12 +-- kernel/src/syscall/dup.rs | 18 ++-- kernel/src/syscall/epoll.rs | 26 +++--- kernel/src/syscall/eventfd.rs | 5 +- kernel/src/syscall/execve.rs | 27 +++--- kernel/src/syscall/fallocate.rs | 11 +-- kernel/src/syscall/fcntl.rs | 82 ++++++++----------- kernel/src/syscall/flock.rs | 14 +--- kernel/src/syscall/fsync.rs | 24 ++---- kernel/src/syscall/getdents64.rs | 23 ++---- kernel/src/syscall/getpeername.rs | 12 +-- kernel/src/syscall/getsockname.rs | 12 +-- kernel/src/syscall/getsockopt.rs | 8 +- kernel/src/syscall/ioctl.rs | 38 +++++---- kernel/src/syscall/listen.rs | 11 +-- kernel/src/syscall/lseek.rs | 11 +-- kernel/src/syscall/mmap.rs | 13 +-- kernel/src/syscall/open.rs | 7 +- kernel/src/syscall/pipe.rs | 11 +-- kernel/src/syscall/poll.rs | 33 ++++++-- kernel/src/syscall/pread64.rs | 13 +-- kernel/src/syscall/preadv.rs | 14 ++-- kernel/src/syscall/pwrite64.rs | 14 ++-- kernel/src/syscall/pwritev.rs | 23 ++++-- kernel/src/syscall/read.rs | 11 +-- kernel/src/syscall/recvfrom.rs | 10 +-- kernel/src/syscall/recvmsg.rs | 11 +-- kernel/src/syscall/sendfile.rs | 22 +++-- kernel/src/syscall/sendmsg.rs | 8 +- kernel/src/syscall/sendto.rs | 8 +- kernel/src/syscall/setsockopt.rs | 8 +- kernel/src/syscall/shutdown.rs | 12 +-- kernel/src/syscall/socket.rs | 5 +- kernel/src/syscall/socketpair.rs | 7 +- kernel/src/syscall/stat.rs | 9 +- kernel/src/syscall/statfs.rs | 12 +-- kernel/src/syscall/truncate.rs | 9 +- kernel/src/syscall/write.rs | 11 +-- 59 files changed, 483 insertions(+), 390 deletions(-) diff --git a/kernel/src/device/pty/pty.rs b/kernel/src/device/pty/pty.rs index 47e1abc6..7e95cfda 100644 --- a/kernel/src/device/pty/pty.rs +++ b/kernel/src/device/pty/pty.rs @@ -2,6 +2,8 @@ use alloc::format; +use ostd::task::Task; + use crate::{ current_userspace, device::tty::{line_discipline::LineDiscipline, new_job_control_and_ldisc}, @@ -16,7 +18,7 @@ use crate::{ }, prelude::*, process::{ - posix_thread::AsPosixThread, + posix_thread::{AsPosixThread, AsThreadLocal}, signal::{PollHandle, Pollable, Pollee}, JobControl, Terminal, }, @@ -192,8 +194,9 @@ impl FileIo for PtyMaster { Ok(0) } IoctlCmd::TIOCGPTPEER => { - let current = current_thread!(); - let current = current.as_posix_thread().unwrap(); + let current_task = Task::current().unwrap(); + let posix_thread = current_task.as_posix_thread().unwrap(); + let thread_local = current_task.as_thread_local().unwrap(); // TODO: deal with open options let slave = { @@ -205,7 +208,7 @@ impl FileIo for PtyMaster { let fs_path = FsPath::try_from(slave_name.as_str())?; let inode_handle = { - let fs = current.fs().resolver().read(); + let fs = posix_thread.fs().resolver().read(); let flags = AccessMode::O_RDWR as u32; let mode = (InodeMode::S_IRUSR | InodeMode::S_IWUSR).bits(); fs.open(&fs_path, flags, mode)? @@ -214,9 +217,10 @@ impl FileIo for PtyMaster { }; let fd = { - let mut file_table = current.file_table().lock(); + let file_table = thread_local.file_table().borrow(); + let mut file_table_locked = file_table.write(); // TODO: deal with the O_CLOEXEC flag - file_table.insert(slave, FdFlags::empty()) + file_table_locked.insert(slave, FdFlags::empty()) }; Ok(fd) } diff --git a/kernel/src/fs/epoll/file.rs b/kernel/src/fs/epoll/file.rs index 5c0ec64e..4588321b 100644 --- a/kernel/src/fs/epoll/file.rs +++ b/kernel/src/fs/epoll/file.rs @@ -14,12 +14,12 @@ use crate::{ events::IoEvents, fs::{ file_handle::FileLike, - file_table::FileDesc, + file_table::{get_file_fast, FileDesc}, utils::{InodeMode, IoctlCmd, Metadata}, }, prelude::*, process::{ - posix_thread::AsPosixThread, + posix_thread::ThreadLocal, signal::{PollHandle, Pollable}, }, }; @@ -56,19 +56,16 @@ impl EpollFile { } /// Controls the interest list of the epoll file. - pub fn control(&self, cmd: &EpollCtl) -> Result<()> { + pub fn control(&self, thread_local: &ThreadLocal, cmd: &EpollCtl) -> Result<()> { let fd = match cmd { EpollCtl::Add(fd, ..) => *fd, EpollCtl::Del(fd) => *fd, EpollCtl::Mod(fd, ..) => *fd, }; - let file = { - let current = current_thread!(); - let current = current.as_posix_thread().unwrap(); - let file_table = current.file_table().lock(); - file_table.get_file(fd)?.clone() - }; + let mut file_table = thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd).into_owned(); + drop(file_table); match *cmd { EpollCtl::Add(fd, ep_event, ep_flags) => { diff --git a/kernel/src/fs/file_handle.rs b/kernel/src/fs/file_handle.rs index 98caa5db..8bbf42f1 100644 --- a/kernel/src/fs/file_handle.rs +++ b/kernel/src/fs/file_handle.rs @@ -4,6 +4,7 @@ //! Opened File Handle +use super::inode_handle::InodeHandle; use crate::{ fs::utils::{AccessMode, FallocMode, InodeMode, IoctlCmd, Metadata, SeekFrom, StatusFlags}, net::socket::Socket, @@ -131,4 +132,10 @@ impl dyn FileLike { self.as_socket() .ok_or_else(|| Error::with_message(Errno::ENOTSOCK, "the file is not a socket")) } + + pub fn as_inode_or_err(&self) -> Result<&InodeHandle> { + self.downcast_ref().ok_or_else(|| { + Error::with_message(Errno::EINVAL, "the file is not related to an inode") + }) + } } diff --git a/kernel/src/fs/file_table.rs b/kernel/src/fs/file_table.rs index 1f15fb94..cd3f3473 100644 --- a/kernel/src/fs/file_table.rs +++ b/kernel/src/fs/file_table.rs @@ -5,6 +5,7 @@ use core::sync::atomic::{AtomicU8, Ordering}; use aster_util::slot_vec::SlotVec; +use ostd::sync::RwArc; use super::{ file_handle::FileLike, @@ -237,6 +238,67 @@ impl Drop for FileTable { } } +/// A helper trait that provides methods to operate the file table. +pub trait WithFileTable { + /// Calls `f` with the file table. + /// + /// This method is lockless if the file table is not shared. Otherwise, `f` is called while + /// holding the read lock on the file table. + fn read_with(&mut self, f: impl FnOnce(&FileTable) -> R) -> R; +} + +impl WithFileTable for RwArc { + fn read_with(&mut self, f: impl FnOnce(&FileTable) -> R) -> R { + if let Some(inner) = self.get() { + f(inner) + } else { + f(&self.read()) + } + } +} + +/// Gets a file from a file descriptor as fast as possible. +/// +/// `file_table` should be a mutable borrow of the file table contained in the `file_table` field +/// (which is a [`RefCell`]) in [`ThreadLocal`]. A mutable borrow is required because its +/// exclusivity can be useful for achieving lockless file lookups. +/// +/// If the file table is not shared with another thread, this macro will be free of locks +/// ([`RwArc::read`]) and free of reference counting ([`Arc::clone`]). +/// +/// If the file table is shared, the read lock is taken, the file is cloned, and then the read lock +/// is released. Cloning and releasing the lock is necessary because we cannot hold such locks when +/// operating on files, since many operations on files can block. +/// +/// Note: This has to be a macro due to a limitation in the Rust borrow check implementation. Once +/// is fixed, we can try to convert this macro to +/// a function. +/// +/// [`RefCell`]: core::cell::RefCell +/// [`ThreadLocal`]: crate::process::posix_thread::ThreadLocal +macro_rules! get_file_fast { + ($file_table:expr, $file_desc:expr) => {{ + use alloc::borrow::Cow; + + use ostd::sync::RwArc; + + use crate::fs::file_table::{FileDesc, FileTable}; + + let file_table: &mut RwArc = $file_table; + let file_desc: FileDesc = $file_desc; + + if let Some(inner) = file_table.get() { + // Fast path: The file table is not shared, we can get the file in a lockless way. + Cow::Borrowed(inner.get_file(file_desc)?) + } else { + // Slow path: The file table is shared, we need to hold the lock and clone the file. + Cow::Owned(file_table.read().get_file(file_desc)?.clone()) + } + }}; +} + +pub(crate) use get_file_fast; + #[derive(Copy, Clone, Debug)] pub enum FdEvents { Close(FileDesc), diff --git a/kernel/src/fs/fs_resolver.rs b/kernel/src/fs/fs_resolver.rs index c9afd6f2..c9d8fc30 100644 --- a/kernel/src/fs/fs_resolver.rs +++ b/kernel/src/fs/fs_resolver.rs @@ -2,14 +2,16 @@ use alloc::str; +use ostd::task::Task; + use super::{ - file_table::FileDesc, + file_table::{get_file_fast, FileDesc}, inode_handle::InodeHandle, path::Dentry, rootfs::root_mount, utils::{AccessMode, CreationFlags, InodeMode, InodeType, StatusFlags, PATH_MAX, SYMLINKS_MAX}, }; -use crate::{prelude::*, process::posix_thread::AsPosixThread}; +use crate::{prelude::*, process::posix_thread::AsThreadLocal}; /// The file descriptor of the current working directory. pub const AT_FDCWD: FileDesc = -100; @@ -166,10 +168,17 @@ impl FsResolver { } FsPathInner::Cwd => self.cwd.clone(), FsPathInner::FdRelative(fd, path) => { - let parent = self.lookup_from_fd(fd)?; - self.lookup_from_parent(&parent, path, lookup_ctx)? + let task = Task::current().unwrap(); + let mut file_table = task.as_thread_local().unwrap().file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); + self.lookup_from_parent(file.as_inode_or_err()?.dentry(), path, lookup_ctx)? + } + FsPathInner::Fd(fd) => { + let task = Task::current().unwrap(); + let mut file_table = task.as_thread_local().unwrap().file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); + file.as_inode_or_err()?.dentry().clone() } - FsPathInner::Fd(fd) => self.lookup_from_fd(fd)?, }; Ok(dentry) @@ -280,18 +289,6 @@ impl FsResolver { Ok(dentry) } - /// Lookups the target dentry according to the given `fd`. - pub fn lookup_from_fd(&self, fd: FileDesc) -> Result { - let current = current_thread!(); - let current = current.as_posix_thread().unwrap(); - let file_table = current.file_table().lock(); - let inode_handle = file_table - .get_file(fd)? - .downcast_ref::() - .ok_or(Error::with_message(Errno::EBADF, "not inode"))?; - Ok(inode_handle.dentry().clone()) - } - /// Lookups the target parent directory dentry and /// the base file name according to the given `path`. /// diff --git a/kernel/src/fs/procfs/pid/fd.rs b/kernel/src/fs/procfs/pid/fd.rs index 93601bf6..5fa945ef 100644 --- a/kernel/src/fs/procfs/pid/fd.rs +++ b/kernel/src/fs/procfs/pid/fd.rs @@ -25,7 +25,7 @@ impl FdDirOps { .build() .unwrap(); let main_thread = process_ref.main_thread(); - let file_table = main_thread.as_posix_thread().unwrap().file_table().lock(); + let file_table = main_thread.as_posix_thread().unwrap().file_table().read(); let weak_ptr = Arc::downgrade(&fd_inode); file_table.register_observer(weak_ptr); fd_inode @@ -52,7 +52,7 @@ impl DirOps for FdDirOps { .parse::() .map_err(|_| Error::new(Errno::ENOENT))?; let main_thread = self.0.main_thread(); - let file_table = main_thread.as_posix_thread().unwrap().file_table().lock(); + let file_table = main_thread.as_posix_thread().unwrap().file_table().read(); file_table .get_file(fd) .map_err(|_| Error::new(Errno::ENOENT))? @@ -68,7 +68,7 @@ impl DirOps for FdDirOps { }; let mut cached_children = this.cached_children().write(); let main_thread = self.0.main_thread(); - let file_table = main_thread.as_posix_thread().unwrap().file_table().lock(); + let file_table = main_thread.as_posix_thread().unwrap().file_table().read(); for (fd, file) in file_table.fds_and_files() { cached_children.put_entry_if_not_found(&fd.to_string(), || { FileSymOps::new_inode(file.clone(), this_ptr.clone()) diff --git a/kernel/src/fs/procfs/pid/mod.rs b/kernel/src/fs/procfs/pid/mod.rs index eff3b411..5274e0bd 100644 --- a/kernel/src/fs/procfs/pid/mod.rs +++ b/kernel/src/fs/procfs/pid/mod.rs @@ -34,7 +34,7 @@ impl PidDirOps { .build() .unwrap(); let main_thread = process_ref.main_thread(); - let file_table = main_thread.as_posix_thread().unwrap().file_table().lock(); + let file_table = main_thread.as_posix_thread().unwrap().file_table().read(); let weak_ptr = Arc::downgrade(&pid_inode); file_table.register_observer(weak_ptr); pid_inode diff --git a/kernel/src/fs/procfs/pid/status.rs b/kernel/src/fs/procfs/pid/status.rs index 127a8148..e184efbe 100644 --- a/kernel/src/fs/procfs/pid/status.rs +++ b/kernel/src/fs/procfs/pid/status.rs @@ -81,7 +81,7 @@ impl FileOps for StatusFileOps { writeln!(status_output, "Pid:\t{}", process.pid()).unwrap(); writeln!(status_output, "PPid:\t{}", process.parent().pid()).unwrap(); writeln!(status_output, "TracerPid:\t{}", process.parent().pid()).unwrap(); // Assuming TracerPid is the same as PPid - writeln!(status_output, "FDSize:\t{}", file_table.lock().len()).unwrap(); + writeln!(status_output, "FDSize:\t{}", file_table.read().len()).unwrap(); writeln!( status_output, "Threads:\t{}", diff --git a/kernel/src/process/clone.rs b/kernel/src/process/clone.rs index e166a6b0..f5adbef9 100644 --- a/kernel/src/process/clone.rs +++ b/kernel/src/process/clone.rs @@ -4,6 +4,7 @@ use core::{num::NonZeroU64, sync::atomic::Ordering}; use ostd::{ cpu::UserContext, + sync::RwArc, task::Task, user::{UserContextApi, UserSpace}, }; @@ -215,6 +216,7 @@ fn clone_child_task( let Context { process, + thread_local, posix_thread, .. } = ctx; @@ -223,7 +225,7 @@ fn clone_child_task( clone_sysvsem(clone_flags)?; // clone file table - let child_file_table = clone_files(posix_thread.file_table(), clone_flags); + let child_file_table = clone_files(&thread_local.file_table().borrow(), clone_flags); // clone fs let child_fs = clone_fs(posix_thread.fs(), clone_flags); @@ -281,6 +283,7 @@ fn clone_child_process( ) -> Result> { let Context { process, + thread_local, posix_thread, .. } = ctx; @@ -310,7 +313,7 @@ fn clone_child_process( }; // clone file table - let child_file_table = clone_files(posix_thread.file_table(), clone_flags); + let child_file_table = clone_files(&thread_local.file_table().borrow(), clone_flags); // clone fs let child_fs = clone_fs(posix_thread.fs(), clone_flags); @@ -466,17 +469,14 @@ fn clone_fs(parent_fs: &Arc, clone_flags: CloneFlags) -> Arc>, - clone_flags: CloneFlags, -) -> Arc> { +fn clone_files(parent_file_table: &RwArc, clone_flags: CloneFlags) -> RwArc { // if CLONE_FILES is set, the child and parent shares the same file table // Otherwise, the child will deep copy a new file table. // FIXME: the clone may not be deep copy. if clone_flags.contains(CloneFlags::CLONE_FILES) { parent_file_table.clone() } else { - Arc::new(SpinLock::new(parent_file_table.lock().clone())) + RwArc::new(parent_file_table.read().clone()) } } diff --git a/kernel/src/process/exit.rs b/kernel/src/process/exit.rs index 5e86fad9..f9aa6590 100644 --- a/kernel/src/process/exit.rs +++ b/kernel/src/process/exit.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MPL-2.0 -use super::{posix_thread::PosixThread, process_table, Pid, Process}; +use super::{posix_thread::ThreadLocal, process_table, Pid, Process}; use crate::{prelude::*, process::signal::signals::kernel::KernelSignal}; /// Exits the current POSIX process. @@ -10,12 +10,12 @@ use crate::{prelude::*, process::signal::signals::kernel::KernelSignal}; /// /// [`do_exit`]: crate::process::posix_thread::do_exit /// [`do_exit_group`]: crate::process::posix_thread::do_exit_group -pub(super) fn exit_process(current_thread: &PosixThread, current_process: &Process) { +pub(super) fn exit_process(thread_local: &ThreadLocal, current_process: &Process) { current_process.status().set_zombie(); // FIXME: This is obviously wrong in a number of ways, since different threads can have // different file tables, and different processes can share the same file table. - current_thread.file_table().lock().close_all(); + thread_local.file_table().borrow().write().close_all(); send_parent_death_signal(current_process); diff --git a/kernel/src/process/posix_thread/builder.rs b/kernel/src/process/posix_thread/builder.rs index c560061b..61399905 100644 --- a/kernel/src/process/posix_thread/builder.rs +++ b/kernel/src/process/posix_thread/builder.rs @@ -2,7 +2,7 @@ #![allow(dead_code)] -use ostd::{cpu::CpuSet, task::Task, user::UserSpace}; +use ostd::{cpu::CpuSet, sync::RwArc, task::Task, user::UserSpace}; use super::{thread_table, PosixThread, ThreadLocal}; use crate::{ @@ -30,7 +30,7 @@ pub struct PosixThreadBuilder { thread_name: Option, set_child_tid: Vaddr, clear_child_tid: Vaddr, - file_table: Option>>, + file_table: Option>, fs: Option>, sig_mask: AtomicSigMask, sig_queues: SigQueues, @@ -75,7 +75,7 @@ impl PosixThreadBuilder { self } - pub fn file_table(mut self, file_table: Arc>) -> Self { + pub fn file_table(mut self, file_table: RwArc) -> Self { self.file_table = Some(file_table); self } @@ -111,8 +111,7 @@ impl PosixThreadBuilder { priority, } = self; - let file_table = - file_table.unwrap_or_else(|| Arc::new(SpinLock::new(FileTable::new_with_stdio()))); + let file_table = file_table.unwrap_or_else(|| RwArc::new(FileTable::new_with_stdio())); let fs = fs.unwrap_or_else(|| Arc::new(ThreadFsInfo::default())); @@ -127,7 +126,7 @@ impl PosixThreadBuilder { tid, name: Mutex::new(thread_name), credentials, - file_table, + file_table: file_table.clone_ro(), fs, sig_mask, sig_queues, @@ -146,7 +145,7 @@ impl PosixThreadBuilder { cpu_affinity, )); - let thread_local = ThreadLocal::new(set_child_tid, clear_child_tid); + let thread_local = ThreadLocal::new(set_child_tid, clear_child_tid, file_table); thread_table::add_thread(tid, thread.clone()); task::create_new_user_task(user_space, thread, thread_local) diff --git a/kernel/src/process/posix_thread/exit.rs b/kernel/src/process/posix_thread/exit.rs index 783216a6..9ed8643e 100644 --- a/kernel/src/process/posix_thread/exit.rs +++ b/kernel/src/process/posix_thread/exit.rs @@ -80,7 +80,7 @@ fn exit_internal(term_status: TermStatus, is_exiting_group: bool) { } if is_last_thread { - exit_process(posix_thread, &posix_process); + exit_process(thread_local, &posix_process); } } diff --git a/kernel/src/process/posix_thread/mod.rs b/kernel/src/process/posix_thread/mod.rs index cd7c7278..9698b161 100644 --- a/kernel/src/process/posix_thread/mod.rs +++ b/kernel/src/process/posix_thread/mod.rs @@ -5,7 +5,7 @@ use core::sync::atomic::{AtomicU32, Ordering}; use aster_rights::{ReadOp, WriteOp}; -use ostd::sync::Waker; +use ostd::sync::{RoArc, Waker}; use super::{ kill::SignalSenderIds, @@ -57,7 +57,7 @@ pub struct PosixThread { // Files /// File table - file_table: Arc>, + file_table: RoArc, /// File system fs: Arc, @@ -98,7 +98,7 @@ impl PosixThread { &self.name } - pub fn file_table(&self) -> &Arc> { + pub fn file_table(&self) -> &RoArc { &self.file_table } diff --git a/kernel/src/process/posix_thread/thread_local.rs b/kernel/src/process/posix_thread/thread_local.rs index a78eb194..6758f109 100644 --- a/kernel/src/process/posix_thread/thread_local.rs +++ b/kernel/src/process/posix_thread/thread_local.rs @@ -2,10 +2,10 @@ use core::cell::{Cell, RefCell}; -use ostd::{mm::Vaddr, task::CurrentTask}; +use ostd::{mm::Vaddr, sync::RwArc, task::CurrentTask}; use super::RobustListHead; -use crate::process::signal::SigStack; +use crate::{fs::file_table::FileTable, process::signal::SigStack}; /// Local data for a POSIX thread. pub struct ThreadLocal { @@ -18,6 +18,9 @@ pub struct ThreadLocal { // https://man7.org/linux/man-pages/man2/get_robust_list.2.html robust_list: RefCell>, + // Files. + file_table: RefCell>, + // Signal. /// `ucontext` address for the signal handler. // FIXME: This field may be removed. For glibc applications with RESTORER flag set, the @@ -28,11 +31,16 @@ pub struct ThreadLocal { } impl ThreadLocal { - pub(super) fn new(set_child_tid: Vaddr, clear_child_tid: Vaddr) -> Self { + pub(super) fn new( + set_child_tid: Vaddr, + clear_child_tid: Vaddr, + file_table: RwArc, + ) -> Self { Self { set_child_tid: Cell::new(set_child_tid), clear_child_tid: Cell::new(clear_child_tid), robust_list: RefCell::new(None), + file_table: RefCell::new(file_table), sig_context: Cell::new(None), sig_stack: RefCell::new(None), } @@ -50,6 +58,10 @@ impl ThreadLocal { &self.robust_list } + pub fn file_table(&self) -> &RefCell> { + &self.file_table + } + pub fn sig_context(&self) -> &Cell> { &self.sig_context } diff --git a/kernel/src/process/program_loader/mod.rs b/kernel/src/process/program_loader/mod.rs index 6fe5af9e..bb177036 100644 --- a/kernel/src/process/program_loader/mod.rs +++ b/kernel/src/process/program_loader/mod.rs @@ -12,7 +12,7 @@ use crate::{ fs::{ fs_resolver::{FsPath, FsResolver, AT_FDCWD}, path::Dentry, - utils::Permission, + utils::{InodeType, Permission}, }, prelude::*, }; @@ -74,6 +74,10 @@ pub fn check_executable_file(dentry: &Dentry) -> Result<()> { return_errno_with_message!(Errno::EISDIR, "the file is a directory"); } + if dentry.type_() == InodeType::SymLink { + return_errno_with_message!(Errno::ELOOP, "the file is a symbolic link"); + } + if !dentry.type_().is_regular_file() { return_errno_with_message!(Errno::EACCES, "the dentry is not a regular file"); } diff --git a/kernel/src/syscall/accept.rs b/kernel/src/syscall/accept.rs index bac1da51..b3d0824a 100644 --- a/kernel/src/syscall/accept.rs +++ b/kernel/src/syscall/accept.rs @@ -3,7 +3,7 @@ use super::SyscallReturn; use crate::{ fs::{ - file_table::{FdFlags, FileDesc}, + file_table::{get_file_fast, FdFlags, FileDesc}, utils::{CreationFlags, StatusFlags}, }, prelude::*, @@ -47,10 +47,8 @@ fn do_accept( flags: Flags, ctx: &Context, ) -> Result { - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(sockfd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, sockfd); let socket = file.as_socket_or_err()?; let (connected_socket, socket_addr) = { @@ -76,8 +74,8 @@ fn do_accept( } let fd = { - let mut file_table = ctx.posix_thread.file_table().lock(); - file_table.insert(connected_socket, fd_flags) + let mut file_table_locked = file_table.write(); + file_table_locked.insert(connected_socket, fd_flags) }; Ok(fd) diff --git a/kernel/src/syscall/bind.rs b/kernel/src/syscall/bind.rs index 8418dbc7..b8dcc0cb 100644 --- a/kernel/src/syscall/bind.rs +++ b/kernel/src/syscall/bind.rs @@ -1,7 +1,11 @@ // SPDX-License-Identifier: MPL-2.0 use super::SyscallReturn; -use crate::{fs::file_table::FileDesc, prelude::*, util::net::read_socket_addr_from_user}; +use crate::{ + fs::file_table::{get_file_fast, FileDesc}, + prelude::*, + util::net::read_socket_addr_from_user, +}; pub fn sys_bind( sockfd: FileDesc, @@ -12,10 +16,8 @@ pub fn sys_bind( let socket_addr = read_socket_addr_from_user(sockaddr_ptr, addrlen as usize)?; debug!("sockfd = {sockfd}, socket_addr = {socket_addr:?}"); - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(sockfd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, sockfd); let socket = file.as_socket_or_err()?; socket.bind(socket_addr)?; diff --git a/kernel/src/syscall/chdir.rs b/kernel/src/syscall/chdir.rs index b61a0e47..0e4ee906 100644 --- a/kernel/src/syscall/chdir.rs +++ b/kernel/src/syscall/chdir.rs @@ -2,7 +2,11 @@ use super::SyscallReturn; use crate::{ - fs::{file_table::FileDesc, fs_resolver::FsPath, inode_handle::InodeHandle, utils::InodeType}, + fs::{ + file_table::{get_file_fast, FileDesc}, + fs_resolver::FsPath, + utils::InodeType, + }, prelude::*, syscall::constants::MAX_FILENAME_LEN, }; @@ -31,12 +35,9 @@ pub fn sys_fchdir(fd: FileDesc, ctx: &Context) -> Result { debug!("fd = {}", fd); let dentry = { - let file_table = ctx.posix_thread.file_table().lock(); - let file = file_table.get_file(fd)?; - let inode_handle = file - .downcast_ref::() - .ok_or(Error::with_message(Errno::EBADF, "not inode"))?; - inode_handle.dentry().clone() + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); + file.as_inode_or_err()?.dentry().clone() }; if dentry.type_() != InodeType::Dir { return_errno_with_message!(Errno::ENOTDIR, "must be directory"); diff --git a/kernel/src/syscall/chmod.rs b/kernel/src/syscall/chmod.rs index 8e5fdc25..0106e716 100644 --- a/kernel/src/syscall/chmod.rs +++ b/kernel/src/syscall/chmod.rs @@ -3,7 +3,7 @@ use super::SyscallReturn; use crate::{ fs::{ - file_table::FileDesc, + file_table::{get_file_fast, FileDesc}, fs_resolver::{FsPath, AT_FDCWD}, utils::{InodeMode, PATH_MAX}, }, @@ -13,10 +13,8 @@ use crate::{ pub fn sys_fchmod(fd: FileDesc, mode: u16, ctx: &Context) -> Result { debug!("fd = {}, mode = 0o{:o}", fd, mode); - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(fd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); file.set_mode(InodeMode::from_bits_truncate(mode))?; Ok(SyscallReturn::Return(0)) } diff --git a/kernel/src/syscall/chown.rs b/kernel/src/syscall/chown.rs index 5a67c139..fd90748b 100644 --- a/kernel/src/syscall/chown.rs +++ b/kernel/src/syscall/chown.rs @@ -3,7 +3,7 @@ use super::SyscallReturn; use crate::{ fs::{ - file_table::FileDesc, + file_table::{get_file_fast, FileDesc}, fs_resolver::{FsPath, AT_FDCWD}, utils::PATH_MAX, }, @@ -20,10 +20,8 @@ pub fn sys_fchown(fd: FileDesc, uid: i32, gid: i32, ctx: &Context) -> Result Result { debug!("fd = {}", fd); let file = { - let mut file_table = ctx.posix_thread.file_table().lock(); - let _ = file_table.get_file(fd)?; - file_table.close_file(fd).unwrap() + let file_table = ctx.thread_local.file_table().borrow(); + let mut file_table_locked = file_table.write(); + let _ = file_table_locked.get_file(fd)?; + file_table_locked.close_file(fd).unwrap() }; // Cleanup work needs to be done in the `Drop` impl. diff --git a/kernel/src/syscall/connect.rs b/kernel/src/syscall/connect.rs index 90a22a94..36932269 100644 --- a/kernel/src/syscall/connect.rs +++ b/kernel/src/syscall/connect.rs @@ -1,7 +1,11 @@ // SPDX-License-Identifier: MPL-2.0 use super::SyscallReturn; -use crate::{fs::file_table::FileDesc, prelude::*, util::net::read_socket_addr_from_user}; +use crate::{ + fs::file_table::{get_file_fast, FileDesc}, + prelude::*, + util::net::read_socket_addr_from_user, +}; pub fn sys_connect( sockfd: FileDesc, @@ -12,10 +16,8 @@ pub fn sys_connect( let socket_addr = read_socket_addr_from_user(sockaddr_ptr, addr_len as _)?; debug!("fd = {sockfd}, socket_addr = {socket_addr:?}"); - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(sockfd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, sockfd); let socket = file.as_socket_or_err()?; socket diff --git a/kernel/src/syscall/dup.rs b/kernel/src/syscall/dup.rs index 3fc40f3a..7749fae0 100644 --- a/kernel/src/syscall/dup.rs +++ b/kernel/src/syscall/dup.rs @@ -2,7 +2,7 @@ use super::SyscallReturn; use crate::{ - fs::file_table::{FdFlags, FileDesc}, + fs::file_table::{get_file_fast, FdFlags, FileDesc}, prelude::*, process::ResourceType, }; @@ -10,8 +10,9 @@ use crate::{ pub fn sys_dup(old_fd: FileDesc, ctx: &Context) -> Result { debug!("old_fd = {}", old_fd); - let mut file_table = ctx.posix_thread.file_table().lock(); - let new_fd = file_table.dup(old_fd, 0, FdFlags::empty())?; + let file_table = ctx.thread_local.file_table().borrow(); + let mut file_table_locked = file_table.write(); + let new_fd = file_table_locked.dup(old_fd, 0, FdFlags::empty())?; Ok(SyscallReturn::Return(new_fd as _)) } @@ -20,8 +21,8 @@ pub fn sys_dup2(old_fd: FileDesc, new_fd: FileDesc, ctx: &Context) -> Result Result { }; let epoll_file: Arc = EpollFile::new(); - let mut file_table = ctx.posix_thread.file_table().lock(); - let fd = file_table.insert(epoll_file, fd_flags); + let file_table = ctx.thread_local.file_table().borrow(); + let fd = file_table.write().insert(epoll_file, fd_flags); Ok(SyscallReturn::Return(fd as _)) } @@ -79,14 +79,15 @@ pub fn sys_epoll_ctl( _ => return_errno_with_message!(Errno::EINVAL, "invalid op"), }; - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(epfd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, epfd).into_owned(); + // Drop `file_table` as `EpollFile::control` also performs `file_table().borrow_mut()`. + drop(file_table); + let epoll_file = file .downcast_ref::() .ok_or(Error::with_message(Errno::EINVAL, "not epoll file"))?; - epoll_file.control(&cmd)?; + epoll_file.control(ctx.thread_local, &cmd)?; Ok(SyscallReturn::Return(0 as _)) } @@ -109,13 +110,12 @@ fn do_epoll_wait( None }; - let epoll_file_arc = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(epfd)?.clone() - }; - let epoll_file = epoll_file_arc + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, epfd); + let epoll_file = file .downcast_ref::() .ok_or(Error::with_message(Errno::EINVAL, "not epoll file"))?; + let result = epoll_file.wait(max_events, timeout.as_ref()); // As mentioned in the manual, the return value should be zero if no file descriptor becomes ready diff --git a/kernel/src/syscall/eventfd.rs b/kernel/src/syscall/eventfd.rs index af258437..af69ed76 100644 --- a/kernel/src/syscall/eventfd.rs +++ b/kernel/src/syscall/eventfd.rs @@ -54,13 +54,14 @@ pub fn sys_eventfd2(init_val: u64, flags: u32, ctx: &Context) -> Result FileDesc { let event_file = EventFile::new(init_val, flags); let fd = { - let mut file_table = ctx.posix_thread.file_table().lock(); + let file_table = ctx.thread_local.file_table().borrow(); + let mut file_table_locked = file_table.write(); let fd_flags = if flags.contains(Flags::EFD_CLOEXEC) { FdFlags::CLOEXEC } else { FdFlags::empty() }; - file_table.insert(Arc::new(event_file), fd_flags) + file_table_locked.insert(Arc::new(event_file), fd_flags) }; fd } diff --git a/kernel/src/syscall/execve.rs b/kernel/src/syscall/execve.rs index 66f4e0a3..25a4b940 100644 --- a/kernel/src/syscall/execve.rs +++ b/kernel/src/syscall/execve.rs @@ -9,10 +9,9 @@ use ostd::{ use super::{constants::*, SyscallReturn}; use crate::{ fs::{ - file_table::FileDesc, + file_table::{get_file_fast, FileDesc}, fs_resolver::{FsPath, AT_FDCWD}, path::Dentry, - utils::InodeType, }, prelude::*, process::{ @@ -62,22 +61,22 @@ fn lookup_executable_file( flags: OpenFlags, ctx: &Context, ) -> Result { - let fs_resolver = ctx.posix_thread.fs().resolver().read(); let dentry = if flags.contains(OpenFlags::AT_EMPTY_PATH) && filename.is_empty() { - fs_resolver.lookup_from_fd(dfd) + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, dfd); + file.as_inode_or_err()?.dentry().clone() } else { + let fs_resolver = ctx.posix_thread.fs().resolver().read(); let fs_path = FsPath::new(dfd, &filename)?; if flags.contains(OpenFlags::AT_SYMLINK_NOFOLLOW) { - let dentry = fs_resolver.lookup_no_follow(&fs_path)?; - if dentry.type_() == InodeType::SymLink { - return_errno_with_message!(Errno::ELOOP, "the executable file is a symlink"); - } - Ok(dentry) + fs_resolver.lookup_no_follow(&fs_path)? } else { - fs_resolver.lookup(&fs_path) + fs_resolver.lookup(&fs_path)? } - }?; + }; + check_executable_file(&dentry)?; + Ok(dentry) } @@ -111,7 +110,11 @@ fn do_execve( // Ensure that the file descriptors with the close-on-exec flag are closed. // FIXME: This is just wrong if the file table is shared with other processes. - let closed_files = posix_thread.file_table().lock().close_files_on_exec(); + let closed_files = thread_local + .file_table() + .borrow() + .write() + .close_files_on_exec(); drop(closed_files); debug!("load program to root vmar"); diff --git a/kernel/src/syscall/fallocate.rs b/kernel/src/syscall/fallocate.rs index 91206a7c..dcb5fa55 100644 --- a/kernel/src/syscall/fallocate.rs +++ b/kernel/src/syscall/fallocate.rs @@ -2,7 +2,10 @@ use super::SyscallReturn; use crate::{ - fs::{file_table::FileDesc, utils::FallocMode}, + fs::{ + file_table::{get_file_fast, FileDesc}, + utils::FallocMode, + }, prelude::*, process::ResourceType, }; @@ -21,10 +24,8 @@ pub fn sys_fallocate( check_offset_and_len(offset, len, ctx)?; - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(fd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); let falloc_mode = FallocMode::try_from( RawFallocMode::from_bits(mode as _) diff --git a/kernel/src/syscall/fcntl.rs b/kernel/src/syscall/fcntl.rs index 9bf13b3f..6a23fa6a 100644 --- a/kernel/src/syscall/fcntl.rs +++ b/kernel/src/syscall/fcntl.rs @@ -4,8 +4,7 @@ use super::SyscallReturn; use crate::{ fs::{ file_handle::FileLike, - file_table::{FdFlags, FileDesc}, - inode_handle::InodeHandle, + file_table::{get_file_fast, FdFlags, FileDesc, WithFileTable}, utils::{ FileRange, RangeLockItem, RangeLockItemBuilder, RangeLockType, StatusFlags, OFFSET_MAX, }, @@ -36,16 +35,17 @@ pub fn sys_fcntl(fd: FileDesc, cmd: i32, arg: u64, ctx: &Context) -> Result Result { - let mut file_table = ctx.posix_thread.file_table().lock(); - let new_fd = file_table.dup(fd, arg as FileDesc, flags)?; + let file_table = ctx.thread_local.file_table().borrow(); + let new_fd = file_table.write().dup(fd, arg as FileDesc, flags)?; Ok(SyscallReturn::Return(new_fd as _)) } fn handle_getfd(fd: FileDesc, ctx: &Context) -> Result { - let file_table = ctx.posix_thread.file_table().lock(); - let entry = file_table.get_entry(fd)?; - let fd_flags = entry.flags(); - Ok(SyscallReturn::Return(fd_flags.bits() as _)) + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + file_table.read_with(|inner| { + let fd_flags = inner.get_entry(fd)?.flags(); + Ok(SyscallReturn::Return(fd_flags.bits() as _)) + }) } fn handle_setfd(fd: FileDesc, arg: u64, ctx: &Context) -> Result { @@ -54,17 +54,16 @@ fn handle_setfd(fd: FileDesc, arg: u64, ctx: &Context) -> Result } else { FdFlags::from_bits(arg as u8).ok_or(Error::with_message(Errno::EINVAL, "invalid flags"))? }; - let file_table = ctx.posix_thread.file_table().lock(); - let entry = file_table.get_entry(fd)?; - entry.set_flags(flags); - Ok(SyscallReturn::Return(0)) + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + file_table.read_with(|inner| { + inner.get_entry(fd)?.set_flags(flags); + Ok(SyscallReturn::Return(0)) + }) } fn handle_getfl(fd: FileDesc, ctx: &Context) -> Result { - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(fd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); let status_flags = file.status_flags(); let access_mode = file.access_mode(); Ok(SyscallReturn::Return( @@ -73,10 +72,8 @@ fn handle_getfl(fd: FileDesc, ctx: &Context) -> Result { } fn handle_setfl(fd: FileDesc, arg: u64, ctx: &Context) -> Result { - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(fd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); let valid_flags_mask = StatusFlags::O_APPEND | StatusFlags::O_ASYNC | StatusFlags::O_DIRECT @@ -90,10 +87,8 @@ fn handle_setfl(fd: FileDesc, arg: u64, ctx: &Context) -> Result } fn handle_getlk(fd: FileDesc, arg: u64, ctx: &Context) -> Result { - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(fd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); let lock_mut_ptr = arg as Vaddr; let mut lock_mut_c = ctx.user_space().read_val::(lock_mut_ptr)?; let lock_type = RangeLockType::try_from(lock_mut_c.l_type)?; @@ -102,11 +97,9 @@ fn handle_getlk(fd: FileDesc, arg: u64, ctx: &Context) -> Result } let mut lock = RangeLockItemBuilder::new() .type_(lock_type) - .range(from_c_flock_and_file(&lock_mut_c, file.clone())?) + .range(from_c_flock_and_file(&lock_mut_c, &**file)?) .build()?; - let inode_file = file - .downcast_ref::() - .ok_or(Error::with_message(Errno::EBADF, "not inode"))?; + let inode_file = file.as_inode_or_err()?; lock = inode_file.test_range_lock(lock)?; lock_mut_c.copy_from_range_lock(&lock); ctx.user_space().write_val(lock_mut_ptr, &lock_mut_c)?; @@ -119,29 +112,26 @@ fn handle_setlk( is_nonblocking: bool, ctx: &Context, ) -> Result { - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(fd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); let lock_mut_ptr = arg as Vaddr; let lock_mut_c = ctx.user_space().read_val::(lock_mut_ptr)?; let lock_type = RangeLockType::try_from(lock_mut_c.l_type)?; let lock = RangeLockItemBuilder::new() .type_(lock_type) - .range(from_c_flock_and_file(&lock_mut_c, file.clone())?) + .range(from_c_flock_and_file(&lock_mut_c, &**file)?) .build()?; - let inode_file = file - .downcast_ref::() - .ok_or(Error::with_message(Errno::EBADF, "not inode"))?; + let inode_file = file.as_inode_or_err()?; inode_file.set_range_lock(&lock, is_nonblocking)?; Ok(SyscallReturn::Return(0)) } fn handle_getown(fd: FileDesc, ctx: &Context) -> Result { - let file_table = ctx.posix_thread.file_table().lock(); - let file_entry = file_table.get_entry(fd)?; - let pid = file_entry.owner().unwrap_or(0); - Ok(SyscallReturn::Return(pid as _)) + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + file_table.read_with(|inner| { + let pid = inner.get_entry(fd)?.owner().unwrap_or(0); + Ok(SyscallReturn::Return(pid as _)) + }) } fn handle_setown(fd: FileDesc, arg: u64, ctx: &Context) -> Result { @@ -162,8 +152,9 @@ fn handle_setown(fd: FileDesc, arg: u64, ctx: &Context) -> Result ))?) }; - let mut file_table = ctx.posix_thread.file_table().lock(); - let file_entry = file_table.get_entry_mut(fd)?; + let file_table = ctx.thread_local.file_table().borrow(); + let mut file_table_locked = file_table.write(); + let file_entry = file_table_locked.get_entry_mut(fd)?; file_entry.set_owner(owner_process.as_ref())?; Ok(SyscallReturn::Return(0)) } @@ -230,15 +221,12 @@ impl c_flock { } /// Create the file range through C flock and opened file reference -fn from_c_flock_and_file(lock: &c_flock, file: Arc) -> Result { +fn from_c_flock_and_file(lock: &c_flock, file: &dyn FileLike) -> Result { let start = { let whence = RangeLockWhence::try_from(lock.l_whence)?; match whence { RangeLockWhence::SEEK_SET => lock.l_start, - RangeLockWhence::SEEK_CUR => (file - .downcast_ref::() - .ok_or(Error::with_message(Errno::EBADF, "not inode"))? - .offset() as off_t) + RangeLockWhence::SEEK_CUR => (file.as_inode_or_err()?.offset() as off_t) .checked_add(lock.l_start) .ok_or(Error::with_message(Errno::EOVERFLOW, "start overflow"))?, diff --git a/kernel/src/syscall/flock.rs b/kernel/src/syscall/flock.rs index b1989a6f..915e827f 100644 --- a/kernel/src/syscall/flock.rs +++ b/kernel/src/syscall/flock.rs @@ -3,8 +3,7 @@ use super::SyscallReturn; use crate::{ fs::{ - file_table::FileDesc, - inode_handle::InodeHandle, + file_table::{get_file_fast, FileDesc}, utils::{FlockItem, FlockType}, }, prelude::*, @@ -13,14 +12,9 @@ use crate::{ pub fn sys_flock(fd: FileDesc, ops: i32, ctx: &Context) -> Result { debug!("flock: fd: {}, ops: {:?}", fd, ops); - let file = { - let current = ctx.posix_thread; - let file_table = current.file_table().lock(); - file_table.get_file(fd)?.clone() - }; - let inode_file = file - .downcast_ref::() - .ok_or(Error::with_message(Errno::EBADF, "not inode"))?; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); + let inode_file = file.as_inode_or_err()?; let ops: FlockOps = FlockOps::from_i32(ops)?; if ops.contains(FlockOps::LOCK_UN) { inode_file.unlock_flock(); diff --git a/kernel/src/syscall/fsync.rs b/kernel/src/syscall/fsync.rs index aad82d10..6bd3e5ce 100644 --- a/kernel/src/syscall/fsync.rs +++ b/kernel/src/syscall/fsync.rs @@ -2,21 +2,16 @@ use super::SyscallReturn; use crate::{ - fs::{file_table::FileDesc, inode_handle::InodeHandle}, + fs::file_table::{get_file_fast, FileDesc}, prelude::*, }; pub fn sys_fsync(fd: FileDesc, ctx: &Context) -> Result { debug!("fd = {}", fd); - let dentry = { - let file_table = ctx.posix_thread.file_table().lock(); - let file = file_table.get_file(fd)?; - let inode_handle = file - .downcast_ref::() - .ok_or(Error::with_message(Errno::EINVAL, "not inode"))?; - inode_handle.dentry().clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); + let dentry = file.as_inode_or_err()?.dentry(); dentry.sync_all()?; Ok(SyscallReturn::Return(0)) } @@ -24,14 +19,9 @@ pub fn sys_fsync(fd: FileDesc, ctx: &Context) -> Result { pub fn sys_fdatasync(fd: FileDesc, ctx: &Context) -> Result { debug!("fd = {}", fd); - let dentry = { - let file_table = ctx.posix_thread.file_table().lock(); - let file = file_table.get_file(fd)?; - let inode_handle = file - .downcast_ref::() - .ok_or(Error::with_message(Errno::EINVAL, "not inode"))?; - inode_handle.dentry().clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); + let dentry = file.as_inode_or_err()?.dentry(); dentry.sync_data()?; Ok(SyscallReturn::Return(0)) } diff --git a/kernel/src/syscall/getdents64.rs b/kernel/src/syscall/getdents64.rs index cc3cc188..eeb1e177 100644 --- a/kernel/src/syscall/getdents64.rs +++ b/kernel/src/syscall/getdents64.rs @@ -5,8 +5,7 @@ use core::marker::PhantomData; use super::SyscallReturn; use crate::{ fs::{ - file_table::FileDesc, - inode_handle::InodeHandle, + file_table::{get_file_fast, FileDesc}, utils::{DirentVisitor, InodeType}, }, prelude::*, @@ -23,13 +22,9 @@ pub fn sys_getdents( fd, buf_addr, buf_len ); - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(fd)?.clone() - }; - let inode_handle = file - .downcast_ref::() - .ok_or(Error::with_message(Errno::EBADF, "not inode"))?; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); + let inode_handle = file.as_inode_or_err()?; if inode_handle.dentry().type_() != InodeType::Dir { return_errno!(Errno::ENOTDIR); } @@ -53,13 +48,9 @@ pub fn sys_getdents64( fd, buf_addr, buf_len ); - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(fd)?.clone() - }; - let inode_handle = file - .downcast_ref::() - .ok_or(Error::with_message(Errno::EBADF, "not inode"))?; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); + let inode_handle = file.as_inode_or_err()?; if inode_handle.dentry().type_() != InodeType::Dir { return_errno!(Errno::ENOTDIR); } diff --git a/kernel/src/syscall/getpeername.rs b/kernel/src/syscall/getpeername.rs index a2fa8b40..6cbb39f8 100644 --- a/kernel/src/syscall/getpeername.rs +++ b/kernel/src/syscall/getpeername.rs @@ -1,7 +1,11 @@ // SPDX-License-Identifier: MPL-2.0 use super::SyscallReturn; -use crate::{fs::file_table::FileDesc, prelude::*, util::net::write_socket_addr_to_user}; +use crate::{ + fs::file_table::{get_file_fast, FileDesc}, + prelude::*, + util::net::write_socket_addr_to_user, +}; pub fn sys_getpeername( sockfd: FileDesc, @@ -11,10 +15,8 @@ pub fn sys_getpeername( ) -> Result { debug!("sockfd = {sockfd}, addr = 0x{addr:x}, addrlen_ptr = 0x{addrlen_ptr:x}"); - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(sockfd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, sockfd); let socket = file.as_socket_or_err()?; let peer_addr = socket.peer_addr()?; diff --git a/kernel/src/syscall/getsockname.rs b/kernel/src/syscall/getsockname.rs index bf16df4f..7a69456e 100644 --- a/kernel/src/syscall/getsockname.rs +++ b/kernel/src/syscall/getsockname.rs @@ -1,7 +1,11 @@ // SPDX-License-Identifier: MPL-2.0 use super::SyscallReturn; -use crate::{fs::file_table::FileDesc, prelude::*, util::net::write_socket_addr_to_user}; +use crate::{ + fs::file_table::{get_file_fast, FileDesc}, + prelude::*, + util::net::write_socket_addr_to_user, +}; pub fn sys_getsockname( sockfd: FileDesc, @@ -11,10 +15,8 @@ pub fn sys_getsockname( ) -> Result { debug!("sockfd = {sockfd}, addr = 0x{addr:x}, addrlen_ptr = 0x{addrlen_ptr:x}"); - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(sockfd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, sockfd); let socket = file.as_socket_or_err()?; let socket_addr = socket.addr()?; diff --git a/kernel/src/syscall/getsockopt.rs b/kernel/src/syscall/getsockopt.rs index 2ae24e64..b3b407e8 100644 --- a/kernel/src/syscall/getsockopt.rs +++ b/kernel/src/syscall/getsockopt.rs @@ -2,7 +2,7 @@ use super::SyscallReturn; use crate::{ - fs::file_table::FileDesc, + fs::file_table::{get_file_fast, FileDesc}, prelude::*, util::net::{new_raw_socket_option, CSocketOptionLevel}, }; @@ -25,10 +25,8 @@ pub fn sys_getsockopt( debug!("level = {level:?}, sockfd = {sockfd}, optname = {optname:?}, optlen = {optlen}"); - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(sockfd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, sockfd); let socket = file.as_socket_or_err()?; let mut raw_option = new_raw_socket_option(level, optname)?; diff --git a/kernel/src/syscall/ioctl.rs b/kernel/src/syscall/ioctl.rs index 0c461a4e..7b094abb 100644 --- a/kernel/src/syscall/ioctl.rs +++ b/kernel/src/syscall/ioctl.rs @@ -3,7 +3,7 @@ use super::SyscallReturn; use crate::{ fs::{ - file_table::{FdFlags, FileDesc}, + file_table::{get_file_fast, FdFlags, FileDesc, WithFileTable}, utils::{IoctlCmd, StatusFlags}, }, prelude::*, @@ -16,10 +16,8 @@ pub fn sys_ioctl(fd: FileDesc, cmd: u32, arg: Vaddr, ctx: &Context) -> Result { let is_nonblocking = ctx.user_space().read_val::(arg)? != 0; @@ -43,21 +41,31 @@ pub fn sys_ioctl(fd: FileDesc, cmd: u32, arg: Vaddr, ctx: &Context) -> Result(0) + })? } IoctlCmd::FIONCLEX => { // Clears the close-on-exec flag of the file. - let file_table = ctx.posix_thread.file_table().lock(); - let entry = file_table.get_entry(fd)?; - entry.set_flags(entry.flags() & (!FdFlags::CLOEXEC)); - 0 + // Follow the implementation of fcntl() + + file_table.read_with(|inner| { + let entry = inner.get_entry(fd)?; + entry.set_flags(entry.flags() - FdFlags::CLOEXEC); + Ok::<_, Error>(0) + })? } // FIXME: ioctl operations involving blocking I/O should be able to restart if interrupted - _ => file.ioctl(ioctl_cmd, arg)?, + _ => { + let file_owned = file.into_owned(); + // We have to drop `file_table` because some I/O command will modify the file table + // (e.g., TIOCGPTPEER). + drop(file_table); + + file_owned.ioctl(ioctl_cmd, arg)? + } }; Ok(SyscallReturn::Return(res as _)) } diff --git a/kernel/src/syscall/listen.rs b/kernel/src/syscall/listen.rs index 3f8a2087..a0fd8b0d 100644 --- a/kernel/src/syscall/listen.rs +++ b/kernel/src/syscall/listen.rs @@ -1,15 +1,16 @@ // SPDX-License-Identifier: MPL-2.0 use super::SyscallReturn; -use crate::{fs::file_table::FileDesc, prelude::*}; +use crate::{ + fs::file_table::{get_file_fast, FileDesc}, + prelude::*, +}; pub fn sys_listen(sockfd: FileDesc, backlog: i32, ctx: &Context) -> Result { debug!("sockfd = {sockfd}, backlog = {backlog}"); - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(sockfd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, sockfd); let socket = file.as_socket_or_err()?; socket.listen(backlog as usize)?; diff --git a/kernel/src/syscall/lseek.rs b/kernel/src/syscall/lseek.rs index a487e621..ab5d35c7 100644 --- a/kernel/src/syscall/lseek.rs +++ b/kernel/src/syscall/lseek.rs @@ -2,7 +2,10 @@ use super::SyscallReturn; use crate::{ - fs::{file_table::FileDesc, utils::SeekFrom}, + fs::{ + file_table::{get_file_fast, FileDesc}, + utils::SeekFrom, + }, prelude::*, }; @@ -20,10 +23,8 @@ pub fn sys_lseek(fd: FileDesc, offset: isize, whence: u32, ctx: &Context) -> Res 2 => SeekFrom::End(offset), _ => return_errno!(Errno::EINVAL), }; - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(fd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); let offset = file.seek(seek_from)?; Ok(SyscallReturn::Return(offset as _)) diff --git a/kernel/src/syscall/mmap.rs b/kernel/src/syscall/mmap.rs index 2a17f29e..fbbaa084 100644 --- a/kernel/src/syscall/mmap.rs +++ b/kernel/src/syscall/mmap.rs @@ -7,7 +7,10 @@ use aster_rights::Rights; use super::SyscallReturn; use crate::{ - fs::{file_handle::FileLike, file_table::FileDesc, inode_handle::InodeHandle}, + fs::{ + file_handle::FileLike, + file_table::{get_file_fast, FileDesc}, + }, prelude::*, vm::{ perms::VmPerms, @@ -121,11 +124,9 @@ fn do_sys_mmap( } } else { let vmo = { - let file_table = ctx.posix_thread.file_table().lock(); - let file = file_table.get_file(fd)?; - let inode_handle = file - .downcast_ref::() - .ok_or(Error::with_message(Errno::EINVAL, "no inode"))?; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); + let inode_handle = file.as_inode_or_err()?; let access_mode = inode_handle.access_mode(); if vm_perms.contains(VmPerms::READ) && !access_mode.is_readable() { diff --git a/kernel/src/syscall/open.rs b/kernel/src/syscall/open.rs index db0dcccf..059037ad 100644 --- a/kernel/src/syscall/open.rs +++ b/kernel/src/syscall/open.rs @@ -40,16 +40,19 @@ pub fn sys_openat( })?; Arc::new(inode_handle) }; - let mut file_table = current.file_table().lock(); + let fd = { + let file_table = ctx.thread_local.file_table().borrow(); + let mut file_table_locked = file_table.write(); let fd_flags = if CreationFlags::from_bits_truncate(flags).contains(CreationFlags::O_CLOEXEC) { FdFlags::CLOEXEC } else { FdFlags::empty() }; - file_table.insert(file_handle, fd_flags) + file_table_locked.insert(file_handle, fd_flags) }; + Ok(SyscallReturn::Return(fd as _)) } diff --git a/kernel/src/syscall/pipe.rs b/kernel/src/syscall/pipe.rs index 650075e9..ba02cdea 100644 --- a/kernel/src/syscall/pipe.rs +++ b/kernel/src/syscall/pipe.rs @@ -21,17 +21,18 @@ pub fn sys_pipe2(fds: Vaddr, flags: u32, ctx: &Context) -> Result FdFlags::empty() }; - let mut file_table = ctx.posix_thread.file_table().lock(); + let file_table = ctx.thread_local.file_table().borrow(); + let mut file_table_locked = file_table.write(); let pipe_fds = PipeFds { - reader_fd: file_table.insert(pipe_reader, fd_flags), - writer_fd: file_table.insert(pipe_writer, fd_flags), + reader_fd: file_table_locked.insert(pipe_reader, fd_flags), + writer_fd: file_table_locked.insert(pipe_writer, fd_flags), }; debug!("pipe_fds: {:?}", pipe_fds); if let Err(err) = ctx.user_space().write_val(fds, &pipe_fds) { - file_table.close_file(pipe_fds.reader_fd).unwrap(); - file_table.close_file(pipe_fds.writer_fd).unwrap(); + file_table_locked.close_file(pipe_fds.reader_fd).unwrap(); + file_table_locked.close_file(pipe_fds.writer_fd).unwrap(); return Err(err); } diff --git a/kernel/src/syscall/poll.rs b/kernel/src/syscall/poll.rs index 55e528ea..114a20bd 100644 --- a/kernel/src/syscall/poll.rs +++ b/kernel/src/syscall/poll.rs @@ -1,11 +1,15 @@ // SPDX-License-Identifier: MPL-2.0 +use alloc::borrow::Cow; use core::{cell::Cell, time::Duration}; use super::SyscallReturn; use crate::{ events::IoEvents, - fs::{file_handle::FileLike, file_table::FileDesc}, + fs::{ + file_handle::FileLike, + file_table::{FileDesc, FileTable}, + }, prelude::*, process::signal::Poller, }; @@ -56,7 +60,15 @@ pub fn sys_poll(fds: Vaddr, nfds: u64, timeout: i32, ctx: &Context) -> Result, ctx: &Context) -> Result { - let (result, files) = hold_files(poll_fds, ctx); + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let (result, files) = if let Some(file_table_inner) = file_table.get() { + hold_files(poll_fds, file_table_inner, Cow::Borrowed) + } else { + let file_table_locked = file_table.read(); + hold_files(poll_fds, &file_table_locked, |file| { + Cow::Owned(file.clone()) + }) + }; match result { FileResult::AllValid => (), FileResult::SomeInvalid => { @@ -99,9 +111,14 @@ enum FileResult { } /// Holds all the files we're going to poll. -fn hold_files(poll_fds: &[PollFd], ctx: &Context) -> (FileResult, Vec>>) { - let file_table = ctx.posix_thread.file_table().lock(); - +fn hold_files<'a, F, R>( + poll_fds: &[PollFd], + file_table: &'a FileTable, + f: F, +) -> (FileResult, Vec>) +where + F: Fn(&'a Arc) -> R, +{ let mut files = Vec::with_capacity(poll_fds.len()); let mut result = FileResult::AllValid; @@ -119,7 +136,7 @@ fn hold_files(poll_fds: &[PollFd], ctx: &Context) -> (FileResult, Vec>]) -> PollerResult { +fn register_poller(poll_fds: &[PollFd], files: &[Option>>]) -> PollerResult { let mut poller = Poller::new(); for (i, (poll_fd, file)) in poll_fds.iter().zip(files.iter()).enumerate() { @@ -152,7 +169,7 @@ fn register_poller(poll_fds: &[PollFd], files: &[Option>]) -> } /// Counts the number of the ready files. -fn count_all_events(poll_fds: &[PollFd], files: &[Option>]) -> usize { +fn count_all_events(poll_fds: &[PollFd], files: &[Option>>]) -> usize { let mut counter = 0; for (poll_fd, file) in poll_fds.iter().zip(files.iter()) { diff --git a/kernel/src/syscall/pread64.rs b/kernel/src/syscall/pread64.rs index a20adcb2..7366fc57 100644 --- a/kernel/src/syscall/pread64.rs +++ b/kernel/src/syscall/pread64.rs @@ -1,7 +1,10 @@ // SPDX-License-Identifier: MPL-2.0 use super::SyscallReturn; -use crate::{fs::file_table::FileDesc, prelude::*}; +use crate::{ + fs::file_table::{get_file_fast, FileDesc}, + prelude::*, +}; pub fn sys_pread64( fd: FileDesc, @@ -18,10 +21,10 @@ pub fn sys_pread64( if offset < 0 { return_errno_with_message!(Errno::EINVAL, "offset cannot be negative"); } - let file = { - let filetable = ctx.posix_thread.file_table().lock(); - filetable.get_file(fd)?.clone() - }; + + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); + // TODO: Check (f.file->f_mode & FMODE_PREAD); We don't have f_mode in our FileLike trait if user_buf_len == 0 { return Ok(SyscallReturn::Return(0)); diff --git a/kernel/src/syscall/preadv.rs b/kernel/src/syscall/preadv.rs index 5a62b90c..527c1f41 100644 --- a/kernel/src/syscall/preadv.rs +++ b/kernel/src/syscall/preadv.rs @@ -2,7 +2,7 @@ use super::SyscallReturn; use crate::{ - fs::file_table::FileDesc, + fs::file_table::{get_file_fast, FileDesc}, prelude::*, util::{MultiWrite, VmWriterArray}, }; @@ -65,10 +65,8 @@ fn do_sys_preadv( return_errno_with_message!(Errno::EINVAL, "offset cannot be negative"); } - let file = { - let filetable = ctx.posix_thread.file_table().lock(); - filetable.get_file(fd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); if io_vec_count == 0 { return Ok(0); @@ -127,10 +125,8 @@ fn do_sys_readv( fd, io_vec_ptr, io_vec_count ); - let file = { - let filetable = ctx.posix_thread.file_table().lock(); - filetable.get_file(fd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); if io_vec_count == 0 { return Ok(0); diff --git a/kernel/src/syscall/pwrite64.rs b/kernel/src/syscall/pwrite64.rs index 69fb333f..64c4927a 100644 --- a/kernel/src/syscall/pwrite64.rs +++ b/kernel/src/syscall/pwrite64.rs @@ -1,7 +1,10 @@ // SPDX-License-Identifier: MPL-2.0 use super::SyscallReturn; -use crate::{fs::file_table::FileDesc, prelude::*}; +use crate::{ + fs::file_table::{get_file_fast, FileDesc}, + prelude::*, +}; pub fn sys_pwrite64( fd: FileDesc, @@ -14,13 +17,14 @@ pub fn sys_pwrite64( "fd = {}, user_buf_ptr = 0x{:x}, user_buf_len = 0x{:x}, offset = 0x{:x}", fd, user_buf_ptr, user_buf_len, offset ); + if offset < 0 { return_errno_with_message!(Errno::EINVAL, "offset cannot be negative"); } - let file = { - let filetable = ctx.posix_thread.file_table().lock(); - filetable.get_file(fd)?.clone() - }; + + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); + // TODO: Check (f.file->f_mode & FMODE_PWRITE); We don't have f_mode in our FileLike trait if user_buf_len == 0 { return Ok(SyscallReturn::Return(0)); diff --git a/kernel/src/syscall/pwritev.rs b/kernel/src/syscall/pwritev.rs index c2975cdd..b44aa6c5 100644 --- a/kernel/src/syscall/pwritev.rs +++ b/kernel/src/syscall/pwritev.rs @@ -1,7 +1,11 @@ // SPDX-License-Identifier: MPL-2.0 use super::SyscallReturn; -use crate::{fs::file_table::FileDesc, prelude::*, util::VmReaderArray}; +use crate::{ + fs::file_table::{get_file_fast, FileDesc}, + prelude::*, + util::VmReaderArray, +}; pub fn sys_writev( fd: FileDesc, @@ -57,13 +61,14 @@ fn do_sys_pwritev( "fd = {}, io_vec_ptr = 0x{:x}, io_vec_counter = 0x{:x}, offset = 0x{:x}", fd, io_vec_ptr, io_vec_count, offset ); + if offset < 0 { return_errno_with_message!(Errno::EINVAL, "offset cannot be negative"); } - let file = { - let filetable = ctx.posix_thread.file_table().lock(); - filetable.get_file(fd)?.clone() - }; + + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); + // TODO: Check (f.file->f_mode & FMODE_PREAD); We don't have f_mode in our FileLike trait if io_vec_count == 0 { return Ok(0); @@ -116,10 +121,10 @@ fn do_sys_writev( "fd = {}, io_vec_ptr = 0x{:x}, io_vec_counter = 0x{:x}", fd, io_vec_ptr, io_vec_count ); - let file = { - let filetable = ctx.posix_thread.file_table().lock(); - filetable.get_file(fd)?.clone() - }; + + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); + let mut total_len = 0; let mut reader_array = VmReaderArray::from_user_io_vecs(ctx, io_vec_ptr, io_vec_count)?; diff --git a/kernel/src/syscall/read.rs b/kernel/src/syscall/read.rs index 000d1b7a..3635cbdf 100644 --- a/kernel/src/syscall/read.rs +++ b/kernel/src/syscall/read.rs @@ -1,7 +1,10 @@ // SPDX-License-Identifier: MPL-2.0 use super::SyscallReturn; -use crate::{fs::file_table::FileDesc, prelude::*}; +use crate::{ + fs::file_table::{get_file_fast, FileDesc}, + prelude::*, +}; pub fn sys_read( fd: FileDesc, @@ -14,10 +17,8 @@ pub fn sys_read( fd, user_buf_addr, buf_len ); - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(fd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); // According to , if // the user specified an empty buffer, we should detect errors by checking diff --git a/kernel/src/syscall/recvfrom.rs b/kernel/src/syscall/recvfrom.rs index 98eb50d3..47c8cfb2 100644 --- a/kernel/src/syscall/recvfrom.rs +++ b/kernel/src/syscall/recvfrom.rs @@ -2,7 +2,9 @@ use super::SyscallReturn; use crate::{ - fs::file_table::FileDesc, net::socket::SendRecvFlags, prelude::*, + fs::file_table::{get_file_fast, FileDesc}, + net::socket::SendRecvFlags, + prelude::*, util::net::write_socket_addr_to_user, }; @@ -18,10 +20,8 @@ pub fn sys_recvfrom( let flags = SendRecvFlags::from_bits_truncate(flags); debug!("sockfd = {sockfd}, buf = 0x{buf:x}, len = {len}, flags = {flags:?}, src_addr = 0x{src_addr:x}, addrlen_ptr = 0x{addrlen_ptr:x}"); - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(sockfd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, sockfd); let socket = file.as_socket_or_err()?; let mut writers = { diff --git a/kernel/src/syscall/recvmsg.rs b/kernel/src/syscall/recvmsg.rs index 824deac7..9f76d61f 100644 --- a/kernel/src/syscall/recvmsg.rs +++ b/kernel/src/syscall/recvmsg.rs @@ -2,7 +2,10 @@ use super::SyscallReturn; use crate::{ - fs::file_table::FileDesc, net::socket::SendRecvFlags, prelude::*, util::net::CUserMsgHdr, + fs::file_table::{get_file_fast, FileDesc}, + net::socket::SendRecvFlags, + prelude::*, + util::net::CUserMsgHdr, }; pub fn sys_recvmsg( @@ -19,10 +22,8 @@ pub fn sys_recvmsg( sockfd, c_user_msghdr, flags ); - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(sockfd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, sockfd); let socket = file.as_socket_or_err()?; let (total_bytes, message_header) = { diff --git a/kernel/src/syscall/sendfile.rs b/kernel/src/syscall/sendfile.rs index 6891fc74..f8b47960 100644 --- a/kernel/src/syscall/sendfile.rs +++ b/kernel/src/syscall/sendfile.rs @@ -1,7 +1,10 @@ // SPDX-License-Identifier: MPL-2.0 use super::SyscallReturn; -use crate::{fs::file_table::FileDesc, prelude::*}; +use crate::{ + fs::file_table::{FileDesc, WithFileTable}, + prelude::*, +}; pub fn sys_sendfile( out_fd: FileDesc, @@ -33,13 +36,16 @@ pub fn sys_sendfile( count as usize }; - let (out_file, in_file) = { - let file_table = ctx.posix_thread.file_table().lock(); - let out_file = file_table.get_file(out_fd)?.clone(); - // FIXME: the in_file must support mmap-like operations (i.e., it cannot be a socket). - let in_file = file_table.get_file(in_fd)?.clone(); - (out_file, in_file) - }; + let (out_file, in_file) = ctx + .thread_local + .file_table() + .borrow_mut() + .read_with(|inner| { + let out_file = inner.get_file(out_fd)?.clone(); + // FIXME: the in_file must support mmap-like operations (i.e., it cannot be a socket). + let in_file = inner.get_file(in_fd)?.clone(); + Ok::<_, Error>((out_file, in_file)) + })?; // sendfile can send at most `MAX_COUNT` bytes const MAX_COUNT: usize = 0x7fff_f000; diff --git a/kernel/src/syscall/sendmsg.rs b/kernel/src/syscall/sendmsg.rs index 0c74373d..46b45749 100644 --- a/kernel/src/syscall/sendmsg.rs +++ b/kernel/src/syscall/sendmsg.rs @@ -2,7 +2,7 @@ use super::SyscallReturn; use crate::{ - fs::file_table::FileDesc, + fs::file_table::{get_file_fast, FileDesc}, net::socket::{MessageHeader, SendRecvFlags}, prelude::*, util::net::CUserMsgHdr, @@ -22,10 +22,8 @@ pub fn sys_sendmsg( sockfd, c_user_msghdr, flags ); - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(sockfd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, sockfd); let socket = file.as_socket_or_err()?; let (mut io_vec_reader, message_header) = { diff --git a/kernel/src/syscall/sendto.rs b/kernel/src/syscall/sendto.rs index f2c70672..a213969e 100644 --- a/kernel/src/syscall/sendto.rs +++ b/kernel/src/syscall/sendto.rs @@ -2,7 +2,7 @@ use super::SyscallReturn; use crate::{ - fs::file_table::FileDesc, + fs::file_table::{get_file_fast, FileDesc}, net::socket::{MessageHeader, SendRecvFlags}, prelude::*, util::net::read_socket_addr_from_user, @@ -26,10 +26,8 @@ pub fn sys_sendto( }; debug!("sockfd = {sockfd}, buf = 0x{buf:x}, len = 0x{len:x}, flags = {flags:?}, socket_addr = {socket_addr:?}"); - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(sockfd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, sockfd); let socket = file.as_socket_or_err()?; let message_header = MessageHeader::new(socket_addr, None); diff --git a/kernel/src/syscall/setsockopt.rs b/kernel/src/syscall/setsockopt.rs index 0cee2199..aaa56009 100644 --- a/kernel/src/syscall/setsockopt.rs +++ b/kernel/src/syscall/setsockopt.rs @@ -2,7 +2,7 @@ use super::SyscallReturn; use crate::{ - fs::file_table::FileDesc, + fs::file_table::{get_file_fast, FileDesc}, prelude::*, util::net::{new_raw_socket_option, CSocketOptionLevel}, }; @@ -25,10 +25,8 @@ pub fn sys_setsockopt( level, sockfd, optname, optlen ); - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(sockfd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, sockfd); let socket = file.as_socket_or_err()?; let raw_option = { diff --git a/kernel/src/syscall/shutdown.rs b/kernel/src/syscall/shutdown.rs index 4870b073..ccb7e212 100644 --- a/kernel/src/syscall/shutdown.rs +++ b/kernel/src/syscall/shutdown.rs @@ -1,16 +1,18 @@ // SPDX-License-Identifier: MPL-2.0 use super::SyscallReturn; -use crate::{fs::file_table::FileDesc, net::socket::SockShutdownCmd, prelude::*}; +use crate::{ + fs::file_table::{get_file_fast, FileDesc}, + net::socket::SockShutdownCmd, + prelude::*, +}; pub fn sys_shutdown(sockfd: FileDesc, how: i32, ctx: &Context) -> Result { let shutdown_cmd = SockShutdownCmd::try_from(how)?; debug!("sockfd = {sockfd}, cmd = {shutdown_cmd:?}"); - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(sockfd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, sockfd); let socket = file.as_socket_or_err()?; socket.shutdown(shutdown_cmd)?; diff --git a/kernel/src/syscall/socket.rs b/kernel/src/syscall/socket.rs index fdb9a813..21dda135 100644 --- a/kernel/src/syscall/socket.rs +++ b/kernel/src/syscall/socket.rs @@ -43,13 +43,14 @@ pub fn sys_socket(domain: i32, type_: i32, protocol: i32, ctx: &Context) -> Resu _ => return_errno_with_message!(Errno::EAFNOSUPPORT, "unsupported domain"), }; let fd = { - let mut file_table = ctx.posix_thread.file_table().lock(); + let file_table = ctx.thread_local.file_table().borrow(); + let mut file_table_locked = file_table.write(); let fd_flags = if sock_flags.contains(SockFlags::SOCK_CLOEXEC) { FdFlags::CLOEXEC } else { FdFlags::empty() }; - file_table.insert(file_like, fd_flags) + file_table_locked.insert(file_like, fd_flags) }; Ok(SyscallReturn::Return(fd as _)) } diff --git a/kernel/src/syscall/socketpair.rs b/kernel/src/syscall/socketpair.rs index 285c176a..6b2fda41 100644 --- a/kernel/src/syscall/socketpair.rs +++ b/kernel/src/syscall/socketpair.rs @@ -37,14 +37,15 @@ pub fn sys_socketpair( }; let socket_fds = { - let mut file_table = ctx.posix_thread.file_table().lock(); + let file_table = ctx.thread_local.file_table().borrow(); + let mut file_table_locked = file_table.write(); let fd_flags = if sock_flags.contains(SockFlags::SOCK_CLOEXEC) { FdFlags::CLOEXEC } else { FdFlags::empty() }; - let fd_a = file_table.insert(socket_a, fd_flags); - let fd_b = file_table.insert(socket_b, fd_flags); + let fd_a = file_table_locked.insert(socket_a, fd_flags); + let fd_b = file_table_locked.insert(socket_b, fd_flags); SocketFds(fd_a, fd_b) }; diff --git a/kernel/src/syscall/stat.rs b/kernel/src/syscall/stat.rs index 6667338c..c31bc64e 100644 --- a/kernel/src/syscall/stat.rs +++ b/kernel/src/syscall/stat.rs @@ -3,7 +3,7 @@ use super::SyscallReturn; use crate::{ fs::{ - file_table::FileDesc, + file_table::{get_file_fast, FileDesc}, fs_resolver::{FsPath, AT_FDCWD}, utils::Metadata, }, @@ -15,13 +15,12 @@ use crate::{ pub fn sys_fstat(fd: FileDesc, stat_buf_ptr: Vaddr, ctx: &Context) -> Result { debug!("fd = {}, stat_buf_addr = 0x{:x}", fd, stat_buf_ptr); - let file = { - let file_table = ctx.posix_thread.file_table().lock(); - file_table.get_file(fd)?.clone() - }; + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); let stat = Stat::from(file.metadata()); ctx.user_space().write_val(stat_buf_ptr, &stat)?; + Ok(SyscallReturn::Return(0)) } diff --git a/kernel/src/syscall/statfs.rs b/kernel/src/syscall/statfs.rs index cca0b4a7..eb9c00a3 100644 --- a/kernel/src/syscall/statfs.rs +++ b/kernel/src/syscall/statfs.rs @@ -3,9 +3,8 @@ use super::SyscallReturn; use crate::{ fs::{ - file_table::FileDesc, + file_table::{get_file_fast, FileDesc}, fs_resolver::FsPath, - inode_handle::InodeHandle, utils::{SuperBlock, PATH_MAX}, }, prelude::*, @@ -30,12 +29,9 @@ pub fn sys_fstatfs(fd: FileDesc, statfs_buf_ptr: Vaddr, ctx: &Context) -> Result debug!("fd = {}, statfs_buf_addr = 0x{:x}", fd, statfs_buf_ptr); let fs = { - let file_table = ctx.posix_thread.file_table().lock(); - let file = file_table.get_file(fd)?; - let inode_handle = file - .downcast_ref::() - .ok_or(Error::with_message(Errno::EBADF, "not inode"))?; - inode_handle.dentry().fs() + let mut file_table = ctx.thread_local.file_table().borrow_mut(); + let file = get_file_fast!(&mut file_table, fd); + file.as_inode_or_err()?.dentry().fs() }; let statfs = Statfs::from(fs.sb()); diff --git a/kernel/src/syscall/truncate.rs b/kernel/src/syscall/truncate.rs index acafade1..d6982b43 100644 --- a/kernel/src/syscall/truncate.rs +++ b/kernel/src/syscall/truncate.rs @@ -3,7 +3,7 @@ use super::SyscallReturn; use crate::{ fs::{ - file_table::FileDesc, + file_table::{get_file_fast, FileDesc}, fs_resolver::{FsPath, AT_FDCWD}, utils::PATH_MAX, }, @@ -16,11 +16,8 @@ pub fn sys_ftruncate(fd: FileDesc, len: isize, ctx: &Context) -> Result, if // the user specified an empty buffer, we should detect errors by checking